summaryrefslogtreecommitdiffstatshomepage
path: root/src/mess/machine
diff options
context:
space:
mode:
author Miodrag Milanovic <mmicko@gmail.com>2012-08-21 10:41:19 +0000
committer Miodrag Milanovic <mmicko@gmail.com>2012-08-21 10:41:19 +0000
commit7285b359d259b2ae0fdf85096571c386ec8c991a (patch)
treea027aff57f1a255f9ec6cfd3b68cabe4b6683998 /src/mess/machine
parent67c425e90757876a6716b7867df30c0149912e74 (diff)
Merge of MESS sources (no whatsnew)
Diffstat (limited to 'src/mess/machine')
-rw-r--r--src/mess/machine/3c503.c308
-rw-r--r--src/mess/machine/3c503.h63
-rw-r--r--src/mess/machine/3c505.c1448
-rw-r--r--src/mess/machine/3c505.h297
-rw-r--r--src/mess/machine/64h156.c714
-rw-r--r--src/mess/machine/64h156.h204
-rw-r--r--src/mess/machine/6883sam.c427
-rw-r--r--src/mess/machine/6883sam.h229
-rw-r--r--src/mess/machine/74145.c178
-rw-r--r--src/mess/machine/74145.h83
-rw-r--r--src/mess/machine/8530scc.c675
-rw-r--r--src/mess/machine/8530scc.h101
-rw-r--r--src/mess/machine/990_dk.c881
-rw-r--r--src/mess/machine/990_dk.h10
-rw-r--r--src/mess/machine/990_hd.c1053
-rw-r--r--src/mess/machine/990_hd.h18
-rw-r--r--src/mess/machine/990_tap.c1093
-rw-r--r--src/mess/machine/990_tap.h25
-rw-r--r--src/mess/machine/a2alfam2.c112
-rw-r--r--src/mess/machine/a2alfam2.h48
-rw-r--r--src/mess/machine/a2bus.c285
-rw-r--r--src/mess/machine/a2bus.h166
-rw-r--r--src/mess/machine/a2cffa.c264
-rw-r--r--src/mess/machine/a2cffa.h83
-rw-r--r--src/mess/machine/a2diskii.c162
-rw-r--r--src/mess/machine/a2diskii.h65
-rw-r--r--src/mess/machine/a2eauxslot.c198
-rw-r--r--src/mess/machine/a2eauxslot.h144
-rw-r--r--src/mess/machine/a2echoii.c105
-rw-r--r--src/mess/machine/a2echoii.h47
-rw-r--r--src/mess/machine/a2lang.c117
-rw-r--r--src/mess/machine/a2lang.h43
-rw-r--r--src/mess/machine/a2memexp.c231
-rw-r--r--src/mess/machine/a2memexp.h71
-rw-r--r--src/mess/machine/a2mockingboard.c510
-rw-r--r--src/mess/machine/a2mockingboard.h85
-rw-r--r--src/mess/machine/a2sam.c88
-rw-r--r--src/mess/machine/a2sam.h47
-rw-r--r--src/mess/machine/a2scsi.c249
-rw-r--r--src/mess/machine/a2scsi.h57
-rw-r--r--src/mess/machine/a2softcard.c192
-rw-r--r--src/mess/machine/a2softcard.h54
-rw-r--r--src/mess/machine/a2ssc.c214
-rw-r--r--src/mess/machine/a2ssc.h53
-rw-r--r--src/mess/machine/a2swyft.c138
-rw-r--r--src/mess/machine/a2swyft.h47
-rw-r--r--src/mess/machine/a2themill.c345
-rw-r--r--src/mess/machine/a2themill.h57
-rw-r--r--src/mess/machine/a2thunderclock.c186
-rw-r--r--src/mess/machine/a2thunderclock.h56
-rw-r--r--src/mess/machine/a2videoterm.c376
-rw-r--r--src/mess/machine/a2videoterm.h108
-rw-r--r--src/mess/machine/a7800.c531
-rw-r--r--src/mess/machine/abc1600_bus.c564
-rw-r--r--src/mess/machine/abc1600_bus.h220
-rw-r--r--src/mess/machine/abc77.c667
-rw-r--r--src/mess/machine/abc77.h142
-rw-r--r--src/mess/machine/abc800kb.c518
-rw-r--r--src/mess/machine/abc800kb.h113
-rw-r--r--src/mess/machine/abc80kb.c228
-rw-r--r--src/mess/machine/abc80kb.h89
-rw-r--r--src/mess/machine/abc830.c143
-rw-r--r--src/mess/machine/abc830.h44
-rw-r--r--src/mess/machine/abc890.c305
-rw-r--r--src/mess/machine/abc890.h113
-rw-r--r--src/mess/machine/abc99.c858
-rw-r--r--src/mess/machine/abc99.h130
-rw-r--r--src/mess/machine/abc_dos.c143
-rw-r--r--src/mess/machine/abc_dos.h53
-rw-r--r--src/mess/machine/abc_fd2.c248
-rw-r--r--src/mess/machine/abc_fd2.h68
-rw-r--r--src/mess/machine/abc_hdc.c186
-rw-r--r--src/mess/machine/abc_hdc.h63
-rw-r--r--src/mess/machine/abc_sio.c196
-rw-r--r--src/mess/machine/abc_sio.h53
-rw-r--r--src/mess/machine/abc_slutprov.c77
-rw-r--r--src/mess/machine/abc_slutprov.h44
-rw-r--r--src/mess/machine/abc_turbo.c172
-rw-r--r--src/mess/machine/abc_turbo.h63
-rw-r--r--src/mess/machine/abc_uni800.c108
-rw-r--r--src/mess/machine/abc_uni800.h44
-rw-r--r--src/mess/machine/abc_xebec.c179
-rw-r--r--src/mess/machine/abc_xebec.h63
-rw-r--r--src/mess/machine/abcbus.c374
-rw-r--r--src/mess/machine/abcbus.h218
-rw-r--r--src/mess/machine/ac1.c121
-rw-r--r--src/mess/machine/advision.c176
-rw-r--r--src/mess/machine/aim65.c419
-rw-r--r--src/mess/machine/amigacd.c539
-rw-r--r--src/mess/machine/amigacd.h14
-rw-r--r--src/mess/machine/amigacrt.c463
-rw-r--r--src/mess/machine/amigacrt.h8
-rw-r--r--src/mess/machine/amigakbd.c254
-rw-r--r--src/mess/machine/amigakbd.h8
-rw-r--r--src/mess/machine/amstr_pc.c420
-rw-r--r--src/mess/machine/amstrad.c3307
-rw-r--r--src/mess/machine/ap2_lang.c122
-rw-r--r--src/mess/machine/ap2_lang.h35
-rw-r--r--src/mess/machine/ap2_slot.c233
-rw-r--r--src/mess/machine/ap2_slot.h85
-rw-r--r--src/mess/machine/apollo.c1475
-rw-r--r--src/mess/machine/apollo_dbg.c1185
-rw-r--r--src/mess/machine/apollo_eth.c355
-rw-r--r--src/mess/machine/apollo_kbd.c1182
-rw-r--r--src/mess/machine/apollo_kbd.h201
-rw-r--r--src/mess/machine/apollo_net.c890
-rw-r--r--src/mess/machine/apple1.c554
-rw-r--r--src/mess/machine/apple2.c1952
-rw-r--r--src/mess/machine/apple2gs.c2033
-rw-r--r--src/mess/machine/apple3.c738
-rw-r--r--src/mess/machine/applefdc.c863
-rw-r--r--src/mess/machine/applefdc.h93
-rw-r--r--src/mess/machine/apricotkb.c412
-rw-r--r--src/mess/machine/apricotkb.h97
-rw-r--r--src/mess/machine/at.c347
-rw-r--r--src/mess/machine/at29040a.c444
-rw-r--r--src/mess/machine/at29040a.h89
-rw-r--r--src/mess/machine/at45dbxx.c473
-rw-r--r--src/mess/machine/at45dbxx.h55
-rw-r--r--src/mess/machine/at_keybc.c229
-rw-r--r--src/mess/machine/at_keybc.h98
-rw-r--r--src/mess/machine/ataricrt.c718
-rw-r--r--src/mess/machine/ataridev.h55
-rw-r--r--src/mess/machine/atarifdc.c844
-rw-r--r--src/mess/machine/avr8.h297
-rw-r--r--src/mess/machine/ay31015.c746
-rw-r--r--src/mess/machine/ay31015.h108
-rw-r--r--src/mess/machine/ay3600.c629
-rw-r--r--src/mess/machine/ay3600.h20
-rw-r--r--src/mess/machine/b2m.c377
-rw-r--r--src/mess/machine/bbc.c2136
-rw-r--r--src/mess/machine/bebox.c1093
-rw-r--r--src/mess/machine/beta.c362
-rw-r--r--src/mess/machine/beta.h40
-rw-r--r--src/mess/machine/bk.c172
-rw-r--r--src/mess/machine/c128.c1307
-rw-r--r--src/mess/machine/c128_comal80.c101
-rw-r--r--src/mess/machine/c128_comal80.h53
-rw-r--r--src/mess/machine/c1541.c1030
-rw-r--r--src/mess/machine/c1541.h220
-rw-r--r--src/mess/machine/c1551.c574
-rw-r--r--src/mess/machine/c1551.h100
-rw-r--r--src/mess/machine/c1571.c881
-rw-r--r--src/mess/machine/c1571.h180
-rw-r--r--src/mess/machine/c1581.c503
-rw-r--r--src/mess/machine/c1581.h122
-rw-r--r--src/mess/machine/c16.c715
-rw-r--r--src/mess/machine/c2031.c502
-rw-r--r--src/mess/machine/c2031.h93
-rw-r--r--src/mess/machine/c2040.c1781
-rw-r--r--src/mess/machine/c2040.h235
-rw-r--r--src/mess/machine/c64.c2064
-rw-r--r--src/mess/machine/c64_16kb.c149
-rw-r--r--src/mess/machine/c64_16kb.h56
-rw-r--r--src/mess/machine/c64_4cga.c112
-rw-r--r--src/mess/machine/c64_4cga.h55
-rw-r--r--src/mess/machine/c64_4dxh.c109
-rw-r--r--src/mess/machine/c64_4dxh.h55
-rw-r--r--src/mess/machine/c64_4ksa.c109
-rw-r--r--src/mess/machine/c64_4ksa.h55
-rw-r--r--src/mess/machine/c64_4tba.c109
-rw-r--r--src/mess/machine/c64_4tba.h55
-rw-r--r--src/mess/machine/c64_bn1541.c160
-rw-r--r--src/mess/machine/c64_bn1541.h74
-rw-r--r--src/mess/machine/c64_comal80.c89
-rw-r--r--src/mess/machine/c64_comal80.h53
-rw-r--r--src/mess/machine/c64_cpm.c231
-rw-r--r--src/mess/machine/c64_cpm.h69
-rw-r--r--src/mess/machine/c64_currah_speech.c271
-rw-r--r--src/mess/machine/c64_currah_speech.h60
-rw-r--r--src/mess/machine/c64_dela_ep256.c179
-rw-r--r--src/mess/machine/c64_dela_ep256.h62
-rw-r--r--src/mess/machine/c64_dela_ep64.c170
-rw-r--r--src/mess/machine/c64_dela_ep64.h65
-rw-r--r--src/mess/machine/c64_dela_ep7x8.c157
-rw-r--r--src/mess/machine/c64_dela_ep7x8.h61
-rw-r--r--src/mess/machine/c64_dinamic.c77
-rw-r--r--src/mess/machine/c64_dinamic.h52
-rw-r--r--src/mess/machine/c64_dqbb.c124
-rw-r--r--src/mess/machine/c64_dqbb.h61
-rw-r--r--src/mess/machine/c64_easy_calc_result.c110
-rw-r--r--src/mess/machine/c64_easy_calc_result.h53
-rw-r--r--src/mess/machine/c64_easyflash.c239
-rw-r--r--src/mess/machine/c64_easyflash.h66
-rw-r--r--src/mess/machine/c64_epyx_fast_load.c119
-rw-r--r--src/mess/machine/c64_epyx_fast_load.h54
-rw-r--r--src/mess/machine/c64_exos.c70
-rw-r--r--src/mess/machine/c64_exos.h49
-rw-r--r--src/mess/machine/c64_final.c138
-rw-r--r--src/mess/machine/c64_final.h56
-rw-r--r--src/mess/machine/c64_final3.c154
-rw-r--r--src/mess/machine/c64_final3.h60
-rw-r--r--src/mess/machine/c64_fun_play.c101
-rw-r--r--src/mess/machine/c64_fun_play.h53
-rw-r--r--src/mess/machine/c64_geocable.c109
-rw-r--r--src/mess/machine/c64_geocable.h59
-rw-r--r--src/mess/machine/c64_georam.c101
-rw-r--r--src/mess/machine/c64_georam.h53
-rw-r--r--src/mess/machine/c64_ide64.c325
-rw-r--r--src/mess/machine/c64_ide64.h68
-rw-r--r--src/mess/machine/c64_ieee488.c322
-rw-r--r--src/mess/machine/c64_ieee488.h78
-rw-r--r--src/mess/machine/c64_kingsoft.c101
-rw-r--r--src/mess/machine/c64_kingsoft.h51
-rw-r--r--src/mess/machine/c64_mach5.c87
-rw-r--r--src/mess/machine/c64_mach5.h50
-rw-r--r--src/mess/machine/c64_magic_desk.c88
-rw-r--r--src/mess/machine/c64_magic_desk.h53
-rw-r--r--src/mess/machine/c64_magic_formel.c277
-rw-r--r--src/mess/machine/c64_magic_formel.h74
-rw-r--r--src/mess/machine/c64_mikro_assembler.c60
-rw-r--r--src/mess/machine/c64_mikro_assembler.h48
-rw-r--r--src/mess/machine/c64_multiscreen.c265
-rw-r--r--src/mess/machine/c64_multiscreen.h59
-rw-r--r--src/mess/machine/c64_neoram.c102
-rw-r--r--src/mess/machine/c64_neoram.h59
-rw-r--r--src/mess/machine/c64_ocean.c117
-rw-r--r--src/mess/machine/c64_ocean.h53
-rw-r--r--src/mess/machine/c64_pagefox.c136
-rw-r--r--src/mess/machine/c64_pagefox.h53
-rw-r--r--src/mess/machine/c64_prophet64.c87
-rw-r--r--src/mess/machine/c64_prophet64.h53
-rw-r--r--src/mess/machine/c64_ps64.c160
-rw-r--r--src/mess/machine/c64_ps64.h54
-rw-r--r--src/mess/machine/c64_rex.c81
-rw-r--r--src/mess/machine/c64_rex.h49
-rw-r--r--src/mess/machine/c64_rex_ep256.c188
-rw-r--r--src/mess/machine/c64_rex_ep256.h62
-rw-r--r--src/mess/machine/c64_ross.c95
-rw-r--r--src/mess/machine/c64_ross.h55
-rw-r--r--src/mess/machine/c64_sfx_sound_expander.c300
-rw-r--r--src/mess/machine/c64_sfx_sound_expander.h70
-rw-r--r--src/mess/machine/c64_silverrock.c135
-rw-r--r--src/mess/machine/c64_silverrock.h53
-rw-r--r--src/mess/machine/c64_simons_basic.c87
-rw-r--r--src/mess/machine/c64_simons_basic.h50
-rw-r--r--src/mess/machine/c64_stardos.c197
-rw-r--r--src/mess/machine/c64_stardos.h63
-rw-r--r--src/mess/machine/c64_std.c71
-rw-r--r--src/mess/machine/c64_std.h49
-rw-r--r--src/mess/machine/c64_structured_basic.c106
-rw-r--r--src/mess/machine/c64_structured_basic.h55
-rw-r--r--src/mess/machine/c64_super_explode.c128
-rw-r--r--src/mess/machine/c64_super_explode.h56
-rw-r--r--src/mess/machine/c64_super_games.c105
-rw-r--r--src/mess/machine/c64_super_games.h53
-rw-r--r--src/mess/machine/c64_sw8k.c116
-rw-r--r--src/mess/machine/c64_sw8k.h55
-rw-r--r--src/mess/machine/c64_system3.c86
-rw-r--r--src/mess/machine/c64_system3.h53
-rw-r--r--src/mess/machine/c64_tdos.c256
-rw-r--r--src/mess/machine/c64_tdos.h70
-rw-r--r--src/mess/machine/c64_vw64.c130
-rw-r--r--src/mess/machine/c64_vw64.h54
-rw-r--r--src/mess/machine/c64_warp_speed.c160
-rw-r--r--src/mess/machine/c64_warp_speed.h58
-rw-r--r--src/mess/machine/c64_westermann.c85
-rw-r--r--src/mess/machine/c64_westermann.h49
-rw-r--r--src/mess/machine/c64_xl80.c257
-rw-r--r--src/mess/machine/c64_xl80.h65
-rw-r--r--src/mess/machine/c64_zaxxon.c69
-rw-r--r--src/mess/machine/c64_zaxxon.h51
-rw-r--r--src/mess/machine/c64exp.c476
-rw-r--r--src/mess/machine/c64exp.h202
-rw-r--r--src/mess/machine/c64user.c141
-rw-r--r--src/mess/machine/c64user.h156
-rw-r--r--src/mess/machine/c65.c1068
-rw-r--r--src/mess/machine/c8280.c451
-rw-r--r--src/mess/machine/c8280.h82
-rw-r--r--src/mess/machine/cbm.c359
-rw-r--r--src/mess/machine/cbmb.c504
-rw-r--r--src/mess/machine/cbmiec.c659
-rw-r--r--src/mess/machine/cbmiec.h197
-rw-r--r--src/mess/machine/cbmipt.c1236
-rw-r--r--src/mess/machine/cbmipt.h165
-rw-r--r--src/mess/machine/cgenie.c620
-rw-r--r--src/mess/machine/cmdhd.c226
-rw-r--r--src/mess/machine/cmdhd.h73
-rw-r--r--src/mess/machine/cntr_covox.c112
-rw-r--r--src/mess/machine/cntr_covox.h62
-rw-r--r--src/mess/machine/coco.c1438
-rw-r--r--src/mess/machine/coco12.c158
-rw-r--r--src/mess/machine/coco3.c181
-rw-r--r--src/mess/machine/coco_232.c89
-rw-r--r--src/mess/machine/coco_232.h41
-rw-r--r--src/mess/machine/coco_fdc.c733
-rw-r--r--src/mess/machine/coco_fdc.h162
-rw-r--r--src/mess/machine/coco_multi.c266
-rw-r--r--src/mess/machine/coco_multi.h65
-rw-r--r--src/mess/machine/coco_orch90.c83
-rw-r--r--src/mess/machine/coco_orch90.h41
-rw-r--r--src/mess/machine/coco_pak.c199
-rw-r--r--src/mess/machine/coco_pak.h65
-rw-r--r--src/mess/machine/coco_vhd.c280
-rw-r--r--src/mess/machine/coco_vhd.h73
-rw-r--r--src/mess/machine/cococart.c477
-rw-r--r--src/mess/machine/cococart.h174
-rw-r--r--src/mess/machine/coleco.c267
-rw-r--r--src/mess/machine/coleco.h11
-rw-r--r--src/mess/machine/compis.c1404
-rw-r--r--src/mess/machine/comx_clm.c295
-rw-r--r--src/mess/machine/comx_clm.h68
-rw-r--r--src/mess/machine/comx_eb.c405
-rw-r--r--src/mess/machine/comx_eb.h86
-rw-r--r--src/mess/machine/comx_epr.c123
-rw-r--r--src/mess/machine/comx_epr.h58
-rw-r--r--src/mess/machine/comx_fd.c332
-rw-r--r--src/mess/machine/comx_fd.h82
-rw-r--r--src/mess/machine/comx_joy.c113
-rw-r--r--src/mess/machine/comx_joy.h52
-rw-r--r--src/mess/machine/comx_prn.c143
-rw-r--r--src/mess/machine/comx_prn.h57
-rw-r--r--src/mess/machine/comx_ram.c106
-rw-r--r--src/mess/machine/comx_ram.h55
-rw-r--r--src/mess/machine/comx_thm.c128
-rw-r--r--src/mess/machine/comx_thm.h57
-rw-r--r--src/mess/machine/comxexp.c228
-rw-r--r--src/mess/machine/comxexp.h163
-rw-r--r--src/mess/machine/comxpl80.c347
-rw-r--r--src/mess/machine/comxpl80.h98
-rw-r--r--src/mess/machine/concept.c728
-rw-r--r--src/mess/machine/corvushd.c1708
-rw-r--r--src/mess/machine/cpc_rom.c137
-rw-r--r--src/mess/machine/cpc_rom.h90
-rw-r--r--src/mess/machine/cpc_ssa1.c227
-rw-r--r--src/mess/machine/cpc_ssa1.h128
-rw-r--r--src/mess/machine/cpcexp.c109
-rw-r--r--src/mess/machine/cpcexp.h131
-rw-r--r--src/mess/machine/cs4031.c333
-rw-r--r--src/mess/machine/cs4031.h95
-rw-r--r--src/mess/machine/cs8221.c165
-rw-r--r--src/mess/machine/cs8221.h86
-rw-r--r--src/mess/machine/cuda.c563
-rw-r--r--src/mess/machine/cuda.h126
-rw-r--r--src/mess/machine/cybiko.c674
-rw-r--r--src/mess/machine/d9060.c601
-rw-r--r--src/mess/machine/d9060.h134
-rw-r--r--src/mess/machine/dai.c254
-rw-r--r--src/mess/machine/dccons.c709
-rw-r--r--src/mess/machine/dec_lk201.c264
-rw-r--r--src/mess/machine/dec_lk201.h68
-rw-r--r--src/mess/machine/dgn_beta.c1317
-rw-r--r--src/mess/machine/dgnalpha.c440
-rw-r--r--src/mess/machine/docg3.c828
-rw-r--r--src/mess/machine/docg3.h103
-rw-r--r--src/mess/machine/dp8390.c479
-rw-r--r--src/mess/machine/dp8390.h132
-rw-r--r--src/mess/machine/dragon.c175
-rw-r--r--src/mess/machine/ds1315.c268
-rw-r--r--src/mess/machine/ds1315.h42
-rw-r--r--src/mess/machine/e01.c824
-rw-r--r--src/mess/machine/e01.h129
-rw-r--r--src/mess/machine/e05a03.c242
-rw-r--r--src/mess/machine/e05a03.h54
-rw-r--r--src/mess/machine/ecb_grip.c947
-rw-r--r--src/mess/machine/ecb_grip.h125
-rw-r--r--src/mess/machine/ecbbus.c286
-rw-r--r--src/mess/machine/ecbbus.h163
-rw-r--r--src/mess/machine/econet.c355
-rw-r--r--src/mess/machine/econet.h175
-rw-r--r--src/mess/machine/egret.c477
-rw-r--r--src/mess/machine/egret.h117
-rw-r--r--src/mess/machine/einstein.c199
-rw-r--r--src/mess/machine/electron.c354
-rw-r--r--src/mess/machine/er59256.c252
-rw-r--r--src/mess/machine/er59256.h93
-rw-r--r--src/mess/machine/esqvfd.c358
-rw-r--r--src/mess/machine/esqvfd.h97
-rw-r--r--src/mess/machine/europc.c365
-rw-r--r--src/mess/machine/fd2000.c229
-rw-r--r--src/mess/machine/fd2000.h74
-rw-r--r--src/mess/machine/fm_scsi.c446
-rw-r--r--src/mess/machine/fm_scsi.h107
-rw-r--r--src/mess/machine/galaxy.c214
-rw-r--r--src/mess/machine/gamecom.c637
-rw-r--r--src/mess/machine/gamepock.c226
-rw-r--r--src/mess/machine/gb.c2237
-rw-r--r--src/mess/machine/genpc.c861
-rw-r--r--src/mess/machine/hd63450.c488
-rw-r--r--src/mess/machine/hd63450.h34
-rw-r--r--src/mess/machine/hd64610.c375
-rw-r--r--src/mess/machine/hd64610.h114
-rw-r--r--src/mess/machine/hec2hrp.c899
-rw-r--r--src/mess/machine/hecdisk2.c327
-rw-r--r--src/mess/machine/hp48.c1238
-rw-r--r--src/mess/machine/i82371ab.c263
-rw-r--r--src/mess/machine/i82371ab.h52
-rw-r--r--src/mess/machine/i82371sb.c185
-rw-r--r--src/mess/machine/i82371sb.h49
-rw-r--r--src/mess/machine/i82439tx.c331
-rw-r--r--src/mess/machine/i82439tx.h56
-rw-r--r--src/mess/machine/i8271.c1600
-rw-r--r--src/mess/machine/i8271.h48
-rw-r--r--src/mess/machine/ieee488.c685
-rw-r--r--src/mess/machine/ieee488.h226
-rw-r--r--src/mess/machine/interpod.c267
-rw-r--r--src/mess/machine/interpod.h84
-rw-r--r--src/mess/machine/intv.c853
-rw-r--r--src/mess/machine/iq151_disc2.c149
-rw-r--r--src/mess/machine/iq151_disc2.h51
-rw-r--r--src/mess/machine/iq151_minigraf.c165
-rw-r--r--src/mess/machine/iq151_minigraf.h55
-rw-r--r--src/mess/machine/iq151_ms151a.c165
-rw-r--r--src/mess/machine/iq151_ms151a.h55
-rw-r--r--src/mess/machine/iq151_rom.c227
-rw-r--r--src/mess/machine/iq151_rom.h143
-rw-r--r--src/mess/machine/iq151_staper.c149
-rw-r--r--src/mess/machine/iq151_staper.h58
-rw-r--r--src/mess/machine/iq151cart.c220
-rw-r--r--src/mess/machine/iq151cart.h147
-rw-r--r--src/mess/machine/irisha.c155
-rw-r--r--src/mess/machine/isa.c636
-rw-r--r--src/mess/machine/isa.h347
-rw-r--r--src/mess/machine/isa_adlib.c91
-rw-r--r--src/mess/machine/isa_adlib.h38
-rw-r--r--src/mess/machine/isa_aha1542.c210
-rw-r--r--src/mess/machine/isa_aha1542.h61
-rw-r--r--src/mess/machine/isa_com.c192
-rw-r--r--src/mess/machine/isa_com.h58
-rw-r--r--src/mess/machine/isa_fdc.c485
-rw-r--r--src/mess/machine/isa_fdc.h83
-rw-r--r--src/mess/machine/isa_finalchs.c127
-rw-r--r--src/mess/machine/isa_finalchs.h41
-rw-r--r--src/mess/machine/isa_gblaster.c89
-rw-r--r--src/mess/machine/isa_gblaster.h38
-rw-r--r--src/mess/machine/isa_gus.c1704
-rw-r--r--src/mess/machine/isa_gus.h284
-rw-r--r--src/mess/machine/isa_hdc.c828
-rw-r--r--src/mess/machine/isa_hdc.h102
-rw-r--r--src/mess/machine/isa_ibm_mfc.c537
-rw-r--r--src/mess/machine/isa_ibm_mfc.h97
-rw-r--r--src/mess/machine/isa_ide.c118
-rw-r--r--src/mess/machine/isa_ide.h42
-rw-r--r--src/mess/machine/isa_ide_cd.c464
-rw-r--r--src/mess/machine/isa_ide_cd.h93
-rw-r--r--src/mess/machine/isa_mpu401.c105
-rw-r--r--src/mess/machine/isa_mpu401.h39
-rw-r--r--src/mess/machine/isa_sblaster.c616
-rw-r--r--src/mess/machine/isa_sblaster.h115
-rw-r--r--src/mess/machine/isa_wdxt_gen.c398
-rw-r--r--src/mess/machine/isa_wdxt_gen.h87
-rw-r--r--src/mess/machine/jupiter.c119
-rw-r--r--src/mess/machine/k7659kb.c312
-rw-r--r--src/mess/machine/k7659kb.h77
-rw-r--r--src/mess/machine/kay_kbd.c517
-rw-r--r--src/mess/machine/kaypro.c391
-rw-r--r--src/mess/machine/kb3600.c178
-rw-r--r--src/mess/machine/kb3600.h144
-rw-r--r--src/mess/machine/kb_7007_3.h121
-rw-r--r--src/mess/machine/kb_keytro.c651
-rw-r--r--src/mess/machine/kb_keytro.h75
-rw-r--r--src/mess/machine/kb_msnat.c435
-rw-r--r--src/mess/machine/kb_msnat.h57
-rw-r--r--src/mess/machine/kc.c802
-rw-r--r--src/mess/machine/kc_d002.c210
-rw-r--r--src/mess/machine/kc_d002.h59
-rw-r--r--src/mess/machine/kc_d004.c530
-rw-r--r--src/mess/machine/kc_d004.h113
-rw-r--r--src/mess/machine/kc_keyb.c633
-rw-r--r--src/mess/machine/kc_keyb.h76
-rw-r--r--src/mess/machine/kc_ram.c447
-rw-r--r--src/mess/machine/kc_ram.h188
-rw-r--r--src/mess/machine/kc_rom.c228
-rw-r--r--src/mess/machine/kc_rom.h101
-rw-r--r--src/mess/machine/kcexp.c394
-rw-r--r--src/mess/machine/kcexp.h137
-rw-r--r--src/mess/machine/keyboard.c461
-rw-r--r--src/mess/machine/keyboard.h101
-rw-r--r--src/mess/machine/kr2376.c397
-rw-r--r--src/mess/machine/kr2376.h88
-rw-r--r--src/mess/machine/kramermc.c54
-rw-r--r--src/mess/machine/laser128.c123
-rw-r--r--src/mess/machine/laser128.h52
-rw-r--r--src/mess/machine/lh5810.c192
-rw-r--r--src/mess/machine/lh5810.h97
-rw-r--r--src/mess/machine/lisa.c2027
-rw-r--r--src/mess/machine/llc.c245
-rw-r--r--src/mess/machine/lux10828.c734
-rw-r--r--src/mess/machine/lux10828.h130
-rw-r--r--src/mess/machine/lux21046.c792
-rw-r--r--src/mess/machine/lux21046.h126
-rw-r--r--src/mess/machine/lux4105.c408
-rw-r--r--src/mess/machine/lux4105.h88
-rw-r--r--src/mess/machine/lviv.c372
-rw-r--r--src/mess/machine/lynx.c2137
-rw-r--r--src/mess/machine/mac.c3283
-rw-r--r--src/mess/machine/macadb.c987
-rw-r--r--src/mess/machine/mackbd.c142
-rw-r--r--src/mess/machine/mackbd.h59
-rw-r--r--src/mess/machine/macpci.c256
-rw-r--r--src/mess/machine/macrtc.c371
-rw-r--r--src/mess/machine/mb8795.c333
-rw-r--r--src/mess/machine/mb8795.h109
-rw-r--r--src/mess/machine/mb89352.c648
-rw-r--r--src/mess/machine/mb89352.h129
-rw-r--r--src/mess/machine/mbc55x.c480
-rw-r--r--src/mess/machine/mbee.c823
-rw-r--r--src/mess/machine/mboard.c557
-rw-r--r--src/mess/machine/mboard.h98
-rw-r--r--src/mess/machine/mc68328.c2833
-rw-r--r--src/mess/machine/mc68328.h541
-rw-r--r--src/mess/machine/mc6843.c856
-rw-r--r--src/mess/machine/mc6843.h41
-rw-r--r--src/mess/machine/mc6846.c635
-rw-r--r--src/mess/machine/mc6846.h65
-rw-r--r--src/mess/machine/mc6854.c1065
-rw-r--r--src/mess/machine/mc6854.h82
-rw-r--r--src/mess/machine/mc80.c203
-rw-r--r--src/mess/machine/mface2.c348
-rw-r--r--src/mess/machine/mface2.h70
-rw-r--r--src/mess/machine/micropolis.c395
-rw-r--r--src/mess/machine/micropolis.h66
-rw-r--r--src/mess/machine/microtan.c584
-rw-r--r--src/mess/machine/mikro80.c113
-rw-r--r--src/mess/machine/mm58274c.c542
-rw-r--r--src/mess/machine/mm58274c.h38
-rw-r--r--src/mess/machine/mos6530.c459
-rw-r--r--src/mess/machine/mos6530.h79
-rw-r--r--src/mess/machine/mpc105.c256
-rw-r--r--src/mess/machine/mpc105.h57
-rw-r--r--src/mess/machine/msx.c1184
-rw-r--r--src/mess/machine/msx_slot.c2487
-rw-r--r--src/mess/machine/mtx.c400
-rw-r--r--src/mess/machine/mz700.c679
-rw-r--r--src/mess/machine/mz80.c103
-rw-r--r--src/mess/machine/n82077aa.c1212
-rw-r--r--src/mess/machine/n82077aa.h203
-rw-r--r--src/mess/machine/nascom1.c295
-rw-r--r--src/mess/machine/nc.c144
-rw-r--r--src/mess/machine/ncr5380.c485
-rw-r--r--src/mess/machine/ncr5380.h89
-rw-r--r--src/mess/machine/ncr5390.c870
-rw-r--r--src/mess/machine/ncr5390.h228
-rw-r--r--src/mess/machine/ne1000.c101
-rw-r--r--src/mess/machine/ne1000.h34
-rw-r--r--src/mess/machine/ne2000.c111
-rw-r--r--src/mess/machine/ne2000.h32
-rw-r--r--src/mess/machine/nes.c1711
-rw-r--r--src/mess/machine/nes_ines.c465
-rw-r--r--src/mess/machine/nes_mmc.c707
-rw-r--r--src/mess/machine/nes_mmc.h147
-rw-r--r--src/mess/machine/nes_pcb.c13270
-rw-r--r--src/mess/machine/nes_unif.c176
-rw-r--r--src/mess/machine/nextkbd.c298
-rw-r--r--src/mess/machine/nextkbd.h57
-rw-r--r--src/mess/machine/nextmo.c197
-rw-r--r--src/mess/machine/nextmo.h56
-rw-r--r--src/mess/machine/northbridge.c46
-rw-r--r--src/mess/machine/northbridge.h32
-rw-r--r--src/mess/machine/nubus.c479
-rw-r--r--src/mess/machine/nubus.h167
-rw-r--r--src/mess/machine/nubus_asntmc3b.c214
-rw-r--r--src/mess/machine/nubus_asntmc3b.h66
-rw-r--r--src/mess/machine/null_modem.c27
-rw-r--r--src/mess/machine/null_modem.h27
-rw-r--r--src/mess/machine/odyssey2.c241
-rw-r--r--src/mess/machine/omti8621.c1363
-rw-r--r--src/mess/machine/omti8621.h58
-rw-r--r--src/mess/machine/ondra.c97
-rw-r--r--src/mess/machine/orao.c78
-rw-r--r--src/mess/machine/oric.c1430
-rw-r--r--src/mess/machine/orion.c626
-rw-r--r--src/mess/machine/osborne1.c543
-rw-r--r--src/mess/machine/p2000t.c160
-rw-r--r--src/mess/machine/partner.c390
-rw-r--r--src/mess/machine/pc.c1787
-rw-r--r--src/mess/machine/pc1251.c118
-rw-r--r--src/mess/machine/pc1350.c136
-rw-r--r--src/mess/machine/pc1401.c238
-rw-r--r--src/mess/machine/pc1403.c172
-rw-r--r--src/mess/machine/pc1512kb.c524
-rw-r--r--src/mess/machine/pc1512kb.h111
-rw-r--r--src/mess/machine/pc_fdc.c581
-rw-r--r--src/mess/machine/pc_fdc.h52
-rw-r--r--src/mess/machine/pc_joy.c91
-rw-r--r--src/mess/machine/pc_joy.h20
-rw-r--r--src/mess/machine/pc_kbdc.c252
-rw-r--r--src/mess/machine/pc_kbdc.h147
-rw-r--r--src/mess/machine/pc_keyboards.c16
-rw-r--r--src/mess/machine/pc_keyboards.h25
-rw-r--r--src/mess/machine/pc_lpt.c342
-rw-r--r--src/mess/machine/pc_lpt.h85
-rw-r--r--src/mess/machine/pc_turbo.c54
-rw-r--r--src/mess/machine/pc_turbo.h15
-rw-r--r--src/mess/machine/pce.c1827
-rw-r--r--src/mess/machine/pce220_ser.c306
-rw-r--r--src/mess/machine/pce220_ser.h94
-rw-r--r--src/mess/machine/pcf8593.c474
-rw-r--r--src/mess/machine/pcf8593.h41
-rw-r--r--src/mess/machine/pecom.c193
-rw-r--r--src/mess/machine/pet.c840
-rw-r--r--src/mess/machine/pf10.c162
-rw-r--r--src/mess/machine/pf10.h49
-rw-r--r--src/mess/machine/pk8020.c1012
-rw-r--r--src/mess/machine/plus4_sid.c184
-rw-r--r--src/mess/machine/plus4_sid.h63
-rw-r--r--src/mess/machine/plus4_std.c72
-rw-r--r--src/mess/machine/plus4_std.h49
-rw-r--r--src/mess/machine/plus4exp.c404
-rw-r--r--src/mess/machine/plus4exp.h197
-rw-r--r--src/mess/machine/plus4user.c104
-rw-r--r--src/mess/machine/plus4user.h126
-rw-r--r--src/mess/machine/pmd85.c966
-rw-r--r--src/mess/machine/pokemini.c1585
-rw-r--r--src/mess/machine/poly88.c332
-rw-r--r--src/mess/machine/pp01.c238
-rw-r--r--src/mess/machine/primo.c374
-rw-r--r--src/mess/machine/ps2.c96
-rw-r--r--src/mess/machine/psion_pack.c330
-rw-r--r--src/mess/machine/psion_pack.h78
-rw-r--r--src/mess/machine/psxcard.c258
-rw-r--r--src/mess/machine/psxcard.h42
-rw-r--r--src/mess/machine/psxcd.c1686
-rw-r--r--src/mess/machine/psxcd.h186
-rw-r--r--src/mess/machine/psxcddrv.c533
-rw-r--r--src/mess/machine/psxcddrv.h133
-rw-r--r--src/mess/machine/radio86.c282
-rw-r--r--src/mess/machine/rm380z.c300
-rw-r--r--src/mess/machine/rmnimbus.c3055
-rw-r--r--src/mess/machine/rx01.c263
-rw-r--r--src/mess/machine/rx01.h81
-rw-r--r--src/mess/machine/s100.c319
-rw-r--r--src/mess/machine/s100.h297
-rw-r--r--src/mess/machine/s100_dj2db.c517
-rw-r--r--src/mess/machine/s100_dj2db.h87
-rw-r--r--src/mess/machine/s100_djdma.c129
-rw-r--r--src/mess/machine/s100_djdma.h54
-rw-r--r--src/mess/machine/s100_mm65k16s.c269
-rw-r--r--src/mess/machine/s100_mm65k16s.h58
-rw-r--r--src/mess/machine/s100_wunderbus.c554
-rw-r--r--src/mess/machine/s100_wunderbus.h75
-rw-r--r--src/mess/machine/s1410.c227
-rw-r--r--src/mess/machine/s1410.h73
-rw-r--r--src/mess/machine/s3c44b0.c2058
-rw-r--r--src/mess/machine/s3c44b0.h688
-rw-r--r--src/mess/machine/samcoupe.c278
-rw-r--r--src/mess/machine/sapi1.c55
-rw-r--r--src/mess/machine/sc499.c1183
-rw-r--r--src/mess/machine/sc499.h159
-rw-r--r--src/mess/machine/scsibus.c1018
-rw-r--r--src/mess/machine/scsibus.h219
-rw-r--r--src/mess/machine/ser_mouse.c246
-rw-r--r--src/mess/machine/ser_mouse.h77
-rw-r--r--src/mess/machine/serial.c136
-rw-r--r--src/mess/machine/serial.h123
-rw-r--r--src/mess/machine/serialbox.c151
-rw-r--r--src/mess/machine/serialbox.h69
-rw-r--r--src/mess/machine/sgi.c512
-rw-r--r--src/mess/machine/sgi.h18
-rw-r--r--src/mess/machine/smartmed.c807
-rw-r--r--src/mess/machine/smartmed.h201
-rw-r--r--src/mess/machine/smc92x4.c2015
-rw-r--r--src/mess/machine/smc92x4.h219
-rw-r--r--src/mess/machine/sms.c2322
-rw-r--r--src/mess/machine/snescart.c1488
-rw-r--r--src/mess/machine/snescart.h19
-rw-r--r--src/mess/machine/softbox.c203
-rw-r--r--src/mess/machine/softbox.h63
-rw-r--r--src/mess/machine/sorcerer.c426
-rw-r--r--src/mess/machine/southbridge.c479
-rw-r--r--src/mess/machine/southbridge.h147
-rw-r--r--src/mess/machine/special.c395
-rw-r--r--src/mess/machine/sst39vfx.c223
-rw-r--r--src/mess/machine/sst39vfx.h72
-rw-r--r--src/mess/machine/strata.c695
-rw-r--r--src/mess/machine/strata.h15
-rw-r--r--src/mess/machine/super80.c227
-rw-r--r--src/mess/machine/svi318.c915
-rw-r--r--src/mess/machine/sym1.c310
-rw-r--r--src/mess/machine/tandy1t.c401
-rw-r--r--src/mess/machine/tandy2kb.c424
-rw-r--r--src/mess/machine/tandy2kb.h104
-rw-r--r--src/mess/machine/teleprinter.c237
-rw-r--r--src/mess/machine/teleprinter.h45
-rw-r--r--src/mess/machine/terminal.c548
-rw-r--r--src/mess/machine/terminal.h119
-rw-r--r--src/mess/machine/tf20.c388
-rw-r--r--src/mess/machine/tf20.h58
-rw-r--r--src/mess/machine/thomflop.c1951
-rw-r--r--src/mess/machine/thomflop.h53
-rw-r--r--src/mess/machine/thomson.c5466
-rw-r--r--src/mess/machine/ti85.c725
-rw-r--r--src/mess/machine/ti85_ser.c1544
-rw-r--r--src/mess/machine/ti85_ser.h34
-rw-r--r--src/mess/machine/ti99/bwg.c489
-rw-r--r--src/mess/machine/ti99/bwg.h94
-rw-r--r--src/mess/machine/ti99/datamux.c330
-rw-r--r--src/mess/machine/ti99/datamux.h115
-rw-r--r--src/mess/machine/ti99/evpc.c368
-rw-r--r--src/mess/machine/ti99/evpc.h62
-rw-r--r--src/mess/machine/ti99/genboard.c1493
-rw-r--r--src/mess/machine/ti99/genboard.h200
-rw-r--r--src/mess/machine/ti99/grom.c260
-rw-r--r--src/mess/machine/ti99/grom.h102
-rw-r--r--src/mess/machine/ti99/gromport.c2234
-rw-r--r--src/mess/machine/ti99/gromport.h497
-rw-r--r--src/mess/machine/ti99/handset.c536
-rw-r--r--src/mess/machine/ti99/handset.h90
-rw-r--r--src/mess/machine/ti99/hfdc.c586
-rw-r--r--src/mess/machine/ti99/hfdc.h116
-rw-r--r--src/mess/machine/ti99/horizon.c448
-rw-r--r--src/mess/machine/ti99/horizon.h66
-rw-r--r--src/mess/machine/ti99/hsgpl.c628
-rw-r--r--src/mess/machine/ti99/hsgpl.h81
-rw-r--r--src/mess/machine/ti99/joyport.c104
-rw-r--r--src/mess/machine/ti99/joyport.h94
-rw-r--r--src/mess/machine/ti99/mapper8.c570
-rw-r--r--src/mess/machine/ti99/mapper8.h169
-rw-r--r--src/mess/machine/ti99/mecmouse.c205
-rw-r--r--src/mess/machine/ti99/mecmouse.h46
-rw-r--r--src/mess/machine/ti99/memex.c175
-rw-r--r--src/mess/machine/ti99/memex.h44
-rw-r--r--src/mess/machine/ti99/myarcmem.c209
-rw-r--r--src/mess/machine/ti99/myarcmem.h44
-rw-r--r--src/mess/machine/ti99/p_code.c325
-rw-r--r--src/mess/machine/ti99/p_code.h49
-rw-r--r--src/mess/machine/ti99/peribox.c664
-rw-r--r--src/mess/machine/ti99/peribox.h251
-rw-r--r--src/mess/machine/ti99/samsmem.c133
-rw-r--r--src/mess/machine/ti99/samsmem.h43
-rw-r--r--src/mess/machine/ti99/spchsyn.c308
-rw-r--r--src/mess/machine/ti99/spchsyn.h53
-rw-r--r--src/mess/machine/ti99/speech8.c261
-rw-r--r--src/mess/machine/ti99/speech8.h71
-rw-r--r--src/mess/machine/ti99/ti32kmem.c110
-rw-r--r--src/mess/machine/ti99/ti32kmem.h36
-rw-r--r--src/mess/machine/ti99/ti99_hd.c504
-rw-r--r--src/mess/machine/ti99/ti99_hd.h87
-rw-r--r--src/mess/machine/ti99/ti99defs.h93
-rw-r--r--src/mess/machine/ti99/ti_fdc.c319
-rw-r--r--src/mess/machine/ti99/ti_fdc.h80
-rw-r--r--src/mess/machine/ti99/ti_rs232.c1125
-rw-r--r--src/mess/machine/ti99/ti_rs232.h156
-rw-r--r--src/mess/machine/ti99/tn_ide.c385
-rw-r--r--src/mess/machine/ti99/tn_ide.h61
-rw-r--r--src/mess/machine/ti99/tn_usbsm.c344
-rw-r--r--src/mess/machine/ti99/tn_usbsm.h55
-rw-r--r--src/mess/machine/ti99/videowrp.c236
-rw-r--r--src/mess/machine/ti99/videowrp.h183
-rw-r--r--src/mess/machine/ti990.c177
-rw-r--r--src/mess/machine/ti990.h23
-rw-r--r--src/mess/machine/tms5501.c463
-rw-r--r--src/mess/machine/tms5501.h101
-rw-r--r--src/mess/machine/trs80.c904
-rw-r--r--src/mess/machine/trs80m2kb.c389
-rw-r--r--src/mess/machine/trs80m2kb.h103
-rw-r--r--src/mess/machine/tvc_hbf.c196
-rw-r--r--src/mess/machine/tvc_hbf.h57
-rw-r--r--src/mess/machine/tvcexp.c187
-rw-r--r--src/mess/machine/tvcexp.h133
-rw-r--r--src/mess/machine/upd65031.c637
-rw-r--r--src/mess/machine/upd65031.h112
-rw-r--r--src/mess/machine/upd7002.c234
-rw-r--r--src/mess/machine/upd7002.h58
-rw-r--r--src/mess/machine/upd71071.c444
-rw-r--r--src/mess/machine/upd71071.h26
-rw-r--r--src/mess/machine/upd765.c2547
-rw-r--r--src/mess/machine/upd765.h165
-rw-r--r--src/mess/machine/ut88.c176
-rw-r--r--src/mess/machine/v1050kb.c424
-rw-r--r--src/mess/machine/v1050kb.h88
-rw-r--r--src/mess/machine/vb_money_minder.c77
-rw-r--r--src/mess/machine/vb_money_minder.h49
-rw-r--r--src/mess/machine/vb_std.c63
-rw-r--r--src/mess/machine/vb_std.h48
-rw-r--r--src/mess/machine/vb_timeshare.c76
-rw-r--r--src/mess/machine/vb_timeshare.h49
-rw-r--r--src/mess/machine/vcs_joy.c74
-rw-r--r--src/mess/machine/vcs_joy.h51
-rw-r--r--src/mess/machine/vcsctrl.c83
-rw-r--r--src/mess/machine/vcsctrl.h85
-rw-r--r--src/mess/machine/vector06.c190
-rw-r--r--src/mess/machine/vic1010.c162
-rw-r--r--src/mess/machine/vic1010.h72
-rw-r--r--src/mess/machine/vic10exp.c326
-rw-r--r--src/mess/machine/vic10exp.h186
-rw-r--r--src/mess/machine/vic10std.c81
-rw-r--r--src/mess/machine/vic10std.h50
-rw-r--r--src/mess/machine/vic1110.c117
-rw-r--r--src/mess/machine/vic1110.h53
-rw-r--r--src/mess/machine/vic1111.c75
-rw-r--r--src/mess/machine/vic1111.h50
-rw-r--r--src/mess/machine/vic1112.c272
-rw-r--r--src/mess/machine/vic1112.h76
-rw-r--r--src/mess/machine/vic1210.c80
-rw-r--r--src/mess/machine/vic1210.h51
-rw-r--r--src/mess/machine/vic20_megacart.c131
-rw-r--r--src/mess/machine/vic20_megacart.h63
-rw-r--r--src/mess/machine/vic20exp.c375
-rw-r--r--src/mess/machine/vic20exp.h185
-rw-r--r--src/mess/machine/vic20std.c72
-rw-r--r--src/mess/machine/vic20std.h49
-rw-r--r--src/mess/machine/vic20user.c136
-rw-r--r--src/mess/machine/vic20user.h151
-rw-r--r--src/mess/machine/victor9kb.c389
-rw-r--r--src/mess/machine/victor9kb.h102
-rw-r--r--src/mess/machine/vidbrain_exp.c247
-rw-r--r--src/mess/machine/vidbrain_exp.h175
-rw-r--r--src/mess/machine/vip_byteio.c132
-rw-r--r--src/mess/machine/vip_byteio.h148
-rw-r--r--src/mess/machine/vip_exp.c253
-rw-r--r--src/mess/machine/vip_exp.h182
-rw-r--r--src/mess/machine/vp550.c250
-rw-r--r--src/mess/machine/vp550.h68
-rw-r--r--src/mess/machine/vp570.c118
-rw-r--r--src/mess/machine/vp570.h54
-rw-r--r--src/mess/machine/vp575.c352
-rw-r--r--src/mess/machine/vp575.h96
-rw-r--r--src/mess/machine/vp585.c131
-rw-r--r--src/mess/machine/vp585.h55
-rw-r--r--src/mess/machine/vp590.c269
-rw-r--r--src/mess/machine/vp590.h72
-rw-r--r--src/mess/machine/vp595.c101
-rw-r--r--src/mess/machine/vp595.h55
-rw-r--r--src/mess/machine/vp620.c106
-rw-r--r--src/mess/machine/vp620.h59
-rw-r--r--src/mess/machine/vp700.c83
-rw-r--r--src/mess/machine/vp700.h54
-rw-r--r--src/mess/machine/vtech2.c536
-rw-r--r--src/mess/machine/wangpc_emb.c176
-rw-r--r--src/mess/machine/wangpc_emb.h58
-rw-r--r--src/mess/machine/wangpc_lic.c160
-rw-r--r--src/mess/machine/wangpc_lic.h56
-rw-r--r--src/mess/machine/wangpc_lvc.c363
-rw-r--r--src/mess/machine/wangpc_lvc.h71
-rw-r--r--src/mess/machine/wangpc_mcc.c336
-rw-r--r--src/mess/machine/wangpc_mcc.h63
-rw-r--r--src/mess/machine/wangpc_mvc.c354
-rw-r--r--src/mess/machine/wangpc_mvc.h72
-rw-r--r--src/mess/machine/wangpc_rtc.c349
-rw-r--r--src/mess/machine/wangpc_rtc.h70
-rw-r--r--src/mess/machine/wangpc_tig.c342
-rw-r--r--src/mess/machine/wangpc_tig.h68
-rw-r--r--src/mess/machine/wangpc_wdc.c356
-rw-r--r--src/mess/machine/wangpc_wdc.h84
-rw-r--r--src/mess/machine/wangpcbus.c328
-rw-r--r--src/mess/machine/wangpcbus.h207
-rw-r--r--src/mess/machine/wangpckb.c583
-rw-r--r--src/mess/machine/wangpckb.h87
-rw-r--r--src/mess/machine/wd11c00_17.c495
-rw-r--r--src/mess/machine/wd11c00_17.h128
-rw-r--r--src/mess/machine/wd1772.c1779
-rw-r--r--src/mess/machine/wd1772.h321
-rw-r--r--src/mess/machine/wd2010.c426
-rw-r--r--src/mess/machine/wd2010.h109
-rw-r--r--src/mess/machine/wswan.c1518
-rw-r--r--src/mess/machine/x1.c67
-rw-r--r--src/mess/machine/x68k_hdc.c430
-rw-r--r--src/mess/machine/x68k_hdc.h129
-rw-r--r--src/mess/machine/x68k_neptunex.c153
-rw-r--r--src/mess/machine/x68k_neptunex.h53
-rw-r--r--src/mess/machine/x68k_scsiext.c115
-rw-r--r--src/mess/machine/x68k_scsiext.h45
-rw-r--r--src/mess/machine/x68kexp.c98
-rw-r--r--src/mess/machine/x68kexp.h149
-rw-r--r--src/mess/machine/z80ne.c796
-rw-r--r--src/mess/machine/z88_flash.c92
-rw-r--r--src/mess/machine/z88_flash.h45
-rw-r--r--src/mess/machine/z88_ram.c108
-rw-r--r--src/mess/machine/z88_ram.h93
-rw-r--r--src/mess/machine/z88_rom.c88
-rw-r--r--src/mess/machine/z88_rom.h75
-rw-r--r--src/mess/machine/z88cart.c222
-rw-r--r--src/mess/machine/z88cart.h145
-rw-r--r--src/mess/machine/zx.c397
-rw-r--r--src/mess/machine/zx8302.c685
-rw-r--r--src/mess/machine/zx8302.h192
867 files changed, 289453 insertions, 0 deletions
diff --git a/src/mess/machine/3c503.c b/src/mess/machine/3c503.c
new file mode 100644
index 00000000000..d1ce2884d2a
--- /dev/null
+++ b/src/mess/machine/3c503.c
@@ -0,0 +1,308 @@
+#include "emu.h"
+#include "machine/3c503.h"
+#include "machine/devhelpr.h"
+
+#define SADDR 0xcc000
+
+static const dp8390_interface el2_3c503_dp8390_interface = {
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, el2_3c503_device, el2_3c503_irq_w),
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, el2_3c503_device, el2_3c503_mem_read),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, el2_3c503_device, el2_3c503_mem_write)
+};
+
+static MACHINE_CONFIG_FRAGMENT(el2_3c503_config)
+ MCFG_DP8390D_ADD("dp8390d", el2_3c503_dp8390_interface)
+MACHINE_CONFIG_END
+
+const device_type EL2_3C503 = &device_creator<el2_3c503_device>;
+
+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),
+ 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");
+ }
+ 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");
+ return;
+ case 3:
+ logerror("3c503: invalid low register write, page 3");
+ 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", 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", data);
+ }
+ case 9:
+ if(m_regs.ctrl & 0x80) logerror("3c503: changing dma address during dma is undefined");
+ 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");
+ 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", 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/mess/machine/3c503.h b/src/mess/machine/3c503.h
new file mode 100644
index 00000000000..5db061c700f
--- /dev/null
+++ b/src/mess/machine/3c503.h
@@ -0,0 +1,63 @@
+/* 3com Etherlink II 3c503 */
+
+#ifndef __3C503_H__
+#define __3C503_H__
+
+#include "emu.h"
+#include "machine/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();
+ virtual void device_config_complete() { m_shortname = "el2_3c503"; }
+private:
+ required_device<dp8390d_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/mess/machine/3c505.c b/src/mess/machine/3c505.c
new file mode 100644
index 00000000000..9b74caf4398
--- /dev/null
+++ b/src/mess/machine/3c505.c
@@ -0,0 +1,1448 @@
+/*
+ * 3c505.c - 3COM 3C505 ethernet controller (for Apollo DN3x00)
+ *
+ * Created on: August 27, 2010
+ * Author: Hans Ostermeyer
+ *
+ * Released for general non-commercial use under the MAME license
+ * Visit http://mamedev.org for licensing and usage restrictions.
+ *
+ * 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/3C500_Mar83.pdf
+ */
+
+#include "machine/3c505.h"
+
+#define VERBOSE 0
+
+static int verbose = VERBOSE;
+
+#define LOG(x) { logerror ("%s: ", m_device->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"
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+//const device_type THREECOM3C505 = threecom3c505_device_config::static_alloc_device_config;
+
+//**************************************************************************
+// 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_MC_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
+};
+
+/* These 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
+
+// FIXME:
+// #define lsb_first(a) (((a & 255) << 8) | ((a >>8) & 255))
+#define lsb_first(a) (a)
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+// device type definition
+const device_type THREECOM3C505 = &device_creator<threecom3c505_device>;
+
+//-------------------------------------------------
+// sc499_device - constructor
+//-------------------------------------------------
+
+threecom3c505_device::threecom3c505_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, THREECOM3C505, "Threecom 3C505", tag, owner, clock),
+ device_network_interface(mconfig, *this, 10.0f)
+{
+ memset(static_cast<threecom3c505_interface *>(this), 0, sizeof(threecom3c505_interface));
+}
+
+//-------------------------------------------------
+// static_set_interface - set the interface struct
+//-------------------------------------------------
+
+void threecom3c505_device::static_set_interface(device_t &device, const threecom3c505_interface &interface)
+{
+ threecom3c505_device &threecom3c505 = downcast<threecom3c505_device &>(device);
+ static_cast<threecom3c505_interface &>(threecom3c505) = interface;
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void threecom3c505_device::device_start()
+{
+ m_device = this;
+ LOG1(("start 3COM 3C505"));
+
+ 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);
+
+ if (tx_init != NULL)
+ {
+ (*tx_init)(this);
+ }
+
+ m_timer = m_device->machine().scheduler().timer_alloc(FUNC(static_set_interrupt), this);
+}
+
+//-------------------------------------------------
+// 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;
+ m_control = 0;
+ m_command_index = 0;
+ m_command_pending = 0;
+ m_mc_f9_pending = 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;
+
+ // FIXME: test data
+ m_netstat.tot_recv = 1;
+ m_netstat.tot_xmit = 2;
+ m_netstat.err_CRC = 3;
+ m_netstat.err_align = 4;
+ m_netstat.err_res = 5;
+ m_netstat.err_ovrrun = 6;
+
+ memset(m_station_address, 0 , sizeof(m_station_address));
+ memset(m_multicast_list, 0 , sizeof(m_multicast_list));
+ set_filter_list();
+ set_promisc(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_get_previouspc(cpu), tag());
+ }
+ else
+ {
+ sprintf(statebuf, "%d.%03d", s, ms);
+ }
+ return statebuf;
+}
+
+//**************************************************************************
+// data_buffer
+//**************************************************************************
+
+threecom3c505_device::data_buffer::data_buffer() :
+ m_device(NULL),
+ m_size(0L),
+ m_data(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_size = size;
+ m_data = auto_alloc_array(device->machine(), UINT8, 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_size = m_size;
+ db->m_length = m_length;
+ memcpy(db->m_data, m_data, m_size);
+}
+
+int threecom3c505_device::data_buffer::append(UINT8 data)
+{
+ if (m_length >= m_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] = new 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;
+}
+
+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, 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));
+
+ if (setfilter != NULL)
+ {
+ 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));
+ if (set_irq != NULL)
+ {
+ (*set_irq)(this, state);
+ }
+ irq_state = state;
+
+ // FIXME: hack?
+ if ( m_command_buffer[0] == CMD_EXECUTE_PROGRAM && state == 1)
+ {
+ m_status |= ASF_PCB_END;
+ }
+ }
+}
+
+TIMER_CALLBACK( threecom3c505_device::static_set_interrupt )
+{
+ reinterpret_cast<threecom3c505_device *> (ptr)->set_interrupt(ASSERT_LINE);
+}
+
+// -------------------------------------
+
+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("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_MC_F9: // 0xf9
+ logerror("CMD_MC_F9");
+ break;
+ case CMD_MC_FA: // 0xfa
+ logerror("!!! CMD_MC_FA");
+ break;
+
+ default:
+ logerror("!!! Unexpected Command !!!");
+ }
+
+ switch (m_command_buffer[0])
+ {
+ case CMD_MC_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");
+ }
+}
+
+void threecom3c505_device::do_receive_command()
+{
+ LOG2(("do_receive_command - data_length=%x rx_pending=%d",
+ m_rx_data_buffer.get_length(), m_rx_pending));
+#if 0
+ if (m_microcode_running && m_microcode_version == APOLLO_MC_VERSION_SR10_4)
+ {
+ m_response.command = CMD_MC_E1_RESPONSE;
+ m_response.length = 0;
+ m_response_length = 0;
+ m_response_index = 0;
+
+ m_rx_pending++;
+ }
+ else
+#endif
+
+ {
+ m_response.command = CMD_RECEIVE_PACKET_COMPLETE; // 0x38
+ m_response.length = 16;
+ m_response.data.rcv_resp.buf_ofs = 0;
+ m_response.data.rcv_resp.buf_seg = 0;
+ m_response.data.rcv_resp.buf_len = m_rx_data_buffer.get_length();
+ m_response.data.rcv_resp.pkt_len = m_rx_data_buffer.get_length(); // (?)
+ m_response.data.rcv_resp.timeout = 0; // successful completion
+ m_response.data.rcv_resp.status = m_rx_data_buffer.get_length() > 0 ? 0 : 0xffff;
+ m_response.data.rcv_resp.timetag = 0L; // TODO
+
+ m_response_length = m_response.length + 2;
+ m_response_index = 0;
+ }
+
+ m_status |= ACRF; /* adapter command register full */
+
+ if (m_control & CMDE)
+ {
+ LOG2(("do_receive_command - set_interrupt(%d)", ASSERT_LINE));
+ // set_interrupt(ASSERT_LINE);
+
+ // interrupt later
+ m_timer->adjust( attotime::from_usec(10));
+ }
+}
+
+void threecom3c505_device::set_command_pending(int onoff)
+{
+ m_command_pending = onoff;
+ LOG2(("set_command_pending %d m_rx_pending=%d m_rx_data_buffer.get_length()=%x%s",
+ m_command_pending, m_rx_pending, m_rx_data_buffer.get_length(), onoff ? "" :"\n"));
+
+//- verbose = onoff ? 1 : 2;
+
+ if (!m_command_pending)
+ {
+ // clear previous command byte
+ m_command_buffer[0] = 0;
+
+ m_mc_f9_pending = 0;
+ m_wait_for_ack = 0;
+
+ if (m_rx_pending > 0 && m_rx_data_buffer.get_length() > 0)
+ {
+ m_rx_pending--;
+ m_command_pending = 1;
+
+ LOG2(("set_command_pending %d m_rx_pending=%d", m_command_pending, m_rx_pending));
+
+ do_receive_command();
+ }
+ }
+}
+
+/***************************************************************************
+ do_command
+ ***************************************************************************/
+
+void threecom3c505_device::do_command()
+{
+ // default to successful completion
+ m_response.command = m_command_buffer[0] + CMD_RESPONSE_OFFSET;
+ m_response.length = 1;
+ m_response.data.failed = 0; // successful completion
+
+ switch (m_command_buffer[0])
+ {
+ case CMD_RESET: // 0x00
+// FIXME:
+// device_reset();
+ break;
+
+ case CMD_CONFIGURE_ADAPTER_MEMORY: // 0x01
+ m_i82586_config = m_program_buffer.get_word(1);
+ break;
+
+ case CMD_RECEIVE_PACKET: // 0x08
+ if (m_rx_data_buffer.get_length() == 0 && !m_rx_fifo.get(&m_rx_data_buffer))
+ {
+ // receive data not yet available
+ m_rx_pending++;
+ set_command_pending(0);
+ }
+ else
+ {
+ do_receive_command();
+ }
+ return;
+ // break;
+
+ case CMD_MC_F9:
+ m_response.command = CMD_TRANSMIT_PACKET_COMPLETE;
+ // fall through
+
+ case CMD_TRANSMIT_PACKET: // 0x09
+ case CMD_TRANSMIT_PACKET_18: // 0x18
+ m_response.length = 8;
+ 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;
+ m_microcode_running = 1;
+ m_microcode_version = m_program_buffer.get_word(1);
+ break;
+
+ case CMD_NETWORK_STATISTICS: // 0x0a
+ m_response.length = sizeof(struct Netstat);
+ // response data must be LSB first!
+ m_response.data.netstat.tot_recv = lsb_first(m_netstat.tot_recv);
+ m_response.data.netstat.tot_xmit = lsb_first(m_netstat.tot_xmit);
+ m_response.data.netstat.err_CRC = lsb_first(m_netstat.err_CRC);
+ m_response.data.netstat.err_align = lsb_first(m_netstat.err_align);
+ m_response.data.netstat.err_res = lsb_first(m_netstat.err_res);
+ m_response.data.netstat.err_ovrrun = lsb_first(m_netstat.err_ovrrun);
+ break;
+
+ case CMD_ADAPTER_INFO: // 0x11
+ m_response.length = sizeof(struct Info);
+ // FIXME: replace test data; must be LSB first!
+ m_response.data.info.minor_vers = 1;
+ m_response.data.info.major_vers = 2;
+ m_response.data.info.ROM_cksum = lsb_first(3);
+ m_response.data.info.RAM_sz = lsb_first(4);
+ m_response.data.info.free_ofs = lsb_first(5);
+ m_response.data.info.free_seg = lsb_first(6);
+ break;
+
+ case CMD_LOAD_MULTICAST_LIST:// 0x0b
+ if (m_command_buffer[1] > sizeof(m_multicast_list) ||
+ (m_command_buffer[1] % ETHERNET_ADDR_SIZE) != 0)
+ {
+ LOG(("CMD_LOAD_MULTICAST_LIST - !!! unexpected data size %d !!!", m_command_buffer[1]));
+ }
+ else
+ {
+ memset(m_multicast_list, 0 , sizeof(m_multicast_list));
+ memcpy(m_multicast_list, m_command_buffer+2 , m_command_buffer[1]-2);
+ set_filter_list();
+ }
+ break;
+
+ case CMD_SET_STATION_ADDRESS: // 0x10
+ if (m_command_buffer[1] != sizeof(m_station_address))
+ {
+ LOG(("CMD_SET_STATION_ADDRESS - !!! unexpected data size %d !!!", m_command_buffer[1]));
+ memset(m_station_address, 0 , sizeof(m_station_address));
+ }
+ else
+ {
+ memcpy(m_station_address, m_command_buffer+2 , m_command_buffer[1]);
+ }
+ set_filter_list();
+ set_mac((char *)m_station_address);
+ break;
+
+ case CMD_CONFIGURE_82586: // 0x02
+ case CMD_DOWNLOAD_PROGRAM: // 0x0d
+ case CMD_MC_17: // 0x17
+ default:
+ break;
+ }
+
+ m_response_index = 0;
+ m_response_length = m_response.length + 2;
+ m_status |= ACRF; /* adapter command register full */
+
+ if (m_control & CMDE)
+ {
+ switch (m_command_buffer[0])
+ {
+ case CMD_NETWORK_STATISTICS: // 0x0a
+ case CMD_DOWNLOAD_PROGRAM: // 0xd
+ case CMD_EXECUTE_PROGRAM: // 0x0e
+ case CMD_ADAPTER_INFO: // 0x11
+ // interrupt later
+ m_timer->adjust( attotime::from_msec(5));
+ break;
+
+ default:
+ // interrupt at once
+ set_interrupt(ASSERT_LINE);
+ break;
+ }
+ }
+}
+
+/***************************************************************************
+ 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;
+ 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;
+ }
+ }
+ 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));
+
+ if (m_rx_data_buffer.get_length() == 0)
+ {
+ m_rx_fifo.get(&m_rx_data_buffer);
+ }
+
+ if (!m_command_pending && m_rx_pending > 0
+ && m_rx_data_buffer.get_length() > 0)
+ {
+ m_rx_pending--;
+ set_command_pending(1);
+ do_receive_command();
+ }
+ }
+}
+
+bool threecom3c505_device::mcast_chk(const UINT8 *buf, int len) {
+ int i;
+ for (i = 0; i + ETHERNET_ADDR_SIZE < sizeof(m_multicast_list); i += ETHERNET_ADDR_SIZE)
+ {
+ if (memcmp(buf, m_multicast_list + i, ETHERNET_ADDR_SIZE) == 0)
+ {
+ LOG2(("threecom3c505_device::mcast_chk: true (len=%d)", len));
+ return true;
+ }
+ }
+ return false;
+}
+
+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_control & HSF_PCB_MASK) != HSF_PCB_END)
+ {
+ m_command_buffer[m_command_index++] = data;
+ m_status |= HCRE; /* command register empty */
+
+ if (m_command_index == 1)
+ {
+ switch (data)
+ {
+ case 0:
+ // spurious data; set command register empty
+ m_command_index = 0;
+ m_status |= HCRE;
+ break;
+
+ case CMD_MC_F9:
+// case CMD_MC_FA:
+ // read data length from data port (not from command port)
+ m_tx_data_buffer.reset();
+ m_status |= HRDY; /* data register ready */
+ set_command_pending(1);
+ break;
+
+ default:
+ set_command_pending(1);
+ break;
+ }
+ }
+ }
+ 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;
+
+ default:
+ do_command();
+ break;
+ }
+ }
+}
+
+UINT8 threecom3c505_device::read_command_port()
+{
+ UINT8 data;
+ if (m_response_index == 0)
+ {
+// set_command_pending(1);
+ 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; /* adapter command register no longer full */
+
+ LOG2(("FIXME: reading 3C505 Command Register at offset %02x with index %02x = %02x",
+ PORT_COMMAND, m_response_index, data));
+
+ if (m_mc_f9_pending == 1)
+ {
+ m_mc_f9_pending++;
+ }
+ }
+ else
+ {
+ // should never happen
+ data = 0; // 0xff;
+ LOG(("UNEXPECTED: reading 3C505 Command Register at offset %02x = %02x", PORT_COMMAND, data));
+ }
+
+ 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)
+ {
+ // FIXME:
+ if (!(m_status & DIR_))
+ {
+ m_status &= ~HRDY; /* data register no longer ready */
+ }
+
+ 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 != NULL && //
+ (*tx_data)(this, m_tx_data_buffer.get_data(), m_tx_data_buffer.get_length()) == 0)
+ {
+ // 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_MC_F9)
+ {
+// set_command_pending(0);
+ m_wait_for_ack = 1;
+ }
+ break;
+
+ case CMD_DOWNLOAD_PROGRAM_RESPONSE:
+ m_program_buffer.reset();
+// set_command_pending(0);
+ m_wait_for_ack = 1;
+ break;
+
+ default:
+// set_command_pending(0);
+ m_wait_for_ack = 1;
+ break;
+ }
+ }
+ }
+ return data;
+}
+
+void threecom3c505_device::write_data_port( UINT8 data)
+{
+ if (m_control & FLSH)
+ {
+ // flush input data
+ }
+ else if ((m_status & HRDY) == 0)
+ {
+ // this will happen 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_MC_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
+#if 0
+ if (m_command_buffer[0] == CMD_MC_F8)
+ {
+ // FIXME: what does it do?
+ LOG(("write_data_port: !!! TODO: CMD_MC_F8 !!! command=%x data length=%x", m_command_buffer[0], m_tx_data_length));
+ }
+#endif
+ 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=%x data=%02x", m_command_buffer[0], data));
+ }
+
+ if (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));
+ }
+ }
+}
+
+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(0);
+ m_wait_for_ack = 1;
+ }
+ }
+
+#if 0
+ else if (m_rx_data_index == data_length && (data_length & 1))
+ {
+ // data length is odd, pad with 0 to next even size
+ data = 0;
+ m_rx_data_index++;
+ LOG(("!!!: padding 3C505 Rx Data with odd data length %2x with value %02x", data_length, data));
+ }
+#endif
+
+ else
+ {
+ // FIXME: should never happen
+ data = 0xff;
+ m_status &= ~HRDY; /* data register no longer ready */
+ set_command_pending(0);
+ LOG(("UNEXPECTED: reading 3C505 data Register as %02x (data_length=%02x)", data, data_length));
+ }
+ return data;
+}
+
+void threecom3c505_device::write_control_port( UINT8 data)
+{
+ // if (cpu_get_previouspc(m_device->machine->firstcpu) == 0x3C4BAD48) verbose = 3;
+ // if (cpu_get_previouspc(m_device->machine->firstcpu) == 0x010464DC) verbose = 3;
+
+ if (verbose <= 2 && (data & (DMAE | TCEN /*| CMDE*/)) != 0)
+ {
+ // dma or interrupts enabled
+ LOG1(("writing 3C505 Control Register at offset %02x = %02x", PORT_CONTROL, data));
+ }
+
+ 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_NAK: // HSF2
+ if (m_microcode_running)
+ {
+ m_status = (m_status & ~ASF_PCB_MASK) | ASF_PCB_ACK;
+ }
+ break;
+ case HSF_PCB_END: // (HSF2|HSF1)
+ m_status &= ~(ATTN | DMAE | ASF_PCB_MASK);
+ if (m_microcode_running)
+ {
+ m_status = (m_status & ~ASF_PCB_MASK) | ASF_PCB_ACK;
+ }
+ break;
+ default: // 0
+ m_command_index = 0;
+ m_status |= HCRE; /* command register empty */
+
+ if (m_command_buffer[0] == CMD_MC_F9)
+ {
+ m_mc_f9_pending = 1;
+//- verbose = 2;
+ }
+
+ if (data == 0x00)
+ {
+ // hardware reset
+ m_status |= HRDY; /* data register ready */
+ // flush data register (reset tx data fifo)
+ m_tx_data_length = 0;
+ // FIXME: Don't do this (but why?)
+ // m_tx_data_buffer.reset();
+ }
+ else if (data == DIR_)
+ {
+ // why?? dex ether 20 expects HRDY
+ // m_status &= ~HRDY; /* data register not ready */
+ m_status |= HRDY; /* data register ready */
+ }
+ else if (data & FLSH)
+ {
+ if (data & DIR_)
+ {
+ m_status &= ~HRDY; /* data register not ready */
+ }
+ else
+ {
+ // flush data register (reset tx data fifo)
+// m_tx_data_length = 0;
+ m_tx_data_buffer.reset();
+ m_status |= HRDY; /* data register ready */
+ }
+ }
+ break;
+ }
+
+ if ((m_control & (ATTN | FLSH)) == (ATTN | FLSH) && (data & (ATTN | FLSH)) == 0)
+ {
+ m_status |= ASF_PCB_END;
+ }
+
+ if (m_mc_f9_pending == 2)
+ {
+ m_mc_f9_pending = 0;
+ set_command_pending(0);
+ }
+
+ m_control = data;
+}
+
+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;
+}
+
+void threecom3c505_device::write_port(offs_t offset, UINT8 data)
+{
+ m_reg[offset & 0x0f] = data;
+ LOG2(("writing 3C505 Register at offset %02x = %02x", offset, 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 */
+ case PORT_DATA + 1: /* 0x04 read/write, 16-bit */
+ write_data_port(data);
+ break;
+ case PORT_CONTROL: /* 0x06 read/write, 8-bit */
+ write_control_port(data);
+ break;
+ default:
+ break;
+ }
+}
+
+//READ8_DEVICE_HANDLER( threecom3c505_r )
+UINT8 threecom3c505_device::read_port(offs_t offset)
+{
+ // data to omit excessive logging
+ static UINT8 last_data = 0xff;
+ static UINT32 last_pc = 0;
+
+ UINT8 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();
+
+ set_interrupt(CLEAR_LINE);
+
+ // omit excessive logging
+ if (data == last_data)
+ {
+ UINT32 pc = cpu_get_previouspc(machine().device(MAINCPU));
+ if (pc == last_pc) {
+ return data;
+ }
+ last_pc = pc;
+ }
+ last_data = data;
+
+ break;
+ case PORT_DATA: /* 0x04 read/write, 16-bit */
+ case PORT_DATA + 1: /* 0x04 read/write, 16-bit */
+ data = read_data_port();
+ break;
+ case PORT_CONTROL: /* 0x06 read/write, 8-bit */
+ // just return current value
+ break;
+ default:
+ break;
+ }
+
+ LOG2(("reading 3C505 Register at offset %02x = %02x", offset, data));
+ return data;
+}
+
+//**************************************************************************
+// GLOBAL STUBS
+//**************************************************************************
+
+READ8_DEVICE_HANDLER( threecom3c505_r )
+{
+ return downcast<threecom3c505_device *> (device)->read_port(offset);
+}
+
+WRITE8_DEVICE_HANDLER( threecom3c505_w )
+{
+ downcast<threecom3c505_device *> (device)->write_port(offset, data);
+}
+
+int threecom3c505_receive(device_t *device, const UINT8 data[], int length)
+{
+ downcast<threecom3c505_device *> (device)->recv_cb((UINT8 *)data,length);
+ return 1;
+}
+
+void threecom3c505_set_verbose(int on_off)
+{
+ verbose = on_off == 0 ? 0 : VERBOSE > 1 ? VERBOSE : 1;
+}
diff --git a/src/mess/machine/3c505.h b/src/mess/machine/3c505.h
new file mode 100644
index 00000000000..fa1f4781f46
--- /dev/null
+++ b/src/mess/machine/3c505.h
@@ -0,0 +1,297 @@
+/*
+ * threecom3c505.h - 3COM 3C505 ethernet controller
+ *
+ * Created on: August 27, 2010
+ * Author: Hans Ostermeyer
+ *
+ * Released for general non-commercial use under the MAME license
+ * Visit http://mamedev.org for licensing and usage restrictions.
+ *
+ */
+
+#pragma once
+
+#ifndef THREECOM3C505_H_
+#define THREECOM3C505_H_
+
+#include "emu.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
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+ ***************************************************************************/
+
+READ8_DEVICE_HANDLER( threecom3c505_r );
+WRITE8_DEVICE_HANDLER( threecom3c505_w );
+
+int threecom3c505_receive(device_t *device, const UINT8 *data, int length);
+
+void threecom3c505_set_verbose(int on_off);
+
+//**************************************************************************
+// DEVICE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_THREECOM3C505_ADD(_tag, _interface) \
+ MCFG_DEVICE_ADD(_tag, THREECOM3C505, 0) \
+ threecom3c505_device::static_set_interface(*device, _interface);
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+typedef void (*threecom3c505_set_irq)(device_t *, int);
+typedef void (*threecom3c505_tx_init)(device_t *);
+typedef int (*threecom3c505_tx_data)(device_t *, const UINT8 *, int);
+typedef int (*threecom3c505_setfilter)(device_t *, int);
+
+struct threecom3c505_interface
+{
+ threecom3c505_set_irq set_irq;
+ threecom3c505_tx_init tx_init;
+ threecom3c505_tx_data tx_data;
+ threecom3c505_setfilter setfilter;
+};
+
+#define THREECOM3C505_INTERFACE(name) const struct threecom3c505_interface (name)
+
+// ======================> PCB data structure
+
+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.)
+ */
+typedef 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];
+ UINT8 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;
+} pcb_struct;
+
+// ======================> threecom3c505_device
+
+class threecom3c505_device: public device_t,
+ public device_network_interface,
+ public threecom3c505_interface
+{
+public:
+ // construction/destruction
+ threecom3c505_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // static configuration helpers
+ static void static_set_interface(device_t &device, const threecom3c505_interface &interface);
+
+ void recv_cb(UINT8 *buf, int len);
+ bool mcast_chk(const UINT8 *buf, int len);
+
+ // device register I/O
+ UINT8 read_port(offs_t offset);
+ void write_port(offs_t offset, UINT8 data);
+
+private:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ const char *cpu_context();
+
+ 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_size; };
+ UINT16 get_length() { return m_length; };
+ UINT16 get_size() { return m_size; };
+ UINT8 *get_data() { return m_data; };
+ void copy(data_buffer *db) const;
+ void log(const char *title) const;
+
+ private:
+ threecom3c505_device *m_device; // pointer back to our device
+ UINT16 m_length;
+ UINT16 m_size;
+ UINT8 *m_data;
+ };
+
+ /* data_buffer fifo (used to buffer the received data) */
+ class data_buffer_fifo
+ {
+ public:
+ 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);
+ private:
+ 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);
+ static TIMER_CALLBACK( static_set_interrupt );
+
+ void log_command();
+ void log_response();
+ void log_tx_data();
+ void log_rx_data();
+
+ void do_receive_command();
+ void set_command_pending(int onoff);
+ void do_command();
+
+ 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();
+
+ // pointer to myself (nasty: used for cpu_context)
+ threecom3c505_device *m_device;
+
+ 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_mc_f9_pending;
+ int m_wait_for_ack;
+
+ 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;
+
+ 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_timer; // timer to delay interrupts
+};
+
+// device type definition
+extern const device_type THREECOM3C505;
+
+#endif /* THREECOM3C505_H_ */
diff --git a/src/mess/machine/64h156.c b/src/mess/machine/64h156.c
new file mode 100644
index 00000000000..301d136a1e0
--- /dev/null
+++ b/src/mess/machine/64h156.c
@@ -0,0 +1,714 @@
+/**********************************************************************
+
+ Commodore 64H156 Gate Array emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ TODO:
+
+ http://staff.washington.edu/rrcc/uwweb/1541early/1540-2.GIF
+
+ - model disk rotation for proper track alignment
+ - write circuitry
+ - cycle exact M6502
+ - cycle exact VIA
+ - refactor to use modern floppy system
+
+ - get these running and we're golden
+ - 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 "emu.h"
+#include "64h156.h"
+#include "formats/g64_dsk.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LOG 0
+
+#define ATN (m_atni ^ m_atna)
+
+#define CYCLES_UNTIL_ANALOG_DESYNC 288 // 18 us
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64H156 = &device_creator<c64h156_device>;
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void c64h156_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const c64h156_interface *intf = reinterpret_cast<const c64h156_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<c64h156_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_atn_cb, 0, sizeof(m_out_atn_cb));
+ memset(&m_out_sync_cb, 0, sizeof(m_out_sync_cb));
+ memset(&m_out_byte_cb, 0, sizeof(m_out_byte_cb));
+ }
+}
+
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// set_atn_line -
+//-------------------------------------------------
+
+inline void c64h156_device::set_atn_line()
+{
+ m_out_atn_func(ATN);
+}
+
+
+//-------------------------------------------------
+// read_current_track -
+//-------------------------------------------------
+
+inline void c64h156_device::read_current_track()
+{
+ int track_length = G64_BUFFER_SIZE;
+
+ // read track data
+ floppy_drive_read_track_data_info_buffer(m_image, m_side, m_track_buffer, &track_length);
+
+ // extract track length
+ m_track_len = floppy_drive_get_current_track_size(m_image, m_side);
+
+ // set bit pointer to track start
+ m_buffer_pos = 0;
+ m_bit_pos = 7;
+ m_bit_count = 0;
+ m_zero_count = 0;
+
+ if (m_track_len)
+ {
+ memcpy(m_speed_buffer, m_track_buffer + m_track_len, G64_SPEED_BLOCK_SIZE);
+
+ update_cycles_until_next_bit();
+ }
+}
+
+
+//-------------------------------------------------
+// update_cycles_until_next_bit -
+//-------------------------------------------------
+
+inline void c64h156_device::update_cycles_until_next_bit()
+{
+ int speed_offset = m_buffer_pos / 4;
+ int speed_shift = (3 - (m_buffer_pos % 4)) * 2;
+
+ UINT8 speed = m_speed_buffer[speed_offset];
+
+ int ds = (speed >> speed_shift) & 0x03;
+
+ m_cycles_until_next_bit = (16 - ds) * 4;
+
+ if (LOG) logerror("buff %04x:%u speed %04x shift %u ds %u cycles %u\n", m_buffer_pos, m_bit_pos, speed_offset, speed_shift, ds, m_cycles_until_next_bit);
+}
+
+
+//-------------------------------------------------
+// receive_bit - receive bit
+//-------------------------------------------------
+
+inline void c64h156_device::receive_bit()
+{
+ if (!m_track_len)
+ {
+ m_bit_sync = 0;
+ }
+ else
+ {
+ if (m_cycles_until_next_bit == 0)
+ {
+ m_bit_sync = BIT(m_track_buffer[m_buffer_pos], m_bit_pos);
+
+ if (m_bit_sync)
+ {
+ m_zero_count = 0;
+ m_cycles_until_random_flux = (rand() % 31) + 289;
+ }
+ else
+ {
+ m_zero_count++;
+ }
+
+ if (m_zero_count >= m_cycles_until_random_flux)
+ {
+ // receive phantom bit
+ if (LOG) logerror("PHANTOM BIT SYNC 1 after %u cycles\n", m_zero_count);
+
+ m_bit_sync = 1;
+
+ m_zero_count = 0;
+ m_cycles_until_random_flux = (rand() % 367) + 33;
+ }
+ else
+ {
+ if (LOG) logerror("BIT SYNC %u\n", m_bit_sync);
+ }
+
+ m_shift <<= 1;
+ m_shift |= m_bit_sync;
+
+ m_bit_pos--;
+ m_bit_count++;
+
+ if (m_bit_pos < 0)
+ {
+ m_bit_pos = 7;
+ m_buffer_pos++;
+
+ if (m_buffer_pos >= m_track_len)
+ {
+ // loop to the start of the track
+ m_buffer_pos = 0;
+ }
+ }
+
+ update_cycles_until_next_bit();
+ }
+
+ m_cycles_until_next_bit--;
+ }
+}
+
+
+//-------------------------------------------------
+// decode_bit -
+//-------------------------------------------------
+
+inline void c64h156_device::decode_bit()
+{
+ // UE7
+
+ bool ue7_tc = false;
+
+ if (!m_last_bit_sync && m_bit_sync)
+ {
+ m_ue7 = m_ds;
+ }
+ else
+ {
+ m_ue7++;
+
+ if (m_ue7 == 16)
+ {
+ m_ue7 = m_ds;
+ ue7_tc = true;
+ }
+ }
+
+ if (LOG) logerror("UE7 CTR %01x TC %u, ", m_ue7, ue7_tc);
+
+ // UF4
+
+ if (!m_last_bit_sync && m_bit_sync)
+ {
+ m_uf4 = 0;
+
+ if (LOG) logerror("--");
+ }
+ else
+ {
+ if (!m_ue7_tc && ue7_tc)
+ {
+ m_uf4++;
+ m_uf4 &= 0x0f;
+
+ if (LOG) logerror("++");
+ }
+ else
+ {
+ if (LOG) logerror(" ");
+ }
+ }
+
+ m_last_bit_sync = m_bit_sync;
+ m_ue7_tc = ue7_tc;
+
+ int uf4_qa = BIT(m_uf4, 0);
+ int uf4_qb = BIT(m_uf4, 1);
+ int uf4_qc = BIT(m_uf4, 2);
+ int uf4_qd = BIT(m_uf4, 3);
+
+ int ue5a = !(uf4_qc || uf4_qd);
+
+ if (LOG) logerror("UF4 CTR %01x %u%u%u%u UE5A %u, ", m_uf4, uf4_qd, uf4_qc, uf4_qb, uf4_qa, ue5a);
+
+ if (!m_uf4_qb && uf4_qb)
+ {
+ // shift bits thru flip-flops
+ m_u4b = m_u4a;
+ m_u4a = BIT(m_ud2, 7);
+
+ // shift in data bit
+ m_ud2 <<= 1;
+ m_ud2 |= ue5a;
+
+ if (LOG) logerror("<<");
+ }
+ else
+ {
+ if (LOG) logerror(" ");
+ }
+
+ if (LOG) logerror("UD2 %u%u%u%u%u%u%u%u%u%u : %02x (%02x), ", m_u4b, m_u4a, BIT(m_ud2, 7), BIT(m_ud2, 6), BIT(m_ud2, 5), BIT(m_ud2, 4), BIT(m_ud2, 3), BIT(m_ud2, 2), BIT(m_ud2, 1), BIT(m_ud2, 0), m_ud2, m_shift & 0xff);
+
+ // UE3
+
+ int block_sync = !(m_oe && (m_ud2 == 0xff) && m_u4a && m_u4b);
+
+ if (LOG) logerror("SYNC %u, ", block_sync);
+
+ if (!block_sync)
+ {
+ // load UE3
+ m_ue3 = 8; // pin D is floating and TTL inputs float high
+
+ if (LOG) logerror("--");
+ }
+ else
+ {
+ if (m_block_sync && !m_uf4_qb && uf4_qb)
+ {
+ // clock UE3
+ m_ue3++;
+
+ if (m_ue3 == 16)
+ {
+ m_ue3 = 0;
+ }
+
+ if (LOG) logerror("++");
+ }
+ else
+ {
+ if (LOG) logerror(" ");
+ }
+ }
+
+ int ue3_qa = BIT(m_ue3, 0);
+ int ue3_qb = BIT(m_ue3, 1);
+ int ue3_qc = BIT(m_ue3, 2);
+
+ int uf3a = !(ue3_qa && ue3_qb && ue3_qc);
+ int uc1b = !uf3a; // schmitt trigger
+
+ if (LOG) logerror("UE3 CTR %01x UF3A %u UC1B %u, ", m_ue3, uf3a, uc1b);
+
+ int byte_sync = !(uc1b && m_soe && !uf4_qb);
+
+ if (LOG) logerror("BYTE %u SOE %u\n", m_byte_sync, m_soe);
+
+ // UD3
+
+ int uf3b = !(uc1b && uf4_qa && uf4_qb);
+
+ if (!uf3b)
+ {
+ m_ud3 = m_via_pa;
+ }
+ else if (!m_uf4_qb && uf4_qb)
+ {
+ // shift out bits
+ int ud3_qh = BIT(m_ud3, 0);
+ m_ud3 >>= 1;
+
+ int uf5b = !(!uf4_qb && ud3_qh);
+
+ if (!m_oe && m_wp)
+ {
+ // TODO write bit to disk
+ if (LOG) logerror("WRITE BIT %u\n", uf5b);
+ }
+ }
+
+ // prepare for next cycle
+
+ if (m_block_sync != block_sync)
+ {
+ m_block_sync = block_sync;
+ m_out_sync_func(m_block_sync);
+ }
+
+ if (m_byte_sync != byte_sync)
+ {
+ m_byte_sync = byte_sync;
+ m_out_byte_func(m_byte_sync);
+ }
+
+ m_uf4_qb = uf4_qb;
+
+ m_bit_sync = 0;
+}
+
+
+
+//**************************************************************************
+// 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),
+ device_execute_interface(mconfig, *this),
+ m_icount(0),
+ m_image(*this->owner(), FLOPPY_0),
+ m_side(0),
+ m_track_buffer(NULL),
+ m_track_len(0),
+ m_buffer_pos(0),
+ m_bit_pos(0),
+ m_bit_count(0),
+ m_stp(-1),
+ m_mtr(0),
+ m_accl(1),
+ m_ds(0),
+ m_soe(0),
+ m_oe(0),
+ m_atni(1),
+ m_atna(1),
+ m_last_bit_sync(0),
+ m_bit_sync(0),
+ m_byte_sync(1),
+ m_block_sync(1),
+ m_ue7(0),
+ m_ue7_tc(0),
+ m_uf4(0),
+ m_uf4_qb(0),
+ m_ud2(0),
+ m_u4a(0),
+ m_u4b(0),
+ m_ue3(0),
+ m_uc1b(0),
+ m_wp(0)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void c64h156_device::device_start()
+{
+ // set our instruction counter
+ m_icountptr = &m_icount;
+
+ // allocate track buffer
+ m_track_buffer = auto_alloc_array(machine(), UINT8, G64_BUFFER_SIZE);
+ m_speed_buffer = auto_alloc_array(machine(), UINT8, G64_SPEED_BLOCK_SIZE);
+
+ // resolve callbacks
+ m_out_atn_func.resolve(m_out_atn_cb, *this);
+ m_out_sync_func.resolve(m_out_sync_cb, *this);
+ m_out_byte_func.resolve(m_out_byte_cb, *this);
+
+ // register for state saving
+ save_item(NAME(m_shift));
+ save_item(NAME(m_side));
+ save_pointer(NAME(m_track_buffer), G64_BUFFER_SIZE);
+ save_pointer(NAME(m_speed_buffer), G64_SPEED_BLOCK_SIZE);
+ save_item(NAME(m_track_len));
+ save_item(NAME(m_buffer_pos));
+ save_item(NAME(m_bit_pos));
+ save_item(NAME(m_bit_count));
+ save_item(NAME(m_cycles_until_next_bit));
+ save_item(NAME(m_zero_count));
+ save_item(NAME(m_cycles_until_random_flux));
+ save_item(NAME(m_stp));
+ save_item(NAME(m_mtr));
+ save_item(NAME(m_accl));
+ save_item(NAME(m_ds));
+ save_item(NAME(m_soe));
+ save_item(NAME(m_oe));
+ save_item(NAME(m_atni));
+ save_item(NAME(m_atna));
+ save_item(NAME(m_last_bit_sync));
+ save_item(NAME(m_bit_sync));
+ save_item(NAME(m_byte_sync));
+ save_item(NAME(m_block_sync));
+ save_item(NAME(m_ue7));
+ save_item(NAME(m_ue7_tc));
+ save_item(NAME(m_uf4));
+ save_item(NAME(m_uf4_qb));
+ save_item(NAME(m_ud2));
+ save_item(NAME(m_u4a));
+ save_item(NAME(m_u4b));
+ save_item(NAME(m_ue3));
+ save_item(NAME(m_uc1b));
+ save_item(NAME(m_via_pa));
+ save_item(NAME(m_ud3));
+ save_item(NAME(m_wp));
+}
+
+
+//-------------------------------------------------
+// execute_run -
+//-------------------------------------------------
+
+void c64h156_device::execute_run()
+{
+ do
+ {
+ if (m_mtr)
+ {
+ receive_bit();
+ }
+
+ decode_bit();
+
+ m_icount--;
+ } while (m_icount > 0);
+}
+
+
+//-------------------------------------------------
+// yb_r -
+//-------------------------------------------------
+
+READ8_MEMBER( c64h156_device::yb_r )
+{
+ UINT8 data = 0;
+
+ if (m_soe)
+ {
+ data = m_ud2;
+ }
+
+ if (LOG) logerror("YB read %02x:%02x\n", m_ud2, data);
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// yb_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( c64h156_device::yb_w )
+{
+ m_via_pa = data;
+}
+
+
+//-------------------------------------------------
+// test_w - test write
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( c64h156_device::test_w )
+{
+}
+
+
+//-------------------------------------------------
+// accl_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( c64h156_device::accl_w )
+{
+ m_accl = state;
+}
+
+
+//-------------------------------------------------
+// sync_r - sync read
+//-------------------------------------------------
+
+READ_LINE_MEMBER( c64h156_device::sync_r )
+{
+ return m_block_sync;
+}
+
+
+//-------------------------------------------------
+// byte_r - byte ready read
+//-------------------------------------------------
+
+READ_LINE_MEMBER( c64h156_device::byte_r )
+{
+ return m_byte_sync;
+}
+
+
+//-------------------------------------------------
+// mtr_w - motor write
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( c64h156_device::mtr_w )
+{
+ if (m_mtr != state)
+ {
+ if (LOG) logerror("MTR %u\n", state);
+
+ if (state)
+ {
+ // read track data
+ read_current_track();
+ }
+
+ floppy_mon_w(m_image, !state);
+
+ m_mtr = state;
+ }
+}
+
+
+//-------------------------------------------------
+// oe_w - output enable write
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( c64h156_device::oe_w )
+{
+ if (LOG) logerror("OE %u\n", state);
+
+ m_oe = state;
+}
+
+
+//-------------------------------------------------
+// soe_w - SO enable write
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( c64h156_device::soe_w )
+{
+ if (LOG) logerror("SOE %u\n", state);
+
+ m_soe = state;
+}
+
+
+//-------------------------------------------------
+// atn_r - serial attention read
+//-------------------------------------------------
+
+READ_LINE_MEMBER( c64h156_device::atn_r )
+{
+ return ATN;
+}
+
+
+//-------------------------------------------------
+// atni_w - serial attention input write
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( c64h156_device::atni_w )
+{
+ if (LOG) logerror("ATNI %u\n", state);
+
+ m_atni = state;
+
+ set_atn_line();
+}
+
+
+//-------------------------------------------------
+// atna_w - serial attention acknowledge write
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( c64h156_device::atna_w )
+{
+ if (LOG) logerror("ATNA %u\n", state);
+
+ m_atna = state;
+
+ set_atn_line();
+}
+
+
+//-------------------------------------------------
+// stp_w -
+//-------------------------------------------------
+
+void c64h156_device::stp_w(int data)
+{
+ if (m_mtr && (m_stp != data))
+ {
+ int tracks = 0;
+
+ switch (m_stp)
+ {
+ case 0: if (data == 1) tracks++; else if (data == 3) tracks--; break;
+ case 1: if (data == 2) tracks++; else if (data == 0) tracks--; break;
+ case 2: if (data == 3) tracks++; else if (data == 1) tracks--; break;
+ case 3: if (data == 0) tracks++; else if (data == 2) tracks--; break;
+ }
+
+ if (tracks != 0)
+ {
+ // step read/write head
+ floppy_drive_seek(m_image, tracks);
+
+ // read new track data
+ read_current_track();
+ }
+
+ m_stp = data;
+ }
+}
+
+
+//-------------------------------------------------
+// ds_w - density select
+//-------------------------------------------------
+
+void c64h156_device::ds_w(int data)
+{
+ m_ds = data;
+}
+
+
+//-------------------------------------------------
+// on_disk_changed -
+//-------------------------------------------------
+
+void c64h156_device::on_disk_changed(int wp)
+{
+ m_wp = wp;
+
+ read_current_track();
+}
+
+
+//-------------------------------------------------
+// set_side -
+//-------------------------------------------------
+
+void c64h156_device::set_side(int side)
+{
+ m_side = side;
+}
diff --git a/src/mess/machine/64h156.h b/src/mess/machine/64h156.h
new file mode 100644
index 00000000000..b21a80f3217
--- /dev/null
+++ b/src/mess/machine/64h156.h
@@ -0,0 +1,204 @@
+/**********************************************************************
+
+ Commodore 64H156 Gate Array emulation
+
+ Used in 1541B/1541C/1541-II/1551/1571
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+ _____ _____
+ 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/flopdrv.h"
+#include "formats/d64_dsk.h"
+#include "formats/g64_dsk.h"
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_64H156_ADD(_tag, _clock, _config) \
+ MCFG_DEVICE_ADD(_tag, C64H156, _clock) \
+ MCFG_DEVICE_CONFIG(_config)
+
+#define C64H156_INTERFACE(_name) \
+ const c64h156_interface (_name) =
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> c64h156_interface
+
+struct c64h156_interface
+{
+ devcb_write_line m_out_atn_cb;
+ devcb_write_line m_out_sync_cb;
+ devcb_write_line m_out_byte_cb;
+};
+
+// ======================> c64h156_device
+
+class c64h156_device : public device_t,
+ public device_execute_interface,
+ public c64h156_interface
+{
+public:
+ // construction/destruction
+ c64h156_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ DECLARE_READ8_MEMBER( yb_r );
+ DECLARE_WRITE8_MEMBER( yb_w );
+ DECLARE_WRITE_LINE_MEMBER( test_w );
+ DECLARE_WRITE_LINE_MEMBER( accl_w );
+ DECLARE_READ_LINE_MEMBER( sync_r );
+ DECLARE_READ_LINE_MEMBER( byte_r );
+ DECLARE_WRITE_LINE_MEMBER( mtr_w );
+ DECLARE_WRITE_LINE_MEMBER( oe_w );
+ DECLARE_WRITE_LINE_MEMBER( soe_w );
+ DECLARE_READ_LINE_MEMBER( atn_r );
+ DECLARE_WRITE_LINE_MEMBER( atni_w );
+ DECLARE_WRITE_LINE_MEMBER( atna_w );
+
+ void stp_w(int data);
+ void ds_w(int data);
+ void set_side(int side);
+
+ void on_disk_changed(int wp);
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+ virtual void device_start();
+
+ // device_execute_interface overrides
+ virtual void execute_run();
+
+ int m_icount;
+
+ inline void set_atn_line();
+ inline void read_current_track();
+ inline void update_cycles_until_next_bit();
+ inline void receive_bit();
+ inline void decode_bit();
+
+private:
+ devcb_resolved_write_line m_out_atn_func;
+ devcb_resolved_write_line m_out_sync_func;
+ devcb_resolved_write_line m_out_byte_func;
+
+ required_device<device_t> m_image;
+
+ // track
+ UINT16 m_shift;
+ int m_side; // disk side
+ UINT8 *m_track_buffer; // track data buffer
+ UINT8 *m_speed_buffer; // speed block buffer
+ int m_track_len; // track length
+ offs_t m_buffer_pos; // current byte position within track buffer
+ int m_bit_pos; // current bit position within track buffer byte
+ int m_bit_count; // current data byte bit counter
+ int m_cycles_until_next_bit;
+ int m_zero_count;
+ int m_cycles_until_random_flux;
+
+ // motors
+ int m_stp; // stepper motor phase
+ int m_mtr; // spindle motor on
+
+ // signals
+ int m_accl; // 1/2 MHz select
+ int m_ds; // density select
+ int m_soe; // s? output enable
+ int m_oe; // output enable (0 = write, 1 = read)
+
+ // IEC
+ int m_atni; // attention input
+ int m_atna; // attention acknowledge
+
+ // read logic
+ int m_last_bit_sync;
+ int m_bit_sync;
+ int m_byte_sync;
+ int m_block_sync;
+ int m_ue7;
+ int m_ue7_tc;
+ int m_uf4;
+ int m_uf4_qb;
+ UINT8 m_ud2;
+ int m_u4a;
+ int m_u4b;
+ int m_ue3;
+ int m_uc1b;
+
+ // write logic
+ UINT8 m_via_pa;
+ UINT8 m_ud3;
+ int m_wp;
+};
+
+
+
+// device type definition
+extern const device_type C64H156;
+
+
+
+#endif
diff --git a/src/mess/machine/6883sam.c b/src/mess/machine/6883sam.c
new file mode 100644
index 00000000000..481532e074d
--- /dev/null
+++ b/src/mess/machine/6883sam.c
@@ -0,0 +1,427 @@
+/***************************************************************************
+
+ 6883sam.c
+
+ Motorola 6883 Synchronous Address Multiplexer
+
+ The Motorola 6883 SAM has 16 bits worth of state, but the state is changed
+ by writing into a 32 byte address space; odd bytes set bits and even bytes
+ clear bits. Here is the layout:
+
+ 31 Set TY Map Type 0: RAM/ROM 1: All RAM
+ 30 Clear TY Map Type
+ 29 Set M1 Memory Size 00: 4K 10: 64K Dynamic
+ 28 Clear M1 Memory Size 01: 16K 11: 64K Static
+ 27 Set M0 Memory Size
+ 26 Clear M0 Memory Size
+ 25 Set R1 MPU Rate 00: Slow 10: Fast
+ 24 Clear R1 MPU Rate 01: Dual 11: Fast
+ 23 Set R0 MPU Rate
+ 22 Clear R0 MPU Rate
+ 21 Set P1 Page #1 0: Low 1: High
+ 20 Clear P1 Page #1
+ 19 Set F6 Display Offset
+ 18 Clear F6 Display Offset
+ 17 Set F5 Display Offset
+ 16 Clear F5 Display Offset
+ 15 Set F4 Display Offset
+ 14 Clear F4 Display Offset
+ 13 Set F3 Display Offset
+ 12 Clear F3 Display Offset
+ 11 Set F2 Display Offset
+ 10 Clear F2 Display Offset
+ 9 Set F1 Display Offset
+ 8 Clear F1 Display Offset
+ 7 Set F0 Display Offset
+ 6 Clear F0 Display Offset
+ 5 Set V2 VDG Mode
+ 4 Clear V2 VDG Mode
+ 3 Set V1 VDG Mode
+ 2 Clear V1 VDG Mode
+ 1 Set V0 VDG Mode
+ 0 Clear V0 VDG Mode
+
+ All parts of the SAM are fully emulated except R1/R0 (the changes in the
+ MPU rate are approximated) and M1/M0
+
+***************************************************************************/
+
+
+#include "machine/6883sam.h"
+
+const device_type SAM6883 = &device_creator<sam6883_device>;
+
+
+//-------------------------------------------------
+// ctor
+//-------------------------------------------------
+
+sam6883_device::sam6883_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, SAM6883, "SAM6883", tag, owner, clock)
+{
+ memset(m_banks, '\0', sizeof(m_banks));
+}
+
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void sam6883_device::device_start()
+{
+ const sam6883_interface *config = (const sam6883_interface *) static_config();
+
+ /* find the CPU */
+ m_cpu = machine().device<cpu_device>(config->m_cpu_tag);
+ m_cpu_space = m_cpu->space(config->m_cpu_space);
+
+ /* resolve callbacks */
+ m_res_input_func.resolve(config->m_input_func, *this);
+
+ /* install SAM handlers */
+ m_cpu_space->install_read_handler(0xFFC0, 0xFFDF, 0, 0, read8_delegate(FUNC(sam6883_device::read), this));
+ m_cpu_space->install_write_handler(0xFFC0, 0xFFDF, 0, 0, write8_delegate(FUNC(sam6883_device::write), this));
+
+ /* save state support */
+ save_item(NAME(m_sam_state));
+ save_item(NAME(m_counter));
+ save_item(NAME(m_counter_xdiv));
+ save_item(NAME(m_counter_ydiv));
+}
+
+
+
+//-------------------------------------------------
+// configure_bank - bank configuration
+//-------------------------------------------------
+
+void sam6883_device::configure_bank(int bank, UINT8 *memory, UINT32 memory_size, bool is_read_only)
+{
+ configure_bank(bank, memory, memory_size, is_read_only, read8_delegate(), write8_delegate());
+}
+
+
+
+//-------------------------------------------------
+// configure_bank - bank configuration
+//-------------------------------------------------
+
+void sam6883_device::configure_bank(int bank, read8_delegate rhandler, write8_delegate whandler)
+{
+ configure_bank(bank, NULL, 0, false, rhandler, whandler);
+}
+
+
+
+//-------------------------------------------------
+// configure_bank - bank configuration
+//-------------------------------------------------
+
+void sam6883_device::configure_bank(int bank, UINT8 *memory, UINT32 memory_size, bool is_read_only, read8_delegate rhandler, write8_delegate whandler)
+{
+ assert((bank >= 0) && (bank < sizeof(m_banks) / sizeof(m_banks[0])));
+ m_banks[bank].m_memory = memory;
+ m_banks[bank].m_memory_size = memory_size;
+ m_banks[bank].m_memory_read_only = is_read_only;
+ m_banks[bank].m_rhandler = rhandler;
+ m_banks[bank].m_whandler = whandler;
+
+ /* if we're configuring a bank that never changes, update it now */
+ switch(bank)
+ {
+ case 4:
+ update_bank(4, 0xFF00, 0xFF1F, 0x0000);
+ break;
+ case 5:
+ update_bank(5, 0xFF20, 0xFF3F, 0x0000);
+ break;
+ case 6:
+ update_bank(6, 0xFF40, 0xFF5F, 0x0000);
+ break;
+ case 7:
+ update_bank(7, 0xFF60, 0xFFBF, 0x0000);
+ break;
+ case 2:
+ update_bank(2, 0xFFE0, 0xFFFF, 0x1FE0);
+ break;
+ }
+}
+
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void sam6883_device::device_reset()
+{
+ m_counter = 0;
+ m_counter_xdiv = 0;
+ m_counter_ydiv = 0;
+ m_sam_state = 0x0000;
+ update_state();
+}
+
+
+
+//-------------------------------------------------
+// device_post_load - device-specific post load
+//-------------------------------------------------
+
+void sam6883_device::device_post_load()
+{
+ device_t::device_post_load();
+ update_state();
+}
+
+
+
+//-------------------------------------------------
+// update_state
+//-------------------------------------------------
+
+void sam6883_device::update_state(void)
+{
+ update_memory();
+ update_cpu_clock();
+}
+
+
+
+//-------------------------------------------------
+// update_memory
+//-------------------------------------------------
+
+void sam6883_device::update_memory(void)
+{
+ /* Memory size - allowed restricting memory accesses to something less than
+ * 32k
+ *
+ * This was a SAM switch that occupied 4 addresses:
+ *
+ * $FFDD (set) R1
+ * $FFDC (clear) R1
+ * $FFDB (set) R0
+ * $FFDA (clear) R0
+ *
+ * R1:R0 formed the following states:
+ * 00 - 4k
+ * 01 - 16k
+ * 10 - 64k
+ * 11 - static RAM (??)
+ *
+ * If something less than 64k was set, the low RAM would be smaller and
+ * mirror the other parts of the RAM
+ *
+ * TODO: Find out what "static RAM" is
+ * TODO: This should affect _all_ memory accesses, not just video ram
+ * TODO: Verify that the CoCo 3 ignored this
+ */
+
+ /* update $0000-$7FFF */
+ update_bank(0, 0x0000, 0x7FFF, m_sam_state & SAM_STATE_P1 ? 0x8000 : 0x0000);
+
+ if (m_sam_state & SAM_STATE_TY)
+ {
+ update_bank(0, 0x8000, 0xFEFF, 0x8000);
+ }
+ else
+ {
+ update_bank(1, 0x8000, 0x9FFF, 0x0000);
+ update_bank(2, 0xA000, 0xBFFF, 0x0000);
+ update_bank(3, 0xC000, 0xFEFF, 0x0000);
+ }
+}
+
+
+
+//-------------------------------------------------
+// install_memory
+//-------------------------------------------------
+
+void sam6883_device::install_memory(offs_t addrstart, offs_t addrend, void *memory, bool is_read_only)
+{
+ if (addrend >= addrstart)
+ {
+ if (memory == NULL)
+ m_cpu_space->unmap_readwrite(addrstart, addrend);
+ else if (is_read_only)
+ m_cpu_space->install_rom(addrstart, addrend, memory);
+ else
+ m_cpu_space->install_ram(addrstart, addrend, memory);
+ }
+}
+
+
+
+//-------------------------------------------------
+// update_bank
+//-------------------------------------------------
+
+void sam6883_device::update_bank(int bank, offs_t addrstart, offs_t addrend, offs_t offset)
+{
+ assert((bank >= 0) && (bank < sizeof(m_banks) / sizeof(m_banks[0])));
+
+ if (m_banks[bank].m_memory != NULL)
+ {
+ /* this bank is a memory bank */
+ install_memory(addrstart, MIN(addrend, addrstart + m_banks[bank].m_memory_size - 1), m_banks[bank].m_memory + m_banks[bank].m_memory_offset + offset, m_banks[bank].m_memory_read_only);
+ install_memory(addrstart + m_banks[bank].m_memory_size, addrend, NULL, m_banks[bank].m_memory_read_only);
+ }
+ else
+ {
+ /* this bank uses handlers */
+ assert(offset == 0); /* changes to the offset are not supported */
+ if (!m_banks[bank].m_rhandler.isnull())
+ m_cpu_space->install_read_handler(addrstart, addrend, 0, 0, m_banks[bank].m_rhandler);
+ if (!m_banks[bank].m_whandler.isnull())
+ m_cpu_space->install_write_handler(addrstart, addrend, 0, 0, m_banks[bank].m_whandler);
+ }
+}
+
+
+
+//-------------------------------------------------
+// update_cpu_clock - adjusts the speed of the CPU
+// clock
+//-------------------------------------------------
+
+void sam6883_friend_device::update_cpu_clock(void)
+{
+ /* The infamous speed up poke.
+ *
+ * This was a SAM switch that occupied 4 addresses:
+ *
+ * $FFD9 (set) R1
+ * $FFD8 (clear) R1
+ * $FFD7 (set) R0
+ * $FFD6 (clear) R0
+ *
+ * R1:R0 formed the following states:
+ * 00 - slow 0.89 MHz
+ * 01 - dual speed ???
+ * 1x - fast 1.78 MHz
+ *
+ * R1 controlled whether the video addressing was speeded up and R0
+ * did the same for the CPU. On pre-CoCo 3 machines, setting R1 caused
+ * the screen to display garbage because the M6847 could not display
+ * fast enough.
+ *
+ * TODO: Make the overclock more accurate. In dual speed, ROM was a fast
+ * access but RAM was not. I don't know how to simulate this.
+ */
+ int speed = (m_sam_state & (SAM_STATE_R1|SAM_STATE_R0)) / SAM_STATE_R0;
+
+ /* the line below is weird because we are not strictly emulating the M6809E with emphasis on the 'E' */
+ m_cpu->set_clock_scale(speed ? 2 : 1);
+}
+
+
+
+//-------------------------------------------------
+// set_bank_offset
+//-------------------------------------------------
+
+void sam6883_device::set_bank_offset(int bank, offs_t offset)
+{
+ if (m_banks[bank].m_memory_offset != offset)
+ {
+ m_banks[bank].m_memory_offset = offset;
+ update_memory();
+ update_bank(2, 0xFFE0, 0xFFFF, 0x1FE0);
+ }
+}
+
+
+
+//-------------------------------------------------
+// read
+//-------------------------------------------------
+
+READ8_MEMBER( sam6883_device::read )
+{
+ return 0;
+}
+
+
+
+//-------------------------------------------------
+// write
+//-------------------------------------------------
+
+WRITE8_MEMBER( sam6883_device::write )
+{
+ /* alter the SAM state */
+ UINT16 xorval = alter_sam_state(offset);
+
+ /* based on the mask, apply effects */
+ if (xorval & (SAM_STATE_TY|SAM_STATE_M1|SAM_STATE_M0|SAM_STATE_P1))
+ update_memory();
+ if (xorval & (SAM_STATE_R1|SAM_STATE_R0))
+ update_cpu_clock();
+}
+
+
+
+//-------------------------------------------------
+// horizontal_sync
+//-------------------------------------------------
+
+void sam6883_device::horizontal_sync(void)
+{
+ bool carry;
+
+ // When horizontal sync occurs, bits B1-B3 or B1-B4 may be cleared (except in DMA mode). The catch
+ // is that the SAM's counter is a chain of flip-flops. Clearing the counter can cause carries to
+ // occur just as they can when the counter is bumped.
+ //
+ // This is critical in getting certain semigraphics modes to work correctly. Guardian uses this
+ // mode (see bug #1153). Special thanks to Ciaran Anscomb and Phill Harvey-Smith for figuring this
+ // out
+ switch((m_sam_state & (SAM_STATE_V2|SAM_STATE_V1|SAM_STATE_V0)) / SAM_STATE_V0)
+ {
+ case 0x01:
+ case 0x03:
+ case 0x05:
+ /* these SAM modes clear bits B1-B3 */
+ carry = (m_counter & 0x0008) ? true : false;
+ m_counter &= ~0x000F;
+ if (carry)
+ counter_carry_bit3();
+ break;
+
+ case 0x00:
+ case 0x02:
+ case 0x04:
+ case 0x06:
+ /* clear bits B1-B4 */
+ carry = (m_counter & 0x0010) ? true : false;
+ m_counter &= ~0x001F;
+ if (carry)
+ counter_carry_bit4();
+ break;
+
+ case 0x07:
+ /* DMA mode - do nothing */
+ break;
+
+ default:
+ fatalerror("Should not get here");
+ return;
+ }
+}
+
+
+
+//-------------------------------------------------
+// hs_w
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( sam6883_device::hs_w )
+{
+ if (state)
+ {
+ horizontal_sync();
+ }
+}
diff --git a/src/mess/machine/6883sam.h b/src/mess/machine/6883sam.h
new file mode 100644
index 00000000000..09c06dc8fce
--- /dev/null
+++ b/src/mess/machine/6883sam.h
@@ -0,0 +1,229 @@
+/***************************************************************************
+
+ 6883sam.h
+
+ Motorola 6883 Synchronous Address Multiplexer
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __6883SAM__
+#define __6883SAM__
+
+#include "emu.h"
+
+#define MCFG_SAM6883_ADD(_tag, _clock, _config) \
+ MCFG_DEVICE_ADD(_tag, SAM6883, _clock) \
+ MCFG_DEVICE_CONFIG(_config)
+
+
+/* interface */
+typedef struct _sam6883_interface sam6883_interface;
+struct _sam6883_interface
+{
+ /* the CPU/space from which the SAM reads data */
+ const char * m_cpu_tag;
+ address_spacenum m_cpu_space;
+
+ /* function for reading from memory for video */
+ devcb_read8 m_input_func;
+};
+
+
+//**************************************************************************
+// SAM6883 CORE
+//**************************************************************************
+
+// base class so that GIME emulation can use some functionality
+class sam6883_friend_device
+{
+public:
+ sam6883_friend_device() { m_cpu = NULL; m_sam_state = 0x0000; }
+
+protected:
+ // SAM state constants
+ static const UINT16 SAM_STATE_TY = 0x8000;
+ static const UINT16 SAM_STATE_M1 = 0x4000;
+ static const UINT16 SAM_STATE_M0 = 0x2000;
+ static const UINT16 SAM_STATE_R1 = 0x1000;
+ static const UINT16 SAM_STATE_R0 = 0x0800;
+ static const UINT16 SAM_STATE_P1 = 0x0400;
+ static const UINT16 SAM_STATE_F6 = 0x0200;
+ static const UINT16 SAM_STATE_F5 = 0x0100;
+ static const UINT16 SAM_STATE_F4 = 0x0080;
+ static const UINT16 SAM_STATE_F3 = 0x0040;
+ static const UINT16 SAM_STATE_F2 = 0x0020;
+ static const UINT16 SAM_STATE_F1 = 0x0010;
+ static const UINT16 SAM_STATE_F0 = 0x0008;
+ static const UINT16 SAM_STATE_V2 = 0x0004;
+ static const UINT16 SAM_STATE_V1 = 0x0002;
+ static const UINT16 SAM_STATE_V0 = 0x0001;
+
+ // incidentals
+ cpu_device * m_cpu;
+
+ // device state
+ UINT16 m_sam_state;
+
+ ATTR_FORCE_INLINE UINT16 display_offset(void)
+ {
+ return ((m_sam_state & (SAM_STATE_F0|SAM_STATE_F1|SAM_STATE_F2|SAM_STATE_F3|SAM_STATE_F4|SAM_STATE_F5|SAM_STATE_F6)) / SAM_STATE_F0) << 9;
+ }
+
+ ATTR_FORCE_INLINE UINT16 alter_sam_state(offs_t offset)
+ {
+ /* determine the mask */
+ UINT16 mask = 1 << (offset >> 1);
+
+ /* determine the new state */
+ UINT16 new_state;
+ if (offset & 0x0001)
+ new_state = m_sam_state | mask;
+ else
+ new_state = m_sam_state & ~mask;
+
+ /* specify the new state */
+ UINT16 xorval = m_sam_state ^ new_state;
+ m_sam_state = new_state;
+ return xorval;
+ }
+
+ void update_cpu_clock(void);
+};
+
+class sam6883_device : public device_t, public sam6883_friend_device
+{
+public:
+ sam6883_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // called to configure banks
+ void configure_bank(int bank, UINT8 *memory, UINT32 memory_size, bool is_read_only);
+ void configure_bank(int bank, read8_delegate rhandler, write8_delegate whandler);
+
+ // typically called by VDG
+ ATTR_FORCE_INLINE DECLARE_READ8_MEMBER( display_read )
+ {
+ if (offset == (offs_t) ~0)
+ {
+ /* the VDG is telling the counter to reset */
+ m_counter = display_offset();
+ m_counter_xdiv = 0;
+ m_counter_ydiv = 0;
+ }
+ else if ((offset & 1) != (m_counter & 0x0001))
+ {
+ /* DA0 has been toggled - first bump B0-B3 of the counter */
+ bool bit3_carry = (m_counter & 0x000F) == 0x000F;
+ m_counter = (m_counter & ~0x000F) | ((m_counter + 1) & 0x000F);
+
+ /* and apply the carry (if applicable */
+ if (bit3_carry)
+ counter_carry_bit3();
+ }
+ return m_res_input_func(m_counter);
+ }
+
+ DECLARE_WRITE_LINE_MEMBER( hs_w );
+
+ // typically called by machine
+ address_space *mpu_address_space(void) const { return m_cpu_space; }
+ void set_bank_offset(int bank, offs_t offset);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_post_load();
+
+private:
+ struct sam_bank
+ {
+ UINT8 * m_memory;
+ UINT32 m_memory_size;
+ offs_t m_memory_offset;
+ bool m_memory_read_only;
+ read8_delegate m_rhandler;
+ write8_delegate m_whandler;
+ };
+
+ // incidentals
+ address_space * m_cpu_space;
+ devcb_resolved_read8 m_res_input_func;
+ sam_bank m_banks[8];
+
+ // SAM state
+ UINT16 m_counter;
+ UINT8 m_counter_xdiv;
+ UINT8 m_counter_ydiv;
+
+ // typically called by CPU
+ DECLARE_READ8_MEMBER( read );
+ DECLARE_WRITE8_MEMBER( write );
+
+ // called when there is a carry out of bit 3 on the counter
+ ATTR_FORCE_INLINE void counter_carry_bit3(void)
+ {
+ UINT8 x_division;
+ switch((m_sam_state & (SAM_STATE_V2|SAM_STATE_V1|SAM_STATE_V0)) / SAM_STATE_V0)
+ {
+ case 0x00: x_division = 1; break;
+ case 0x01: x_division = 3; break;
+ case 0x02: x_division = 1; break;
+ case 0x03: x_division = 2; break;
+ case 0x04: x_division = 1; break;
+ case 0x05: x_division = 1; break;
+ case 0x06: x_division = 1; break;
+ case 0x07: x_division = 1; break;
+ default:
+ fatalerror("Should not get here");
+ return;
+ }
+
+ if (++m_counter_xdiv >= x_division)
+ {
+ m_counter_xdiv = 0;
+ m_counter ^= 0x0010;
+ if ((m_counter & 0x0010) == 0x0000)
+ counter_carry_bit4();
+ }
+ }
+
+ // called when there is a carry out of bit 4 on the counter
+ ATTR_FORCE_INLINE void counter_carry_bit4(void)
+ {
+ UINT8 y_division;
+ switch((m_sam_state & (SAM_STATE_V2|SAM_STATE_V1|SAM_STATE_V0)) / SAM_STATE_V0)
+ {
+ case 0x00: y_division = 12; break;
+ case 0x01: y_division = 1; break;
+ case 0x02: y_division = 3; break;
+ case 0x03: y_division = 1; break;
+ case 0x04: y_division = 2; break;
+ case 0x05: y_division = 1; break;
+ case 0x06: y_division = 1; break;
+ case 0x07: y_division = 1; break;
+ default:
+ fatalerror("Should not get here");
+ return;
+ }
+
+ if (++m_counter_ydiv >= y_division)
+ {
+ m_counter_ydiv = 0;
+ m_counter += 0x0020;
+ }
+ }
+
+ // other members
+ void configure_bank(int bank, UINT8 *memory, UINT32 memory_size, bool is_read_only, read8_delegate rhandler, write8_delegate whandler);
+ void horizontal_sync(void);
+ void update_state(void);
+ void update_memory(void);
+ void update_bank(int bank, offs_t addrstart, offs_t addrend, offs_t offset);
+ void install_memory(offs_t addrstart, offs_t addrend, void *memory, bool is_read_only);
+};
+
+extern const device_type SAM6883;
+
+#endif /* __6883SAM__ */
diff --git a/src/mess/machine/74145.c b/src/mess/machine/74145.c
new file mode 100644
index 00000000000..a97111bdae1
--- /dev/null
+++ b/src/mess/machine/74145.c
@@ -0,0 +1,178 @@
+/*****************************************************************************
+ *
+ * machine/74145.c
+ *
+ * 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"
+
+/*****************************************************************************
+ GLOBAL VARIABLES
+*****************************************************************************/
+
+const ttl74145_interface default_ttl74145 =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+
+const device_type TTL74145 = &device_creator<ttl74145_device>;
+
+/***************************************************************************
+ 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)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void ttl74145_device::device_start()
+{
+ /* resolve callbacks */
+ m_output_line_0_func.resolve(m_output_line_0_cb, *this);
+ m_output_line_1_func.resolve(m_output_line_1_cb, *this);
+ m_output_line_2_func.resolve(m_output_line_2_cb, *this);
+ m_output_line_3_func.resolve(m_output_line_3_cb, *this);
+ m_output_line_4_func.resolve(m_output_line_4_cb, *this);
+ m_output_line_5_func.resolve(m_output_line_5_cb, *this);
+ m_output_line_6_func.resolve(m_output_line_6_cb, *this);
+ m_output_line_7_func.resolve(m_output_line_7_cb, *this);
+ m_output_line_8_func.resolve(m_output_line_8_cb, *this);
+ m_output_line_9_func.resolve(m_output_line_9_cb, *this);
+
+ // register for state saving
+ save_item(NAME(m_number));
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void ttl74145_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const ttl74145_interface *intf = reinterpret_cast<const ttl74145_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<ttl74145_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_output_line_0_cb, 0, sizeof(m_output_line_0_cb));
+ memset(&m_output_line_1_cb, 0, sizeof(m_output_line_1_cb));
+ memset(&m_output_line_2_cb, 0, sizeof(m_output_line_2_cb));
+ memset(&m_output_line_3_cb, 0, sizeof(m_output_line_3_cb));
+ memset(&m_output_line_4_cb, 0, sizeof(m_output_line_4_cb));
+ memset(&m_output_line_5_cb, 0, sizeof(m_output_line_5_cb));
+ memset(&m_output_line_6_cb, 0, sizeof(m_output_line_6_cb));
+ memset(&m_output_line_7_cb, 0, sizeof(m_output_line_7_cb));
+ memset(&m_output_line_8_cb, 0, sizeof(m_output_line_8_cb));
+ memset(&m_output_line_9_cb, 0, sizeof(m_output_line_9_cb));
+ }
+}
+
+//-------------------------------------------------
+// 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_func(new_number == 0);
+ m_output_line_1_func(new_number == 1);
+ m_output_line_2_func(new_number == 2);
+ m_output_line_3_func(new_number == 3);
+ m_output_line_4_func(new_number == 4);
+ m_output_line_5_func(new_number == 5);
+ m_output_line_6_func(new_number == 6);
+ m_output_line_7_func(new_number == 7);
+ m_output_line_8_func(new_number == 8);
+ m_output_line_9_func(new_number == 9);
+ }
+
+ /* update state */
+ m_number = new_number;
+}
+
+
+UINT16 ttl74145_device::read()
+{
+ return (1 << m_number) & 0x3ff;
+}
+
+
+
diff --git a/src/mess/machine/74145.h b/src/mess/machine/74145.h
new file mode 100644
index 00000000000..62a3cf0e30f
--- /dev/null
+++ b/src/mess/machine/74145.h
@@ -0,0 +1,83 @@
+/***************************************************************************
+
+ TTL74145
+
+ BCD-to-Decimal decoder
+
+***************************************************************************/
+
+#ifndef __TTL74145_H__
+#define __TTL74145_H__
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+#define MCFG_TTL74145_ADD(_tag, _intf) \
+ MCFG_DEVICE_ADD(_tag, TTL74145, 0) \
+ MCFG_DEVICE_CONFIG(_intf)
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> ttl74145_interface
+
+struct ttl74145_interface
+{
+ 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;
+};
+
+// ======================> ttl74145_device
+
+class ttl74145_device : public device_t,
+ public ttl74145_interface
+{
+public:
+ // construction/destruction
+ ttl74145_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ UINT16 read();
+ void write(UINT8 data);
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete();
+
+private:
+ devcb_resolved_write_line m_output_line_0_func;
+ devcb_resolved_write_line m_output_line_1_func;
+ devcb_resolved_write_line m_output_line_2_func;
+ devcb_resolved_write_line m_output_line_3_func;
+ devcb_resolved_write_line m_output_line_4_func;
+ devcb_resolved_write_line m_output_line_5_func;
+ devcb_resolved_write_line m_output_line_6_func;
+ devcb_resolved_write_line m_output_line_7_func;
+ devcb_resolved_write_line m_output_line_8_func;
+ devcb_resolved_write_line m_output_line_9_func;
+
+ /* decoded number */
+ UINT16 m_number;
+};
+
+// device type definition
+extern const device_type TTL74145;
+
+//**************************************************************************
+// DEFAULT INTERFACES
+//**************************************************************************
+
+extern const ttl74145_interface default_ttl74145;
+
+
+#endif /* TTL74145 */
diff --git a/src/mess/machine/8530scc.c b/src/mess/machine/8530scc.c
new file mode 100644
index 00000000000..c1c7091fea9
--- /dev/null
+++ b/src/mess/machine/8530scc.c
@@ -0,0 +1,675 @@
+/*********************************************************************
+
+ 8530scc.c
+
+ Zilog 8530 SCC (Serial Control Chip) code
+
+*********************************************************************/
+
+
+#include "emu.h"
+#include "8530scc.h"
+
+const device_type SCC8530 = &device_creator<scc8530_t>;
+
+
+/***************************************************************************
+ 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)
+{
+}
+
+void scc8530_t::set_intrq_cb(line_cb_t cb)
+{
+ intrq_cb = cb;
+}
+
+/*-------------------------------------------------
+ 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)
+ {
+ timer.adjust(attotime::from_hz(rate), 0, attotime::from_hz(rate));
+ }
+ else
+ {
+ timer.adjust(attotime::never, 0, attotime::never);
+ }
+}
+
+/*-------------------------------------------------
+ DEVICE_START( scc8530 )
+-------------------------------------------------*/
+
+void scc8530_t::device_start()
+{
+ 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( scc8530 )
+-------------------------------------------------*/
+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] & 0x05; // pick up TXBE and RXBF 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] & 0x05; // pick up TXBE and RXBF 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 */
+ return channel[1].rxData;
+ break;
+
+ case 3:
+ /* Channel A (Modem Port) Data */
+ return 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/mess/machine/8530scc.h b/src/mess/machine/8530scc.h
new file mode 100644
index 00000000000..c3d24684ae6
--- /dev/null
+++ b/src/mess/machine/8530scc.h
@@ -0,0 +1,101 @@
+/*********************************************************************
+
+ 8530scc.h
+
+ Zilog 8530 SCC (Serial Control Chip) code
+
+*********************************************************************/
+
+#ifndef __8530SCC_H__
+#define __8530SCC_H__
+
+#define MCFG_SCC8530_ADD(_tag, _clock, _intrq_cb) \
+ MCFG_DEVICE_ADD(_tag, SCC8530, _clock) \
+ downcast<scc8530_t *>(device)->set_intrq_cb(_intrq_cb);
+
+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);
+ void set_intrq_cb(line_cb_t cb);
+
+ 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];
+
+ line_cb_t 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/mess/machine/990_dk.c b/src/mess/machine/990_dk.c
new file mode 100644
index 00000000000..ef95a3e5e71
--- /dev/null
+++ b/src/mess/machine/990_dk.c
@@ -0,0 +1,881 @@
+/*
+ 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
+*/
+
+#include "emu.h"
+
+#include "formats/basicdsk.h"
+#include "imagedev/flopdrv.h"
+#include "990_dk.h"
+
+#define MAX_FLOPPIES 4
+
+enum buf_mode_t {
+ bm_off, bm_read, bm_write
+};
+static struct
+{
+ running_machine *machine;
+ UINT16 recv_buf;
+ UINT16 stat_reg;
+ UINT16 xmit_buf;
+ UINT16 cmd_reg;
+
+ int interrupt_f_f;
+ void (*interrupt_callback)(running_machine &, int state);
+
+ UINT8 buf[128];
+ int buf_pos;
+ buf_mode_t buf_mode;
+ int unit;
+ int head;
+ int sector;
+ /*int non_seq_mode;*/
+ int ddam;
+
+ struct
+ {
+ device_image_interface *img;
+ int phys_cylinder;
+ int log_cylinder[2];
+ int seclen;
+ } drv[MAX_FLOPPIES];
+} fd800;
+
+/* 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
+};
+
+LEGACY_FLOPPY_OPTIONS_START(fd800)
+#if 1
+ /* 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]))
+#elif 0
+ /* 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]))
+#endif
+LEGACY_FLOPPY_OPTIONS_END
+
+static void fd800_field_interrupt(void)
+{
+ if (fd800.interrupt_callback)
+ (*fd800.interrupt_callback)(*fd800.machine, (fd800.stat_reg & status_interrupt) && ! fd800.interrupt_f_f);
+}
+
+static void fd800_unload_proc(device_image_interface &image)
+{
+ int unit = floppy_get_drive(&image.device());
+
+ fd800.drv[unit].log_cylinder[0] = fd800.drv[unit].log_cylinder[1] = -1;
+}
+
+void fd800_machine_init(running_machine &machine, void (*interrupt_callback)(running_machine &machine, int state))
+{
+ int i;
+
+ fd800.machine = &machine;
+ fd800.interrupt_callback = interrupt_callback;
+
+ fd800.stat_reg = 0;
+ fd800.interrupt_f_f = 1;
+
+ fd800.buf_pos = 0;
+ fd800.buf_mode = bm_off;
+
+ for (i=0; i<MAX_FLOPPIES; i++)
+ {
+ fd800.drv[i].img = dynamic_cast<device_image_interface *>(floppy_get_device(machine, i));
+ fd800.drv[i].phys_cylinder = -1;
+ fd800.drv[i].log_cylinder[0] = fd800.drv[i].log_cylinder[1] = -1;
+ fd800.drv[i].seclen = 64;
+ floppy_install_unload_proc(&fd800.drv[i].img->device(), fd800_unload_proc);
+ }
+
+ fd800_field_interrupt();
+}
+
+/*
+ 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
+*/
+static int fd800_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 (floppy_drive_get_next_id(&fd800.drv[unit].img->device(), 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
+*/
+static int fd800_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 (floppy_drive_get_next_id(&fd800.drv[unit].img->device(), 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
+*/
+static int fd800_do_seek(int unit, int cylinder, int head)
+{
+ int retries;
+
+ if (cylinder > 76)
+ {
+ fd800.stat_reg |= status_invalid_cmd;
+ return TRUE;
+ }
+
+ if (!fd800.drv[unit].img->exists())
+ {
+ fd800.stat_reg |= status_drv_not_ready; /* right??? */
+ return TRUE;
+ }
+
+ if (fd800.drv[unit].log_cylinder[head] == -1)
+ { /* current track ID is unknown: read it */
+ if (!fd800_read_id(unit, head, &fd800.drv[unit].log_cylinder[head], NULL))
+ {
+ fd800.stat_reg |= status_ID_not_found;
+ return TRUE;
+ }
+ }
+ /* exit if we are already at the requested track */
+ if (fd800.drv[unit].log_cylinder[head] == cylinder)
+ {
+ /*fd800.stat_reg |= status_OP_complete;*/
+ return FALSE;
+ }
+ for (retries=0; retries<10; retries++)
+ { /* seek to requested track */
+ floppy_drive_seek(&fd800.drv[unit].img->device(), cylinder-fd800.drv[unit].log_cylinder[head]);
+ /* update physical track position */
+ if (fd800.drv[unit].phys_cylinder != -1)
+ fd800.drv[unit].phys_cylinder += cylinder-fd800.drv[unit].log_cylinder[head];
+ /* read new track ID */
+ if (!fd800_read_id(unit, head, &fd800.drv[unit].log_cylinder[head], NULL))
+ {
+ fd800.drv[unit].log_cylinder[head] = -1;
+ fd800.stat_reg |= status_ID_not_found;
+ return TRUE;
+ }
+ /* exit if we have reached the requested track */
+ if (fd800.drv[unit].log_cylinder[head] == cylinder)
+ {
+ /*fd800.stat_reg |= status_OP_complete;*/
+ return FALSE;
+ }
+ }
+ /* track not found */
+ fd800.stat_reg |= status_seek_err;
+ return TRUE;
+}
+
+/*
+ Perform restore command
+
+ unit: floppy drive index
+
+ Return FALSE if the restore was successful
+*/
+static int fd800_do_restore(int unit)
+{
+ int seek_count = 0;
+ int seek_complete;
+
+ if (!fd800.drv[unit].img->exists())
+ {
+ fd800.stat_reg |= status_drv_not_ready; /* right??? */
+ return TRUE;
+ }
+
+ /* limit iterations to 76 to prevent an endless loop if the disc is locked */
+ while (!(seek_complete = !floppy_tk00_r(&fd800.drv[unit].img->device())) && (seek_count < 76))
+ {
+ floppy_drive_seek(&fd800.drv[unit].img->device(), -1);
+ seek_count++;
+ }
+ if (! seek_complete)
+ {
+ fd800.drv[unit].phys_cylinder = -1;
+ fd800.stat_reg |= status_seek_err;
+ }
+ else
+ {
+ fd800.drv[unit].phys_cylinder = 0;
+ /*fd800.stat_reg |= status_OP_complete;*/
+ }
+
+ return ! seek_complete;
+}
+
+/*
+ Perform a read operation for one sector
+*/
+static void fd800_do_read(void)
+{
+ int data_id;
+
+ if ((fd800.sector == 0) || (fd800.sector > 26))
+ {
+ fd800.stat_reg |= status_invalid_cmd;
+ return;
+ }
+
+ if (!fd800_find_sector(fd800.unit, fd800.head, fd800.sector, &data_id))
+ {
+ fd800.stat_reg |= status_ID_not_found;
+ return;
+ }
+
+ floppy_drive_read_sector_data(&fd800.drv[fd800.unit].img->device(), fd800.head, data_id, fd800.buf, 128);
+ fd800.buf_pos = 0;
+ fd800.buf_mode = bm_read;
+ fd800.recv_buf = (fd800.buf[fd800.buf_pos<<1] << 8) | fd800.buf[(fd800.buf_pos<<1)+1];
+
+ fd800.stat_reg |= status_XFER_ready;
+ fd800.stat_reg |= status_OP_complete; /* right??? */
+}
+
+/*
+ Perform a write operation for one sector
+*/
+static void fd800_do_write(void)
+{
+ int data_id;
+
+ if (fd800.drv[fd800.unit].seclen < 64)
+ /* fill with 0s */
+ memset(fd800.buf+(fd800.drv[fd800.unit].seclen<<1), 0, (64-fd800.drv[fd800.unit].seclen)<<1);
+
+ if (!fd800_find_sector(fd800.unit, fd800.head, fd800.sector, &data_id))
+ {
+ fd800.stat_reg |= status_ID_not_found;
+ return;
+ }
+
+ floppy_drive_write_sector_data(&fd800.drv[fd800.unit].img->device(), fd800.head, data_id, fd800.buf, 128, fd800.ddam);
+ fd800.buf_pos = 0;
+ fd800.buf_mode = bm_write;
+
+ fd800.stat_reg |= status_XFER_ready;
+ fd800.stat_reg |= status_OP_complete; /* right??? */
+}
+
+/*
+ Execute a fdc command
+*/
+static void fd800_do_cmd(void)
+{
+ int unit;
+ int cylinder;
+ int head;
+ int seclen;
+ int sector;
+
+
+ if (fd800.buf_mode != bm_off)
+ { /* All commands in the midst of read or write are interpreted as Stop */
+ unit = (fd800.cmd_reg >> 10) & 3;
+
+ /* reset status */
+ fd800.stat_reg = unit << status_unit_shift;
+
+ fd800.buf_pos = 0;
+ fd800.buf_mode = bm_off;
+
+ fd800.stat_reg |= status_OP_complete;
+
+ fd800.stat_reg |= status_interrupt;
+ fd800_field_interrupt();
+
+ return;
+ }
+
+ switch (fd800.cmd_reg >> 12)
+ {
+ case 0: /* select
+ bits 16-25: 0s
+ bits 26-27: unit number (0-3) */
+ unit = (fd800.cmd_reg >> 10) & 3;
+
+ /* reset status */
+ fd800.stat_reg = unit << status_unit_shift;
+
+ if (!fd800.drv[unit].img->exists())
+ fd800.stat_reg |= status_drv_not_ready; /* right??? */
+ else if (fd800.drv[unit].img->is_readonly())
+ fd800.stat_reg |= status_write_prot;
+ else
+ fd800.stat_reg |= status_OP_complete;
+
+ fd800.stat_reg |= status_interrupt;
+ fd800_field_interrupt();
+ 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 = (fd800.cmd_reg >> 10) & 3;
+ head = (fd800.cmd_reg >> 9) & 1;
+ cylinder = fd800.cmd_reg & 0x7f;
+
+ /* reset status */
+ fd800.stat_reg = unit << status_unit_shift;
+
+ if (!fd800_do_seek(unit, cylinder, head))
+ fd800.stat_reg |= status_OP_complete;
+
+ fd800.stat_reg |= status_interrupt;
+ fd800_field_interrupt();
+ break;
+
+ case 2: /* restore
+ bits 16-25: 0s
+ bits 26-27: unit number (0-3) */
+ unit = (fd800.cmd_reg >> 10) & 3;
+
+ /* reset status */
+ fd800.stat_reg = unit << status_unit_shift;
+
+ if (!fd800_do_restore(unit))
+ fd800.stat_reg |= status_OP_complete;
+
+ fd800.stat_reg |= status_interrupt;
+ fd800_field_interrupt();
+ 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 = (fd800.cmd_reg >> 10) & 3;
+ seclen = fd800.cmd_reg & 0x7f;
+
+ /* reset status */
+ fd800.stat_reg = unit << status_unit_shift;
+
+ if ((seclen > 64) || (seclen == 0))
+ {
+ fd800.stat_reg |= status_invalid_cmd;
+ }
+ else
+ {
+ fd800.drv[unit].seclen = seclen;
+ fd800.stat_reg |= status_OP_complete;
+ }
+
+ fd800.stat_reg |= status_interrupt;
+ fd800_field_interrupt();
+ 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 = (fd800.cmd_reg >> 10) & 3;
+ head = (fd800.cmd_reg >> 9) & 1;
+ /*non_seq_mode = (fd800.cmd_reg >> 8) & 1;*/
+ sector = fd800.cmd_reg & 0x1f;
+
+ fd800.unit = unit;
+ fd800.head = head;
+ fd800.sector = sector;
+ /*fd800.non_seq_mode = non_seq_mode;*/
+
+ /* reset status */
+ fd800.stat_reg = unit << status_unit_shift;
+
+ fd800_do_read();
+
+ fd800.stat_reg |= status_interrupt;
+ fd800_field_interrupt();
+ break;
+
+ case 5: /* read ID
+ bits 16-24: 0s
+ bit 25: head number (1=upper)
+ bits 26-27: unit number (0-3) */
+ unit = (fd800.cmd_reg >> 10) & 3;
+ head = (fd800.cmd_reg >> 9) & 1;
+
+ /* reset status */
+ fd800.stat_reg = unit << status_unit_shift;
+
+ if (!fd800_read_id(unit, head, &cylinder, &sector))
+ {
+ fd800.stat_reg |= status_ID_not_found;
+ }
+ else
+ {
+ fd800.recv_buf = (cylinder << 8) | sector;
+ fd800.stat_reg |= status_OP_complete;
+ }
+
+ fd800.stat_reg |= status_interrupt;
+ fd800_field_interrupt();
+ 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 = (fd800.cmd_reg >> 10) & 3;
+ head = (fd800.cmd_reg >> 9) & 1;
+ sector = fd800.cmd_reg & 0x1f;
+
+ /* reset status */
+ fd800.stat_reg = unit << status_unit_shift;
+
+ if ((fd800.sector == 0) || (fd800.sector > 26))
+ {
+ fd800.stat_reg |= status_invalid_cmd;
+ }
+ else
+ {
+ fd800.unit = unit;
+ fd800.head = head;
+ fd800.sector = sector;
+ fd800.ddam = 0;
+
+ fd800.buf_pos = 0;
+ fd800.buf_mode = bm_write;
+ fd800.stat_reg |= status_XFER_ready;
+ fd800.stat_reg |= status_OP_complete; /* right??? */
+ }
+
+ fd800.stat_reg |= status_interrupt;
+ fd800_field_interrupt();
+ 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 = (fd800.cmd_reg >> 10) & 3;
+ head = (fd800.cmd_reg >> 9) & 1;
+ sector = fd800.cmd_reg & 0x1f;
+
+ /* reset status */
+ fd800.stat_reg = unit << status_unit_shift;
+
+ if ((fd800.sector == 0) || (fd800.sector > 26))
+ {
+ fd800.stat_reg |= status_invalid_cmd;
+ }
+ else
+ {
+ fd800.unit = unit;
+ fd800.head = head;
+ fd800.sector = sector;
+ fd800.ddam = 1;
+
+ fd800.buf_pos = 0;
+ fd800.buf_mode = bm_write;
+ fd800.stat_reg |= status_XFER_ready;
+ fd800.stat_reg |= status_OP_complete; /* right??? */
+ }
+
+ fd800.stat_reg |= status_interrupt;
+ fd800_field_interrupt();
+ 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 */
+ fd800.interrupt_f_f = fd800.cmd_reg & 1;
+ fd800_field_interrupt();
+ break;
+
+ case 11: /* stop
+ bits 16-25: 0s
+ bits 26-27: unit number (0-3) */
+ unit = (fd800.cmd_reg >> 10) & 3;
+
+ /* reset status */
+ fd800.stat_reg = unit << status_unit_shift;
+
+ fd800.stat_reg |= status_OP_complete;
+
+ fd800.stat_reg |= status_interrupt;
+ fd800_field_interrupt();
+ break;
+
+ case 12: /* step head
+ bits 16-22: track number (0-76)
+ bits 23-25: 0s
+ bits 26-27: unit number (0-3) */
+ unit = (fd800.cmd_reg >> 10) & 3;
+ cylinder = fd800.cmd_reg & 0x7f;
+
+ if (cylinder > 76)
+ {
+ fd800.stat_reg |= status_invalid_cmd;
+ }
+ else if ((fd800.drv[unit].phys_cylinder != -1) || (!fd800_do_restore(unit)))
+ {
+ floppy_drive_seek(&fd800.drv[unit].img->device(), cylinder-fd800.drv[unit].phys_cylinder);
+ fd800.stat_reg |= status_OP_complete;
+ }
+
+ fd800.stat_reg |= status_interrupt;
+ fd800_field_interrupt();
+ break;
+
+ case 13: /* maintenance commands
+ bits 16-23: according to extended command code
+ bits 24-27: extended command code (0-7) */
+ switch ((fd800.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 = (fd800.cmd_reg >> 10) & 3;
+ head = (fd800.cmd_reg >> 9) & 1;
+ /*non_seq_mode = (fd800.cmd_reg >> 8) & 1;*/
+ cylinder = fd800.cmd_reg & 0x7f;
+
+ if (!fd800_do_seek(unit, cylinder, head))
+ {
+ fd800.unit = unit;
+ fd800.head = head;
+ fd800.sector = 1;
+ /*fd800.non_seq_mode = non_seq_mode;*/
+
+ fd800_do_read();
+ }
+
+ fd800.stat_reg |= status_interrupt;
+ fd800_field_interrupt();
+ break;
+
+ case 15: /* Clear Status port
+ bits 16-27: 0s */
+ fd800.stat_reg = 0;
+ fd800_field_interrupt();
+ 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_HANDLER(fd800_cru_r)
+{
+ int reply = 0;
+
+ switch (offset)
+ {
+ case 0:
+ case 1:
+ /* receive buffer */
+ reply = fd800.recv_buf >> (offset*8);
+ break;
+
+ case 2:
+ case 3:
+ /* status register */
+ reply = fd800.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_HANDLER(fd800_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)
+ fd800.xmit_buf |= 1 << offset;
+ else
+ fd800.xmit_buf &= ~(1 << offset);
+ if (offset == 15)
+ {
+ switch (fd800.buf_mode)
+ {
+ case bm_off:
+ break;
+ case bm_read:
+ fd800.buf_pos++;
+ if (fd800.buf_pos == fd800.drv[fd800.unit].seclen)
+ { /* end of sector */
+ if (fd800.sector == 26)
+ { /* end of track -> end command (right???) */
+ fd800.stat_reg &= ~status_XFER_ready;
+ fd800.stat_reg |= status_OP_complete;
+ fd800.stat_reg |= status_interrupt;
+ fd800.buf_mode = bm_off;
+ fd800_field_interrupt();
+ }
+ else
+ { /* read next sector */
+ fd800.sector++;
+ fd800.stat_reg &= ~status_XFER_ready | status_OP_complete | status_interrupt;
+ fd800_do_read();
+ fd800.stat_reg |= status_interrupt;
+ fd800_field_interrupt();
+ }
+ }
+ else
+ fd800.recv_buf = (fd800.buf[fd800.buf_pos<<1] << 8) | fd800.buf[(fd800.buf_pos<<1)+1];
+ break;
+
+ case bm_write:
+ fd800.buf[fd800.buf_pos<<1] = fd800.xmit_buf >> 8;
+ fd800.buf[(fd800.buf_pos<<1)+1] = fd800.xmit_buf & 0xff;
+ fd800.buf_pos++;
+ if (fd800.buf_pos == fd800.drv[fd800.unit].seclen)
+ { /* end of sector */
+ fd800_do_write();
+ if (fd800.sector == 26)
+ {
+ /* end of track -> end command (right???) */
+ fd800.stat_reg &= ~status_XFER_ready;
+ fd800.stat_reg |= status_OP_complete;
+ fd800.stat_reg |= status_interrupt;
+ fd800.buf_mode = bm_off;
+ fd800_field_interrupt();
+ }
+ else
+ { /* increment to next sector */
+ fd800.sector++;
+ fd800.stat_reg |= status_interrupt;
+ fd800_field_interrupt();
+ }
+ }
+ 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)
+ fd800.cmd_reg |= 1 << (offset-16);
+ else
+ fd800.cmd_reg &= ~(1 << (offset-16));
+ if (offset == 31)
+ fd800_do_cmd();
+ break;
+ }
+}
diff --git a/src/mess/machine/990_dk.h b/src/mess/machine/990_dk.h
new file mode 100644
index 00000000000..7607f586788
--- /dev/null
+++ b/src/mess/machine/990_dk.h
@@ -0,0 +1,10 @@
+/*
+ 990_dk.h: include file for 990_dk.c
+*/
+LEGACY_FLOPPY_OPTIONS_EXTERN(fd800);
+
+void fd800_machine_init(running_machine &machine, void (*interrupt_callback)(running_machine &machine, int state));
+
+extern READ8_HANDLER(fd800_cru_r);
+extern WRITE8_HANDLER(fd800_cru_w);
+
diff --git a/src/mess/machine/990_hd.c b/src/mess/machine/990_hd.c
new file mode 100644
index 00000000000..318009bdb73
--- /dev/null
+++ b/src/mess/machine/990_hd.c
@@ -0,0 +1,1053 @@
+/*
+ 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"
+
+static void update_interrupt(running_machine &machine);
+
+/* 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
+
+/* 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 */
+typedef struct UINT32BE
+{
+ UINT8 bytes[4];
+} UINT32BE;
+
+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 */
+typedef 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) */
+} disk_image_header;
+
+enum
+{
+ header_len = sizeof(disk_image_header)
+};
+
+enum format_t
+{
+ format_mame,
+ format_old
+};
+
+/* disk drive unit descriptor */
+typedef 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;
+} hd_unit_t;
+
+/* disk controller */
+typedef struct hdc_t
+{
+ UINT16 w[8];
+
+ void (*interrupt_callback)(running_machine &machine, int state);
+
+ hd_unit_t d[MAX_DISK_UNIT];
+} hdc_t;
+
+/* 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 */
+};
+
+static hdc_t hdc;
+
+
+static int 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;
+}
+
+
+#ifdef UNUSED_FUNCTION
+DEVICE_STOP( ti990_hd )
+{
+ d->img = NULL;
+}
+#endif
+
+/*
+ Initialize hard disk unit and open a hard disk image
+*/
+static DEVICE_IMAGE_LOAD( ti990_hd )
+{
+ int id = get_id_from_device( &image.device() );
+ hd_unit_t *d;
+ hard_disk_file *hd_file;
+
+ d = &hdc.d[id];
+ d->img = &image;
+
+ hd_file = dynamic_cast<harddisk_image_device *>(&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 */
+ hdc.w[0] |= (0x80 >> id);
+
+ return IMAGE_INIT_PASS;
+}
+
+/*
+ close a hard disk image
+*/
+static DEVICE_IMAGE_UNLOAD( ti990_hd )
+{
+ int id = get_id_from_device( image );
+ hd_unit_t *d;
+
+ d = &hdc.d[id];
+
+ d->format = format_mame; /* don't care */
+ d->hd_handle = NULL;
+ d->wp = 1;
+ d->unsafe = 1;
+
+ /* clear attention line */
+ hdc.w[0] &= ~ (0x80 >> id);
+}
+
+/*
+ Return true if a HD image has been loaded
+*/
+INLINE int is_unit_loaded(int unit)
+{
+ int reply = 0;
+
+ switch (hdc.d[unit].format)
+ {
+ case format_mame:
+ reply = (hdc.d[unit].hd_handle != NULL);
+ break;
+
+ case format_old:
+ reply = (hdc.d[unit].img->exists() ? 1 : 0);
+ break;
+ }
+
+ return reply;
+}
+
+/*
+ Init the hdc core
+*/
+MACHINE_START(ti990_hdc)
+{
+ int i;
+
+ /* initialize harddisk information */
+ /* attention lines will be set by DEVICE_IMAGE_LOD */
+ for (i=0; i<MAX_DISK_UNIT; i++)
+ {
+ hdc.d[i].format = format_mame;
+ hdc.d[i].hd_handle = NULL;
+ hdc.d[i].wp = 1;
+ hdc.d[i].unsafe = 1;
+ }
+}
+
+
+void ti990_hdc_init(running_machine &machine, void (*interrupt_callback)(running_machine &machine, int state))
+{
+ memset(hdc.w, 0, sizeof(hdc.w));
+ hdc.w[7] = w7_idle;
+
+ /* get references to harddisk devices */
+ hdc.d[0].img = dynamic_cast<device_image_interface *>(machine.device("harddisk1"));
+ hdc.d[1].img = dynamic_cast<device_image_interface *>(machine.device("harddisk2"));
+ hdc.d[2].img = dynamic_cast<device_image_interface *>(machine.device("harddisk3"));
+ hdc.d[3].img = dynamic_cast<device_image_interface *>(machine.device("harddisk4"));
+
+ hdc.interrupt_callback = interrupt_callback;
+
+ update_interrupt(machine);
+}
+
+
+/*
+ Parse the disk select lines, and return the corresponding tape unit.
+ (-1 if none)
+*/
+static int cur_disk_unit(void)
+{
+ int reply;
+
+
+ if (hdc.w[6] & w6_unit0_sel)
+ reply = 0;
+ else if (hdc.w[6] & w6_unit1_sel)
+ reply = 1;
+ else if (hdc.w[6] & w6_unit2_sel)
+ reply = 2;
+ else if (hdc.w[6] & w6_unit3_sel)
+ reply = 3;
+ else
+ reply = -1;
+
+ if (reply >= MAX_DISK_UNIT)
+ reply = -1;
+
+ return reply;
+}
+
+/*
+ Update interrupt state
+*/
+static void update_interrupt(running_machine &machine)
+{
+ if (hdc.interrupt_callback)
+ (*hdc.interrupt_callback)(machine, (hdc.w[7] & w7_idle)
+ && (((hdc.w[7] & w7_int_enable) && (hdc.w[7] & (w7_complete | w7_error)))
+ || ((hdc.w[0] & (hdc.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.
+*/
+static int check_sector_address(running_machine &machine, int unit, unsigned int cylinder, unsigned int head, unsigned int sector)
+{
+ if ((cylinder > hdc.d[unit].cylinders) || (head > hdc.d[unit].heads) || (sector > hdc.d[unit].sectors_per_track))
+ { /* invalid address */
+ if (cylinder > hdc.d[unit].cylinders)
+ {
+ hdc.w[0] |= w0_seek_incomplete;
+ hdc.w[7] |= w7_idle | w7_error | w7_unit_err;
+ }
+ else if (head > hdc.d[unit].heads)
+ {
+ hdc.w[0] |= w0_end_of_cylinder;
+ hdc.w[7] |= w7_idle | w7_error | w7_unit_err;
+ }
+ else if (sector > hdc.d[unit].sectors_per_track)
+ hdc.w[7] |= w7_idle | w7_error | w7_command_time_out_err;
+ update_interrupt(machine);
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ Seek to sector whose address is given
+*/
+static int sector_to_lba(running_machine &machine, int unit, unsigned int cylinder, unsigned int head, unsigned int sector, unsigned int *lba)
+{
+ if (check_sector_address(machine, unit, cylinder, head, sector))
+ return 1;
+
+ * lba = (cylinder*hdc.d[unit].heads + head)*hdc.d[unit].sectors_per_track + sector;
+
+ return 0;
+}
+
+/*
+ Read one given sector
+*/
+static int read_sector(int unit, unsigned int lba, void *buffer, unsigned int bytes_to_read)
+{
+ unsigned long byte_position;
+ unsigned int bytes_read;
+
+ switch (hdc.d[unit].format)
+ {
+ case format_mame:
+ bytes_read = hdc.d[unit].bytes_per_sector * hard_disk_read(hdc.d[unit].hd_handle, lba, buffer);
+ if (bytes_read > bytes_to_read)
+ bytes_read = bytes_to_read;
+ break;
+
+ case format_old:
+ byte_position = lba*hdc.d[unit].bytes_per_sector + header_len;
+ hdc.d[unit].img->fseek(byte_position, SEEK_SET);
+ bytes_read = hdc.d[unit].img->fread(buffer, bytes_to_read);
+ break;
+
+ default:
+ bytes_read = 0;
+ break;
+ }
+
+ return bytes_read;
+}
+
+/*
+ Write one given sector
+*/
+static int write_sector(int unit, unsigned int lba, const void *buffer, unsigned int bytes_to_write)
+{
+ unsigned long byte_position;
+ unsigned int bytes_written;
+
+ switch (hdc.d[unit].format)
+ {
+ case format_mame:
+ bytes_written = hdc.d[unit].bytes_per_sector * hard_disk_write(hdc.d[unit].hd_handle, lba, buffer);
+ if (bytes_written > bytes_to_write)
+ bytes_written = bytes_to_write;
+ break;
+
+ case format_old:
+ byte_position = lba*hdc.d[unit].bytes_per_sector + header_len;
+ hdc.d[unit].img->fseek(byte_position, SEEK_SET);
+ bytes_written = hdc.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.
+*/
+static void store_registers(running_machine &machine)
+{
+ 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... */
+ hdc.w[7] |= w7_idle | w7_error | w7_abnormal_completion;
+ update_interrupt(machine);
+ return;
+ }
+ else if (! is_unit_loaded(dsk_sel))
+ { /* offline */
+ hdc.w[0] |= w0_offline | w0_not_ready;
+ hdc.w[7] |= w7_idle | w7_error | w7_unit_err;
+ update_interrupt(machine);
+ return;
+ }
+
+ hdc.d[dsk_sel].unsafe = 0; /* I think */
+
+ dma_address = ((((int) hdc.w[6]) << 16) | hdc.w[5]) & 0x1ffffe;
+ byte_count = hdc.w[4] & 0xfffe;
+
+ /* formatted words per track */
+ buffer[0] = (hdc.d[dsk_sel].sectors_per_track*hdc.d[dsk_sel].bytes_per_sector) >> 1;
+ /* MSByte: sectors per track; LSByte: bytes of overhead per sector */
+ buffer[1] = (hdc.d[dsk_sel].sectors_per_track << 8) | 0;
+ /* bits 0-4: heads; bits 5-15: cylinders */
+ buffer[2] = (hdc.d[dsk_sel].heads << 11) | hdc.d[dsk_sel].cylinders;
+
+ real_word_count = byte_count >> 1;
+ if (real_word_count > 3)
+ real_word_count = 3;
+
+ /* DMA */
+ if (! (hdc.w[1] & w1_transfer_inhibit))
+ for (i=0; i<real_word_count; i++)
+ {
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->write_word(dma_address, buffer[i]);
+ dma_address = (dma_address + 2) & 0x1ffffe;
+ }
+
+ hdc.w[7] |= w7_idle | w7_complete;
+ update_interrupt(machine);
+}
+
+/*
+ Handle the write format command: format a complete track on disk.
+
+ The emulation just clears the track data in the disk image.
+*/
+static void write_format(running_machine &machine)
+{
+ 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... */
+ hdc.w[7] |= w7_idle | w7_error | w7_abnormal_completion;
+ update_interrupt(machine);
+ return;
+ }
+ else if (! is_unit_loaded(dsk_sel))
+ { /* offline */
+ hdc.w[0] |= w0_offline | w0_not_ready;
+ hdc.w[7] |= w7_idle | w7_error | w7_unit_err;
+ update_interrupt(machine);
+ return;
+ }
+ else if (hdc.d[dsk_sel].unsafe)
+ { /* disk in unsafe condition */
+ hdc.w[0] |= w0_unsafe | w0_pack_change;
+ hdc.w[7] |= w7_idle | w7_error | w7_unit_err;
+ update_interrupt(machine);
+ return;
+ }
+ else if (hdc.d[dsk_sel].wp)
+ { /* disk write-protected */
+ hdc.w[0] |= w0_write_protect;
+ hdc.w[7] |= w7_idle | w7_error | w7_unit_err;
+ update_interrupt(machine);
+ return;
+ }
+
+ cylinder = hdc.w[3];
+ head = hdc.w[1] & w1_head_address;
+
+ if (sector_to_lba(machine, dsk_sel, cylinder, head, 0, &lba))
+ return;
+
+ memset(buffer, 0, hdc.d[dsk_sel].bytes_per_sector);
+
+ for (sector=0; sector<hdc.d[dsk_sel].sectors_per_track; sector++)
+ {
+ bytes_written = write_sector(dsk_sel, lba, buffer, hdc.d[dsk_sel].bytes_per_sector);
+
+ if (bytes_written != hdc.d[dsk_sel].bytes_per_sector)
+ {
+ hdc.w[0] |= w0_offline | w0_not_ready;
+ hdc.w[7] |= w7_idle | w7_error | w7_unit_err;
+ update_interrupt(machine);
+ return;
+ }
+
+ lba++;
+ }
+
+ hdc.w[7] |= w7_idle | w7_complete;
+ update_interrupt(machine);
+}
+
+/*
+ Handle the read data command: read a variable number of sectors from disk.
+*/
+static void read_data(running_machine &machine)
+{
+ int dma_address;
+ int byte_count;
+
+ unsigned int cylinder, head, sector;
+ unsigned int lba;
+
+ UINT8 buffer[MAX_SECTOR_SIZE];
+ int bytes_to_read;
+ int bytes_read;
+ int i;
+
+ int dsk_sel = cur_disk_unit();
+
+
+ if (dsk_sel == -1)
+ {
+ /* No idea what to report... */
+ hdc.w[7] |= w7_idle | w7_error | w7_abnormal_completion;
+ update_interrupt(machine);
+ return;
+ }
+ else if (! is_unit_loaded(dsk_sel))
+ { /* offline */
+ hdc.w[0] |= w0_offline | w0_not_ready;
+ hdc.w[7] |= w7_idle | w7_error | w7_unit_err;
+ update_interrupt(machine);
+ return;
+ }
+ else if (hdc.d[dsk_sel].unsafe)
+ { /* disk in unsafe condition */
+ hdc.w[0] |= w0_unsafe | w0_pack_change;
+ hdc.w[7] |= w7_idle | w7_error | w7_unit_err;
+ update_interrupt(machine);
+ return;
+ }
+
+ dma_address = ((((int) hdc.w[6]) << 16) | hdc.w[5]) & 0x1ffffe;
+ byte_count = hdc.w[4] & 0xfffe;
+
+ cylinder = hdc.w[3];
+ head = hdc.w[1] & w1_head_address;
+ sector = hdc.w[2] & 0xff;
+
+ if (sector_to_lba(machine, dsk_sel, cylinder, head, sector, &lba))
+ return;
+
+ while (byte_count)
+ { /* read data sector per sector */
+ if (cylinder > hdc.d[dsk_sel].cylinders)
+ {
+ hdc.w[0] |= w0_seek_incomplete;
+ hdc.w[7] |= w7_idle | w7_error | w7_unit_err;
+ update_interrupt(machine);
+ return;
+ }
+
+ bytes_to_read = (byte_count < hdc.d[dsk_sel].bytes_per_sector) ? byte_count : hdc.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 */
+ hdc.w[7] |= w7_idle | w7_error | w7_command_time_out_err;
+ update_interrupt(machine);
+ return;
+ }
+
+ /* DMA */
+ if (! (hdc.w[1] & w1_transfer_inhibit))
+ for (i=0; i<bytes_read; i+=2)
+ {
+ machine.device("maincpu")->memory().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 == hdc.d[dsk_sel].sectors_per_track)
+ {
+ sector = 0;
+ head++;
+ if (head == hdc.d[dsk_sel].heads)
+ {
+ head = 0;
+ cylinder++;
+ }
+ }
+ }
+
+ hdc.w[7] |= w7_idle | w7_complete;
+ update_interrupt(machine);
+}
+
+/*
+ Handle the write data command: write a variable number of sectors from disk.
+*/
+static void write_data(running_machine &machine)
+{
+ 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... */
+ hdc.w[7] |= w7_idle | w7_error | w7_abnormal_completion;
+ update_interrupt(machine);
+ return;
+ }
+ else if (! is_unit_loaded(dsk_sel))
+ { /* offline */
+ hdc.w[0] |= w0_offline | w0_not_ready;
+ hdc.w[7] |= w7_idle | w7_error | w7_unit_err;
+ update_interrupt(machine);
+ return;
+ }
+ else if (hdc.d[dsk_sel].unsafe)
+ { /* disk in unsafe condition */
+ hdc.w[0] |= w0_unsafe | w0_pack_change;
+ hdc.w[7] |= w7_idle | w7_error | w7_unit_err;
+ update_interrupt(machine);
+ return;
+ }
+ else if (hdc.d[dsk_sel].wp)
+ { /* disk write-protected */
+ hdc.w[0] |= w0_write_protect;
+ hdc.w[7] |= w7_idle | w7_error | w7_unit_err;
+ update_interrupt(machine);
+ return;
+ }
+
+ dma_address = ((((int) hdc.w[6]) << 16) | hdc.w[5]) & 0x1ffffe;
+ byte_count = hdc.w[4] & 0xfffe;
+
+ cylinder = hdc.w[3];
+ head = hdc.w[1] & w1_head_address;
+ sector = hdc.w[2] & 0xff;
+
+ if (sector_to_lba(machine, dsk_sel, cylinder, head, sector, &lba))
+ return;
+
+ while (byte_count > 0)
+ { /* write data sector per sector */
+ if (cylinder > hdc.d[dsk_sel].cylinders)
+ {
+ hdc.w[0] |= w0_seek_incomplete;
+ hdc.w[7] |= w7_idle | w7_error | w7_unit_err;
+ update_interrupt(machine);
+ return;
+ }
+
+ /* DMA */
+ for (i=0; (i<byte_count) && (i<hdc.d[dsk_sel].bytes_per_sector); i+=2)
+ {
+ word = machine.device("maincpu")->memory().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<hdc.d[dsk_sel].bytes_per_sector; i+=2)
+ buffer[i] = buffer[i+1] = 0;
+
+ bytes_written = write_sector(dsk_sel, lba, buffer, hdc.d[dsk_sel].bytes_per_sector);
+
+ if (bytes_written != hdc.d[dsk_sel].bytes_per_sector)
+ {
+ hdc.w[0] |= w0_offline | w0_not_ready;
+ hdc.w[7] |= w7_idle | w7_error | w7_unit_err;
+ update_interrupt(machine);
+ return;
+ }
+
+ byte_count -= bytes_written;
+
+ /* update sector address to point to next sector */
+ lba++;
+ sector++;
+ if (sector == hdc.d[dsk_sel].sectors_per_track)
+ {
+ sector = 0;
+ head++;
+ if (head == hdc.d[dsk_sel].heads)
+ {
+ head = 0;
+ cylinder++;
+ }
+ }
+ }
+
+ hdc.w[7] |= w7_idle | w7_complete;
+ update_interrupt(machine);
+}
+
+/*
+ Handle the unformatted read command: read drive geometry information.
+*/
+static void unformatted_read(running_machine &machine)
+{
+ int dma_address;
+ int byte_count;
+
+ unsigned int cylinder, head, sector;
+
+ UINT16 buffer[3];
+ int i, real_word_count;
+
+ int dsk_sel = cur_disk_unit();
+
+
+ if (dsk_sel == -1)
+ {
+ /* No idea what to report... */
+ hdc.w[7] |= w7_idle | w7_error | w7_abnormal_completion;
+ update_interrupt(machine);
+ return;
+ }
+ else if (! is_unit_loaded(dsk_sel))
+ { /* offline */
+ hdc.w[0] |= w0_offline | w0_not_ready;
+ hdc.w[7] |= w7_idle | w7_error | w7_unit_err;
+ update_interrupt(machine);
+ return;
+ }
+ else if (hdc.d[dsk_sel].unsafe)
+ { /* disk in unsafe condition */
+ hdc.w[0] |= w0_unsafe | w0_pack_change;
+ hdc.w[7] |= w7_idle | w7_error | w7_unit_err;
+ update_interrupt(machine);
+ return;
+ }
+
+ dma_address = ((((int) hdc.w[6]) << 16) | hdc.w[5]) & 0x1ffffe;
+ byte_count = hdc.w[4] & 0xfffe;
+
+ cylinder = hdc.w[3];
+ head = hdc.w[1] & w1_head_address;
+ sector = hdc.w[2] & 0xff;
+
+ if (check_sector_address(machine, dsk_sel, cylinder, head, sector))
+ return;
+
+ dma_address = ((((int) hdc.w[6]) << 16) | hdc.w[5]) & 0x1ffffe;
+ byte_count = hdc.w[4] & 0xfffe;
+
+ /* bits 0-4: head address; bits 5-15: cylinder address */
+ buffer[0] = (head << 11) | cylinder;
+ /* MSByte: sectors per record (1); LSByte: sector address */
+ buffer[1] = (1 << 8) | sector;
+ /* formatted words per record */
+ buffer[2] = hdc.d[dsk_sel].bytes_per_sector >> 1;
+
+ real_word_count = byte_count >> 1;
+ if (real_word_count > 3)
+ real_word_count = 3;
+
+ /* DMA */
+ if (! (hdc.w[1] & w1_transfer_inhibit))
+ for (i=0; i<real_word_count; i++)
+ {
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->write_word(dma_address, buffer[i]);
+ dma_address = (dma_address + 2) & 0x1ffffe;
+ }
+
+ hdc.w[7] |= w7_idle | w7_complete;
+ update_interrupt(machine);
+}
+
+/*
+ Handle the restore command: return to track 0.
+*/
+static void restore(running_machine &machine)
+{
+ int dsk_sel = cur_disk_unit();
+
+
+ if (dsk_sel == -1)
+ {
+ /* No idea what to report... */
+ hdc.w[7] |= w7_idle | w7_error | w7_abnormal_completion;
+ update_interrupt(machine);
+ return;
+ }
+ else if (! is_unit_loaded(dsk_sel))
+ { /* offline */
+ hdc.w[0] |= w0_offline | w0_not_ready;
+ hdc.w[7] |= w7_idle | w7_error | w7_unit_err;
+ update_interrupt(machine);
+ return;
+ }
+
+ hdc.d[dsk_sel].unsafe = 0; /* I think */
+
+ /*if (seek_to_sector(dsk_sel, 0, 0, 0))
+ return;*/
+
+ hdc.w[7] |= w7_idle | w7_complete;
+ update_interrupt(machine);
+}
+
+/*
+ Parse command code and execute the command.
+*/
+static void execute_command(running_machine &machine)
+{
+ /* hack */
+ hdc.w[0] &= 0xff;
+
+ if (hdc.w[1] & w1_extended_command)
+ logerror("extended commands not supported\n");
+
+ switch (/*((hdc.w[1] & w1_extended_command) >> 11) |*/ ((hdc.w[1] & w1_command) >> 8))
+ {
+ case 0x00: //0b000:
+ /* store registers */
+ logerror("store registers\n");
+ store_registers(machine);
+ break;
+ case 0x01: //0b001:
+ /* write format */
+ logerror("write format\n");
+ write_format(machine);
+ break;
+ case 0x02: //0b010:
+ /* read data */
+ logerror("read data\n");
+ read_data(machine);
+ break;
+ case 0x03: //0b011:
+ /* write data */
+ logerror("write data\n");
+ write_data(machine);
+ break;
+ case 0x04: //0b100:
+ /* unformatted read */
+ logerror("unformatted read\n");
+ unformatted_read(machine);
+ break;
+ case 0x05: //0b101:
+ /* unformatted write */
+ logerror("unformatted write\n");
+ /* ... */
+ hdc.w[7] |= w7_idle | w7_error | w7_abnormal_completion;
+ update_interrupt(machine);
+ break;
+ case 0x06: //0b110:
+ /* seek */
+ logerror("seek\n");
+ /* This command can (almost) safely be ignored */
+ hdc.w[7] |= w7_idle | w7_complete;
+ update_interrupt(machine);
+ break;
+ case 0x07: //0b111:
+ /* restore */
+ logerror("restore\n");
+ restore(machine);
+ break;
+ }
+}
+
+/*
+ Read one register in TPCS space
+*/
+READ16_HANDLER(ti990_hdc_r)
+{
+ if (offset < 8)
+ return hdc.w[offset];
+ else
+ return 0;
+}
+
+/*
+ Write one register in TPCS space. Execute command if w7_idle is cleared.
+*/
+WRITE16_HANDLER(ti990_hdc_w)
+{
+ if (offset < 8)
+ {
+ /* write protect if a command is in progress */
+ if (hdc.w[7] & w7_idle)
+ {
+ UINT16 old_data = hdc.w[offset];
+
+ /* Only write writable bits AND honor byte accesses (ha!) */
+ hdc.w[offset] = (hdc.w[offset] & ((~w_mask[offset]) | mem_mask)) | (data & w_mask[offset] & ~mem_mask);
+
+ if ((offset == 0) || (offset == 7))
+ update_interrupt(space->machine());
+
+ if ((offset == 7) && (old_data & w7_idle) && ! (data & w7_idle))
+ { /* idle has been cleared: start command execution */
+ execute_command(space->machine());
+ }
+ }
+ }
+}
+
+
+static const struct harddisk_interface ti990_harddisk_config =
+{
+ DEVICE_IMAGE_LOAD_NAME( ti990_hd ),
+ DEVICE_IMAGE_UNLOAD_NAME( ti990_hd ),
+ NULL,
+ NULL
+};
+
+MACHINE_CONFIG_FRAGMENT( ti990_hdc )
+ MCFG_HARDDISK_CONFIG_ADD( "harddisk1", ti990_harddisk_config )
+ MCFG_HARDDISK_CONFIG_ADD( "harddisk2", ti990_harddisk_config )
+ MCFG_HARDDISK_CONFIG_ADD( "harddisk3", ti990_harddisk_config )
+ MCFG_HARDDISK_CONFIG_ADD( "harddisk4", ti990_harddisk_config )
+MACHINE_CONFIG_END
+
diff --git a/src/mess/machine/990_hd.h b/src/mess/machine/990_hd.h
new file mode 100644
index 00000000000..740b4c9bd64
--- /dev/null
+++ b/src/mess/machine/990_hd.h
@@ -0,0 +1,18 @@
+/*
+ 990_hd.h: include file for 990_hd.c
+*/
+#ifndef __990_HD_H_
+#define __990_HD_H_
+
+#include "imagedev/harddriv.h"
+
+MACHINE_START( ti990_hdc );
+
+void ti990_hdc_init(running_machine &machine, void (*interrupt_callback)(running_machine &machine, int state));
+
+READ16_HANDLER(ti990_hdc_r);
+WRITE16_HANDLER(ti990_hdc_w);
+
+MACHINE_CONFIG_EXTERN( ti990_hdc );
+
+#endif
diff --git a/src/mess/machine/990_tap.c b/src/mess/machine/990_tap.c
new file mode 100644
index 00000000000..415cbf7eb95
--- /dev/null
+++ b/src/mess/machine/990_tap.c
@@ -0,0 +1,1093 @@
+/*
+ 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"
+
+
+static void update_interrupt(device_t *device);
+
+#define MAX_TAPE_UNIT 4
+
+typedef struct tape_unit_t
+{
+ device_image_interface *img; /* image descriptor */
+ unsigned int bot : 1; /* TRUE if we are at the beginning of tape */
+ unsigned int eot : 1; /* TRUE if we are at the end of tape */
+ unsigned int wp : 1; /* TRUE if tape is write-protected */
+} tape_unit_t;
+
+typedef struct _tap_990_t tap_990_t;
+struct _tap_990_t
+{
+ UINT16 w[8];
+
+ const ti990_tpc_interface *intf;
+
+ tape_unit_t t[MAX_TAPE_UNIT];
+};
+
+typedef struct _ti990_tape_t ti990_tape_t;
+struct _ti990_tape_t
+{
+ int dummy;
+};
+
+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 */
+};
+
+static int tape_get_id(device_t *image)
+{
+ int drive =0;
+ if (strcmp(image->tag(), ":tape0") == 0) drive = 0;
+ if (strcmp(image->tag(), ":tape1") == 0) drive = 1;
+ if (strcmp(image->tag(), ":tape2") == 0) drive = 2;
+ if (strcmp(image->tag(), ":tape3") == 0) drive = 3;
+ return drive;
+}
+
+/*****************************************************************************
+ INLINE FUNCTIONS
+*****************************************************************************/
+INLINE tap_990_t *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == TI990_TAPE_CTRL);
+
+ return (tap_990_t *)downcast<legacy_device_base *>(device)->token();
+}
+
+
+/*
+ Parse the tape select lines, and return the corresponding tape unit.
+ (-1 if none)
+*/
+static int cur_tape_unit(device_t *device)
+{
+ int reply;
+ tap_990_t *tpc = get_safe_token(device);
+
+ if (tpc->w[6] & w6_unit0_sel)
+ reply = 0;
+ else if (tpc->w[6] & w6_unit1_sel)
+ reply = 1;
+ else if (tpc->w[6] & w6_unit2_sel)
+ reply = 2;
+ else if (tpc->w[6] & w6_unit3_sel)
+ reply = 3;
+ else
+ reply = -1;
+
+ if (reply >= MAX_TAPE_UNIT)
+ reply = -1;
+
+ return reply;
+}
+
+/*
+ Update interrupt state
+*/
+static void update_interrupt(device_t *device)
+{
+ tap_990_t *tpc = get_safe_token(device);
+ if (tpc->intf->interrupt_callback)
+ (*tpc->intf->interrupt_callback)(device->machine(), (tpc->w[7] & w7_idle)
+ && (((tpc->w[7] & w7_int_enable) && (tpc->w[7] & (w7_complete | w7_error)))
+ || ((tpc->w[0] & ~(tpc->w[0] >> 4)) & w0_rewind_mask)));
+}
+
+/*
+ Handle the read binary forward command: read the next record on tape.
+*/
+static void cmd_read_binary_forward(device_t *device)
+{
+ 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;
+ tap_990_t *tpc = get_safe_token(device);
+ int tap_sel = cur_tape_unit(device);
+
+ if (tap_sel == -1)
+ {
+ /* No idea what to report... */
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ return;
+ }
+ else if (! tpc->t[tap_sel].img->exists())
+ { /* offline */
+ tpc->w[0] |= w0_offline;
+ tpc->w[7] |= w7_idle | w7_error | w7_tape_error;
+ update_interrupt(device);
+ return;
+ }
+#if 0
+ else if (0)
+ { /* rewind in progress */
+ tpc->w[0] |= 0x80 >> tap_sel;
+ tpc->w[7] |= w7_idle | w7_error | w7_tape_error;
+ update_interrupt(device);
+ return;
+ }
+#endif
+
+ tpc->t[tap_sel].bot = 0;
+
+ dma_address = ((((int) tpc->w[6]) << 16) | tpc->w[5]) & 0x1ffffe;
+ char_count = tpc->w[4];
+ read_offset = tpc->w[3];
+
+ bytes_read = tpc->t[tap_sel].img->fread(buffer, 4);
+ if (bytes_read != 4)
+ {
+ if (bytes_read == 0)
+ { /* legitimate EOF */
+ tpc->t[tap_sel].eot = 1;
+ tpc->w[0] |= w0_EOT; /* or should it be w0_command_timeout? */
+ tpc->w[7] |= w7_idle | w7_error | w7_tape_error;
+ update_interrupt(device);
+ goto update_registers;
+ }
+ else
+ { /* illegitimate EOF */
+ /* No idea what to report... */
+ /* eject tape to avoid catastrophes */
+ logerror("Tape error\n");
+ tpc->t[tap_sel].img->unload();
+ tpc->w[0] |= w0_offline;
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ 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 */
+ tpc->t[tap_sel].img->unload();
+ tpc->w[0] |= w0_offline;
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ goto update_registers;
+ }
+
+ /* test for EOF mark */
+ if (reclen == 0)
+ {
+ logerror("read binary forward: found EOF, requested %d\n", char_count);
+ tpc->w[0] |= w0_EOF;
+ tpc->w[7] |= w7_idle | w7_error | w7_tape_error;
+ update_interrupt(device);
+ 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 (tpc->t[tap_sel].img->fseek(chunk_len, SEEK_CUR))
+ { /* eject tape */
+ logerror("Tape error\n");
+ tpc->t[tap_sel].img->unload();
+ tpc->w[0] |= w0_offline;
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ goto update_registers;
+ }
+
+ rec_count -= chunk_len;
+ read_offset -= chunk_len;
+ if (read_offset)
+ {
+ tpc->w[0] |= w0_EOR;
+ tpc->w[7] |= w7_idle | w7_error | w7_tape_error;
+ update_interrupt(device);
+ 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 = tpc->t[tap_sel].img->fread(buffer, bytes_to_read);
+
+ if (bytes_read & 1)
+ {
+ buffer[bytes_read] = 0xff;
+ }
+
+ /* DMA */
+ for (i=0; i<bytes_read; i+=2)
+ {
+ device->machine().device("maincpu")->memory().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");
+ tpc->t[tap_sel].img->unload();
+ tpc->w[0] |= w0_offline;
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ goto update_registers;
+ }
+ }
+
+ if (char_count)
+ {
+ tpc->w[0] |= w0_EOR;
+ tpc->w[7] |= w7_idle | w7_error | w7_tape_error;
+ update_interrupt(device);
+ goto skip_trailer;
+ }
+
+ if (rec_count)
+ { /* skip end of record */
+ if (tpc->t[tap_sel].img->fseek(rec_count, SEEK_CUR))
+ { /* eject tape */
+ logerror("Tape error\n");
+ tpc->t[tap_sel].img->unload();
+ tpc->w[0] |= w0_offline;
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ goto update_registers;
+ }
+ }
+
+skip_trailer:
+ if (tpc->t[tap_sel].img->fread(buffer, 4) != 4)
+ { /* eject tape */
+ logerror("Tape error\n");
+ tpc->t[tap_sel].img->unload();
+ tpc->w[0] |= w0_offline;
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ goto update_registers;
+ }
+
+ if (reclen != ((((int) buffer[1]) << 8) | buffer[0]))
+ { /* eject tape */
+ logerror("Tape error\n");
+ tpc->t[tap_sel].img->unload();
+ tpc->w[0] |= w0_offline;
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ 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 */
+ tpc->t[tap_sel].img->unload();
+ tpc->w[0] |= w0_offline;
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ goto update_registers;
+ }
+
+ if (! (tpc->w[7] & w7_error))
+ {
+ tpc->w[7] |= w7_idle | w7_complete;
+ update_interrupt(device);
+ }
+
+update_registers:
+ tpc->w[1] = rec_count & 0xffff;
+ tpc->w[2] = (rec_count >> 8) & 0xff;
+ tpc->w[3] = read_offset;
+ tpc->w[4] = char_count;
+ tpc->w[5] = (dma_address >> 1) & 0xffff;
+ tpc->w[6] = (tpc->w[6] & 0xffe0) | ((dma_address >> 17) & 0xf);
+}
+
+/*
+ Handle the record skip forward command: skip a specified number of records.
+*/
+static void cmd_record_skip_forward(device_t *device)
+{
+ UINT8 buffer[4];
+ int reclen;
+
+ int record_count;
+ int bytes_read;
+ tap_990_t *tpc = get_safe_token(device);
+ int tap_sel = cur_tape_unit(device);
+
+ if (tap_sel == -1)
+ {
+ /* No idea what to report... */
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ return;
+ }
+ else if (! tpc->t[tap_sel].img->exists())
+ { /* offline */
+ tpc->w[0] |= w0_offline;
+ tpc->w[7] |= w7_idle | w7_error | w7_tape_error;
+ update_interrupt(device);
+ return;
+ }
+#if 0
+ else if (0)
+ { /* rewind in progress */
+ tpc->w[0] |= 0x80 >> tap_sel;
+ tpc->w[7] |= w7_idle | w7_error | w7_tape_error;
+ update_interrupt(device);
+ return;
+ }
+#endif
+
+ record_count = tpc->w[4];
+
+ if (record_count)
+ tpc->t[tap_sel].bot = 0;
+
+ while (record_count > 0)
+ {
+ bytes_read = tpc->t[tap_sel].img->fread(buffer, 4);
+ if (bytes_read != 4)
+ {
+ if (bytes_read == 0)
+ { /* legitimate EOF */
+ tpc->t[tap_sel].eot = 1;
+ tpc->w[0] |= w0_EOT; /* or should it be w0_command_timeout? */
+ tpc->w[7] |= w7_idle | w7_error | w7_tape_error;
+ update_interrupt(device);
+ goto update_registers;
+ }
+ else
+ { /* illegitimate EOF */
+ /* No idea what to report... */
+ /* eject tape to avoid catastrophes */
+ tpc->t[tap_sel].img->unload();
+ tpc->w[0] |= w0_offline;
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ 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 */
+ tpc->t[tap_sel].img->unload();
+ tpc->w[0] |= w0_offline;
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ goto update_registers;
+ }
+
+ /* test for EOF mark */
+ if (reclen == 0)
+ {
+ logerror("record skip forward: found EOF\n");
+ tpc->w[0] |= w0_EOF;
+ tpc->w[7] |= w7_idle | w7_error | w7_tape_error;
+ update_interrupt(device);
+ goto update_registers;
+ }
+
+ /* skip record data */
+ if (tpc->t[tap_sel].img->fseek(reclen, SEEK_CUR))
+ { /* eject tape */
+ tpc->t[tap_sel].img->unload();
+ tpc->w[0] |= w0_offline;
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ goto update_registers;
+ }
+
+ if (tpc->t[tap_sel].img->fread(buffer, 4) != 4)
+ { /* eject tape */
+ tpc->t[tap_sel].img->unload();
+ tpc->w[0] |= w0_offline;
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ goto update_registers;
+ }
+
+ if (reclen != ((((int) buffer[1]) << 8) | buffer[0]))
+ { /* eject tape */
+ tpc->t[tap_sel].img->unload();
+ tpc->w[0] |= w0_offline;
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ 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 */
+ tpc->t[tap_sel].img->unload();
+ tpc->w[0] |= w0_offline;
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ goto update_registers;
+ }
+
+ record_count--;
+ }
+
+ tpc->w[7] |= w7_idle | w7_complete;
+ update_interrupt(device);
+
+update_registers:
+ tpc->w[4] = record_count;
+}
+
+/*
+ Handle the record skip reverse command: skip a specified number of records backwards.
+*/
+static void cmd_record_skip_reverse(device_t *device)
+{
+ UINT8 buffer[4];
+ int reclen;
+
+ int record_count;
+
+ int bytes_read;
+ tap_990_t *tpc = get_safe_token(device);
+ int tap_sel = cur_tape_unit(device);
+
+ if (tap_sel == -1)
+ {
+ /* No idea what to report... */
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ return;
+ }
+ else if (! tpc->t[tap_sel].img->exists())
+ { /* offline */
+ tpc->w[0] |= w0_offline;
+ tpc->w[7] |= w7_idle | w7_error | w7_tape_error;
+ update_interrupt(device);
+ return;
+ }
+#if 0
+ else if (0)
+ { /* rewind in progress */
+ tpc->w[0] |= 0x80 >> tap_sel;
+ tpc->w[7] |= w7_idle | w7_error | w7_tape_error;
+ update_interrupt(device);
+ return;
+ }
+#endif
+
+ record_count = tpc->w[4];
+
+ if (record_count)
+ tpc->t[tap_sel].eot = 0;
+
+ while (record_count > 0)
+ {
+ if (tpc->t[tap_sel].img->ftell() == 0)
+ { /* bot */
+ tpc->t[tap_sel].bot = 1;
+ tpc->w[0] |= w0_BOT;
+ tpc->w[7] |= w7_idle | w7_error | w7_tape_error;
+ update_interrupt(device);
+ goto update_registers;
+ }
+ if (tpc->t[tap_sel].img->fseek(-4, SEEK_CUR))
+ { /* eject tape */
+ tpc->t[tap_sel].img->unload();
+ tpc->w[0] |= w0_offline;
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ goto update_registers;
+ }
+ bytes_read = tpc->t[tap_sel].img->fread(buffer, 4);
+ if (bytes_read != 4)
+ {
+ /* illegitimate EOF */
+ /* No idea what to report... */
+ /* eject tape to avoid catastrophes */
+ tpc->t[tap_sel].img->unload();
+ tpc->w[0] |= w0_offline;
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ 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 */
+ tpc->t[tap_sel].img->unload();
+ tpc->w[0] |= w0_offline;
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ goto update_registers;
+ }
+
+ /* look for EOF mark */
+ if (reclen == 0)
+ {
+ logerror("record skip reverse: found EOF\n");
+ if (tpc->t[tap_sel].img->fseek(-4, SEEK_CUR))
+ { /* eject tape */
+ tpc->t[tap_sel].img->unload();
+ tpc->w[0] |= w0_offline;
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ goto update_registers;
+ }
+ tpc->w[0] |= w0_EOF;
+ tpc->w[7] |= w7_idle | w7_error | w7_tape_error;
+ update_interrupt(device);
+ goto update_registers;
+ }
+
+ if (tpc->t[tap_sel].img->fseek(-reclen-8, SEEK_CUR))
+ { /* eject tape */
+ tpc->t[tap_sel].img->unload();
+ tpc->w[0] |= w0_offline;
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ goto update_registers;
+ }
+
+ if (tpc->t[tap_sel].img->fread(buffer, 4) != 4)
+ { /* eject tape */
+ tpc->t[tap_sel].img->unload();
+ tpc->w[0] |= w0_offline;
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ goto update_registers;
+ }
+ if (reclen != ((((int) buffer[1]) << 8) | buffer[0]))
+ { /* eject tape */
+ tpc->t[tap_sel].img->unload();
+ tpc->w[0] |= w0_offline;
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ 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 */
+ tpc->t[tap_sel].img->unload();
+ tpc->w[0] |= w0_offline;
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ goto update_registers;
+ }
+
+ if (tpc->t[tap_sel].img->fseek(-4, SEEK_CUR))
+ { /* eject tape */
+ tpc->t[tap_sel].img->unload();
+ tpc->w[0] |= w0_offline;
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ goto update_registers;
+ }
+
+ record_count--;
+ }
+
+ tpc->w[7] |= w7_idle | w7_complete;
+ update_interrupt(device);
+
+update_registers:
+ tpc->w[4] = record_count;
+}
+
+/*
+ Handle the rewind command: rewind to BOT.
+*/
+static void cmd_rewind(device_t *device)
+{
+ tap_990_t *tpc = get_safe_token(device);
+ int tap_sel = cur_tape_unit(device);
+
+ if (tap_sel == -1)
+ {
+ /* No idea what to report... */
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ return;
+ }
+ else if (! tpc->t[tap_sel].img->exists())
+ { /* offline */
+ tpc->w[0] |= w0_offline;
+ tpc->w[7] |= w7_idle | w7_error | w7_tape_error;
+ update_interrupt(device);
+ return;
+ }
+#if 0
+ else if (0)
+ { /* rewind in progress */
+ tpc->w[0] |= 0x80 >> tap_sel;
+ tpc->w[7] |= w7_idle | w7_error | w7_tape_error;
+ update_interrupt(device);
+ return;
+ }
+#endif
+
+ tpc->t[tap_sel].eot = 0;
+
+ if (tpc->t[tap_sel].img->fseek(0, SEEK_SET))
+ { /* eject tape */
+ tpc->t[tap_sel].img->unload();
+ tpc->w[0] |= w0_offline;
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ return;
+ }
+ tpc->t[tap_sel].bot = 1;
+
+ tpc->w[7] |= w7_idle | w7_complete;
+ update_interrupt(device);
+}
+
+/*
+ Handle the rewind and offline command: disable the tape unit.
+*/
+static void cmd_rewind_and_offline(device_t *device)
+{
+ tap_990_t *tpc = get_safe_token(device);
+ int tap_sel = cur_tape_unit(device);
+
+ if (tap_sel == -1)
+ {
+ /* No idea what to report... */
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ return;
+ }
+ else if (! tpc->t[tap_sel].img->exists())
+ { /* offline */
+ tpc->w[0] |= w0_offline;
+ tpc->w[7] |= w7_idle | w7_error | w7_tape_error;
+ update_interrupt(device);
+ return;
+ }
+#if 0
+ else if (0)
+ { /* rewind in progress */
+ tpc->w[0] |= 0x80 >> tap_sel;
+ tpc->w[7] |= w7_idle | w7_error | w7_tape_error;
+ update_interrupt(device);
+ return;
+ }
+#endif
+
+ /* eject tape */
+ tpc->t[tap_sel].img->unload();
+
+ tpc->w[7] |= w7_idle | w7_complete;
+ update_interrupt(device);
+}
+
+/*
+ Handle the read transport status command: return the current tape status.
+*/
+static void read_transport_status(device_t *device)
+{
+ tap_990_t *tpc = get_safe_token(device);
+ int tap_sel = cur_tape_unit(device);
+
+ if (tap_sel == -1)
+ {
+ /* No idea what to report... */
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ }
+ else if (! tpc->t[tap_sel].img->exists())
+ { /* offline */
+ tpc->w[0] |= w0_offline;
+ tpc->w[7] |= w7_idle | w7_error | w7_tape_error;
+ update_interrupt(device);
+ }
+#if 0
+ else if (0)
+ { /* rewind in progress */
+ tpc->w[0] |= /*...*/;
+ tpc->w[7] |= w7_idle | w7_error | w7_tape_error;
+ update_interrupt(device);
+ }
+#endif
+ else
+ { /* no particular error condition */
+ if (tpc->t[tap_sel].bot)
+ tpc->w[0] |= w0_BOT;
+ if (tpc->t[tap_sel].eot)
+ tpc->w[0] |= w0_EOT;
+ if (tpc->t[tap_sel].wp)
+ tpc->w[0] |= w0_write_ring;
+ tpc->w[7] |= w7_idle | w7_complete;
+ update_interrupt(device);
+ }
+}
+
+/*
+ Parse command code and execute the command.
+*/
+static void execute_command(device_t *device)
+{
+ /* hack */
+ tap_990_t *tpc = get_safe_token(device);
+ tpc->w[0] &= 0xff;
+
+ switch ((tpc->w[6] & w6_command) >> 8)
+ {
+ case 0x00:
+ case 0x0C:
+ case 0x0E:
+ /* NOP */
+ logerror("NOP\n");
+ tpc->w[7] |= w7_idle | w7_complete;
+ update_interrupt(device);
+ break;
+ case 0x01:
+ /* buffer sync: means nothing under emulation */
+ logerror("buffer sync\n");
+ tpc->w[7] |= w7_idle | w7_complete;
+ update_interrupt(device);
+ break;
+ case 0x02:
+ /* write EOF - not emulated */
+ logerror("write EOF\n");
+ /* ... */
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ break;
+ case 0x03:
+ /* record skip reverse - not fully tested */
+ logerror("record skip reverse\n");
+ cmd_record_skip_reverse(device);
+ break;
+ case 0x04:
+ /* read binary forward */
+ logerror("read binary forward\n");
+ cmd_read_binary_forward(device);
+ break;
+ case 0x05:
+ /* record skip forward - not tested */
+ logerror("record skip forward\n");
+ cmd_record_skip_forward(device);
+ break;
+ case 0x06:
+ /* write binary forward - not emulated */
+ logerror("write binary forward\n");
+ /* ... */
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ break;
+ case 0x07:
+ /* erase - not emulated */
+ logerror("erase\n");
+ /* ... */
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ break;
+ case 0x08:
+ case 0x09:
+ /* read transport status */
+ logerror("read transport status\n");
+ read_transport_status(device);
+ break;
+ case 0x0A:
+ /* rewind - not tested */
+ logerror("rewind\n");
+ cmd_rewind(device);
+ break;
+ case 0x0B:
+ /* rewind and offline - not tested */
+ logerror("rewind and offline\n");
+ cmd_rewind_and_offline(device);
+ break;
+ case 0x0F:
+ /* extended control and status - not emulated */
+ logerror("extended control and status\n");
+ /* ... */
+ tpc->w[7] |= w7_idle | w7_error | w7_hard_error;
+ update_interrupt(device);
+ break;
+ }
+}
+
+
+/*
+ Read one register in TPCS space
+*/
+READ16_DEVICE_HANDLER(ti990_tpc_r)
+{
+ tap_990_t *tpc = get_safe_token(device);
+ if (offset < 8)
+ return tpc->w[offset];
+ else
+ return 0;
+}
+
+/*
+ Write one register in TPCS space. Execute command if w7_idle is cleared.
+*/
+WRITE16_DEVICE_HANDLER(ti990_tpc_w)
+{
+ tap_990_t *tpc = get_safe_token(device);
+ if (offset < 8)
+ {
+ /* write protect if a command is in progress */
+ if (tpc->w[7] & w7_idle)
+ {
+ UINT16 old_data = tpc->w[offset];
+
+ /* Only write writable bits AND honor byte accesses (ha!) */
+ tpc->w[offset] = (tpc->w[offset] & ((~w_mask[offset]) | mem_mask)) | (data & w_mask[offset] & ~mem_mask);
+
+ if ((offset == 0) || (offset == 7))
+ update_interrupt(device);
+
+ if ((offset == 7) && (old_data & w7_idle) && ! (data & w7_idle))
+ { /* idle has been cleared: start command execution */
+ execute_command(device);
+ }
+ }
+ }
+}
+
+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();
+};
+
+const device_type TI990_TAPE = &device_creator<ti990_tape_image_device>;
+
+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, "TI990 Magnetic Tape", tag, owner, clock),
+ device_image_interface(mconfig, *this)
+{
+}
+
+void ti990_tape_image_device::device_config_complete()
+{
+ update_names();
+}
+
+void ti990_tape_image_device::device_start()
+{
+ tape_unit_t *t;
+ tap_990_t *tpc = get_safe_token(owner());
+ int id = tape_get_id(this);
+
+ t = &tpc->t[id];
+ memset(t, 0, sizeof(*t));
+
+ t->img = this;
+ t->wp = 1;
+ t->bot = 0;
+ t->eot = 0;
+}
+
+/*
+ Open a tape image
+*/
+bool ti990_tape_image_device::call_load()
+{
+ tape_unit_t *t;
+ tap_990_t *tpc = get_safe_token(owner());
+ int id = tape_get_id(this);
+
+ t = &tpc->t[id];
+ memset(t, 0, sizeof(*t));
+
+ /* tell whether the image is writable */
+ t->wp = is_readonly();
+
+ t->bot = 1;
+
+ return IMAGE_INIT_PASS;
+}
+
+/*
+ Close a tape image
+*/
+void ti990_tape_image_device::call_unload()
+{
+ tape_unit_t *t;
+ tap_990_t *tpc = get_safe_token(owner());
+ int id = tape_get_id(this);
+
+ t = &tpc->t[id];
+ t->wp = 1;
+ t->bot = 0;
+ t->eot = 0;
+}
+
+#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
+
+/*
+ Init the tape controller core
+*/
+static DEVICE_START(tap_990)
+{
+ tap_990_t *tpc = get_safe_token(device);
+ /* verify that we have an interface assigned */
+ assert(device->static_config() != NULL);
+
+ /* copy interface pointer */
+ tpc->intf = (const ti990_tpc_interface*)device->static_config();
+
+ memset(tpc->w, 0, sizeof(tpc->w));
+ /* The PE bit is always set for the MT3200 (but not MT1600) */
+ /* According to MT3200 manual, w7 bit #4 (reserved) is always set */
+ tpc->w[7] = w7_idle /*| w7_PE_format*/ | 0x0800;
+
+ update_interrupt(device);
+}
+
+
+DEVICE_GET_INFO( tap_990 )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(tap_990_t); break;
+
+ /* --- the following bits of info are returned as pointers --- */
+ case DEVINFO_PTR_MACHINE_CONFIG: info->machine_config = MACHINE_CONFIG_NAME(tap_990); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(tap_990); break;
+ case DEVINFO_FCT_STOP: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "Generic TI990 Tape Controller"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "TI990 Tape Controller"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright the MESS Team"); break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(TI990_TAPE_CTRL, tap_990);
diff --git a/src/mess/machine/990_tap.h b/src/mess/machine/990_tap.h
new file mode 100644
index 00000000000..8f3b4dc187a
--- /dev/null
+++ b/src/mess/machine/990_tap.h
@@ -0,0 +1,25 @@
+/*
+ 990_tap.h: include file for 990_tap.c
+*/
+extern READ16_DEVICE_HANDLER(ti990_tpc_r);
+extern WRITE16_DEVICE_HANDLER(ti990_tpc_w);
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _ti990_tpc_interface ti990_tpc_interface;
+struct _ti990_tpc_interface
+{
+ void (*interrupt_callback)(running_machine &machine, int state);
+};
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+DECLARE_LEGACY_DEVICE(TI990_TAPE_CTRL, tap_990);
+
+#define MCFG_TI990_TAPE_CTRL_ADD(_tag, _intrf) \
+ MCFG_DEVICE_ADD((_tag), TI990_TAPE_CTRL, 0)\
+ MCFG_DEVICE_CONFIG(_intrf)
+
diff --git a/src/mess/machine/a2alfam2.c b/src/mess/machine/a2alfam2.c
new file mode 100644
index 00000000000..bc10dc507c6
--- /dev/null
+++ b/src/mess/machine/a2alfam2.c
@@ -0,0 +1,112 @@
+/*********************************************************************
+
+ a2alfsm2.c
+
+ Implementation of the ALF Apple Music II card
+
+*********************************************************************/
+
+#include "a2alfam2.h"
+#include "includes/apple2.h"
+#include "sound/sn76496.h"
+
+/***************************************************************************
+ PARAMETERS
+***************************************************************************/
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type A2BUS_ALFAM2 = &device_creator<a2bus_alfam2_device>;
+
+#define SN1_TAG "sn76489_1" // left
+#define SN2_TAG "sn76489_2" // center
+#define SN3_TAG "sn76489_3" // right
+
+MACHINE_CONFIG_FRAGMENT( a2alfam2 )
+ MCFG_SPEAKER_STANDARD_STEREO("alf_l", "alf_r")
+ MCFG_SOUND_ADD(SN1_TAG, SN76489, XTAL_3_579545MHz)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "alf_l", 0.50)
+ MCFG_SOUND_ADD(SN2_TAG, SN76489, XTAL_3_579545MHz)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "alf_l", 0.50)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "alf_r", 0.50)
+ MCFG_SOUND_ADD(SN3_TAG, SN76489, XTAL_3_579545MHz)
+ 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_alfam2_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( a2alfam2 );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+a2bus_alfam2_device::a2bus_alfam2_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),
+ device_a2bus_card_interface(mconfig, *this),
+ m_sn1(*this, SN1_TAG),
+ m_sn2(*this, SN2_TAG),
+ m_sn3(*this, SN3_TAG)
+{
+ m_shortname = "a2alfam2";
+}
+
+a2bus_alfam2_device::a2bus_alfam2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, A2BUS_ALFAM2, "ALF Apple Music II", tag, owner, clock),
+ device_a2bus_card_interface(mconfig, *this),
+ m_sn1(*this, SN1_TAG),
+ m_sn2(*this, SN2_TAG),
+ m_sn3(*this, SN3_TAG)
+{
+ m_shortname = "a2alfam2";
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void a2bus_alfam2_device::device_start()
+{
+ // set_a2bus_device makes m_slot valid
+ set_a2bus_device();
+}
+
+void a2bus_alfam2_device::device_reset()
+{
+}
+
+void a2bus_alfam2_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data)
+{
+ switch (offset)
+ {
+ case 0:
+ sn76496_w(m_sn1, 0, data);
+ break;
+
+ case 1:
+ sn76496_w(m_sn2, 0, data);
+ break;
+
+ case 2:
+ sn76496_w(m_sn3, 0, data);
+ break;
+ }
+}
+
+bool a2bus_alfam2_device::take_c800()
+{
+ return false;
+}
+
diff --git a/src/mess/machine/a2alfam2.h b/src/mess/machine/a2alfam2.h
new file mode 100644
index 00000000000..325855cac0c
--- /dev/null
+++ b/src/mess/machine/a2alfam2.h
@@ -0,0 +1,48 @@
+/*********************************************************************
+
+ a2alfam2.h
+
+ Implementation of the ALF Apple Music II card
+
+*********************************************************************/
+
+#ifndef __A2BUS_ALFAM2__
+#define __A2BUS_ALFAM2__
+
+#include "emu.h"
+#include "machine/a2bus.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class a2bus_alfam2_device:
+ public device_t,
+ public device_a2bus_card_interface
+{
+public:
+ // construction/destruction
+ a2bus_alfam2_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
+ a2bus_alfam2_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<device_t> m_sn1;
+ required_device<device_t> m_sn2;
+ required_device<device_t> m_sn3;
+
+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_ALFAM2;
+
+#endif /* __A2BUS_ALFAM2__ */
+
diff --git a/src/mess/machine/a2bus.c b/src/mess/machine/a2bus.c
new file mode 100644
index 00000000000..aa2f4d8f644
--- /dev/null
+++ b/src/mess/machine/a2bus.c
@@ -0,0 +1,285 @@
+/***************************************************************************
+
+ 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 "machine/a2bus.h"
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type A2BUS_SLOT = &device_creator<a2bus_slot_device>;
+
+//**************************************************************************
+// 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),
+ 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) :
+ device_t(mconfig, type, name, tag, owner, clock),
+ 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<a2bus_slot_device &>(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<device_a2bus_card_interface *>(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<a2bus_device>;
+
+void a2bus_device::static_set_cputag(device_t &device, const char *tag)
+{
+ a2bus_device &a2bus = downcast<a2bus_device &>(device);
+ a2bus.m_cputag = tag;
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void a2bus_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const a2bus_interface *intf = reinterpret_cast<const a2bus_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<a2bus_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_irq_cb, 0, sizeof(m_out_irq_cb));
+ memset(&m_out_nmi_cb, 0, sizeof(m_out_nmi_cb));
+ memset(&m_out_inh_cb, 0, sizeof(m_out_inh_cb));
+ }
+}
+
+//**************************************************************************
+// 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_device::a2bus_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)
+{
+}
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void a2bus_device::device_start()
+{
+ m_maincpu = machine().device(m_cputag);
+
+ // resolve callbacks
+ m_out_irq_func.resolve(m_out_irq_cb, *this);
+ m_out_nmi_func.resolve(m_out_nmi_cb, *this);
+ m_out_inh_func.resolve(m_out_inh_cb, *this);
+
+ // clear slots
+ for (int i = 0; i < 8; i++)
+ {
+ m_device_list[i] = NULL;
+ }
+}
+
+//-------------------------------------------------
+// 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;
+ }
+
+ return m_device_list[slot];
+}
+
+void a2bus_device::add_a2bus_card(int slot, device_a2bus_card_interface *card)
+{
+ m_device_list[slot] = card;
+}
+
+void a2bus_device::set_irq_line(int state)
+{
+ m_out_irq_func(state);
+}
+
+void a2bus_device::set_nmi_line(int state)
+{
+ m_out_nmi_func(state);
+}
+
+void a2bus_device::set_inh_slotnum(int slot)
+{
+ m_out_inh_func(slot);
+}
+
+// interrupt request from a2bus card
+WRITE_LINE_MEMBER( a2bus_device::irq_w ) { m_out_irq_func(state); }
+WRITE_LINE_MEMBER( a2bus_device::nmi_w ) { m_out_nmi_func(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_interface &>(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<a2bus_device *>(device().machine().device(m_a2bus_tag));
+ m_a2bus->add_a2bus_card(m_slot, this);
+}
+
diff --git a/src/mess/machine/a2bus.h b/src/mess/machine/a2bus.h
new file mode 100644
index 00000000000..3fc80c25843
--- /dev/null
+++ b/src/mess/machine/a2bus.h
@@ -0,0 +1,166 @@
+/***************************************************************************
+
+ a2bus.h - Apple II slot bus and card emulation
+
+ by R. Belmont
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __A2BUS_H__
+#define __A2BUS_H__
+
+#include "emu.h"
+
+#define INH_SLOT_INVALID (255)
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_A2BUS_BUS_ADD(_tag, _cputag, _config) \
+ MCFG_DEVICE_ADD(_tag, A2BUS, 0) \
+ MCFG_DEVICE_CONFIG(_config) \
+ a2bus_device::static_set_cputag(*device, _cputag); \
+
+#define MCFG_A2BUS_SLOT_ADD(_nbtag, _tag, _slot_intf, _def_slot, _def_inp) \
+ MCFG_DEVICE_ADD(_tag, A2BUS_SLOT, 0) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, 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);
+
+#define MCFG_A2BUS_BUS_REMOVE(_tag) \
+ MCFG_DEVICE_REMOVE(_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);
+
+ // 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;
+
+// ======================> a2bus_interface
+
+struct a2bus_interface
+{
+ devcb_write_line m_out_irq_cb;
+ devcb_write_line m_out_nmi_cb;
+ devcb_write_line m_out_inh_cb;
+};
+
+class device_a2bus_card_interface;
+// ======================> a2bus_device
+class a2bus_device : public device_t,
+ public a2bus_interface
+{
+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);
+ // inline configuration
+ static void static_set_cputag(device_t &device, const char *tag);
+
+ void add_a2bus_card(int slot, device_a2bus_card_interface *card);
+ device_a2bus_card_interface *get_a2bus_card(int slot);
+
+ void set_irq_line(int state);
+ void set_nmi_line(int state);
+ void set_inh_slotnum(int slot);
+
+ DECLARE_WRITE_LINE_MEMBER( irq_w );
+ DECLARE_WRITE_LINE_MEMBER( nmi_w );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete();
+
+ // internal state
+ device_t *m_maincpu;
+
+ devcb_resolved_write_line m_out_irq_func;
+ devcb_resolved_write_line m_out_nmi_func;
+ devcb_resolved_write_line m_out_inh_func;
+
+ device_a2bus_card_interface *m_device_list[8];
+ const char *m_cputag;
+};
+
+
+// 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) { printf("a2bus: unhandled read at C0n%x\n", offset); return 0; } // C0nX - /DEVSEL
+ virtual void write_c0nx(address_space &space, UINT8 offset, UINT8 data) { printf("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) { printf("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) { printf("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) { }
+
+ 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); }
+ void lower_slot_irq() { m_a2bus->set_irq_line(CLEAR_LINE); }
+ void raise_slot_nmi() { m_a2bus->set_nmi_line(ASSERT_LINE); }
+ void lower_slot_nmi() { m_a2bus->set_nmi_line(CLEAR_LINE); }
+ void raise_slot_inh() { m_a2bus->set_inh_slotnum(m_slot); }
+ void lower_slot_inh() { m_a2bus->set_inh_slotnum(INH_SLOT_INVALID); }
+
+ // 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/mess/machine/a2cffa.c b/src/mess/machine/a2cffa.c
new file mode 100644
index 00000000000..4792dbc22d0
--- /dev/null
+++ b/src/mess/machine/a2cffa.c
@@ -0,0 +1,264 @@
+/*********************************************************************
+
+ 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/idectrl.h"
+#include "imagedev/harddriv.h"
+
+
+/***************************************************************************
+ PARAMETERS
+***************************************************************************/
+
+#define LOG_A2CFFA 1
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type A2BUS_CFFA2 = &device_creator<a2bus_cffa2_device>;
+const device_type A2BUS_CFFA2_6502 = &device_creator<a2bus_cffa2_6502_device>;
+
+#define CFFA2_ROM_REGION "cffa2_rom"
+#define CFFA2_IDE_TAG "cffa2_ide"
+
+MACHINE_CONFIG_FRAGMENT( cffa2 )
+ MCFG_IDE_CONTROLLER_ADD(CFFA2_IDE_TAG, NULL, ide_image_devices, "hdd", "hdd", false)
+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) :
+ device_t(mconfig, type, name, tag, owner, clock),
+ device_a2bus_card_interface(mconfig, *this),
+ m_ide(*this, CFFA2_IDE_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),
+ device_nvram_interface(mconfig, *this)
+{
+ m_shortname = "a2cffa2";
+}
+
+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),
+ device_nvram_interface(mconfig, *this)
+{
+ m_shortname = "a2cffa02";
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void a2bus_cffa2000_device::device_start()
+{
+ // set_a2bus_device makes m_slot valid
+ set_a2bus_device();
+
+ astring tempstring;
+ m_rom = device().machine().root_device().memregion(this->subtag(tempstring, CFFA2_ROM_REGION))->base();
+
+ // patch default setting so slave device is enabled
+ m_rom[0x801] = 4;
+
+ save_item(NAME(m_lastdata));
+ save_item(NAME(m_writeprotect));
+ save_item(NAME(m_eeprom));
+}
+
+void a2bus_cffa2000_device::device_reset()
+{
+ m_writeprotect = true;
+}
+
+
+/*-------------------------------------------------
+ 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_lastdata>>8;
+
+ case 3:
+ m_writeprotect = false;
+ break;
+
+ case 4:
+ m_writeprotect = true;
+ break;
+
+ case 8:
+ m_lastdata = ide_controller_r(m_ide, 0x1f0+offset-8, 2);
+ return m_lastdata & 0xff;
+
+ case 9:
+ case 0xa:
+ case 0xb:
+ case 0xc:
+ case 0xd:
+ case 0xe:
+ case 0xf:
+ return ide_controller_r(m_ide, 0x1f0+offset-8, 1);
+ }
+
+ 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)
+{
+ switch (offset)
+ {
+ case 0:
+ m_lastdata &= 0x00ff;
+ m_lastdata |= data<<8;
+ break;
+
+ case 3:
+ m_writeprotect = false;
+ break;
+
+ case 4:
+ m_writeprotect = true;
+ break;
+
+ case 8:
+ m_lastdata &= 0xff00;
+ m_lastdata |= data;
+ ide_controller_w(m_ide, 0x1f0+offset-8, 2, m_lastdata);
+ break;
+
+ case 9:
+ case 0xa:
+ case 0xb:
+ case 0xc:
+ case 0xd:
+ case 0xe:
+ case 0xf:
+ ide_controller_w(m_ide, 0x1f0+offset-8, 1, data);
+ 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, cpu_get_pc(&space.device()));
+ 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/mess/machine/a2cffa.h b/src/mess/machine/a2cffa.h
new file mode 100644
index 00000000000..9b64ec265ae
--- /dev/null
+++ b/src/mess/machine/a2cffa.h
@@ -0,0 +1,83 @@
+/*********************************************************************
+
+ a2cffa.h
+
+ Implementation of Rich Dreher's IDE/CompactFlash board for
+ the Apple II
+
+*********************************************************************/
+
+#ifndef __A2BUS_CFFA2__
+#define __A2BUS_CFFA2__
+
+#include "emu.h"
+#include "machine/a2bus.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);
+
+ // 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<device_t> m_ide;
+
+ UINT8 *m_rom;
+ UINT8 m_eeprom[0x1000];
+
+private:
+ UINT16 m_lastdata;
+ bool m_writeprotect;
+};
+
+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/mess/machine/a2diskii.c b/src/mess/machine/a2diskii.c
new file mode 100644
index 00000000000..a9ed3e0259a
--- /dev/null
+++ b/src/mess/machine/a2diskii.c
@@ -0,0 +1,162 @@
+/*********************************************************************
+
+ 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 "devices/appldriv.h"
+#include "machine/applefdc.h"
+#include "machine/a2diskii.h"
+
+
+/***************************************************************************
+ PARAMETERS
+***************************************************************************/
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type A2BUS_DISKII = &device_creator<a2bus_diskii_device>;
+const device_type A2BUS_IWM_FDC = &device_creator<a2bus_iwmflop_device>;
+
+#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 =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ FLOPPY_STANDARD_5_25_DSHD,
+ LEGACY_FLOPPY_OPTIONS_NAME(apple2),
+ "floppy_5_25",
+ NULL
+};
+
+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) :
+ device_t(mconfig, type, name, tag, owner, clock),
+ 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)
+{
+ m_shortname = "a2diskii";
+}
+
+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)
+{
+ m_shortname = "a2diskii";
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void a2bus_floppy_device::device_start()
+{
+ // set_a2bus_device makes m_slot valid
+ set_a2bus_device();
+
+ astring tempstring;
+ m_rom = device().machine().root_device().memregion(this->subtag(tempstring, DISKII_ROM_REGION))->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 applefdc_r(m_fdc, 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)
+{
+ applefdc_w(m_fdc, 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/mess/machine/a2diskii.h b/src/mess/machine/a2diskii.h
new file mode 100644
index 00000000000..f7c3b567516
--- /dev/null
+++ b/src/mess/machine/a2diskii.h
@@ -0,0 +1,65 @@
+/*********************************************************************
+
+ a2diskii.h
+
+ Apple II Disk II Controller Card
+
+*********************************************************************/
+
+#ifndef __A2BUS_DISKII__
+#define __A2BUS_DISKII__
+
+#include "emu.h"
+#include "machine/a2bus.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);
+
+ // 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<device_t> 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/mess/machine/a2eauxslot.c b/src/mess/machine/a2eauxslot.c
new file mode 100644
index 00000000000..568907b525b
--- /dev/null
+++ b/src/mess/machine/a2eauxslot.c
@@ -0,0 +1,198 @@
+/***************************************************************************
+
+ a2eauxslot.c - Apple IIe auxiliary slot and card emulation
+
+ by R. Belmont
+
+***************************************************************************/
+
+#include "emu.h"
+#include "emuopts.h"
+#include "machine/a2eauxslot.h"
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type A2EAUXSLOT_SLOT = &device_creator<a2eauxslot_slot_device>;
+
+//**************************************************************************
+// 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 II Slot", tag, owner, clock),
+ 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) :
+ device_t(mconfig, type, name, tag, owner, clock),
+ 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<a2eauxslot_slot_device &>(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<device_a2eauxslot_card_interface *>(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<a2eauxslot_device>;
+
+void a2eauxslot_device::static_set_cputag(device_t &device, const char *tag)
+{
+ a2eauxslot_device &a2eauxslot = downcast<a2eauxslot_device &>(device);
+ a2eauxslot.m_cputag = tag;
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void a2eauxslot_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const a2eauxslot_interface *intf = reinterpret_cast<const a2eauxslot_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<a2eauxslot_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_irq_cb, 0, sizeof(m_out_irq_cb));
+ memset(&m_out_nmi_cb, 0, sizeof(m_out_nmi_cb));
+ }
+}
+
+//**************************************************************************
+// 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 II Bus", tag, owner, clock)
+{
+}
+
+a2eauxslot_device::a2eauxslot_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)
+{
+}
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void a2eauxslot_device::device_start()
+{
+ m_maincpu = machine().device(m_cputag);
+
+ // resolve callbacks
+ m_out_irq_func.resolve(m_out_irq_cb, *this);
+ m_out_nmi_func.resolve(m_out_nmi_cb, *this);
+
+ // clear slot
+ m_device = NULL;
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void a2eauxslot_device::device_reset()
+{
+}
+
+device_a2eauxslot_card_interface *a2eauxslot_device::get_a2eauxslot_card(int slot)
+{
+ 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_func(state);
+}
+
+void a2eauxslot_device::set_nmi_line(int state)
+{
+ m_out_nmi_func(state);
+}
+
+// interrupt request from a2eauxslot card
+WRITE_LINE_MEMBER( a2eauxslot_device::irq_w ) { m_out_irq_func(state); }
+WRITE_LINE_MEMBER( a2eauxslot_device::nmi_w ) { m_out_nmi_func(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_interface &>(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<a2eauxslot_device *>(device().machine().device(m_a2eauxslot_tag));
+ m_a2eauxslot->add_a2eauxslot_card(this);
+}
+
diff --git a/src/mess/machine/a2eauxslot.h b/src/mess/machine/a2eauxslot.h
new file mode 100644
index 00000000000..8e645c7b352
--- /dev/null
+++ b/src/mess/machine/a2eauxslot.h
@@ -0,0 +1,144 @@
+/***************************************************************************
+
+ a2eauxslot.h - Apple IIe auxiliary slot and card emulation
+
+ by R. Belmont
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __A2EAUXSLOT_H__
+#define __A2EAUXSLOT_H__
+
+#include "emu.h"
+#include "machine/a2bus.h"
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_A2EAUXSLOT_BUS_ADD(_tag, _cputag, _config) \
+ MCFG_DEVICE_ADD(_tag, A2EAUXSLOT, 0) \
+ MCFG_DEVICE_CONFIG(_config) \
+ a2eauxslot_device::static_set_cputag(*device, _cputag); \
+
+#define MCFG_A2EAUXSLOT_SLOT_ADD(_nbtag, _tag, _slot_intf, _def_slot, _def_inp) \
+ MCFG_DEVICE_ADD(_tag, A2EAUXSLOT_SLOT, 0) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false) \
+ a2eauxslot_slot_device::static_set_a2eauxslot_slot(*device, _nbtag, _tag); \
+
+#define MCFG_A2EAUXSLOT_SLOT_REMOVE(_tag) \
+ MCFG_DEVICE_REMOVE(_tag)
+
+#define MCFG_A2EAUXSLOT_BUS_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);
+
+ // 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;
+
+// ======================> a2eauxslot_interface
+
+struct a2eauxslot_interface
+{
+ devcb_write_line m_out_irq_cb;
+ devcb_write_line m_out_nmi_cb;
+};
+
+class device_a2eauxslot_card_interface;
+// ======================> a2eauxslot_device
+class a2eauxslot_device : public device_t,
+ public a2eauxslot_interface
+{
+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);
+ // inline configuration
+ static void static_set_cputag(device_t &device, const char *tag);
+
+ void add_a2eauxslot_card(device_a2eauxslot_card_interface *card);
+ device_a2eauxslot_card_interface *get_a2eauxslot_card(int slot);
+
+ 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();
+ virtual void device_config_complete();
+
+ // internal state
+ device_t *m_maincpu;
+
+ devcb_resolved_write_line m_out_irq_func;
+ devcb_resolved_write_line m_out_nmi_func;
+
+ 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 void write_c07x(address_space &space, UINT8 offset, UINT8 data) { printf("a2eauxslot: unhandled write %02x to C07%x\n", data, offset); }
+
+ 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/mess/machine/a2echoii.c b/src/mess/machine/a2echoii.c
new file mode 100644
index 00000000000..4d271fdfee8
--- /dev/null
+++ b/src/mess/machine/a2echoii.c
@@ -0,0 +1,105 @@
+/*********************************************************************
+
+ 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<a2bus_echoii_device>;
+
+#define TMS_TAG "tms5220"
+
+MACHINE_CONFIG_FRAGMENT( a2echoii )
+ MCFG_SPEAKER_STANDARD_MONO("echoii")
+ MCFG_SOUND_ADD(TMS_TAG, TMS5220, 720000)
+ 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) :
+ device_t(mconfig, type, name, tag, owner, clock),
+ device_a2bus_card_interface(mconfig, *this),
+ m_tms(*this, TMS_TAG)
+{
+ m_shortname = "a2echoii";
+}
+
+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),
+ device_a2bus_card_interface(mconfig, *this),
+ m_tms(*this, TMS_TAG)
+{
+ m_shortname = "a2echoii";
+}
+
+//-------------------------------------------------
+// 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 | tms5220_status_r(m_tms, 0);
+ break;
+ }
+
+ return 0;
+}
+
+void a2bus_echoii_device::write_c0nx(address_space &space, UINT8 offset, UINT8 data)
+{
+ switch (offset)
+ {
+ case 0:
+ tms5220_data_w(m_tms, offset, data);
+ break;
+ }
+}
+
+bool a2bus_echoii_device::take_c800()
+{
+ return false;
+}
+
diff --git a/src/mess/machine/a2echoii.h b/src/mess/machine/a2echoii.h
new file mode 100644
index 00000000000..e1452d5338b
--- /dev/null
+++ b/src/mess/machine/a2echoii.h
@@ -0,0 +1,47 @@
+/*********************************************************************
+
+ a2echoii.h
+
+ Implementation of the Street Electronics Echo II speech card
+
+*********************************************************************/
+
+#ifndef __A2BUS_ECHOII__
+#define __A2BUS_ECHOII__
+
+#include "emu.h"
+#include "machine/a2bus.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);
+ 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<device_t> 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/mess/machine/a2lang.c b/src/mess/machine/a2lang.c
new file mode 100644
index 00000000000..43ed6d1f03f
--- /dev/null
+++ b/src/mess/machine/a2lang.c
@@ -0,0 +1,117 @@
+/*********************************************************************
+
+ 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 "machine/a2lang.h"
+
+
+/***************************************************************************
+ PARAMETERS
+***************************************************************************/
+
+#define LOG_LANGCARD 0
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type A2BUS_LANG = &device_creator<a2bus_lang_device>;
+
+
+//**************************************************************************
+// 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),
+ device_a2bus_card_interface(mconfig, *this)
+{
+ m_shortname = "a2lang";
+}
+
+a2bus_lang_device::a2bus_lang_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),
+ device_a2bus_card_interface(mconfig, *this)
+{
+ m_shortname = "a2lang";
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void a2bus_lang_device::device_start()
+{
+ // set_a2bus_device makes m_slot valid
+ set_a2bus_device();
+}
+
+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_setvar(machine(), val, mask);
+}
+
+
+
+/*-------------------------------------------------
+ read_c0nx - called for reads from this card's c0nx space
+-------------------------------------------------*/
+
+UINT8 a2bus_lang_device::read_c0nx(address_space &space, UINT8 offset)
+{
+ langcard_touch(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);
+}
diff --git a/src/mess/machine/a2lang.h b/src/mess/machine/a2lang.h
new file mode 100644
index 00000000000..942f2dcaa1e
--- /dev/null
+++ b/src/mess/machine/a2lang.h
@@ -0,0 +1,43 @@
+/*********************************************************************
+
+ a2lang.h
+
+ Apple II Language Card
+
+*********************************************************************/
+
+#ifndef __A2BUS_LANG__
+#define __A2BUS_LANG__
+
+#include "emu.h"
+#include "machine/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);
+
+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);
+};
+
+// device type definition
+extern const device_type A2BUS_LANG;
+
+#endif /* __A2BUS_LANG__ */
+
diff --git a/src/mess/machine/a2memexp.c b/src/mess/machine/a2memexp.c
new file mode 100644
index 00000000000..8309798460d
--- /dev/null
+++ b/src/mess/machine/a2memexp.c
@@ -0,0 +1,231 @@
+/*********************************************************************
+
+ 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<a2bus_memexpapple_device>;
+const device_type A2BUS_RAMFACTOR = &device_creator<a2bus_ramfactor_device>;
+
+#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) :
+ device_t(mconfig, type, name, tag, owner, clock),
+ 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)
+{
+ m_shortname = "a2memexp";
+ 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)
+{
+ m_shortname = "a2ramfac";
+ 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();
+
+ astring tempstring;
+ m_rom = device().machine().root_device().memregion(this->subtag(tempstring, MEMEXP_ROM_REGION))->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, cpu_get_pc(&space.device()), 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, cpu_get_pc(&space.device()));
+
+ 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/mess/machine/a2memexp.h b/src/mess/machine/a2memexp.h
new file mode 100644
index 00000000000..6fb1583d47a
--- /dev/null
+++ b/src/mess/machine/a2memexp.h
@@ -0,0 +1,71 @@
+/*********************************************************************
+
+ a2memexp.h
+
+ Implementation of the Apple II Memory Expansion Card
+
+*********************************************************************/
+
+#ifndef __A2BUS_MEMEXP__
+#define __A2BUS_MEMEXP__
+
+#include "emu.h"
+#include "machine/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);
+
+ // 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/mess/machine/a2mockingboard.c b/src/mess/machine/a2mockingboard.c
new file mode 100644
index 00000000000..98e51703f13
--- /dev/null
+++ b/src/mess/machine/a2mockingboard.c
@@ -0,0 +1,510 @@
+/*********************************************************************
+
+ a2mockingboard.c
+
+ Implementation of the Sweet Micro Systems Mockingboard card
+
+*********************************************************************/
+
+#include "emu.h"
+#include "machine/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"
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type A2BUS_MOCKINGBOARD = &device_creator<a2bus_mockingboard_device>;
+const device_type A2BUS_PHASOR = &device_creator<a2bus_phasor_device>;
+
+static const ay8910_interface mockingboard_ay8910_interface =
+{
+ AY8910_LEGACY_OUTPUT,
+ AY8910_DEFAULT_LOADS,
+ DEVCB_NULL
+};
+
+const via6522_interface mockingboard_via1_intf =
+{
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, a2bus_ayboard_device, via1_in_a), DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, a2bus_ayboard_device, via1_in_b),
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, a2bus_ayboard_device, via1_out_a), DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, a2bus_ayboard_device, via1_out_b),
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, a2bus_ayboard_device, via1_irq_w)
+};
+
+const via6522_interface mockingboard_via2_intf =
+{
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, a2bus_ayboard_device, via2_in_a), DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, a2bus_ayboard_device, via2_in_b),
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, a2bus_ayboard_device, via2_out_a), DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, a2bus_ayboard_device, via2_out_b),
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, a2bus_ayboard_device, via2_irq_w)
+};
+
+MACHINE_CONFIG_FRAGMENT( mockingboard )
+ MCFG_VIA6522_ADD(VIA1_TAG, 1022727, mockingboard_via1_intf)
+ MCFG_VIA6522_ADD(VIA2_TAG, 1022727, mockingboard_via2_intf)
+
+ MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
+ MCFG_SOUND_ADD(AY1_TAG, AY8913, 1022727)
+ MCFG_SOUND_CONFIG(mockingboard_ay8910_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.0)
+ MCFG_SOUND_ADD(AY2_TAG, AY8913, 1022727)
+ MCFG_SOUND_CONFIG(mockingboard_ay8910_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.0)
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_FRAGMENT( phasor )
+ MCFG_VIA6522_ADD(VIA1_TAG, 1022727, mockingboard_via1_intf)
+ MCFG_VIA6522_ADD(VIA2_TAG, 1022727, mockingboard_via2_intf)
+
+ MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
+ MCFG_SPEAKER_STANDARD_STEREO("lspeaker2", "rspeaker2")
+ MCFG_SOUND_ADD(AY1_TAG, AY8913, 1022727)
+ MCFG_SOUND_CONFIG(mockingboard_ay8910_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.0)
+ MCFG_SOUND_ADD(AY2_TAG, AY8913, 1022727)
+ MCFG_SOUND_CONFIG(mockingboard_ay8910_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker2", 1.0)
+ MCFG_SOUND_ADD(AY3_TAG, AY8913, 1022727)
+ MCFG_SOUND_CONFIG(mockingboard_ay8910_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.0)
+ MCFG_SOUND_ADD(AY4_TAG, AY8913, 1022727)
+ MCFG_SOUND_CONFIG(mockingboard_ay8910_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker2", 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 );
+}
+
+//**************************************************************************
+// 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) :
+ device_t(mconfig, type, name, tag, owner, clock),
+ 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)
+{
+ m_shortname = "a2mockbd";
+ 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)
+{
+ m_shortname = "a2phasor";
+ m_isPhasor = true;
+ 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 c0nx space
+-------------------------------------------------*/
+
+UINT8 a2bus_ayboard_device::read_cnxx(address_space &space, UINT8 offset)
+{
+// printf("Mockingboard(%d): read @ Cn%02X (PC=%x)\n", m_slot, offset, cpu_get_pc(&space.device()));
+ 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, cpu_get_pc(&space.device()), 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, cpu_get_pc(&space.device()));
+ }
+ }
+}
+
+
+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();
+ }
+}
+
+READ8_MEMBER( a2bus_ayboard_device::via1_in_a )
+{
+ return 0;
+}
+
+WRITE8_MEMBER( a2bus_ayboard_device::via1_out_a )
+{
+ m_porta1 = data;
+}
+
+READ8_MEMBER( a2bus_ayboard_device::via1_in_b )
+{
+ return 0;
+}
+
+WRITE8_MEMBER( a2bus_ayboard_device::via1_out_b )
+{
+ if (!(data & 4))
+ {
+ ay8910_reset_w(m_ay1, 0, 0);
+ if (m_isPhasor && m_PhasorNative)
+ {
+ ay8910_reset_w(m_ay2, 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 = ay8910_r(m_ay1, 0);
+ break;
+
+ case 2: // BDIR=1, BC1=0 (write PSG)
+ ay8910_data_w(m_ay1, 0, m_porta1);
+ break;
+
+ case 3: // BDIR=1, BC1=1 (latch)
+ ay8910_address_w(m_ay1, 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 = ay8910_r(m_ay1, 0);
+ }
+ if (chipSel & 2)
+ {
+ m_porta1 = ay8910_r(m_ay2, 0);
+ }
+ break;
+
+ case 2: // BDIR=1, BC1=0 (write PSG)
+ if (chipSel & 1)
+ {
+ ay8910_data_w(m_ay1, 0, m_porta1);
+ }
+ if (chipSel & 2)
+ {
+ ay8910_data_w(m_ay2, 0, m_porta1);
+ }
+ break;
+
+ case 3: // BDIR=1, BC1=1 (latch)
+ if (chipSel & 1)
+ {
+ ay8910_address_w(m_ay1, 0, m_porta1);
+ }
+ if (chipSel & 2)
+ {
+ ay8910_address_w(m_ay2, 0, m_porta1);
+ }
+ break;
+ }
+ }
+ }
+}
+
+READ8_MEMBER( a2bus_ayboard_device::via2_in_a )
+{
+ return 0;
+}
+
+WRITE8_MEMBER( a2bus_ayboard_device::via2_out_a )
+{
+ m_porta2 = data;
+}
+
+READ8_MEMBER( a2bus_ayboard_device::via2_in_b )
+{
+ return 0;
+}
+
+WRITE8_MEMBER( a2bus_ayboard_device::via2_out_b )
+{
+ if (!(data & 4))
+ {
+ if (m_isPhasor && m_PhasorNative)
+ {
+ ay8910_reset_w(m_ay3, 0, 0);
+ ay8910_reset_w(m_ay4, 0, 0);
+ }
+ else
+ {
+ ay8910_reset_w(m_ay2, 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 = ay8910_r(m_ay2, 0);
+ break;
+
+ case 2: // BDIR=1, BC1=0 (write PSG)
+ ay8910_data_w(m_ay2, 0, m_porta2);
+ break;
+
+ case 3: // BDIR=1, BC1=1 (latch)
+ ay8910_address_w(m_ay2, 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 = ay8910_r(m_ay3, 0);
+ }
+ if (chipSel & 2)
+ {
+ m_porta2 = ay8910_r(m_ay4, 0);
+ }
+ break;
+
+ case 2: // BDIR=1, BC1=0 (write PSG)
+ if (chipSel & 1)
+ {
+ ay8910_data_w(m_ay3, 0, m_porta2);
+ }
+ if (chipSel & 2)
+ {
+ ay8910_data_w(m_ay4, 0, m_porta2);
+ }
+ break;
+
+ case 3: // BDIR=1, BC1=1 (latch)
+ if (chipSel & 1)
+ {
+ ay8910_address_w(m_ay3, 0, m_porta2);
+ }
+ if (chipSel & 2)
+ {
+ ay8910_address_w(m_ay4, 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;
+ }
+}
diff --git a/src/mess/machine/a2mockingboard.h b/src/mess/machine/a2mockingboard.h
new file mode 100644
index 00000000000..116718b0ec4
--- /dev/null
+++ b/src/mess/machine/a2mockingboard.h
@@ -0,0 +1,85 @@
+/*********************************************************************
+
+ a2mockingboard.h
+
+ Sweet Micro Systems Mockingboard and compatibles
+
+*********************************************************************/
+
+#ifndef __A2BUS_MOCKINGBOARD__
+#define __A2BUS_MOCKINGBOARD__
+
+#include "emu.h"
+#include "machine/a2bus.h"
+#include "machine/6522via.h"
+#include "sound/ay8910.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);
+
+ // 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_READ8_MEMBER(via1_in_a);
+ DECLARE_READ8_MEMBER(via1_in_b);
+ DECLARE_WRITE8_MEMBER(via1_out_a);
+ DECLARE_WRITE8_MEMBER(via1_out_b);
+ DECLARE_READ8_MEMBER(via2_in_a);
+ DECLARE_READ8_MEMBER(via2_in_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<via6522_device> m_via1;
+ required_device<via6522_device> m_via2;
+ required_device<device_t> m_ay1;
+ required_device<device_t> m_ay2;
+ optional_device<device_t> m_ay3;
+ optional_device<device_t> 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;
+};
+
+// device type definition
+extern const device_type A2BUS_MOCKINGBOARD;
+extern const device_type A2BUS_PHASOR;
+
+#endif /* __A2BUS_MOCKINGBOARD__ */
+
diff --git a/src/mess/machine/a2sam.c b/src/mess/machine/a2sam.c
new file mode 100644
index 00000000000..1ec01cd088d
--- /dev/null
+++ b/src/mess/machine/a2sam.c
@@ -0,0 +1,88 @@
+/*********************************************************************
+
+ 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<a2bus_sam_device>;
+
+#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) :
+ device_t(mconfig, type, name, tag, owner, clock),
+ device_a2bus_card_interface(mconfig, *this),
+ m_dac(*this, DAC_TAG)
+{
+ m_shortname = "a2sam";
+}
+
+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),
+ device_a2bus_card_interface(mconfig, *this),
+ m_dac(*this, DAC_TAG)
+{
+ m_shortname = "a2sam";
+}
+
+//-------------------------------------------------
+// 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/mess/machine/a2sam.h b/src/mess/machine/a2sam.h
new file mode 100644
index 00000000000..7303939642e
--- /dev/null
+++ b/src/mess/machine/a2sam.h
@@ -0,0 +1,47 @@
+/*********************************************************************
+
+ a2sam.h
+
+ Implementation of the S.A.M. "Software Automated Mouth" card
+
+*********************************************************************/
+
+#ifndef __A2BUS_SAM__
+#define __A2BUS_SAM__
+
+#include "emu.h"
+#include "machine/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);
+ 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<dac_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/mess/machine/a2scsi.c b/src/mess/machine/a2scsi.c
new file mode 100644
index 00000000000..111d165214a
--- /dev/null
+++ b/src/mess/machine/a2scsi.c
@@ -0,0 +1,249 @@
+/*********************************************************************
+
+ 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
+ C0n9 = DIP switches
+ C0na = RAM and ROM bank switching
+ C0nb = reset 5380
+ C0ne = into the PAL stuff
+
+*********************************************************************/
+
+#include "a2scsi.h"
+#include "includes/apple2.h"
+
+
+/***************************************************************************
+ PARAMETERS
+***************************************************************************/
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type A2BUS_SCSI = &device_creator<a2bus_scsi_device>;
+
+#define SCSI_ROM_REGION "scsi_rom"
+#define SCSI_5380_TAG "ncr5380"
+
+static const SCSIConfigTable dev_table =
+{
+ 0, /* 2 SCSI devices */
+ {
+// { SCSI_ID_6, "harddisk1", SCSI_DEVICE_HARDDISK }, /* SCSI ID 6, using disk1, and it's a harddisk */
+// { SCSI_ID_5, "harddisk2", SCSI_DEVICE_HARDDISK } /* SCSI ID 5, using disk2, and it's a harddisk */
+ }
+};
+
+static const struct NCR5380interface a2scsi_5380_intf =
+{
+ &dev_table, // SCSI device table
+ NULL // IRQ handler (unconnected according to schematic)
+};
+
+MACHINE_CONFIG_FRAGMENT( scsi )
+ MCFG_NCR5380_ADD(SCSI_5380_TAG, (XTAL_28_63636MHz/4), a2scsi_5380_intf)
+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) :
+ device_t(mconfig, type, name, tag, owner, clock),
+ device_a2bus_card_interface(mconfig, *this),
+ m_ncr5380(*this, SCSI_5380_TAG)
+{
+ m_shortname = "a2scsi";
+}
+
+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),
+ device_a2bus_card_interface(mconfig, *this),
+ m_ncr5380(*this, SCSI_5380_TAG)
+{
+ m_shortname = "a2scsi";
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void a2bus_scsi_device::device_start()
+{
+ // set_a2bus_device makes m_slot valid
+ set_a2bus_device();
+
+ astring tempstring;
+ m_rom = device().machine().root_device().memregion(this->subtag(tempstring, SCSI_ROM_REGION))->base();
+
+ memset(m_ram, 0, 8192);
+
+ save_item(NAME(m_ram));
+ save_item(NAME(m_rambank));
+ save_item(NAME(m_rombank));
+}
+
+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
+}
+
+
+/*-------------------------------------------------
+ read_c0nx - called for reads from this card's c0nx space
+-------------------------------------------------*/
+
+UINT8 a2bus_scsi_device::read_c0nx(address_space &space, UINT8 offset)
+{
+ printf("Read c0n%x (PC=%x)\n", offset, cpu_get_pc(&space.device()));
+
+ switch (offset)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ return ncr5380_read_reg(m_ncr5380, offset);
+
+ case 9: // card's ID?
+ return 7;
+ }
+
+ 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)
+{
+ printf("Write %02x to c0n%x (PC=%x)\n", data, offset, cpu_get_pc(&space.device()));
+
+ switch (offset)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ ncr5380_write_reg(m_ncr5380, offset, 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;
+ printf("RAM bank to %x, ROM bank to %x\n", m_rambank, m_rombank);
+ break;
+
+ case 0xb:
+ printf("Reset NCR5380\n");
+ 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)
+{
+ printf("Write %02x to cn%02x (PC=%x)\n", data, offset, cpu_get_pc(&space.device()));
+}
+
+/*-------------------------------------------------
+ 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]);
+ 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);
+ m_ram[offset + m_rambank] = data;
+ }
+}
diff --git a/src/mess/machine/a2scsi.h b/src/mess/machine/a2scsi.h
new file mode 100644
index 00000000000..55e55fcc962
--- /dev/null
+++ b/src/mess/machine/a2scsi.h
@@ -0,0 +1,57 @@
+/*********************************************************************
+
+ a2scsi.h
+
+ Implementation of the Apple II SCSI Card
+
+*********************************************************************/
+
+#ifndef __A2BUS_SCSI__
+#define __A2BUS_SCSI__
+
+#include "emu.h"
+#include "machine/a2bus.h"
+#include "machine/ncr5380.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);
+ 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;
+
+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<device_t> m_ncr5380;
+
+private:
+ UINT8 *m_rom;
+ UINT8 m_ram[8192]; // 8 banks of 1024 bytes
+ int m_rambank, m_rombank;
+};
+
+// device type definition
+extern const device_type A2BUS_SCSI;
+
+#endif /* __A2BUS_SCSI__ */
+
diff --git a/src/mess/machine/a2softcard.c b/src/mess/machine/a2softcard.c
new file mode 100644
index 00000000000..adc2836941e
--- /dev/null
+++ b/src/mess/machine/a2softcard.c
@@ -0,0 +1,192 @@
+/*********************************************************************
+
+ 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<a2bus_softcard_device>;
+
+#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) :
+ device_t(mconfig, type, name, tag, owner, clock),
+ device_a2bus_card_interface(mconfig, *this),
+ m_z80(*this, Z80_TAG),
+ m_6502space(NULL)
+{
+ m_shortname = "a2softcard";
+}
+
+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),
+ device_a2bus_card_interface(mconfig, *this),
+ m_z80(*this, Z80_TAG),
+ m_6502space(NULL)
+{
+ m_shortname = "a2softcard";
+}
+
+//-------------------------------------------------
+// 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_6502space = NULL;
+ m_FirstZ80Boot = true;
+ device_set_input_line(m_z80, INPUT_LINE_HALT, ASSERT_LINE);
+}
+
+void a2bus_softcard_device::write_cnxx(address_space &space, UINT8 offset, UINT8 data)
+{
+ apple2_state *state = machine().driver_data<apple2_state>();
+
+ if (!m_bEnabled)
+ {
+ // steal the 6502's address space
+ m_6502space = &space;
+
+ device_set_input_line(m_z80, INPUT_LINE_HALT, CLEAR_LINE);
+ device_set_input_line(state->m_maincpu, INPUT_LINE_HALT, ASSERT_LINE);
+
+ if (m_FirstZ80Boot)
+ {
+ m_FirstZ80Boot = false;
+ m_z80->reset();
+ }
+
+ m_bEnabled = true;
+ }
+ else
+ {
+ device_set_input_line(m_z80, INPUT_LINE_HALT, ASSERT_LINE);
+ device_set_input_line(state->m_maincpu, INPUT_LINE_HALT, CLEAR_LINE);
+ m_bEnabled = false;
+ }
+}
+
+READ8_MEMBER( a2bus_softcard_device::dma_r )
+{
+ if (m_6502space)
+ {
+ if (offset <= 0xafff)
+ {
+ return m_6502space->read_byte(offset+0x1000);
+ }
+ else if (offset <= 0xbfff) // LC bank 2 d000-dfff
+ {
+ return m_6502space->read_byte((offset&0xfff) + 0xd000);
+ }
+ else if (offset <= 0xcfff) // LC e000-efff
+ {
+ return m_6502space->read_byte((offset&0xfff) + 0xe000);
+ }
+ else if (offset <= 0xdfff) // LC f000-ffff (or ROM?)
+ {
+ return m_6502space->read_byte((offset&0xfff) + 0xf000);
+ }
+ else if (offset <= 0xefff) // I/O space c000-cfff
+ {
+ return m_6502space->read_byte((offset&0xfff) + 0xc000);
+ }
+ else // zero page
+ {
+ return m_6502space->read_byte(offset&0xfff);
+ }
+ }
+
+ return 0xff;
+}
+
+
+//-------------------------------------------------
+// dma_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( a2bus_softcard_device::dma_w )
+{
+ if (m_6502space)
+ {
+ if (offset <= 0xafff)
+ {
+ m_6502space->write_byte(offset+0x1000, data);
+ }
+ else if (offset <= 0xbfff) // LC bank 2 d000-dfff
+ {
+ m_6502space->write_byte((offset&0xfff) + 0xd000, data);
+ }
+ else if (offset <= 0xcfff) // LC e000-efff
+ {
+ m_6502space->write_byte((offset&0xfff) + 0xe000, data);
+ }
+ else if (offset <= 0xdfff) // LC f000-ffff (or ROM?)
+ {
+ m_6502space->write_byte((offset&0xfff) + 0xf000, data);
+ }
+ else if (offset <= 0xefff) // I/O space c000-cfff
+ {
+ m_6502space->write_byte((offset&0xfff) + 0xc000, data);
+ }
+ else // zero page
+ {
+ m_6502space->write_byte(offset&0xfff, data);
+ }
+ }
+}
+
+bool a2bus_softcard_device::take_c800()
+{
+ return false;
+}
+
diff --git a/src/mess/machine/a2softcard.h b/src/mess/machine/a2softcard.h
new file mode 100644
index 00000000000..73dd189fa67
--- /dev/null
+++ b/src/mess/machine/a2softcard.h
@@ -0,0 +1,54 @@
+/*********************************************************************
+
+ a2softcard.h
+
+ Implementation of the Microsoft SoftCard Z-80 card
+
+*********************************************************************/
+
+#ifndef __A2BUS_SOFTCARD__
+#define __A2BUS_SOFTCARD__
+
+#include "emu.h"
+#include "machine/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);
+ 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<cpu_device> m_z80;
+
+private:
+ bool m_bEnabled;
+ bool m_FirstZ80Boot;
+ address_space *m_6502space;
+};
+
+// device type definition
+extern const device_type A2BUS_SOFTCARD;
+
+#endif /* __A2BUS_SOFTCARD__ */
+
diff --git a/src/mess/machine/a2ssc.c b/src/mess/machine/a2ssc.c
new file mode 100644
index 00000000000..92f06c260f2
--- /dev/null
+++ b/src/mess/machine/a2ssc.c
@@ -0,0 +1,214 @@
+/*********************************************************************
+
+ a2ssc.c
+
+ Apple II Super Serial Card
+
+*********************************************************************/
+
+#include "emu.h"
+#include "includes/apple2.h"
+#include "machine/a2ssc.h"
+
+
+/***************************************************************************
+ PARAMETERS
+***************************************************************************/
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type A2BUS_SSC = &device_creator<a2bus_ssc_device>;
+
+#define SSC_ROM_REGION "ssc_rom"
+#define SSC_ACIA_TAG "ssc_acia"
+
+
+MACHINE_CONFIG_FRAGMENT( ssc )
+ MCFG_ACIA6551_ADD(SSC_ACIA_TAG)
+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),
+ device_a2bus_card_interface(mconfig, *this),
+ m_acia(*this, SSC_ACIA_TAG)
+{
+ m_shortname = "a2ssc";
+}
+
+a2bus_ssc_device::a2bus_ssc_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),
+ device_a2bus_card_interface(mconfig, *this),
+ m_acia(*this, SSC_ACIA_TAG)
+{
+ m_shortname = "a2ssc";
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void a2bus_ssc_device::device_start()
+{
+ // set_a2bus_device makes m_slot valid
+ set_a2bus_device();
+
+ astring tempstring;
+ m_rom = device().machine().root_device().memregion(this->subtag(tempstring, SSC_ROM_REGION))->base();
+}
+
+void a2bus_ssc_device::device_reset()
+{
+}
+
+/*-------------------------------------------------
+ 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+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 device().ioport("DSW1")->read();
+ case 2:
+ return device().ioport("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;
+
+ }
+}
+
diff --git a/src/mess/machine/a2ssc.h b/src/mess/machine/a2ssc.h
new file mode 100644
index 00000000000..5d479dc0580
--- /dev/null
+++ b/src/mess/machine/a2ssc.h
@@ -0,0 +1,53 @@
+/*********************************************************************
+
+ a2ssc.h
+
+ Apple II Super Serial Card
+
+*********************************************************************/
+
+#ifndef __A2BUS_SSC__
+#define __A2BUS_SSC__
+
+#include "emu.h"
+#include "machine/a2bus.h"
+#include "machine/6551acia.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);
+
+ // 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:
+ 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<acia6551_device> m_acia;
+
+private:
+ UINT8 *m_rom;
+};
+
+// device type definition
+extern const device_type A2BUS_SSC;
+
+#endif /* __A2BUS_SSC__ */
+
diff --git a/src/mess/machine/a2swyft.c b/src/mess/machine/a2swyft.c
new file mode 100644
index 00000000000..6171de44ab1
--- /dev/null
+++ b/src/mess/machine/a2swyft.c
@@ -0,0 +1,138 @@
+/*********************************************************************
+
+ a2swyft.c
+
+ Implementation of the IAI SwyftCard
+
+*********************************************************************/
+
+#include "emu.h"
+#include "includes/apple2.h"
+#include "machine/a2swyft.h"
+
+
+/***************************************************************************
+ PARAMETERS
+***************************************************************************/
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type A2BUS_SWYFT = &device_creator<a2bus_swyft_device>;
+
+#define SWYFT_ROM_REGION "swyft_rom"
+
+ROM_START( swyft )
+ ROM_REGION(0x4000, SWYFT_ROM_REGION, 0)
+ ROM_LOAD( "swyftcard rom.bin", 0x000000, 0x004000, CRC(5d6673e9) SHA1(1554bd03c536789f0ff7d1ef6c992265e311935d) )
+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),
+ device_a2bus_card_interface(mconfig, *this)
+{
+ m_shortname = "a2swyft";
+}
+
+a2bus_swyft_device::a2bus_swyft_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),
+ device_a2bus_card_interface(mconfig, *this)
+{
+ m_shortname = "a2swyft";
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void a2bus_swyft_device::device_start()
+{
+ // set_a2bus_device makes m_slot valid
+ set_a2bus_device();
+
+ astring tempstring;
+ m_rom = device().machine().root_device().memregion(this->subtag(tempstring, SWYFT_ROM_REGION))->base();
+
+ save_item(NAME(m_rombank));
+}
+
+void a2bus_swyft_device::device_reset()
+{
+ m_rombank = 0;
+
+ // take over the machine
+ apple2_state *state = machine().driver_data<apple2_state>();
+ raise_slot_inh();
+ state->m_maincpu->reset();
+}
+
+UINT8 a2bus_swyft_device::read_c0nx(address_space &space, UINT8 offset)
+{
+ switch (offset)
+ {
+ case 0:
+ m_rombank = 0;
+ raise_slot_inh();
+ break;
+
+ case 1:
+ m_rombank = 0;
+ lower_slot_inh();
+ break;
+
+ case 2:
+ m_rombank = 0x1000;
+ raise_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;
+ raise_slot_inh();
+ break;
+
+ case 1:
+ m_rombank = 0;
+ lower_slot_inh();
+ break;
+
+ case 2:
+ m_rombank = 0x1000;
+ raise_slot_inh();
+ break;
+ }
+}
+
+UINT8 a2bus_swyft_device::read_inh_rom(address_space &space, UINT16 offset)
+{
+ if (offset < 0x1000) // banked area d000-dfff
+ {
+ return m_rom[offset + m_rombank];
+ }
+ else // fixed area e000-ffff
+ {
+ return m_rom[offset - 0x1000 + 0x2000];
+ }
+}
+
diff --git a/src/mess/machine/a2swyft.h b/src/mess/machine/a2swyft.h
new file mode 100644
index 00000000000..5a4ec743c0f
--- /dev/null
+++ b/src/mess/machine/a2swyft.h
@@ -0,0 +1,47 @@
+/*********************************************************************
+
+ a2swyft.h
+
+ IAI SwyftCard
+
+*********************************************************************/
+
+#ifndef __A2BUS_SWYFT__
+#define __A2BUS_SWYFT__
+
+#include "emu.h"
+#include "machine/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);
+
+ 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);
+
+private:
+ UINT8 *m_rom;
+ int m_rombank;
+};
+
+// device type definition
+extern const device_type A2BUS_SWYFT;
+
+#endif /* __A2BUS_SWYFT__ */
+
diff --git a/src/mess/machine/a2themill.c b/src/mess/machine/a2themill.c
new file mode 100644
index 00000000000..c080f04cba7
--- /dev/null
+++ b/src/mess/machine/a2themill.c
@@ -0,0 +1,345 @@
+/*********************************************************************
+
+ 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<a2bus_themill_device>;
+
+#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) :
+ device_t(mconfig, type, name, tag, owner, clock),
+ device_a2bus_card_interface(mconfig, *this),
+ m_6809(*this, M6809_TAG),
+ m_6502space(NULL)
+{
+ m_shortname = "a2themill";
+}
+
+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),
+ device_a2bus_card_interface(mconfig, *this),
+ m_6809(*this, M6809_TAG),
+ m_6502space(NULL)
+{
+ m_shortname = "a2themill";
+}
+
+//-------------------------------------------------
+// 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_6502space = NULL;
+ m_flipAddrSpace = false;
+ m_6809Mode = false;
+ m_status = 0xc0; // OS9 loader relies on this
+ device_set_input_line(m_6809, INPUT_LINE_HALT, ASSERT_LINE);
+ device_set_input_line(m_6809, 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)
+ {
+ // steal the 6502's address space
+ m_6502space = &space;
+ m_6809->reset();
+
+ device_set_input_line(m_6809, INPUT_LINE_HALT, CLEAR_LINE);
+ device_set_input_line(m_6809, INPUT_LINE_RESET, CLEAR_LINE);
+
+ m_bEnabled = true;
+ m_status &= ~0x04;
+ }
+ else
+ {
+ device_set_input_line(m_6809, 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)
+ {
+ device_set_input_line(m_6809, INPUT_LINE_NMI, CLEAR_LINE);
+ m_status |= 0x08;
+ }
+ else
+ {
+ device_set_input_line(m_6809, INPUT_LINE_NMI, ASSERT_LINE);
+ m_status &= ~0x08;
+ }
+ break;
+
+ case 4: // 6809 FIRQ
+ if (data & 0x80)
+ {
+ device_set_input_line(m_6809, M6809_FIRQ_LINE, CLEAR_LINE);
+ m_status |= 0x10;
+ }
+ else
+ {
+ device_set_input_line(m_6809, M6809_FIRQ_LINE, ASSERT_LINE);
+ m_status &= ~0x10;
+ }
+ break;
+
+ case 5: // 6809 IRQ
+ if (data & 0x80)
+ {
+ device_set_input_line(m_6809, M6809_IRQ_LINE, CLEAR_LINE);
+ m_status |= 0x20;
+ }
+ else
+ {
+ device_set_input_line(m_6809, 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_6502space)
+ {
+ if (m_6809Mode)
+ {
+ if (offset <= 0xafff)
+ {
+ return m_6502space->read_byte(offset+0x1000);
+ }
+ else if (offset <= 0xbfff)
+ {
+ return m_6502space->read_byte((offset&0xfff) + 0xd000);
+ }
+ else if (offset <= 0xcfff)
+ {
+ return m_6502space->read_byte((offset&0xfff) + 0xe000);
+ }
+ else if (offset <= 0xdfff)
+ {
+ return m_6502space->read_byte((offset&0xfff) + 0xf000);
+ }
+ else if (offset <= 0xefff)
+ {
+ return m_6502space->read_byte((offset&0xfff) + 0xc000);
+ }
+ else // 6809 Fxxx -> 6502 ZP
+ {
+ return m_6502space->read_byte(offset&0xfff);
+ }
+ }
+ else
+ {
+ if (m_flipAddrSpace)
+ {
+ return m_6502space->read_byte(offset^0x8000);
+ }
+ else
+ {
+ return m_6502space->read_byte(offset);
+ }
+ }
+ }
+
+ return 0xff;
+}
+
+
+//-------------------------------------------------
+// dma_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( a2bus_themill_device::dma_w )
+{
+ if (m_6502space)
+ {
+ if (m_6809Mode)
+ {
+ if (offset <= 0xafff)
+ {
+ m_6502space->write_byte(offset+0x1000, data);
+ }
+ else if (offset <= 0xbfff)
+ {
+ m_6502space->write_byte((offset&0xfff) + 0xd000, data);
+ }
+ else if (offset <= 0xcfff)
+ {
+ m_6502space->write_byte((offset&0xfff) + 0xe000, data);
+ }
+ else if (offset <= 0xdfff)
+ {
+ m_6502space->write_byte((offset&0xfff) + 0xf000, data);
+ }
+ else if (offset <= 0xefff)
+ {
+ m_6502space->write_byte((offset&0xfff) + 0xc000, data);
+ }
+ else // 6809 Fxxx -> 6502 ZP
+ {
+ m_6502space->write_byte(offset&0xfff, data);
+ }
+ }
+ else
+ {
+ if (m_flipAddrSpace)
+ {
+ m_6502space->write_byte(offset^0x8000, data);
+ }
+ else
+ {
+ m_6502space->write_byte(offset, data);
+ }
+ }
+ }
+}
+
+bool a2bus_themill_device::take_c800()
+{
+ return false;
+}
+
diff --git a/src/mess/machine/a2themill.h b/src/mess/machine/a2themill.h
new file mode 100644
index 00000000000..db447292794
--- /dev/null
+++ b/src/mess/machine/a2themill.h
@@ -0,0 +1,57 @@
+/*********************************************************************
+
+ a2themill.h
+
+ Implementation of the Stellation Two The Mill 6809 card
+
+*********************************************************************/
+
+#ifndef __A2BUS_THEMILL__
+#define __A2BUS_THEMILL__
+
+#include "emu.h"
+#include "machine/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);
+ 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<cpu_device> m_6809;
+
+private:
+ bool m_bEnabled;
+ bool m_flipAddrSpace;
+ bool m_6809Mode;
+ address_space *m_6502space;
+ UINT8 m_status;
+};
+
+// device type definition
+extern const device_type A2BUS_THEMILL;
+
+#endif /* __A2BUS_THEMILL__ */
+
diff --git a/src/mess/machine/a2thunderclock.c b/src/mess/machine/a2thunderclock.c
new file mode 100644
index 00000000000..ad7e81305fc
--- /dev/null
+++ b/src/mess/machine/a2thunderclock.c
@@ -0,0 +1,186 @@
+/*********************************************************************
+
+ 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<a2bus_thunderclock_device>;
+
+#define THUNDERCLOCK_ROM_REGION "thunclk_rom"
+#define THUNDERCLOCK_UPD1990_TAG "thunclk_upd"
+
+static UPD1990A_INTERFACE( thunderclock_upd1990a_intf )
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, a2bus_thunderclock_device, upd_dataout_w),
+ DEVCB_NULL // TP out not used? for Thunderclock
+};
+
+MACHINE_CONFIG_FRAGMENT( thunderclock )
+ MCFG_UPD1990A_ADD(THUNDERCLOCK_UPD1990_TAG, 1021800, thunderclock_upd1990a_intf)
+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) :
+ device_t(mconfig, type, name, tag, owner, clock),
+ device_a2bus_card_interface(mconfig, *this),
+ m_upd1990ac(*this, THUNDERCLOCK_UPD1990_TAG)
+{
+ m_shortname = "a2thunpl";
+}
+
+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),
+ device_a2bus_card_interface(mconfig, *this),
+ m_upd1990ac(*this, THUNDERCLOCK_UPD1990_TAG)
+{
+ m_shortname = "a2thunpl";
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void a2bus_thunderclock_device::device_start()
+{
+ // set_a2bus_device makes m_slot valid
+ set_a2bus_device();
+
+ astring tempstring;
+ m_rom = device().machine().root_device().memregion(this->subtag(tempstring, THUNDERCLOCK_ROM_REGION))->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/mess/machine/a2thunderclock.h b/src/mess/machine/a2thunderclock.h
new file mode 100644
index 00000000000..29b45936f7f
--- /dev/null
+++ b/src/mess/machine/a2thunderclock.h
@@ -0,0 +1,56 @@
+/*********************************************************************
+
+ a2thunderclock.h
+
+ Implemention of the Thunderware Thunderclock Plus.
+
+*********************************************************************/
+
+#ifndef __A2BUS_THUNDERCLOCK__
+#define __A2BUS_THUNDERCLOCK__
+
+#include "emu.h"
+#include "machine/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);
+ 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<upd1990a_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/mess/machine/a2videoterm.c b/src/mess/machine/a2videoterm.c
new file mode 100644
index 00000000000..dedd69ca661
--- /dev/null
+++ b/src/mess/machine/a2videoterm.c
@@ -0,0 +1,376 @@
+/*********************************************************************
+
+ 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<a2bus_videoterm_device>;
+const device_type A2BUS_IBSAP16 = &device_creator<a2bus_ap16_device>;
+const device_type A2BUS_IBSAP16ALT = &device_creator<a2bus_ap16alt_device>;
+const device_type A2BUS_VTC1 = &device_creator<a2bus_vtc1_device>;
+const device_type A2BUS_VTC2 = &device_creator<a2bus_vtc2_device>;
+
+#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
+
+static MC6845_UPDATE_ROW( videoterm_update_row );
+
+static const mc6845_interface mc6845_mda_intf =
+{
+ VIDEOTERM_SCREEN_NAME, /* screen number */
+ 8, /* number of pixels per video memory address */
+ NULL, /* begin_update */
+ videoterm_update_row, /* update_row */
+ NULL, /* end_update */
+ DEVCB_NULL, /* on_de_changed */
+ DEVCB_NULL, /* on_cur_changed */
+ DEVCB_NULL, /* on hsync changed */
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, a2bus_videx80_device, vsync_changed), /* on_vsync_changed */
+ NULL
+};
+
+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, MDA_CLOCK/9, mc6845_mda_intf)
+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
+
+/***************************************************************************
+ 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 );
+}
+
+//**************************************************************************
+// 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) :
+ device_t(mconfig, type, name, tag, owner, clock),
+ device_a2bus_card_interface(mconfig, *this),
+ m_crtc(*this, VIDEOTERM_MC6845_NAME)
+{
+}
+
+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)
+{
+ m_shortname = "a2vidtrm";
+}
+
+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)
+{
+ m_shortname = "a2ap16";
+}
+
+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)
+{
+ m_shortname = "a2ap16a";
+}
+
+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)
+{
+ m_shortname = "a2vtc1";
+}
+
+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)
+{
+ m_shortname = "a2vtc2";
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void a2bus_videx80_device::device_start()
+{
+ // set_a2bus_device makes m_slot valid
+ set_a2bus_device();
+
+ astring tempstring;
+ m_rom = device().machine().root_device().memregion(this->subtag(tempstring, VIDEOTERM_ROM_REGION))->base();
+
+ astring tempstring2;
+ m_chrrom = device().machine().root_device().memregion(this->subtag(tempstring2, VIDEOTERM_GFX_REGION))->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, cpu_get_pc(&space.device()));
+
+ 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, cpu_get_pc(&space.device()));
+
+ 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;
+ }
+}
+
+static MC6845_UPDATE_ROW( videoterm_update_row )
+{
+ a2bus_videx80_device *vterm = downcast<a2bus_videx80_device *>(device->owner());
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ 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 = vterm->m_ram[ offset ];
+ UINT8 data = vterm->m_chrrom[ chr_base + chr * 16 ];
+ UINT8 fg = 15;
+ UINT8 bg = 0;
+
+ if ( i == cursor_x )
+ {
+ if ( vterm->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/mess/machine/a2videoterm.h b/src/mess/machine/a2videoterm.h
new file mode 100644
index 00000000000..18a8d10dc11
--- /dev/null
+++ b/src/mess/machine/a2videoterm.h
@@ -0,0 +1,108 @@
+/*********************************************************************
+
+ a2videoterm.h
+
+ Implementation of the Apple II Memory Expansion Card
+
+*********************************************************************/
+
+#ifndef __A2BUS_VIDEOTERM__
+#define __A2BUS_VIDEOTERM__
+
+#include "emu.h"
+#include "machine/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);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+ DECLARE_WRITE_LINE_MEMBER(vsync_changed);
+
+ 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<mc6845_device> m_crtc;
+
+private:
+ int m_rambank;
+};
+
+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;
+};
+
+// 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;
+
+#endif /* __A2BUS_VIDEOTERM__ */
+
diff --git a/src/mess/machine/a7800.c b/src/mess/machine/a7800.c
new file mode 100644
index 00000000000..f860e2a779f
--- /dev/null
+++ b/src/mess/machine/a7800.c
@@ -0,0 +1,531 @@
+/***************************************************************************
+
+ a7800.c
+
+ Machine file to handle emulation of the Atari 7800.
+
+ 5-Nov-2003 npwoods Cleanups
+
+ 14-May-2002 kubecj Fixed Fatal Run - adding simple riot timer helped.
+ maybe someone with knowledge should add full fledged
+ riot emulation?
+
+ 13-May-2002 kubecj Fixed a7800_cart_type not to be too short ;-D
+ fixed for loading of bank6 cart (uh, I hope)
+ fixed for loading 64k supercarts
+ fixed for using PAL bios
+ cart not needed when in PAL mode
+ added F18 Hornet bank select type
+ added Activision bank select type
+ 19-Feb-2010 DanB Added return values for TIA collision registers
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/a7800.h"
+#include "cpu/m6502/m6502.h"
+#include "sound/tiasound.h"
+#include "machine/6532riot.h"
+#include "sound/pokey.h"
+#include "sound/tiaintf.h"
+
+
+
+/* local */
+
+
+
+/***************************************************************************
+ 6532 RIOT
+***************************************************************************/
+
+static READ8_DEVICE_HANDLER( riot_joystick_r )
+{
+ return device->machine().root_device().ioport("joysticks")->read();
+}
+
+static READ8_DEVICE_HANDLER( riot_console_button_r )
+{
+ return device->machine().root_device().ioport("console_buttons")->read();
+}
+
+static WRITE8_DEVICE_HANDLER( riot_button_pullup_w )
+{
+ a7800_state *state = device->machine().driver_data<a7800_state>();
+ state->m_p1_one_button = data & 0x04; // pin 6 of the controller port is held high by the riot chip when reading two-button controllers (from schematic)
+ state->m_p2_one_button = data & 0x10;
+}
+
+const riot6532_interface a7800_r6532_interface =
+{
+ DEVCB_HANDLER(riot_joystick_r),
+ DEVCB_HANDLER(riot_console_button_r),
+ DEVCB_NULL,
+ DEVCB_HANDLER(riot_button_pullup_w),
+ DEVCB_NULL
+};
+
+
+/***************************************************************************
+ DRIVER INIT
+***************************************************************************/
+
+static void a7800_driver_init(running_machine &machine, int ispal, int lines)
+{
+ a7800_state *state = machine.driver_data<a7800_state>();
+ address_space* space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ state->m_ROM = state->memregion("maincpu")->base();
+ state->m_ispal = ispal;
+ state->m_lines = lines;
+ state->m_p1_one_button = 1;
+ state->m_p2_one_button = 1;
+
+ /* standard banks */
+ state->membank("bank5")->set_base(&state->m_ROM[0x2040]); /* RAM0 */
+ state->membank("bank6")->set_base(&state->m_ROM[0x2140]); /* RAM1 */
+ state->membank("bank7")->set_base(&state->m_ROM[0x2000]); /* MAINRAM */
+
+ /* Brutal hack put in as a consequence of new memory system; fix this */
+ space->install_readwrite_bank(0x0480, 0x04FF,"bank10");
+ state->membank("bank10")->set_base(state->m_ROM + 0x0480);
+ space->install_readwrite_bank(0x1800, 0x27FF, "bank11");
+ state->membank("bank11")->set_base(state->m_ROM + 0x1800);
+}
+
+
+DRIVER_INIT_MEMBER(a7800_state,a7800_ntsc)
+{
+ a7800_driver_init(machine(), FALSE, 262);
+}
+
+
+DRIVER_INIT_MEMBER(a7800_state,a7800_pal)
+{
+ a7800_driver_init(machine(), TRUE, 312);
+}
+
+
+MACHINE_RESET( a7800 )
+{
+ a7800_state *state = machine.driver_data<a7800_state>();
+ UINT8 *memory;
+ address_space* space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ state->m_ctrl_lock = 0;
+ state->m_ctrl_reg = 0;
+ state->m_maria_flag = 0;
+
+ /* set banks to default states */
+ memory = state->memregion("maincpu")->base();
+ state->membank("bank1")->set_base(memory + 0x4000 );
+ state->membank("bank2")->set_base(memory + 0x8000 );
+ state->membank("bank3")->set_base(memory + 0xA000 );
+ state->membank("bank4")->set_base(memory + 0xC000 );
+
+ /* pokey cartridge */
+ if (state->m_cart_type & 0x01)
+ {
+ pokey_device *pokey = machine.device<pokey_device>("pokey");
+ space->install_readwrite_handler(0x4000, 0x7FFF, read8_delegate(FUNC(pokey_device::read),pokey), write8_delegate(FUNC(pokey_device::write),pokey));
+ }
+}
+
+
+/***************************************************************************
+ CARTRIDGE HANDLING
+***************************************************************************/
+
+#define MBANK_TYPE_ATARI 0x0000
+#define MBANK_TYPE_ACTIVISION 0x0100
+#define MBANK_TYPE_ABSOLUTE 0x0200
+
+/* Header format
+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
+ bit 0 0x01 - pokey cart
+ bit 1 0x02 - supercart bank switched
+ bit 2 0x04 - supercart RAM at $4000
+ bit 3 0x08 - additional state->m_ROM at $4000
+
+ bit 8-15 - Special
+ 0 = Normal cart
+ 1 = Absolute (F18 Hornet)
+ 2 = Activision
+
+55 controller 1 type - 1 byte
+56 controller 2 type - 1 byte
+ 0 = None
+ 1 = Joystick
+ 2 = Light Gun
+57 0 = NTSC/1 = PAL
+
+100..127 "ACTUAL CART DATA STARTS HERE" - 28 bytes
+
+Versions:
+ Version 0: Initial release
+ Version 1: Added PAL/NTSC bit. Added Special cart byte.
+ Changed 53 bit 2, added bit 3
+
+*/
+void a7800_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);
+}
+
+
+static int a7800_verify_cart(char header[128])
+{
+ const char* tag = "ATARI7800";
+
+ if( strncmp( tag, header + 1, 9 ) )
+ {
+ logerror("Not a valid A7800 image\n");
+ return IMAGE_VERIFY_FAIL;
+ }
+
+ logerror("returning ID_OK\n");
+ return IMAGE_VERIFY_PASS;
+}
+
+
+DEVICE_START( a7800_cart )
+{
+ a7800_state *state = device->machine().driver_data<a7800_state>();
+ UINT8 *memory = state->memregion("maincpu")->base();
+
+ state->m_bios_bkup = NULL;
+ state->m_cart_bkup = NULL;
+
+ /* Allocate memory for BIOS bank switching */
+ state->m_bios_bkup = auto_alloc_array_clear(device->machine(), UINT8, 0x4000);
+ state->m_cart_bkup = auto_alloc_array(device->machine(), UINT8, 0x4000);
+
+ /* save the BIOS so we can switch it in and out */
+ memcpy( state->m_bios_bkup, memory + 0xC000, 0x4000 );
+
+ /* Initialize cart area to "no data" */
+ memset( state->m_cart_bkup, 0xFF, 0x4000 );
+
+ /* defaults for PAL bios without cart */
+ state->m_cart_type = 0;
+ state->m_stick_type = 1;
+}
+
+struct a7800_pcb
+{
+ const char *pcb_name;
+ UINT16 type;
+};
+
+// sketchy support for a7800 cart types
+// TODO: proper emulation of the banking based on xml
+// (and on the real cart layout!)
+static const a7800_pcb pcb_list[] =
+{
+ { "ABSOLUTE", MBANK_TYPE_ABSOLUTE },
+ { "ACTIVISION", MBANK_TYPE_ACTIVISION },
+ { "TYPE-0", 0x0 },
+ { "TYPE-1", 0x1 },
+ { "TYPE-2", 0x2 },
+ { "TYPE-3", 0x3 },
+ { "TYPE-6", 0x6 },
+ { "TYPE-A", 0xa },
+ { 0 }
+};
+
+static UINT16 a7800_get_pcb_id(const char *pcb)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_LENGTH(pcb_list); i++)
+ {
+ if (!mame_stricmp(pcb_list[i].pcb_name, pcb))
+ return pcb_list[i].type;
+ }
+
+ return 0;
+}
+
+DEVICE_IMAGE_LOAD( a7800_cart )
+{
+ a7800_state *state = image.device().machine().driver_data<a7800_state>();
+ UINT32 len = 0, start = 0;
+ unsigned char header[128];
+ UINT8 *memory = image.device().machine().root_device().memregion("maincpu")->base();
+ const char *pcb_name;
+
+ // detect cart type either from xml or from header
+ if (image.software_entry() == NULL)
+ {
+ /* Load and decode the header */
+ image.fread(header, 128);
+
+ /* Check the cart */
+ if( a7800_verify_cart((char *)header) == IMAGE_VERIFY_FAIL)
+ return IMAGE_INIT_FAIL;
+
+ len =(header[49] << 24) |(header[50] << 16) |(header[51] << 8) | header[52];
+ state->m_cart_size = len;
+
+ state->m_cart_type =(header[53] << 8) | header[54];
+ state->m_stick_type = header[55];
+ logerror("Cart type: %x\n", state->m_cart_type);
+
+ /* For now, if game support stick and gun, set it to stick */
+ if (state->m_stick_type == 3)
+ state->m_stick_type = 1;
+ }
+ else
+ {
+ len = image.get_software_region_length("rom");
+ state->m_cart_size = len;
+ // TODO: add stick/gun support to xml!
+ state->m_stick_type = 1;
+ if ((pcb_name = image.get_feature("pcb_type")) == NULL)
+ state->m_cart_type = 0;
+ else
+ state->m_cart_type = a7800_get_pcb_id(pcb_name);
+ }
+
+ if (state->m_cart_type == 0 || state->m_cart_type == 1)
+ {
+ /* Normal Cart */
+ start = 0x10000 - len;
+ state->m_cartridge_rom = memory + start;
+ if (image.software_entry() == NULL)
+ image.fread(state->m_cartridge_rom, len);
+ else
+ memcpy(state->m_cartridge_rom, image.get_software_region("rom"), len);
+ }
+ else if (state->m_cart_type & 0x02)
+ {
+ /* Super Cart */
+ /* Extra ROM at $4000 */
+ if (state->m_cart_type & 0x08)
+ {
+ if (image.software_entry() == NULL)
+ image.fread(memory + 0x4000, 0x4000);
+ else
+ memcpy(memory + 0x4000, image.get_software_region("rom"), 0x4000);
+ len -= 0x4000;
+ start = 0x4000;
+ }
+
+ state->m_cartridge_rom = memory + 0x10000;
+ if (image.software_entry() == NULL)
+ image.fread(state->m_cartridge_rom, len);
+ else
+ memcpy(state->m_cartridge_rom, image.get_software_region("rom") + start, len);
+
+ /* bank 0 */
+ memcpy(memory + 0x8000, memory + 0x10000, 0x4000);
+
+ /* last bank */
+ memcpy(memory + 0xC000, memory + 0x10000 + len - 0x4000, 0x4000);
+
+ /* fixed 2002/05/13 kubecj
+ there was 0x08, I added also two other cases.
+ Now, it loads bank n-2 to $4000 if it's empty.
+ */
+
+ /* bank n-2 */
+ if (!(state->m_cart_type & 0x0d))
+ {
+ memcpy(memory + 0x4000, memory + 0x10000 + len - 0x8000, 0x4000);
+ }
+ }
+ else if (state->m_cart_type == MBANK_TYPE_ABSOLUTE)
+ {
+ /* F18 Hornet */
+
+ logerror("Cart type: %x Absolute\n",state->m_cart_type);
+
+ state->m_cartridge_rom = memory + 0x10000;
+ if (image.software_entry() == NULL)
+ image.fread(state->m_cartridge_rom, len);
+ else
+ memcpy(state->m_cartridge_rom, image.get_software_region("rom") + start, len);
+
+ /* bank 0 */
+ memcpy(memory + 0x4000, memory + 0x10000, 0x4000);
+
+ /* last bank */
+ memcpy(memory + 0x8000, memory + 0x18000, 0x8000);
+ }
+ else if (state->m_cart_type == MBANK_TYPE_ACTIVISION)
+ {
+ /* Activision */
+
+ logerror("Cart type: %x Activision\n",state->m_cart_type);
+
+ state->m_cartridge_rom = memory + 0x10000;
+ if (image.software_entry() == NULL)
+ image.fread(state->m_cartridge_rom, len);
+ else
+ memcpy(state->m_cartridge_rom, image.get_software_region("rom") + start, len);
+
+ /* bank 0 */
+ memcpy(memory + 0xa000, memory + 0x10000, 0x4000);
+
+ /* bank6 hi */
+ memcpy(memory + 0x4000, memory + 0x2a000, 0x2000);
+
+ /* bank6 lo */
+ memcpy(memory + 0x6000, memory + 0x28000, 0x2000);
+
+ /* bank7 hi */
+ memcpy(memory + 0x8000, memory + 0x2e000, 0x2000);
+
+ /* bank7 lo */
+ memcpy(memory + 0xe000, memory + 0x2c000, 0x2000);
+
+ }
+
+ memcpy(state->m_cart_bkup, memory + 0xc000, 0x4000);
+ memcpy(memory + 0xc000, state->m_bios_bkup, 0x4000);
+ return IMAGE_INIT_PASS;
+}
+
+
+WRITE8_MEMBER(a7800_state::a7800_RAM0_w)
+{
+ m_ROM[0x2040 + offset] = data;
+ m_ROM[0x40 + offset] = data;
+}
+
+
+WRITE8_MEMBER(a7800_state::a7800_cart_w)
+{
+ UINT8 *memory = memregion("maincpu")->base();
+
+ if(offset < 0x4000)
+ {
+ if(m_cart_type & 0x04)
+ {
+ m_ROM[0x4000 + offset] = data;
+ }
+ else if(m_cart_type & 0x01)
+ {
+ pokey_device *pokey = machine().device<pokey_device>("pokey");
+ pokey->write(space, offset, data);
+ }
+ else
+ {
+ logerror("Undefined write A: %x",offset + 0x4000);
+ }
+ }
+
+ if(( m_cart_type & 0x02 ) &&( offset >= 0x4000 ) )
+ {
+ /* fix for 64kb supercart */
+ if( m_cart_size == 0x10000 )
+ {
+ data &= 0x03;
+ }
+ else
+ {
+ data &= 0x07;
+ }
+ membank("bank2")->set_base(memory + 0x10000 + (data << 14));
+ membank("bank3")->set_base(memory + 0x12000 + (data << 14));
+ /* logerror("BANK SEL: %d\n",data); */
+ }
+ else if(( m_cart_type == MBANK_TYPE_ABSOLUTE ) &&( offset == 0x4000 ) )
+ {
+ /* F18 Hornet */
+ /*logerror( "F18 BANK SEL: %d\n", data );*/
+ if( data & 1 )
+ {
+ membank("bank1")->set_base(memory + 0x10000 );
+ }
+ else if( data & 2 )
+ {
+ membank("bank1")->set_base(memory + 0x14000 );
+ }
+ }
+ else if(( m_cart_type == MBANK_TYPE_ACTIVISION ) &&( offset >= 0xBF80 ) )
+ {
+ /* Activision */
+ data = offset & 7;
+
+ /*logerror( "Activision BANK SEL: %d\n", data );*/
+
+ membank("bank3")->set_base(memory + 0x10000 + ( data << 14 ) );
+ membank("bank4")->set_base(memory + 0x12000 + ( data << 14 ) );
+ }
+}
+
+
+/***************************************************************************
+ TIA
+***************************************************************************/
+
+READ8_MEMBER(a7800_state::a7800_TIA_r)
+{
+ switch(offset & 0x0f)
+ {
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ /* Even though the 7800 doesn't use the TIA graphics the collision registers should
+ still return a reasonable value */
+ return 0x00;
+ case 0x08:
+ return((ioport("buttons")->read() & 0x02) << 6);
+ case 0x09:
+ return((ioport("buttons")->read() & 0x08) << 4);
+ case 0x0A:
+ return((ioport("buttons")->read() & 0x01) << 7);
+ case 0x0B:
+ return((ioport("buttons")->read() & 0x04) << 5);
+ case 0x0c:
+ if(((ioport("buttons")->read() & 0x08) ||(ioport("buttons")->read() & 0x02)) && m_p1_one_button)
+ return 0x00;
+ else
+ return 0x80;
+ case 0x0d:
+ if(((ioport("buttons")->read() & 0x01) ||(ioport("buttons")->read() & 0x04)) && m_p2_one_button)
+ return 0x00;
+ else
+ return 0x80;
+ default:
+ logerror("undefined TIA read %x\n",offset);
+
+ }
+ return 0xFF;
+}
+
+
+WRITE8_MEMBER(a7800_state::a7800_TIA_w)
+{
+ switch(offset) {
+ case 0x01:
+ if(data & 0x01)
+ {
+ m_maria_flag=1;
+ }
+ if(!m_ctrl_lock)
+ {
+ m_ctrl_lock = data & 0x01;
+ m_ctrl_reg = data;
+
+ if (data & 0x04)
+ memcpy( m_ROM + 0xC000, m_cart_bkup, 0x4000 );
+ else
+ memcpy( m_ROM + 0xC000, m_bios_bkup, 0x4000 );
+ }
+ break;
+ }
+ tia_sound_w(machine().device("tia"), offset, data);
+ m_ROM[offset] = data;
+}
diff --git a/src/mess/machine/abc1600_bus.c b/src/mess/machine/abc1600_bus.c
new file mode 100644
index 00000000000..600c16a369f
--- /dev/null
+++ b/src/mess/machine/abc1600_bus.c
@@ -0,0 +1,564 @@
+/**********************************************************************
+
+ Luxor ABC 1600 Expansion Bus emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "abc1600_bus.h"
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ABC1600BUS_SLOT = &device_creator<abc1600bus_slot_device>;
+
+
+
+//**************************************************************************
+// DEVICE ABC1600BUS CARD INTERFACE
+//**************************************************************************
+
+//-------------------------------------------------
+// device_abc1600bus_card_interface - constructor
+//-------------------------------------------------
+
+device_abc1600bus_card_interface::device_abc1600bus_card_interface(const machine_config &mconfig, device_t &device)
+ : device_slot_card_interface(mconfig, device)
+{
+}
+
+
+//-------------------------------------------------
+// ~device_abc1600bus_card_interface - destructor
+//-------------------------------------------------
+
+device_abc1600bus_card_interface::~device_abc1600bus_card_interface()
+{
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// abc1600bus_slot_device - constructor
+//-------------------------------------------------
+
+abc1600bus_slot_device::abc1600bus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, ABC1600BUS_SLOT, "ABC 1600 bus slot", tag, owner, clock),
+ device_slot_interface(mconfig, *this),
+ m_int(CLEAR_LINE),
+ m_pren(1),
+ m_trrq(1),
+ m_nmi(CLEAR_LINE),
+ m_xint2(CLEAR_LINE),
+ m_xint3(CLEAR_LINE),
+ m_xint4(CLEAR_LINE),
+ m_xint5(CLEAR_LINE)
+{
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void abc1600bus_slot_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const abc1600bus_interface *intf = reinterpret_cast<const abc1600bus_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<abc1600bus_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_int_cb, 0, sizeof(m_out_int_cb));
+ memset(&m_out_pren_cb, 0, sizeof(m_out_pren_cb));
+ memset(&m_out_trrq_cb, 0, sizeof(m_out_trrq_cb));
+ memset(&m_out_nmi_cb, 0, sizeof(m_out_nmi_cb));
+ memset(&m_out_xint2_cb, 0, sizeof(m_out_xint2_cb));
+ memset(&m_out_xint3_cb, 0, sizeof(m_out_xint3_cb));
+ memset(&m_out_xint4_cb, 0, sizeof(m_out_xint4_cb));
+ memset(&m_out_xint5_cb, 0, sizeof(m_out_xint5_cb));
+ }
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void abc1600bus_slot_device::device_start()
+{
+ m_card = dynamic_cast<device_abc1600bus_card_interface *>(get_card_device());
+
+ // resolve callbacks
+ m_out_int_func.resolve(m_out_int_cb, *this);
+ m_out_pren_func.resolve(m_out_pren_cb, *this);
+ m_out_trrq_func.resolve(m_out_trrq_cb, *this);
+ m_out_nmi_func.resolve(m_out_nmi_cb, *this);
+ m_out_xint2_func.resolve(m_out_xint2_cb, *this);
+ m_out_xint3_func.resolve(m_out_xint3_cb, *this);
+ m_out_xint4_func.resolve(m_out_xint4_cb, *this);
+ m_out_xint5_func.resolve(m_out_xint5_cb, *this);
+
+ // state saving
+ save_item(NAME(m_int));
+ save_item(NAME(m_pren));
+ save_item(NAME(m_trrq));
+ save_item(NAME(m_nmi));
+ save_item(NAME(m_xint2));
+ save_item(NAME(m_xint3));
+ save_item(NAME(m_xint4));
+ save_item(NAME(m_xint5));
+}
+
+
+//-------------------------------------------------
+// cs_w -
+//-------------------------------------------------
+
+void abc1600bus_slot_device::cs_w(UINT8 data)
+{
+ if (m_card != NULL)
+ {
+ m_card->abc1600bus_cs(data);
+ }
+}
+
+
+//-------------------------------------------------
+// csb_r -
+//-------------------------------------------------
+
+READ_LINE_MEMBER( abc1600bus_slot_device::csb_r )
+{
+ int data = 1;
+
+ if (m_card != NULL)
+ {
+ data = m_card->abc1600bus_csb();
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// brst_w - reset
+//-------------------------------------------------
+
+void abc1600bus_slot_device::brst_w()
+{
+ if (m_card != NULL)
+ {
+ m_card->abc1600bus_brst();
+ }
+}
+
+
+//-------------------------------------------------
+// inp_r -
+//-------------------------------------------------
+
+UINT8 abc1600bus_slot_device::inp_r()
+{
+ UINT8 data = 0xff;
+
+ if (m_card != NULL)
+ {
+ data &= m_card->abc1600bus_inp();
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// out_w -
+//-------------------------------------------------
+
+void abc1600bus_slot_device::out_w(UINT8 data)
+{
+ if (m_card != NULL)
+ {
+ m_card->abc1600bus_out(data);
+ }
+}
+
+
+//-------------------------------------------------
+// stat_r -
+//-------------------------------------------------
+
+UINT8 abc1600bus_slot_device::stat_r()
+{
+ UINT8 data = 0xff;
+
+ if (m_card != NULL)
+ {
+ data &= m_card->abc1600bus_stat();
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// stat_r -
+//-------------------------------------------------
+
+UINT8 abc1600bus_slot_device::ops_r()
+{
+ UINT8 data = 0xff;
+
+ if (m_card != NULL)
+ {
+ data &= m_card->abc1600bus_ops();
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// c1_w -
+//-------------------------------------------------
+
+void abc1600bus_slot_device::c1_w(UINT8 data)
+{
+ if (m_card != NULL)
+ {
+ m_card->abc1600bus_c1(data);
+ }
+}
+
+
+//-------------------------------------------------
+// c2_w -
+//-------------------------------------------------
+
+void abc1600bus_slot_device::c2_w(UINT8 data)
+{
+ if (m_card != NULL)
+ {
+ m_card->abc1600bus_c2(data);
+ }
+}
+
+
+//-------------------------------------------------
+// c3_w -
+//-------------------------------------------------
+
+void abc1600bus_slot_device::c3_w(UINT8 data)
+{
+ if (m_card != NULL)
+ {
+ m_card->abc1600bus_c3(data);
+ }
+}
+
+
+//-------------------------------------------------
+// c4_w -
+//-------------------------------------------------
+
+void abc1600bus_slot_device::c4_w(UINT8 data)
+{
+ if (m_card != NULL)
+ {
+ m_card->abc1600bus_c4(data);
+ }
+}
+
+
+//-------------------------------------------------
+// exp_r -
+//-------------------------------------------------
+
+UINT8 abc1600bus_slot_device::exp_r()
+{
+ UINT8 data = 0xff;
+
+ if (m_card != NULL)
+ {
+ data &= m_card->abc1600bus_exp();
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// xcsb2_r -
+//-------------------------------------------------
+
+READ_LINE_MEMBER( abc1600bus_slot_device::xcsb2_r )
+{
+ int data = 1;
+
+ if (m_card != NULL)
+ {
+ data = m_card->abc1600bus_xcsb2();
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// xcsb3_r -
+//-------------------------------------------------
+
+READ_LINE_MEMBER( abc1600bus_slot_device::xcsb3_r )
+{
+ int data = 1;
+
+ if (m_card != NULL)
+ {
+ data = m_card->abc1600bus_xcsb3();
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// xcsb4_r -
+//-------------------------------------------------
+
+READ_LINE_MEMBER( abc1600bus_slot_device::xcsb4_r )
+{
+ int data = 1;
+
+ if (m_card != NULL)
+ {
+ data = m_card->abc1600bus_xcsb4();
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// xcsb5_r -
+//-------------------------------------------------
+
+READ_LINE_MEMBER( abc1600bus_slot_device::xcsb5_r )
+{
+ int data = 1;
+
+ if (m_card != NULL)
+ {
+ data = m_card->abc1600bus_xcsb5();
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// tren_w - transfer enable
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( abc1600bus_slot_device::tren_w )
+{
+ if (m_card != NULL)
+ {
+ m_card->abc1600bus_tren(state);
+ }
+}
+
+
+//-------------------------------------------------
+// prac_w - peripheral acknowledge
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( abc1600bus_slot_device::prac_w )
+{
+ if (m_card != NULL)
+ {
+ m_card->abc1600bus_prac(state);
+ }
+}
+
+
+//-------------------------------------------------
+// int_w - interrupt request
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( abc1600bus_slot_device::int_w )
+{
+ m_int = state;
+ m_out_int_func(state);
+}
+
+
+//-------------------------------------------------
+// pren_w - peripheral enable
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( abc1600bus_slot_device::pren_w )
+{
+ m_pren = state;
+ m_out_pren_func(state);
+}
+
+
+//-------------------------------------------------
+// trrq_w - transfer request
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( abc1600bus_slot_device::trrq_w )
+{
+ m_trrq = state;
+ m_out_trrq_func(state);
+}
+
+
+//-------------------------------------------------
+// nmi_w - non-maskable interrupt
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( abc1600bus_slot_device::nmi_w )
+{
+ m_nmi = state;
+ m_out_nmi_func(state);
+}
+
+
+//-------------------------------------------------
+// xint2_w - expansion interrupt
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( abc1600bus_slot_device::xint2_w )
+{
+ m_xint2 = state;
+ m_out_xint2_func(state);
+}
+
+
+//-------------------------------------------------
+// xint3_w - expansion interrupt
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( abc1600bus_slot_device::xint3_w )
+{
+ m_xint3 = state;
+ m_out_xint3_func(state);
+}
+
+
+//-------------------------------------------------
+// xint4_w - expansion interrupt
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( abc1600bus_slot_device::xint4_w )
+{
+ m_xint4 = state;
+ m_out_xint4_func(state);
+}
+
+
+//-------------------------------------------------
+// xint5_w - expansion interrupt
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( abc1600bus_slot_device::xint5_w )
+{
+ m_xint5 = state;
+ m_out_xint5_func(state);
+}
+
+
+//-------------------------------------------------
+// int_r - interrupt request
+//-------------------------------------------------
+
+READ_LINE_MEMBER( abc1600bus_slot_device::int_r )
+{
+ return m_int;
+}
+
+
+//-------------------------------------------------
+// pren_r - peripheral enable
+//-------------------------------------------------
+
+READ_LINE_MEMBER( abc1600bus_slot_device::pren_r )
+{
+ return m_pren;
+}
+
+
+//-------------------------------------------------
+// trrq_r - transfer request
+//-------------------------------------------------
+
+READ_LINE_MEMBER( abc1600bus_slot_device::trrq_r )
+{
+ return m_trrq;
+}
+
+
+//-------------------------------------------------
+// nmi_r - non-maskable interrupt
+//-------------------------------------------------
+
+READ_LINE_MEMBER( abc1600bus_slot_device::nmi_r )
+{
+ return m_nmi;
+}
+
+
+//-------------------------------------------------
+// xint2_r - expansion interrupt
+//-------------------------------------------------
+
+READ_LINE_MEMBER( abc1600bus_slot_device::xint2_r )
+{
+ return m_xint2;
+}
+
+
+//-------------------------------------------------
+// xint3_r - expansion interrupt
+//-------------------------------------------------
+
+READ_LINE_MEMBER( abc1600bus_slot_device::xint3_r )
+{
+ return m_xint3;
+}
+
+
+//-------------------------------------------------
+// xint4_r - expansion interrupt
+//-------------------------------------------------
+
+READ_LINE_MEMBER( abc1600bus_slot_device::xint4_r )
+{
+ return m_xint4;
+}
+
+
+//-------------------------------------------------
+// xint5_r - expansion interrupt
+//-------------------------------------------------
+
+READ_LINE_MEMBER( abc1600bus_slot_device::xint5_r )
+{
+ return m_xint5;
+}
diff --git a/src/mess/machine/abc1600_bus.h b/src/mess/machine/abc1600_bus.h
new file mode 100644
index 00000000000..05f06f31f35
--- /dev/null
+++ b/src/mess/machine/abc1600_bus.h
@@ -0,0 +1,220 @@
+/**********************************************************************
+
+ Luxor ABC 1600 Expansion Bus emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+
+ 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
+ --- * 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 __ABC1600BUS__
+#define __ABC1600BUS__
+
+#include "emu.h"
+
+
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
+
+#define ABC1600BUS_TAG "abc1600bus"
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define ABC1600BUS_INTERFACE(_name) \
+ const abc1600bus_interface (_name) =
+
+
+#define MCFG_ABC1600BUS_SLOT_ADD(_tag, _config, _slot_intf, _def_slot, _def_inp) \
+ MCFG_DEVICE_ADD(_tag, ABC1600BUS_SLOT, 0) \
+ MCFG_DEVICE_CONFIG(_config) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false)
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> abc1600bus_interface
+
+struct abc1600bus_interface
+{
+ devcb_write_line m_out_int_cb;
+ devcb_write_line m_out_pren_cb;
+ devcb_write_line m_out_trrq_cb;
+
+ // the following are connected only on BUS0X
+ devcb_write_line m_out_nmi_cb;
+ devcb_write_line m_out_xint2_cb;
+ devcb_write_line m_out_xint3_cb;
+ devcb_write_line m_out_xint4_cb;
+ devcb_write_line m_out_xint5_cb;
+};
+
+
+// ======================> device_abc1600bus_card_interface
+
+class abc1600bus_slot_device;
+
+// class representing interface-specific live abc1600bus card
+class device_abc1600bus_card_interface : public device_slot_card_interface
+{
+ friend class abc1600bus_slot_device;
+
+public:
+ // construction/destruction
+ device_abc1600bus_card_interface(const machine_config &mconfig, device_t &device);
+ virtual ~device_abc1600bus_card_interface();
+
+ // required operation overrides
+ virtual void abc1600bus_cs(UINT8 data) = 0;
+ virtual int abc1600bus_csb() = 0;
+
+ // optional operation overrides
+ virtual void abc1600bus_brst() { };
+ virtual UINT8 abc1600bus_inp() { return 0xff; };
+ virtual void abc1600bus_out(UINT8 data) { };
+ virtual UINT8 abc1600bus_stat() { return 0xff; };
+ virtual UINT8 abc1600bus_ops() { return 0xff; };
+ virtual void abc1600bus_c1(UINT8 data) { };
+ virtual void abc1600bus_c2(UINT8 data) { };
+ virtual void abc1600bus_c3(UINT8 data) { };
+ virtual void abc1600bus_c4(UINT8 data) { };
+ virtual void abc1600bus_tren(int state) { };
+ virtual void abc1600bus_prac(int state) { };
+ virtual UINT8 abc1600bus_exp() { return 0xff; };
+ virtual int abc1600bus_xcsb2() { return 1; };
+ virtual int abc1600bus_xcsb3() { return 1; };
+ virtual int abc1600bus_xcsb4() { return 1; };
+ virtual int abc1600bus_xcsb5() { return 1; };
+
+public:
+ abc1600bus_slot_device *m_bus;
+};
+
+
+// ======================> abc1600bus_slot_device
+
+class abc1600bus_slot_device : public device_t,
+ public device_slot_interface,
+ public abc1600bus_interface
+{
+public:
+ // construction/destruction
+ abc1600bus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_config_complete();
+
+ void cs_w(UINT8 data);
+ DECLARE_READ_LINE_MEMBER( csb_r );
+ void brst_w();
+ UINT8 inp_r();
+ void out_w(UINT8 data);
+ UINT8 stat_r();
+ UINT8 ops_r();
+ void c1_w(UINT8 data);
+ void c2_w(UINT8 data);
+ void c3_w(UINT8 data);
+ void c4_w(UINT8 data);
+ UINT8 exp_r();
+ DECLARE_READ_LINE_MEMBER( xcsb2_r );
+ DECLARE_READ_LINE_MEMBER( xcsb3_r );
+ DECLARE_READ_LINE_MEMBER( xcsb4_r );
+ DECLARE_READ_LINE_MEMBER( xcsb5_r );
+ DECLARE_WRITE_LINE_MEMBER( tren_w );
+ DECLARE_WRITE_LINE_MEMBER( prac_w );
+
+ DECLARE_WRITE_LINE_MEMBER( int_w );
+ DECLARE_WRITE_LINE_MEMBER( pren_w );
+ DECLARE_WRITE_LINE_MEMBER( trrq_w );
+ DECLARE_WRITE_LINE_MEMBER( nmi_w );
+ DECLARE_WRITE_LINE_MEMBER( xint2_w );
+ DECLARE_WRITE_LINE_MEMBER( xint3_w );
+ DECLARE_WRITE_LINE_MEMBER( xint4_w );
+ DECLARE_WRITE_LINE_MEMBER( xint5_w );
+
+ DECLARE_READ_LINE_MEMBER( int_r );
+ DECLARE_READ_LINE_MEMBER( pren_r );
+ DECLARE_READ_LINE_MEMBER( trrq_r );
+ DECLARE_READ_LINE_MEMBER( nmi_r );
+ DECLARE_READ_LINE_MEMBER( xint2_r );
+ DECLARE_READ_LINE_MEMBER( xint3_r );
+ DECLARE_READ_LINE_MEMBER( xint4_r );
+ DECLARE_READ_LINE_MEMBER( xint5_r );
+
+private:
+ devcb_resolved_write_line m_out_int_func;
+ devcb_resolved_write_line m_out_pren_func;
+ devcb_resolved_write_line m_out_trrq_func;
+ devcb_resolved_write_line m_out_nmi_func;
+ devcb_resolved_write_line m_out_xint2_func;
+ devcb_resolved_write_line m_out_xint3_func;
+ devcb_resolved_write_line m_out_xint4_func;
+ devcb_resolved_write_line m_out_xint5_func;
+
+ device_abc1600bus_card_interface *m_card;
+
+ int m_int;
+ int m_pren;
+ int m_trrq;
+ int m_nmi;
+ int m_xint2;
+ int m_xint3;
+ int m_xint4;
+ int m_xint5;
+};
+
+
+// device type definition
+extern const device_type ABC1600BUS_SLOT;
+
+
+
+#endif
diff --git a/src/mess/machine/abc77.c b/src/mess/machine/abc77.c
new file mode 100644
index 00000000000..b835e104cf6
--- /dev/null
+++ b/src/mess/machine/abc77.c
@@ -0,0 +1,667 @@
+/**********************************************************************
+
+ Luxor ABC-55/77 keyboard emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+/*
+
+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<abc77_device>;
+const device_type ABC55 = &device_creator<abc55_device>;
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void abc77_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const abc77_interface *intf = reinterpret_cast<const abc77_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<abc77_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_clock_cb, 0, sizeof(m_out_clock_cb));
+ memset(&m_out_keydown_cb, 0, sizeof(m_out_keydown_cb));
+ }
+
+ m_shortname = "abc77";
+}
+
+
+//-------------------------------------------------
+// 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, RES_K(2.7), RES_K(15), 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_SOUND_CONFIG_DISCRETE(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( 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;
+ }
+}
+
+
+//-------------------------------------------------
+// serial_clock -
+//-------------------------------------------------
+
+inline void abc77_device::serial_clock()
+{
+ m_clock = !m_clock;
+
+ m_out_clock_func(!m_clock);
+}
+
+
+//-------------------------------------------------
+// keydown -
+//-------------------------------------------------
+
+inline void abc77_device::key_down(int state)
+{
+ if (m_keydown != state)
+ {
+ m_out_keydown_func(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),
+ m_maincpu(*this, I8035_TAG),
+ m_discrete(*this, DISCRETE_TAG),
+ 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)
+ : device_t(mconfig, type, name, tag, owner, clock),
+ m_maincpu(*this, I8035_TAG),
+ m_discrete(*this, DISCRETE_TAG),
+ 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) { }
+
+
+//-------------------------------------------------
+// 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);
+
+ // resolve callbacks
+ m_out_clock_func.resolve(m_out_clock_cb, *this);
+ m_out_keydown_func.resolve(m_out_keydown_cb, *this);
+}
+
+
+//-------------------------------------------------
+// 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(ioport("DSW")->read(), 7);
+
+ // trigger reset
+ device_set_input_line(m_maincpu, INPUT_LINE_RESET, ASSERT_LINE);
+ m_reset_timer->adjust(attotime::from_msec(t));
+
+ device_set_input_line(m_maincpu, MCS48_INPUT_EA, ea ? CLEAR_LINE : ASSERT_LINE);
+}
+
+
+//-------------------------------------------------
+// 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:
+ device_set_input_line(m_maincpu, INPUT_LINE_RESET, CLEAR_LINE);
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// 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
+
+ */
+
+ static const char *const keynames[] = { "X0", "X1", "X2", "X3", "X4", "X5", "X6", "X7", "X8", "X9", "X10", "X11" };
+ UINT8 data = 0xff;
+
+ if (m_stb && m_keylatch < 12)
+ {
+ data = ioport(keynames[m_keylatch])->read();
+ }
+
+ 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
+ discrete_sound_w(m_discrete, 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;
+}
+
+
+//-------------------------------------------------
+// rxd_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( abc77_device::rxd_w )
+{
+ device_set_input_line(m_maincpu, MCS48_INPUT_IRQ, state ? CLEAR_LINE : ASSERT_LINE);
+}
+
+
+//-------------------------------------------------
+// txd_r -
+//-------------------------------------------------
+
+READ_LINE_MEMBER( abc77_device::txd_r )
+{
+ return m_txd;
+}
+
+
+//-------------------------------------------------
+// reset_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( abc77_device::reset_w )
+{
+ if (m_reset && !state)
+ {
+ device_reset();
+ }
+
+ m_reset = state;
+}
diff --git a/src/mess/machine/abc77.h b/src/mess/machine/abc77.h
new file mode 100644
index 00000000000..51564bc5066
--- /dev/null
+++ b/src/mess/machine/abc77.h
@@ -0,0 +1,142 @@
+/**********************************************************************
+
+ Luxor ABC-55/77 keyboard emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#pragma once
+
+#ifndef __ABC77__
+#define __ABC77__
+
+
+#include "emu.h"
+#include "cpu/mcs48/mcs48.h"
+#include "sound/discrete.h"
+#include "sound/speaker.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define ABC77_TAG "abc77"
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_ABC55_ADD(_config) \
+ MCFG_DEVICE_ADD(ABC77_TAG, ABC55, 0) \
+ MCFG_DEVICE_CONFIG(_config)
+
+
+#define MCFG_ABC77_ADD(_config) \
+ MCFG_DEVICE_ADD(ABC77_TAG, ABC77, 0) \
+ MCFG_DEVICE_CONFIG(_config)
+
+
+#define ABC77_INTERFACE(_name) \
+ const abc77_interface (_name) =
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> abc77_interface
+
+struct abc77_interface
+{
+ devcb_write_line m_out_clock_cb;
+ devcb_write_line m_out_keydown_cb;
+};
+
+
+// ======================> abc77_device
+
+class abc77_device : public device_t,
+ public abc77_interface
+{
+public:
+ // construction/destruction
+ abc77_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
+ 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;
+
+ 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 );
+
+ DECLARE_WRITE_LINE_MEMBER( rxd_w );
+ DECLARE_READ_LINE_MEMBER( txd_r );
+ DECLARE_WRITE_LINE_MEMBER( reset_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);
+ virtual void device_config_complete();
+
+ static const device_timer_id TIMER_SERIAL = 0;
+ static const device_timer_id TIMER_RESET = 1;
+
+ inline void serial_output(int state);
+ inline void serial_clock();
+ inline void key_down(int state);
+
+ devcb_resolved_write_line m_out_clock_func;
+ devcb_resolved_write_line m_out_keydown_func;
+
+ required_device<cpu_device> m_maincpu;
+ required_device<device_t> m_discrete;
+
+ 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/mess/machine/abc800kb.c b/src/mess/machine/abc800kb.c
new file mode 100644
index 00000000000..6ef5b4e1921
--- /dev/null
+++ b/src/mess/machine/abc800kb.c
@@ -0,0 +1,518 @@
+/**********************************************************************
+
+ Luxor ABC-800 keyboard emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+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<abc800_keyboard_device>;
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void abc800_keyboard_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const abc800_keyboard_interface *intf = reinterpret_cast<const abc800_keyboard_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<abc800_keyboard_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_clock_cb, 0, sizeof(m_out_clock_cb));
+ memset(&m_out_keydown_cb, 0, sizeof(m_out_keydown_cb));
+ }
+
+ m_shortname = "abc800kb";
+}
+
+
+//-------------------------------------------------
+// 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;
+ }
+}
+
+
+//-------------------------------------------------
+// serial_clock -
+//-------------------------------------------------
+
+inline void abc800_keyboard_device::serial_clock()
+{
+ m_clk = !m_clk;
+
+ m_out_clock_func(!m_clk);
+}
+
+
+//-------------------------------------------------
+// keydown -
+//-------------------------------------------------
+
+inline void abc800_keyboard_device::key_down(int state)
+{
+ if (m_keydown != state)
+ {
+ m_keydown = state;
+
+ m_out_keydown_func(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),
+ m_maincpu(*this, I8048_TAG),
+ 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)); // ???
+
+ // resolve callbacks
+ m_out_clock_func.resolve(m_out_clock_cb, *this);
+ m_out_keydown_func.resolve(m_out_keydown_cb, *this);
+
+ // 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();
+}
+
+
+//-------------------------------------------------
+// rxd_w - keyboard receive data write
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( abc800_keyboard_device::rxd_w )
+{
+ m_maincpu->set_input_line(MCS48_INPUT_IRQ, state ? CLEAR_LINE : ASSERT_LINE);
+}
+
+
+//-------------------------------------------------
+// txd_r - keyboard transmit data read
+//-------------------------------------------------
+
+READ_LINE_MEMBER( abc800_keyboard_device::txd_r )
+{
+ return m_txd;
+}
+
+
+//-------------------------------------------------
+// kb_p1_r - keyboard column data read
+//-------------------------------------------------
+
+READ8_MEMBER( abc800_keyboard_device::kb_p1_r )
+{
+ static const char *const ABC800_KEY_ROW[] = { "X0", "X1", "X2", "X3", "X4", "X5", "X6", "X7", "X8", "X9", "X10", "X11" };
+ UINT8 data = 0xff;
+
+ if (m_stb && m_row < 12)
+ {
+ data = ioport(ABC800_KEY_ROW[m_row])->read();
+ }
+
+ 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/mess/machine/abc800kb.h b/src/mess/machine/abc800kb.h
new file mode 100644
index 00000000000..19ba49d5020
--- /dev/null
+++ b/src/mess/machine/abc800kb.h
@@ -0,0 +1,113 @@
+/**********************************************************************
+
+ Luxor ABC-800 keyboard emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __ABC800_KEYBOARD__
+#define __ABC800_KEYBOARD__
+
+
+#include "emu.h"
+#include "cpu/mcs48/mcs48.h"
+#include "sound/discrete.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define ABC800_KEYBOARD_TAG "abc800kb"
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_ABC800_KEYBOARD_ADD(_config) \
+ MCFG_DEVICE_ADD(ABC800_KEYBOARD_TAG, ABC800_KEYBOARD, 0) \
+ MCFG_DEVICE_CONFIG(_config)
+
+
+#define ABC800_KEYBOARD_INTERFACE(_name) \
+ const abc800_keyboard_interface (_name) =
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> abc800_keyboard_interface
+
+struct abc800_keyboard_interface
+{
+ devcb_write_line m_out_clock_cb;
+ devcb_write_line m_out_keydown_cb;
+};
+
+
+// ======================> abc800_keyboard_device
+
+class abc800_keyboard_device : public device_t,
+ public abc800_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;
+
+ DECLARE_WRITE_LINE_MEMBER( rxd_w );
+ DECLARE_READ_LINE_MEMBER( txd_r );
+
+ // 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_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);
+
+private:
+ devcb_resolved_write_line m_out_clock_func;
+ devcb_resolved_write_line m_out_keydown_func;
+
+ inline void serial_output(int state);
+ inline void serial_clock();
+ inline void key_down(int state);
+
+ required_device<cpu_device> m_maincpu;
+
+ 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/mess/machine/abc80kb.c b/src/mess/machine/abc80kb.c
new file mode 100644
index 00000000000..89ebc3da03c
--- /dev/null
+++ b/src/mess/machine/abc80kb.c
@@ -0,0 +1,228 @@
+/**********************************************************************
+
+ Luxor ABC-80 keyboard emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+PCB Layout
+----------
+
+KTC 65-01870-001 (dated 1978)
+PCB-002B
+
+ |---------------|
+|---| CN1 |---------------------------------------------------|
+| |
+| LS06 LS04 LS04 LS06 LS00 LS123 |
+| LS74 PROM MCU 4051 900C |
+| |
+| |
+| |
+| |
+| |
+| |
+| |
+| |
+|-----------------------------------------------------------------------|
+
+Notes:
+ All IC's shown.
+
+ MCU - General Instruments 30293B-013 20-04592-013 (?)
+ PROM - Synertek N82S141N 512x8 bipolar PROM "053"
+ 900C - Ferranti Interdesign 900C custom (?)
+ CN1 - keyboard data connector
+
+*/
+
+/*
+
+PCB Layout
+----------
+
+KTC A65-01870-001 (dated 1983)
+PCB-201C
+
+ |---------------|
+|---| CN1 |---------------------------------------------------|
+| |
+| LS06 LS04 LS04 LS00 LS123 |
+| MCU 4051 900C |
+| |
+| |
+| |
+| |
+| |
+| |
+| |
+| |
+|-----------------------------------------------------------------------|
+
+Notes:
+ All IC's shown.
+
+ MCU - General Instruments 30293B-047 20-04592-047 (?)
+ 900C - Ferranti Interdesign 900C custom (?)
+ CN1 - keyboard data connector
+
+*/
+
+#include "abc80kb.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define I8048_TAG "i8048"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type ABC80_KEYBOARD = &device_creator<abc80_keyboard_device>;
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void abc80_keyboard_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const abc80_keyboard_interface *intf = reinterpret_cast<const abc80_keyboard_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<abc80_keyboard_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_keydown_cb, 0, sizeof(m_out_keydown_cb));
+ }
+
+ m_shortname = "abc80kb";
+}
+
+
+//-------------------------------------------------
+// ROM( abc80_keyboard )
+//-------------------------------------------------
+
+ROM_START( abc80_keyboard )
+ ROM_REGION( 0x400, I8048_TAG, 0 )
+ ROM_LOAD( "053.z5", 0x0000, 0x0400, NO_DUMP )
+ROM_END
+
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *abc80_keyboard_device::device_rom_region() const
+{
+ return ROM_NAME( abc80_keyboard );
+}
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( abc80_keyboard_io )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( abc80_keyboard_io, AS_IO, 8, abc80_keyboard_device )
+ADDRESS_MAP_END
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( abc80_keyboard )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( abc80_keyboard )
+ MCFG_CPU_ADD(I8048_TAG, I8048, 4000000)
+ MCFG_CPU_IO_MAP(abc80_keyboard_io)
+ MCFG_DEVICE_DISABLE()
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor abc80_keyboard_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( abc80_keyboard );
+}
+
+
+//-------------------------------------------------
+// INPUT_PORTS( abc80_keyboard )
+//-------------------------------------------------
+
+INPUT_PORTS_START( abc80_keyboard )
+INPUT_PORTS_END
+
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+ioport_constructor abc80_keyboard_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( abc80_keyboard );
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// abc80_keyboard_device - constructor
+//-------------------------------------------------
+
+abc80_keyboard_device::abc80_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, ABC80_KEYBOARD, "ABC-80 Keyboard", tag, owner, clock),
+ m_maincpu(*this, I8048_TAG)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void abc80_keyboard_device::device_start()
+{
+ // resolve callbacks
+ m_out_keydown_func.resolve(m_out_keydown_cb, *this);
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void abc80_keyboard_device::device_reset()
+{
+}
+
+
+//-------------------------------------------------
+// data_r - keyboard data read
+//-------------------------------------------------
+
+UINT8 abc80_keyboard_device::data_r()
+{
+ return 0;
+}
diff --git a/src/mess/machine/abc80kb.h b/src/mess/machine/abc80kb.h
new file mode 100644
index 00000000000..6726977c88f
--- /dev/null
+++ b/src/mess/machine/abc80kb.h
@@ -0,0 +1,89 @@
+/**********************************************************************
+
+ Luxor ABC-80 keyboard emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __ABC80_KEYBOARD__
+#define __ABC80_KEYBOARD__
+
+
+#include "emu.h"
+#include "cpu/mcs48/mcs48.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define ABC80_KEYBOARD_TAG "abc80kb"
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_ABC80_KEYBOARD_ADD(_config) \
+ MCFG_DEVICE_ADD(ABC80_KEYBOARD_TAG, ABC80_KEYBOARD, 0) \
+ MCFG_DEVICE_CONFIG(_config)
+
+
+#define ABC80_KEYBOARD_INTERFACE(_name) \
+ const abc80_keyboard_interface (_name) =
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> abc80_keyboard_interface
+
+struct abc80_keyboard_interface
+{
+ devcb_write_line m_out_keydown_cb;
+};
+
+
+// ======================> abc80_keyboard_device
+
+class abc80_keyboard_device : public device_t,
+ public abc80_keyboard_interface
+{
+public:
+ // construction/destruction
+ abc80_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;
+
+ UINT8 data_r();
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+ virtual void device_start();
+ virtual void device_reset();
+
+private:
+ devcb_resolved_write_line m_out_keydown_func;
+
+ required_device<cpu_device> m_maincpu;
+};
+
+
+// device type definition
+extern const device_type ABC80_KEYBOARD;
+
+
+
+#endif
diff --git a/src/mess/machine/abc830.c b/src/mess/machine/abc830.c
new file mode 100644
index 00000000000..b0d43a963a1
--- /dev/null
+++ b/src/mess/machine/abc830.c
@@ -0,0 +1,143 @@
+/*
+
+ Luxor ABC 830
+
+ Type Size Tracks Sides Sectors/track Sectors Speed Drives
+
+ ABC-830 Floppy 160 KB 40 1 16 640 250 Kbps MPI 51, BASF 6106
+ Floppy 80 KB 40 1 8 320 250 Kbps Scandia Metric FD2
+ ABC-832 Floppy 640 KB 80 2 16 2560 250 Kbps Micropolis 1015, Micropolis 1115, BASF 6118
+ ABC-834 Floppy 640 KB 80 2 16 2560 250 Kbps Teac FD 55 F
+ ABC-838 Floppy 1 MB 77 2 25 3978 500 Kbps BASF 6104, BASF 6115
+ ABC-850 Floppy 640 KB 80 2 16 2560 250 Kbps TEAC FD 55 F, BASF 6136
+ HDD 10 MB 320 4 32 40960 5 Mbps Rodime 202, BASF 6186
+ ABC-852 Floppy 640 KB 80 2 16 2560 250 Kbps TEAC FD 55 F, BASF 6136
+ HDD 20 MB 615 4 32 78720 5 Mbps NEC 5126
+ Streamer 45 MB 9 90 Kbps Archive 5945-C (tape: DC300XL 450ft)
+ ABC-856 Floppy 640 KB 80 2 16 2560 250 Kbps TEAC FD 55 F
+ HDD 64 MB 1024 8 32 262144 5 Mbps Micropolis 1325
+ Streamer 45 MB 9 90 Kbps Archive 5945-C (tape: DC300XL 450ft)
+
+*/
+
+#include "abc830.h"
+
+
+
+//**************************************************************************
+// FLOPPY CONFIGURATIONS
+//**************************************************************************
+
+//-------------------------------------------------
+// floppy_interface abc830_floppy_interface
+//-------------------------------------------------
+
+static LEGACY_FLOPPY_OPTIONS_START( abc830 )
+ // NOTE: Real ABC 830 (160KB) disks use a 7:1 sector interleave.
+ // Specify INTERLEAVE([7]) below if you prefer the physical layout.
+ LEGACY_FLOPPY_OPTION(abc830, "dsk", "Luxor ABC 830", basicdsk_identify_default, basicdsk_construct_default, NULL,
+ HEADS([1])
+ TRACKS([40])
+ SECTORS([16])
+ SECTOR_LENGTH([256])
+ FIRST_SECTOR_ID([1]))
+LEGACY_FLOPPY_OPTIONS_END
+
+const floppy_interface abc830_floppy_interface =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ FLOPPY_STANDARD_5_25_SSDD_40,
+ LEGACY_FLOPPY_OPTIONS_NAME(abc830),
+ "abc830",
+ NULL
+};
+
+
+//-------------------------------------------------
+// floppy_interface abc832_floppy_interface
+//-------------------------------------------------
+
+static LEGACY_FLOPPY_OPTIONS_START( abc832 )
+ LEGACY_FLOPPY_OPTION(abc832, "dsk", "Luxor ABC 832/834", basicdsk_identify_default, basicdsk_construct_default, NULL,
+ HEADS([2])
+ TRACKS([80])
+ SECTORS([16])
+ SECTOR_LENGTH([256])
+ FIRST_SECTOR_ID([1]))
+LEGACY_FLOPPY_OPTIONS_END
+
+const floppy_interface abc832_floppy_interface =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ FLOPPY_STANDARD_5_25_DSDD,
+ LEGACY_FLOPPY_OPTIONS_NAME(abc832),
+ "abc832",
+ NULL
+};
+
+
+//-------------------------------------------------
+// floppy_interface abc838_floppy_interface
+//-------------------------------------------------
+
+static LEGACY_FLOPPY_OPTIONS_START( abc838 )
+ LEGACY_FLOPPY_OPTION(abc838, "dsk", "Luxor ABC 838", basicdsk_identify_default, basicdsk_construct_default, NULL,
+ HEADS([2])
+ TRACKS([77])
+ SECTORS([26])
+ SECTOR_LENGTH([256])
+ FIRST_SECTOR_ID([1]))
+LEGACY_FLOPPY_OPTIONS_END
+
+const floppy_interface abc838_floppy_interface =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ FLOPPY_STANDARD_8_DSDD,
+ LEGACY_FLOPPY_OPTIONS_NAME(abc838),
+ "abc838",
+ NULL
+};
+
+
+//-------------------------------------------------
+// floppy_interface fd2_floppy_interface
+//-------------------------------------------------
+
+static LEGACY_FLOPPY_OPTIONS_START( fd2 )
+ // NOTE: FD2 cannot be used with the Luxor controller card,
+ // it has a proprietary one. This is just for reference.
+ LEGACY_FLOPPY_OPTION(fd2, "dsk", "Scandia Metric FD2", basicdsk_identify_default, basicdsk_construct_default, NULL,
+ HEADS([1])
+ TRACKS([40])
+ SECTORS([8])
+ SECTOR_LENGTH([256])
+ FIRST_SECTOR_ID([1]))
+LEGACY_FLOPPY_OPTIONS_END
+
+const floppy_interface fd2_floppy_interface =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ FLOPPY_STANDARD_5_25_SSSD,
+ LEGACY_FLOPPY_OPTIONS_NAME(fd2),
+ "floppy_5_25",
+ NULL
+};
+
+
+
diff --git a/src/mess/machine/abc830.h b/src/mess/machine/abc830.h
new file mode 100644
index 00000000000..6012090606d
--- /dev/null
+++ b/src/mess/machine/abc830.h
@@ -0,0 +1,44 @@
+#pragma once
+
+#ifndef __ABC830__
+#define __ABC830__
+
+
+#include "emu.h"
+#include "formats/basicdsk.h"
+#include "imagedev/flopdrv.h"
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_ABC830_ADD() \
+ MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(abc830_floppy_interface)
+
+#define MCFG_ABC832_ADD() \
+ MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(abc832_floppy_interface)
+
+#define MCFG_ABC834_ADD() \
+ MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(abc832_floppy_interface)
+
+#define MCFG_ABC838_ADD() \
+ MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(abc838_floppy_interface)
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// floppy configuration
+extern const floppy_interface abc830_floppy_interface;
+extern const floppy_interface abc832_floppy_interface;
+extern const floppy_interface abc834_floppy_interface;
+extern const floppy_interface abc838_floppy_interface;
+extern const floppy_interface fd2_floppy_interface;
+
+
+
+#endif
diff --git a/src/mess/machine/abc890.c b/src/mess/machine/abc890.c
new file mode 100644
index 00000000000..fe41a537b88
--- /dev/null
+++ b/src/mess/machine/abc890.c
@@ -0,0 +1,305 @@
+/**********************************************************************
+
+ Luxor ABC 890 bus expander emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#include "abc890.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type ABC890 = &device_creator<abc890_device>;
+const device_type ABC894 = &device_creator<abc894_device>;
+const device_type ABC850 = &device_creator<abc850_device>;
+
+
+//-------------------------------------------------
+// ABCBUS_INTERFACE( abcbus_intf )
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( abc890_device::int_w )
+{
+ m_bus->int_w(state);
+}
+
+WRITE_LINE_MEMBER( abc890_device::nmi_w )
+{
+ m_bus->nmi_w(state);
+}
+
+WRITE_LINE_MEMBER( abc890_device::rdy_w )
+{
+ m_bus->rdy_w(state);
+}
+
+WRITE_LINE_MEMBER( abc890_device::resin_w )
+{
+ m_bus->resin_w(state);
+}
+
+static ABCBUS_INTERFACE( abcbus_intf )
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, abc890_device, int_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, abc890_device, nmi_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, abc890_device, rdy_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, abc890_device, resin_w)
+};
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( abc890 )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( abc890 )
+ MCFG_ABCBUS_SLOT_ADD("io1", abcbus_intf, abcbus_cards, NULL, NULL)
+ MCFG_ABCBUS_SLOT_ADD("io2", abcbus_intf, abcbus_cards, NULL, NULL)
+ MCFG_ABCBUS_SLOT_ADD("io3", abcbus_intf, abcbus_cards, NULL, NULL)
+ MCFG_ABCBUS_SLOT_ADD("io4", abcbus_intf, abcbus_cards, NULL, NULL)
+ MCFG_ABCBUS_SLOT_ADD("mem1", abcbus_intf, abcbus_cards, NULL, NULL)
+ MCFG_ABCBUS_SLOT_ADD("mem2", abcbus_intf, abcbus_cards, NULL, NULL)
+ MCFG_ABCBUS_SLOT_ADD("mem3", abcbus_intf, abcbus_cards, NULL, NULL)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor abc890_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( abc890 );
+}
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( abc894 )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( abc894 )
+ MCFG_ABCBUS_SLOT_ADD("io1", abcbus_intf, abcbus_cards, NULL, NULL)
+ MCFG_ABCBUS_SLOT_ADD("io2", abcbus_intf, abcbus_cards, NULL, NULL)
+ MCFG_ABCBUS_SLOT_ADD("io3", abcbus_intf, abcbus_cards, NULL, NULL)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor abc894_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( abc894 );
+}
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( abc850 )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( abc850 )
+ MCFG_ABCBUS_SLOT_ADD("io1", abcbus_intf, abcbus_cards, "fast", abc850_fast)
+ MCFG_ABCBUS_SLOT_ADD("io2", abcbus_intf, abcbus_cards, "hdc", NULL)
+ MCFG_ABCBUS_SLOT_ADD("io3", abcbus_intf, abcbus_cards, NULL, NULL)
+ MCFG_ABCBUS_SLOT_ADD("io4", abcbus_intf, abcbus_cards, NULL, NULL)
+ MCFG_ABCBUS_SLOT_ADD("io5", abcbus_intf, abcbus_cards, NULL, NULL)
+ MCFG_ABCBUS_SLOT_ADD("io6", abcbus_intf, abcbus_cards, NULL, NULL)
+ MCFG_ABCBUS_SLOT_ADD("io7", abcbus_intf, abcbus_cards, NULL, NULL)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor abc850_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( abc850 );
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// abc890_device - constructor
+//-------------------------------------------------
+
+abc890_device::abc890_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),
+ device_abcbus_card_interface(mconfig, *this)
+{
+}
+
+abc890_device::abc890_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, ABC890, "ABC 890", tag, owner, clock),
+ device_abcbus_card_interface(mconfig, *this),
+ m_slots(7)
+{
+}
+
+abc894_device::abc894_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : abc890_device(mconfig, ABC894, "ABC 894", tag, owner, clock)
+{
+ m_slots = 3;
+}
+
+abc850_device::abc850_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : abc890_device(mconfig, ABC850, "ABC 850", tag, owner, clock)
+{
+ m_slots = 7;
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void abc890_device::device_start()
+{
+ // find devices
+ m_expansion_slot[0] = dynamic_cast<abcbus_slot_device *>(subdevice("io1"));
+ m_expansion_slot[1] = dynamic_cast<abcbus_slot_device *>(subdevice("io2"));
+ m_expansion_slot[2] = dynamic_cast<abcbus_slot_device *>(subdevice("io3"));
+ m_expansion_slot[3] = dynamic_cast<abcbus_slot_device *>(subdevice("io4"));
+ m_expansion_slot[4] = dynamic_cast<abcbus_slot_device *>(subdevice("mem1"));
+ m_expansion_slot[5] = dynamic_cast<abcbus_slot_device *>(subdevice("mem2"));
+ m_expansion_slot[6] = dynamic_cast<abcbus_slot_device *>(subdevice("mem3"));
+}
+
+void abc894_device::device_start()
+{
+ // find devices
+ m_expansion_slot[0] = dynamic_cast<abcbus_slot_device *>(subdevice("io1"));
+ m_expansion_slot[1] = dynamic_cast<abcbus_slot_device *>(subdevice("io2"));
+ m_expansion_slot[2] = dynamic_cast<abcbus_slot_device *>(subdevice("io3"));
+}
+
+void abc850_device::device_start()
+{
+ // find devices
+ m_expansion_slot[0] = dynamic_cast<abcbus_slot_device *>(subdevice("io1"));
+ m_expansion_slot[1] = dynamic_cast<abcbus_slot_device *>(subdevice("io2"));
+ m_expansion_slot[2] = dynamic_cast<abcbus_slot_device *>(subdevice("io3"));
+ m_expansion_slot[3] = dynamic_cast<abcbus_slot_device *>(subdevice("io4"));
+ m_expansion_slot[4] = dynamic_cast<abcbus_slot_device *>(subdevice("io5"));
+ m_expansion_slot[5] = dynamic_cast<abcbus_slot_device *>(subdevice("io6"));
+ m_expansion_slot[6] = dynamic_cast<abcbus_slot_device *>(subdevice("io7"));
+}
+
+
+
+//**************************************************************************
+// ABC BUS INTERFACE
+//**************************************************************************
+
+void abc890_device::abcbus_cs(UINT8 data)
+{
+ for (int i = 0; i < m_slots; i++)
+ {
+ m_expansion_slot[i]->cs_w(data);
+ }
+}
+
+void abc890_device::abcbus_rst(int state)
+{
+ for (int i = 0; i < m_slots; i++)
+ {
+ m_expansion_slot[i]->rst_r();
+ }
+}
+
+UINT8 abc890_device::abcbus_inp()
+{
+ UINT8 data = 0xff;
+
+ for (int i = 0; i < m_slots; i++)
+ {
+ data &= m_expansion_slot[i]->inp_r();
+ }
+
+ return data;
+}
+
+void abc890_device::abcbus_utp(UINT8 data)
+{
+ for (int i = 0; i < m_slots; i++)
+ {
+ m_expansion_slot[i]->utp_w(data);
+ }
+}
+
+UINT8 abc890_device::abcbus_stat()
+{
+ UINT8 data = 0xff;
+
+ for (int i = 0; i < m_slots; i++)
+ {
+ data &= m_expansion_slot[i]->stat_r();
+ }
+
+ return data;
+}
+
+void abc890_device::abcbus_c1(UINT8 data)
+{
+ for (int i = 0; i < m_slots; i++)
+ {
+ m_expansion_slot[i]->c1_w(data);
+ }
+}
+
+void abc890_device::abcbus_c2(UINT8 data)
+{
+ for (int i = 0; i < m_slots; i++)
+ {
+ m_expansion_slot[i]->c2_w(data);
+ }
+}
+
+void abc890_device::abcbus_c3(UINT8 data)
+{
+ for (int i = 0; i < m_slots; i++)
+ {
+ m_expansion_slot[i]->c3_w(data);
+ }
+}
+
+void abc890_device::abcbus_c4(UINT8 data)
+{
+ for (int i = 0; i < m_slots; i++)
+ {
+ m_expansion_slot[i]->c4_w(data);
+ }
+}
+
+UINT8 abc890_device::abcbus_xmemfl(offs_t offset)
+{
+ UINT8 data = 0xff;
+
+ for (int i = 0; i < m_slots; i++)
+ {
+ data &= m_expansion_slot[i]->xmemfl_r(offset);
+ }
+
+ return data;
+}
+
+void abc890_device::abcbus_xmemw(offs_t offset, UINT8 data)
+{
+ for (int i = 0; i < m_slots; i++)
+ {
+ m_expansion_slot[i]->xmemw_w(offset, data);
+ }
+}
diff --git a/src/mess/machine/abc890.h b/src/mess/machine/abc890.h
new file mode 100644
index 00000000000..02b68362fca
--- /dev/null
+++ b/src/mess/machine/abc890.h
@@ -0,0 +1,113 @@
+/**********************************************************************
+
+ Luxor ABC 890 bus expander emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#pragma once
+
+#ifndef __ABC890__
+#define __ABC890__
+
+
+#include "emu.h"
+#include "machine/abcbus.h"
+
+
+
+//**************************************************************************
+// MACROS/CONSTANTS
+//**************************************************************************
+
+#define MAX_SLOTS 8
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> abc890_device
+
+class abc890_device : public device_t,
+ public device_abcbus_card_interface
+{
+public:
+ // construction/destruction
+ abc890_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
+ abc890_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( int_w );
+ DECLARE_WRITE_LINE_MEMBER( nmi_w );
+ DECLARE_WRITE_LINE_MEMBER( rdy_w );
+ DECLARE_WRITE_LINE_MEMBER( resin_w );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_config_complete() { m_shortname = "abc890"; }
+
+ // device_abcbus_interface overrides
+ virtual void abcbus_cs(UINT8 data);
+ virtual void abcbus_rst(int state);
+ virtual UINT8 abcbus_inp();
+ virtual void abcbus_utp(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);
+
+ int m_slots;
+
+ abcbus_slot_device *m_expansion_slot[MAX_SLOTS];
+};
+
+
+class abc894_device : public abc890_device
+{
+public:
+ // construction/destruction
+ abc894_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();
+};
+
+
+class abc850_device : public abc890_device
+{
+public:
+ // construction/destruction
+ abc850_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 type definition
+extern const device_type ABC890;
+extern const device_type ABC894;
+extern const device_type ABC850;
+
+
+
+#endif
diff --git a/src/mess/machine/abc99.c b/src/mess/machine/abc99.c
new file mode 100644
index 00000000000..e9eae6c1675
--- /dev/null
+++ b/src/mess/machine/abc99.c
@@ -0,0 +1,858 @@
+/**********************************************************************
+
+ Luxor ABC-99 keyboard and mouse emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+/*
+
+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
+ - investigate unknown ROMs
+ - 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"
+
+
+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
+};
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type ABC99 = &device_creator<abc99_device>;
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void abc99_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const abc99_interface *intf = reinterpret_cast<const abc99_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<abc99_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_clock_cb, 0, sizeof(m_out_clock_cb));
+ memset(&m_out_keydown_cb, 0, sizeof(m_out_keydown_cb));
+ }
+
+ m_shortname = "abc99";
+}
+
+
+//-------------------------------------------------
+// ROM( abc99 )
+//-------------------------------------------------
+
+ROM_START( abc99 )
+ ROM_REGION( 0x800, I8035_Z2_TAG, 0 )
+ ROM_LOAD( "107268-17.z3", 0x000, 0x800, CRC(2f60cc35) SHA1(ebc6af9cd0a49a0d01698589370e628eebb6221c) )
+
+ ROM_REGION( 0x800, I8035_Z5_TAG, 0 )
+ ROM_LOAD( "107268-16.z6", 0x000, 0x800, CRC(785ec0c6) SHA1(0b261beae20dbc06fdfccc50b19ea48b5b6e22eb) )
+
+ ROM_REGION( 0x1800, "unknown", 0)
+ ROM_LOAD( "106819-09.bin", 0x0000, 0x1000, CRC(ffe32a71) SHA1(fa2ce8e0216a433f9bbad0bdd6e3dc0b540f03b7) )
+ ROM_LOAD( "107268-64.bin", 0x1000, 0x0800, CRC(e33683ae) SHA1(0c1d9e320f82df05f4804992ef6f6f6cd20623f3) )
+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, 0x07ff) 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_WRITE(z5_t0_w)
+ 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)
+
+ // sound hardware
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+ MCFG_SOUND_ADD(SPEAKER_TAG, 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 )
+{
+ device_set_input_line(m_mousecpu, INPUT_LINE_RESET, newval ? CLEAR_LINE : ASSERT_LINE);
+}
+
+
+//-------------------------------------------------
+// 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()
+{
+ device_set_input_line(m_maincpu, MCS48_INPUT_IRQ, (m_si | m_si_en) ? CLEAR_LINE : ASSERT_LINE);
+ device_set_input_line(m_mousecpu, MCS48_INPUT_IRQ, m_si ? CLEAR_LINE : ASSERT_LINE);
+}
+
+
+//-------------------------------------------------
+// serial_output -
+//-------------------------------------------------
+
+inline void abc99_device::serial_output()
+{
+ int so = m_so_z2 & m_so_z5;
+
+ if (m_so != so)
+ {
+ m_so = so;
+ }
+}
+
+
+//-------------------------------------------------
+// serial_clock -
+//-------------------------------------------------
+
+inline void abc99_device::serial_clock()
+{
+ m_out_clock_func(1);
+ m_out_clock_func(0);
+}
+
+
+//-------------------------------------------------
+// keydown -
+//-------------------------------------------------
+
+inline void abc99_device::key_down(int state)
+{
+ if (m_keydown != state)
+ {
+ m_out_keydown_func(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),
+ m_maincpu(*this, I8035_Z2_TAG),
+ m_mousecpu(*this, I8035_Z5_TAG),
+ m_speaker(*this, SPEAKER_TAG),
+ m_si(1),
+ m_si_en(1),
+ m_so(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(0)
+{
+}
+
+
+//-------------------------------------------------
+// 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);
+
+ // resolve callbacks
+ m_out_clock_func.resolve(m_out_clock_cb, *this);
+ m_out_keydown_func.resolve(m_out_keydown_cb, *this);
+
+ // state saving
+ save_item(NAME(m_si));
+ save_item(NAME(m_si_en));
+ save_item(NAME(m_so));
+ 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));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void abc99_device::device_reset()
+{
+ // set EA lines
+ device_set_input_line(m_maincpu, MCS48_INPUT_EA, ASSERT_LINE);
+ device_set_input_line(m_mousecpu, MCS48_INPUT_EA, ASSERT_LINE);
+}
+
+
+//-------------------------------------------------
+// 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;
+ }
+}
+
+
+//-------------------------------------------------
+// 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
+ int so_z2 = BIT(data, 0);
+
+ if (m_so_z2 != so_z2)
+ {
+ m_so_z2 = so_z2;
+ serial_output();
+ }
+
+ // 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
+ speaker_level_w(m_speaker, !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 = ioport("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 |= (ioport("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_reset = reset;
+ device_set_input_line(m_maincpu, INPUT_LINE_RESET, m_reset ? CLEAR_LINE : ASSERT_LINE);
+ }
+
+ // serial output
+ int so_z5 = BIT(data, 6);
+
+ if (m_so_z5 != so_z5)
+ {
+ m_so_z5 = so_z5;
+ serial_output();
+ }
+
+ // keyboard CPU T1
+ m_t1_z2 = BIT(data, 7);
+}
+
+
+//-------------------------------------------------
+// z5_t0_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( abc99_device::z5_t0_w )
+{
+ // clock output to Z2, not necessary to emulate
+}
+
+
+//-------------------------------------------------
+// z5_t1_r -
+//-------------------------------------------------
+
+READ8_MEMBER( abc99_device::z5_t1_r )
+{
+ return m_t1_z5;
+}
+
+
+//-------------------------------------------------
+// rxd_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( abc99_device::rxd_w )
+{
+ if (m_si != state)
+ {
+ m_si = state;
+
+ serial_input();
+ }
+}
+
+
+//-------------------------------------------------
+// txd_r -
+//-------------------------------------------------
+
+READ_LINE_MEMBER( abc99_device::txd_r )
+{
+ return m_so;
+}
+
+
+//-------------------------------------------------
+// reset_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( abc99_device::reset_w )
+{
+ device_set_input_line(m_mousecpu, INPUT_LINE_RESET, state ? CLEAR_LINE : ASSERT_LINE);
+}
diff --git a/src/mess/machine/abc99.h b/src/mess/machine/abc99.h
new file mode 100644
index 00000000000..3dc8f687418
--- /dev/null
+++ b/src/mess/machine/abc99.h
@@ -0,0 +1,130 @@
+/**********************************************************************
+
+ Luxor ABC-99 keyboard and mouse emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#pragma once
+
+#ifndef __ABC99__
+#define __ABC99__
+
+#include "emu.h"
+#include "cpu/mcs48/mcs48.h"
+#include "sound/speaker.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define ABC99_TAG "abc99"
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_ABC99_ADD(_config) \
+ MCFG_DEVICE_ADD(ABC99_TAG, ABC99, 0) \
+ MCFG_DEVICE_CONFIG(_config)
+
+
+#define ABC99_INTERFACE(_name) \
+ const abc99_interface (_name) =
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> abc99_interface
+
+struct abc99_interface
+{
+ devcb_write_line m_out_clock_cb;
+ devcb_write_line m_out_keydown_cb;
+};
+
+// ======================> abc99_device
+
+class abc99_device : public device_t,
+ public abc99_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;
+
+ 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_WRITE8_MEMBER( z5_t0_w );
+ DECLARE_READ8_MEMBER( z5_t1_r );
+
+ DECLARE_WRITE_LINE_MEMBER( rxd_w );
+ DECLARE_READ_LINE_MEMBER( txd_r );
+ DECLARE_WRITE_LINE_MEMBER( reset_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);
+ virtual void device_config_complete();
+
+private:
+ static const device_timer_id TIMER_SERIAL = 0;
+ static const device_timer_id TIMER_MOUSE = 1;
+
+ inline void serial_input();
+ inline void serial_output();
+ inline void serial_clock();
+ inline void key_down(int state);
+ inline void scan_mouse();
+
+ devcb_resolved_write_line m_out_clock_func;
+ devcb_resolved_write_line m_out_keydown_func;
+
+ emu_timer *m_serial_timer;
+ emu_timer *m_mouse_timer;
+
+ required_device<cpu_device> m_maincpu;
+ required_device<cpu_device> m_mousecpu;
+ required_device<device_t> m_speaker;
+
+ int m_si;
+ int m_si_en;
+ int m_so;
+ 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;
+};
+
+
+// device type definition
+extern const device_type ABC99;
+
+
+
+#endif
diff --git a/src/mess/machine/abc_dos.c b/src/mess/machine/abc_dos.c
new file mode 100644
index 00000000000..793763ae9d3
--- /dev/null
+++ b/src/mess/machine/abc_dos.c
@@ -0,0 +1,143 @@
+/**********************************************************************
+
+ Luxor ABC DOS card emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+/*
+
+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 "abc_dos.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type ABC_DOS = &device_creator<abc_dos_device>;
+
+
+//-------------------------------------------------
+// ROM( abc_dos )
+//-------------------------------------------------
+
+ROM_START( abc_dos )
+ ROM_REGION( 0x2000, "dos", ROMREGION_ERASEFF )
+ 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_LOAD( "printer.4c", 0x1000, 0x400, NO_DUMP )
+ //ROM_LOAD( "spare.4a", 0x1400, 0x400, NO_DUMP )
+ ROM_LOAD( "9704.3c", 0x1800, 0x400, NO_DUMP )
+ //ROM_LOAD( "spare.3a", 0x1c00, 0x400, NO_DUMP )
+ROM_END
+
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *abc_dos_device::device_rom_region() const
+{
+ return ROM_NAME( abc_dos );
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// abc_dos_device - constructor
+//-------------------------------------------------
+
+abc_dos_device::abc_dos_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, ABC_DOS, "ABC DOS", tag, owner, clock),
+ device_abcbus_card_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void abc_dos_device::device_start()
+{
+}
+
+
+
+//**************************************************************************
+// ABC BUS INTERFACE
+//**************************************************************************
+
+//-------------------------------------------------
+// abcbus_xmemfl -
+//-------------------------------------------------
+
+UINT8 abc_dos_device::abcbus_xmemfl(offs_t offset)
+{
+ UINT8 data = 0xff;
+
+ if (offset >= 0x6000 && offset < 0x8000)
+ {
+ data = memregion("dos")->base()[offset & 0x1fff];
+ }
+
+ return data;
+}
diff --git a/src/mess/machine/abc_dos.h b/src/mess/machine/abc_dos.h
new file mode 100644
index 00000000000..6ce0e4f7b11
--- /dev/null
+++ b/src/mess/machine/abc_dos.h
@@ -0,0 +1,53 @@
+/**********************************************************************
+
+ Scandia Metric DOS floppy controller emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#pragma once
+
+#ifndef __ABC_DOS__
+#define __ABC_DOS__
+
+
+#include "emu.h"
+#include "machine/abcbus.h"
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> abc_dos_device
+
+class abc_dos_device : public device_t,
+ public device_abcbus_card_interface
+{
+public:
+ // construction/destruction
+ abc_dos_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_config_complete() { m_shortname = "abc_dos"; }
+
+ // device_abcbus_interface overrides
+ virtual void abcbus_cs(UINT8 data) { };
+ virtual UINT8 abcbus_xmemfl(offs_t offset);
+};
+
+
+// device type definition
+extern const device_type ABC_DOS;
+
+
+
+#endif
diff --git a/src/mess/machine/abc_fd2.c b/src/mess/machine/abc_fd2.c
new file mode 100644
index 00000000000..b9796afb6c6
--- /dev/null
+++ b/src/mess/machine/abc_fd2.c
@@ -0,0 +1,248 @@
+/**********************************************************************
+
+ Scandia Metric FD2 floppy controller emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+/*
+
+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 "abc_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<abc_fd2_device>;
+
+
+//-------------------------------------------------
+// ROM( abc_fd2 )
+//-------------------------------------------------
+
+ROM_START( abc_fd2 )
+ ROM_REGION( 0x400, Z80_TAG, 0 )
+ ROM_LOAD( "1.02.3f", 0x000, 0x400, NO_DUMP )
+
+ ROM_REGION( 0x400, "abc80", 0 )
+ ROM_LOAD( "ami 8005saj.1a", 0x000, 0x400, NO_DUMP )
+ROM_END
+
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *abc_fd2_device::device_rom_region() const
+{
+ return ROM_NAME( abc_fd2 );
+}
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( abc_fd2_mem )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( abc_fd2_mem, AS_PROGRAM, 8, abc_fd2_device )
+ AM_RANGE(0x0000, 0x03ff) AM_ROM AM_REGION(Z80_TAG, 0)
+ADDRESS_MAP_END
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( abc_fd2_io )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( abc_fd2_io, AS_IO, 8, abc_fd2_device )
+ADDRESS_MAP_END
+
+
+//-------------------------------------------------
+// Z80PIO_INTERFACE( pio_intf )
+//-------------------------------------------------
+
+static Z80PIO_INTERFACE( pio_intf )
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// z80_daisy_config daisy_chain
+//-------------------------------------------------
+
+static const z80_daisy_config daisy_chain[] =
+{
+ { Z80PIO_TAG },
+ { NULL }
+};
+
+
+//-------------------------------------------------
+// wd17xx_interface fdc_intf
+//-------------------------------------------------
+
+static const floppy_interface fd2_floppy_interface =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ FLOPPY_STANDARD_5_25_SSSD,
+ LEGACY_FLOPPY_OPTIONS_NAME(default),
+ "floppy_5_25",
+ NULL
+};
+
+static const wd17xx_interface fdc_intf =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ { FLOPPY_0, FLOPPY_1, NULL, NULL }
+};
+
+
+//-------------------------------------------------
+// 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_Z80PIO_ADD(Z80PIO_TAG, XTAL_4MHz/2, pio_intf) // ?
+ MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(fd2_floppy_interface)
+ MCFG_FD1771_ADD(FD1771_TAG, fdc_intf)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor abc_fd2_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( abc_fd2 );
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// abc_fd2_device - constructor
+//-------------------------------------------------
+
+abc_fd2_device::abc_fd2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, ABC_FD2, "ABC FD2", tag, owner, clock),
+ device_abcbus_card_interface(mconfig, *this),
+ m_maincpu(*this, Z80_TAG),
+ m_pio(*this, Z80PIO_TAG),
+ m_fdc(*this, FD1771_TAG),
+ m_image0(*this, FLOPPY_0),
+ m_image1(*this, FLOPPY_1)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void abc_fd2_device::device_start()
+{
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void abc_fd2_device::device_reset()
+{
+}
+
+
+
+//**************************************************************************
+// ABC BUS INTERFACE
+//**************************************************************************
+
+//-------------------------------------------------
+// abcbus_cs -
+//-------------------------------------------------
+
+void abc_fd2_device::abcbus_cs(UINT8 data)
+{
+}
+
+
+//-------------------------------------------------
+// abcbus_xmemfl -
+//-------------------------------------------------
+
+UINT8 abc_fd2_device::abcbus_xmemfl(offs_t offset)
+{
+ UINT8 data = 0xff;
+
+ if (offset >= 0x6000 && offset < 0x6400) // TODO is this mirrored?
+ {
+ data = memregion("abc80")->base()[offset & 0x3ff];
+ }
+
+ return data;
+}
diff --git a/src/mess/machine/abc_fd2.h b/src/mess/machine/abc_fd2.h
new file mode 100644
index 00000000000..5718224cdf0
--- /dev/null
+++ b/src/mess/machine/abc_fd2.h
@@ -0,0 +1,68 @@
+/**********************************************************************
+
+ Scandia Metric FD2 floppy controller emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#pragma once
+
+#ifndef __ABC_FD2__
+#define __ABC_FD2__
+
+
+#include "emu.h"
+#include "cpu/z80/z80.h"
+#include "cpu/z80/z80daisy.h"
+#include "formats/basicdsk.h"
+#include "imagedev/flopdrv.h"
+#include "machine/abcbus.h"
+#include "machine/wd17xx.h"
+#include "machine/z80pio.h"
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> abc_fd2_device
+
+class abc_fd2_device : public device_t,
+ public device_abcbus_card_interface
+{
+public:
+ // construction/destruction
+ abc_fd2_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();
+ virtual void device_config_complete() { m_shortname = "abc_fd2"; }
+
+ // device_abcbus_interface overrides
+ virtual void abcbus_cs(UINT8 data);
+ virtual UINT8 abcbus_xmemfl(offs_t offset);
+
+private:
+ required_device<cpu_device> m_maincpu;
+ required_device<z80pio_device> m_pio;
+ required_device<device_t> m_fdc;
+ required_device<legacy_floppy_image_device> m_image0;
+ required_device<legacy_floppy_image_device> m_image1;
+};
+
+
+// device type definition
+extern const device_type ABC_FD2;
+
+
+
+#endif
diff --git a/src/mess/machine/abc_hdc.c b/src/mess/machine/abc_hdc.c
new file mode 100644
index 00000000000..3241f07abc9
--- /dev/null
+++ b/src/mess/machine/abc_hdc.c
@@ -0,0 +1,186 @@
+/**********************************************************************
+
+ Luxor ABC 850 Winchester controller card emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#include "abc_hdc.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define Z80_TAG "z80"
+#define SASIBUS_TAG "sasi"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type ABC_HDC = &device_creator<abc_hdc_device>;
+
+
+//-------------------------------------------------
+// ROM( abc_hdc )
+//-------------------------------------------------
+
+ROM_START( abc_hdc )
+ ROM_REGION( 0x1000, Z80_TAG, 0 )
+ // ABC 850
+ ROM_SYSTEM_BIOS(0, "ro202", "Rodime RO202 (CHS: 321,4,17,512)" )
+ 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, "basf6185", "BASF 6185 (CHS: 440,6,32,256)" )
+ ROMX_LOAD( "basf6185.bin", 0x0000, 0x0800, CRC(06f8fe2e) SHA1(e81f2a47c854e0dbb096bee3428d79e63591059d), ROM_BIOS(2) ) // BASF 6185 (http://stason.org/TULARC/pc/hard-drives-hdd/basf-magnetics/6185-22MB-5-25-FH-MFM-ST412.html)
+ // ABC 852
+ ROM_SYSTEM_BIOS(2, "nec5126", "NEC 5126 (CHS: 615,4,17,512)" )
+ ROMX_LOAD( "nec5126.bin", 0x0000, 0x1000, CRC(17c247e7) SHA1(7339738b87751655cb4d6414422593272fe72f5d), ROM_BIOS(3) ) // NEC 5126 (http://stason.org/TULARC/pc/hard-drives-hdd/nec/D5126-20MB-5-25-HH-MFM-ST506.html)
+ // ABC 856
+ ROM_SYSTEM_BIOS(3, "micr1325", "Micropolis 1325 (CHS: 1024,8,33,256)" )
+ ROMX_LOAD( "micr1325.bin", 0x0000, 0x0800, CRC(084af409) SHA1(342b8e214a8c4c2b014604e53c45ef1bd1c69ea3), ROM_BIOS(4) ) // 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 *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, 0x0fff) 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 }
+};
+
+
+//-------------------------------------------------
+// SCSIBus_interface sasi_intf
+//-------------------------------------------------
+
+static const SCSIConfigTable sasi_dev_table =
+{
+ 1,
+ {
+ { SCSI_ID_0, "harddisk0" }
+ }
+};
+
+static const SCSIBus_interface sasi_intf =
+{
+ &sasi_dev_table,
+ NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_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_SCSIBUS_ADD(SASIBUS_TAG, sasi_intf)
+ MCFG_DEVICE_ADD("harddisk0", SCSIHD, 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),
+ device_abcbus_card_interface(mconfig, *this),
+ m_maincpu(*this, Z80_TAG),
+ m_sasibus(*this, SASIBUS_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/mess/machine/abc_hdc.h b/src/mess/machine/abc_hdc.h
new file mode 100644
index 00000000000..2f3083eaf09
--- /dev/null
+++ b/src/mess/machine/abc_hdc.h
@@ -0,0 +1,63 @@
+/**********************************************************************
+
+ Luxor ABC 850 Winchester controller card emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#pragma once
+
+#ifndef __ABC_HDC__
+#define __ABC_HDC__
+
+
+#include "emu.h"
+#include "cpu/z80/z80.h"
+#include "cpu/z80/z80daisy.h"
+#include "imagedev/harddriv.h"
+#include "machine/abcbus.h"
+#include "machine/scsibus.h"
+#include "machine/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();
+ virtual void device_config_complete() { m_shortname = "abc_hdc"; }
+
+ // device_abcbus_interface overrides
+ virtual void abcbus_cs(UINT8 data);
+
+private:
+ required_device<cpu_device> m_maincpu;
+ required_device<device_t> m_sasibus;
+};
+
+
+// device type definition
+extern const device_type ABC_HDC;
+
+
+
+#endif
diff --git a/src/mess/machine/abc_sio.c b/src/mess/machine/abc_sio.c
new file mode 100644
index 00000000000..2fd4366d4c4
--- /dev/null
+++ b/src/mess/machine/abc_sio.c
@@ -0,0 +1,196 @@
+/*
+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 "abc_sio.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define Z80CTC_TAG "z80ctc"
+#define Z80SIO_TAG "z80sio"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type ABC_SIO = &device_creator<abc_sio_device>;
+
+
+//-------------------------------------------------
+// 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 );
+}
+
+
+//-------------------------------------------------
+// Z80CTC_INTERFACE( ctc_intf )
+//-------------------------------------------------
+
+static Z80CTC_INTERFACE( ctc_intf )
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// Z80DART_INTERFACE( sio_intf )
+//-------------------------------------------------
+
+static Z80DART_INTERFACE( sio_intf )
+{
+ 0, 0, 0, 0,
+
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( abc_sio )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( abc_sio )
+ MCFG_Z80CTC_ADD(Z80CTC_TAG, XTAL_4_9152MHz, ctc_intf)
+ MCFG_Z80DART_ADD(Z80SIO_TAG, 0, sio_intf)
+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),
+ device_abcbus_card_interface(mconfig, *this),
+ m_ctc(*this, Z80CTC_TAG),
+ m_sio(*this, Z80SIO_TAG)
+{
+}
+
+
+//-------------------------------------------------
+// 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 = memregion("abc80")->base()[offset & 0xfff];
+ }
+
+ return data;
+}
diff --git a/src/mess/machine/abc_sio.h b/src/mess/machine/abc_sio.h
new file mode 100644
index 00000000000..4fca2f3ba14
--- /dev/null
+++ b/src/mess/machine/abc_sio.h
@@ -0,0 +1,53 @@
+#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();
+ virtual void device_config_complete() { m_shortname = "abcsio"; }
+
+ // device_abcbus_interface overrides
+ virtual void abcbus_cs(UINT8 data);
+ virtual UINT8 abcbus_xmemfl(offs_t offset);
+
+private:
+ required_device<z80ctc_device> m_ctc;
+ required_device<z80dart_device> m_sio;
+
+};
+
+
+// device type definition
+extern const device_type ABC_SIO;
+
+
+
+#endif
diff --git a/src/mess/machine/abc_slutprov.c b/src/mess/machine/abc_slutprov.c
new file mode 100644
index 00000000000..07983ba1a18
--- /dev/null
+++ b/src/mess/machine/abc_slutprov.c
@@ -0,0 +1,77 @@
+#include "abc_slutprov.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type ABC_SLUTPROV = &device_creator<abc_slutprov_device>;
+
+
+//-------------------------------------------------
+// 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),
+ 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/mess/machine/abc_slutprov.h b/src/mess/machine/abc_slutprov.h
new file mode 100644
index 00000000000..285c0512248
--- /dev/null
+++ b/src/mess/machine/abc_slutprov.h
@@ -0,0 +1,44 @@
+#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();
+ virtual void device_config_complete() { m_shortname = "slutprov"; }
+
+ // device_abcbus_interface overrides
+ virtual void abcbus_cs(UINT8 data);
+};
+
+
+// device type definition
+extern const device_type ABC_SLUTPROV;
+
+
+
+#endif
diff --git a/src/mess/machine/abc_turbo.c b/src/mess/machine/abc_turbo.c
new file mode 100644
index 00000000000..c38882aba4a
--- /dev/null
+++ b/src/mess/machine/abc_turbo.c
@@ -0,0 +1,172 @@
+/**********************************************************************
+
+ MyAB Turbo-Kontroller disk controller emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#include "abc_turbo.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define Z80_TAG "z80"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type TURBO_KONTROLLER = &device_creator<turbo_kontroller_device>;
+
+
+//-------------------------------------------------
+// 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 }
+};
+
+
+//-------------------------------------------------
+// floppy_interface unidisk_floppy_interface
+//-------------------------------------------------
+
+static const floppy_interface unidisk_floppy_interface =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ FLOPPY_STANDARD_5_25_DSDD,
+ LEGACY_FLOPPY_OPTIONS_NAME(default),
+ "floppy_5_25",
+ 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)
+
+ MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(unidisk_floppy_interface)
+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),
+ device_abcbus_card_interface(mconfig, *this),
+ m_maincpu(*this, Z80_TAG),
+ m_image0(*this, FLOPPY_0),
+ m_image1(*this, FLOPPY_1)
+{
+}
+
+
+//-------------------------------------------------
+// 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/mess/machine/abc_turbo.h b/src/mess/machine/abc_turbo.h
new file mode 100644
index 00000000000..3f5a4420fbd
--- /dev/null
+++ b/src/mess/machine/abc_turbo.h
@@ -0,0 +1,63 @@
+/**********************************************************************
+
+ MyAB Turbo-Kontroller disk controller emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#pragma once
+
+#ifndef __TURBO_KONTROLLER__
+#define __TURBO_KONTROLLER__
+
+
+#include "emu.h"
+#include "cpu/z80/z80.h"
+#include "cpu/z80/z80daisy.h"
+#include "formats/basicdsk.h"
+#include "imagedev/flopdrv.h"
+#include "machine/abcbus.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();
+ virtual void device_config_complete() { m_shortname = "unidisk"; }
+
+ // device_abcbus_interface overrides
+ virtual void abcbus_cs(UINT8 data);
+
+private:
+ required_device<cpu_device> m_maincpu;
+ required_device<legacy_floppy_image_device> m_image0;
+ required_device<legacy_floppy_image_device> m_image1;
+};
+
+
+// device type definition
+extern const device_type TURBO_KONTROLLER;
+
+
+
+#endif
diff --git a/src/mess/machine/abc_uni800.c b/src/mess/machine/abc_uni800.c
new file mode 100644
index 00000000000..71f856b40ab
--- /dev/null
+++ b/src/mess/machine/abc_uni800.c
@@ -0,0 +1,108 @@
+/*
+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 "abc_uni800.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type ABC_UNI800 = &device_creator<abc_uni800_device>;
+
+
+//-------------------------------------------------
+// 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),
+ 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/mess/machine/abc_uni800.h b/src/mess/machine/abc_uni800.h
new file mode 100644
index 00000000000..07075c0205b
--- /dev/null
+++ b/src/mess/machine/abc_uni800.h
@@ -0,0 +1,44 @@
+#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();
+ virtual void device_config_complete() { m_shortname = "uni800"; }
+
+ // device_abcbus_interface overrides
+ virtual void abcbus_cs(UINT8 data);
+};
+
+
+// device type definition
+extern const device_type ABC_UNI800;
+
+
+
+#endif
diff --git a/src/mess/machine/abc_xebec.c b/src/mess/machine/abc_xebec.c
new file mode 100644
index 00000000000..80b995c65fd
--- /dev/null
+++ b/src/mess/machine/abc_xebec.c
@@ -0,0 +1,179 @@
+/**********************************************************************
+
+ Unknown Xebec Winchester controller card emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#include "abc_xebec.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define Z80_TAG "z80"
+#define SASIBUS_TAG "sasi"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type ABC_XEBEC = &device_creator<abc_xebec_device>;
+
+
+//-------------------------------------------------
+// ROM( abc_xebec )
+//-------------------------------------------------
+
+ROM_START( abc_xebec )
+ ROM_REGION( 0x800, Z80_TAG, 0 )
+ ROM_SYSTEM_BIOS( 0, "st4038", "Seagate ST4038 (CHS: 733,5,17,512)" )
+ ROMX_LOAD( "st4038.bin", 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.bin", 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_xebec_device::device_rom_region() const
+{
+ return ROM_NAME( abc_xebec );
+}
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( abc_xebec_mem )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( abc_xebec_mem, AS_PROGRAM, 8, abc_xebec_device )
+ AM_RANGE(0x0000, 0x07ff) AM_ROM AM_REGION(Z80_TAG, 0)
+ADDRESS_MAP_END
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( abc_xebec_io )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( abc_xebec_io, AS_IO, 8, abc_xebec_device )
+ADDRESS_MAP_END
+
+
+//-------------------------------------------------
+// z80_daisy_config daisy_chain
+//-------------------------------------------------
+
+static const z80_daisy_config daisy_chain[] =
+{
+ { NULL }
+};
+
+
+//-------------------------------------------------
+// SCSIBus_interface sasi_intf
+//-------------------------------------------------
+
+static const SCSIConfigTable sasi_dev_table =
+{
+ 1,
+ {
+ { SCSI_ID_0, "harddisk0" }
+ }
+};
+
+static const SCSIBus_interface sasi_intf =
+{
+ &sasi_dev_table,
+ NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( abc_xebec )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( abc_xebec )
+ MCFG_CPU_ADD(Z80_TAG, Z80, 4000000)
+ MCFG_CPU_PROGRAM_MAP(abc_xebec_mem)
+ MCFG_CPU_IO_MAP(abc_xebec_io)
+ MCFG_CPU_CONFIG(daisy_chain)
+
+ MCFG_SCSIBUS_ADD(SASIBUS_TAG, sasi_intf)
+ MCFG_DEVICE_ADD("harddisk0", SCSIHD, 0)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor abc_xebec_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( abc_xebec );
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// abc_xebec_device - constructor
+//-------------------------------------------------
+
+abc_xebec_device::abc_xebec_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, ABC_XEBEC, "ABC XEBEC", tag, owner, clock),
+ device_abcbus_card_interface(mconfig, *this),
+ m_maincpu(*this, Z80_TAG),
+ m_sasibus(*this, SASIBUS_TAG)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void abc_xebec_device::device_start()
+{
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void abc_xebec_device::device_reset()
+{
+}
+
+
+
+//**************************************************************************
+// ABC BUS INTERFACE
+//**************************************************************************
+
+//-------------------------------------------------
+// abcbus_cs -
+//-------------------------------------------------
+
+void abc_xebec_device::abcbus_cs(UINT8 data)
+{
+}
diff --git a/src/mess/machine/abc_xebec.h b/src/mess/machine/abc_xebec.h
new file mode 100644
index 00000000000..94c775eb3e2
--- /dev/null
+++ b/src/mess/machine/abc_xebec.h
@@ -0,0 +1,63 @@
+/**********************************************************************
+
+ Unknown Xebec Winchester controller card emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#pragma once
+
+#ifndef __ABC_XEBEC__
+#define __ABC_XEBEC__
+
+
+#include "emu.h"
+#include "cpu/z80/z80.h"
+#include "cpu/z80/z80daisy.h"
+#include "imagedev/harddriv.h"
+#include "machine/abcbus.h"
+#include "machine/scsibus.h"
+#include "machine/scsihd.h"
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> abc_xebec_device
+
+class abc_xebec_device : public device_t,
+ public device_abcbus_card_interface
+{
+public:
+ // construction/destruction
+ abc_xebec_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();
+ virtual void device_config_complete() { m_shortname = "abc_xebec"; }
+
+ // device_abcbus_interface overrides
+ virtual void abcbus_cs(UINT8 data);
+
+private:
+ required_device<cpu_device> m_maincpu;
+ required_device<device_t> m_sasibus;
+};
+
+
+// device type definition
+extern const device_type ABC_XEBEC;
+
+
+
+#endif
diff --git a/src/mess/machine/abcbus.c b/src/mess/machine/abcbus.c
new file mode 100644
index 00000000000..66a9c50211a
--- /dev/null
+++ b/src/mess/machine/abcbus.c
@@ -0,0 +1,374 @@
+/**********************************************************************
+
+ Luxor ABC (Databoard 4680) Bus emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "abcbus.h"
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ABCBUS_SLOT = &device_creator<abcbus_slot_device>;
+
+
+
+//**************************************************************************
+// DEVICE ABCBUS CARD INTERFACE
+//**************************************************************************
+
+//-------------------------------------------------
+// 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)
+{
+}
+
+
+//-------------------------------------------------
+// ~device_abcbus_card_interface - destructor
+//-------------------------------------------------
+
+device_abcbus_card_interface::~device_abcbus_card_interface()
+{
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// abcbus_slot_device - constructor
+//-------------------------------------------------
+
+abcbus_slot_device::abcbus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, ABCBUS_SLOT, "ABC bus slot", tag, owner, clock),
+ device_slot_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void abcbus_slot_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const abcbus_interface *intf = reinterpret_cast<const abcbus_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<abcbus_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_int_cb, 0, sizeof(m_out_int_cb));
+ memset(&m_out_nmi_cb, 0, sizeof(m_out_nmi_cb));
+ memset(&m_out_rdy_cb, 0, sizeof(m_out_rdy_cb));
+ memset(&m_out_resin_cb, 0, sizeof(m_out_resin_cb));
+ }
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void abcbus_slot_device::device_start()
+{
+ m_card = dynamic_cast<device_abcbus_card_interface *>(get_card_device());
+
+ // resolve callbacks
+ m_out_int_func.resolve(m_out_int_cb, *this);
+ m_out_nmi_func.resolve(m_out_nmi_cb, *this);
+ m_out_rdy_func.resolve(m_out_rdy_cb, *this);
+ m_out_resin_func.resolve(m_out_resin_cb, *this);
+}
+
+
+//-------------------------------------------------
+// cs_w -
+//-------------------------------------------------
+
+void abcbus_slot_device::cs_w(UINT8 data)
+{
+ if (m_card != NULL)
+ {
+ m_card->abcbus_cs(data);
+ }
+}
+
+WRITE8_MEMBER( abcbus_slot_device::cs_w )
+{
+ cs_w(data);
+}
+
+
+//-------------------------------------------------
+// rst_r -
+//-------------------------------------------------
+
+UINT8 abcbus_slot_device::rst_r()
+{
+ if (m_card != NULL)
+ {
+ m_card->abcbus_rst(0);
+ m_card->abcbus_rst(1);
+ }
+
+ return 0xff;
+}
+
+READ8_MEMBER( abcbus_slot_device::rst_r )
+{
+ return rst_r();
+}
+
+
+//-------------------------------------------------
+// inp_r -
+//-------------------------------------------------
+
+UINT8 abcbus_slot_device::inp_r()
+{
+ UINT8 data = 0xff;
+
+ if (m_card != NULL)
+ {
+ data &= m_card->abcbus_inp();
+ }
+
+ return data;
+}
+
+READ8_MEMBER( abcbus_slot_device::inp_r )
+{
+ return inp_r();
+}
+
+
+//-------------------------------------------------
+// utp_w -
+//-------------------------------------------------
+
+void abcbus_slot_device::utp_w(UINT8 data)
+{
+ if (m_card != NULL)
+ {
+ m_card->abcbus_utp(data);
+ }
+}
+
+WRITE8_MEMBER( abcbus_slot_device::utp_w )
+{
+ utp_w(data);
+}
+
+
+//-------------------------------------------------
+// stat_r -
+//-------------------------------------------------
+
+UINT8 abcbus_slot_device::stat_r()
+{
+ UINT8 data = 0xff;
+
+ if (m_card != NULL)
+ {
+ data &= m_card->abcbus_stat();
+ }
+
+ return data;
+}
+
+READ8_MEMBER( abcbus_slot_device::stat_r )
+{
+ return stat_r();
+}
+
+
+//-------------------------------------------------
+// c1_w -
+//-------------------------------------------------
+
+void abcbus_slot_device::c1_w(UINT8 data)
+{
+ if (m_card != NULL)
+ {
+ m_card->abcbus_c1(data);
+ }
+}
+
+WRITE8_MEMBER( abcbus_slot_device::c1_w )
+{
+ c1_w(data);
+}
+
+
+//-------------------------------------------------
+// c2_w -
+//-------------------------------------------------
+
+void abcbus_slot_device::c2_w(UINT8 data)
+{
+ if (m_card != NULL)
+ {
+ m_card->abcbus_c2(data);
+ }
+}
+
+WRITE8_MEMBER( abcbus_slot_device::c2_w )
+{
+ c2_w(data);
+}
+
+
+//-------------------------------------------------
+// c3_w -
+//-------------------------------------------------
+
+void abcbus_slot_device::c3_w(UINT8 data)
+{
+ if (m_card != NULL)
+ {
+ m_card->abcbus_c3(data);
+ }
+}
+
+WRITE8_MEMBER( abcbus_slot_device::c3_w )
+{
+ c3_w(data);
+}
+
+
+//-------------------------------------------------
+// c4_w -
+//-------------------------------------------------
+
+void abcbus_slot_device::c4_w(UINT8 data)
+{
+ if (m_card != NULL)
+ {
+ m_card->abcbus_c4(data);
+ }
+}
+
+WRITE8_MEMBER( abcbus_slot_device::c4_w )
+{
+ c4_w(data);
+}
+
+
+//-------------------------------------------------
+// xmemfl_r -
+//-------------------------------------------------
+
+UINT8 abcbus_slot_device::xmemfl_r(offs_t offset)
+{
+ UINT8 data = 0xff;
+
+ if (m_card != NULL)
+ {
+ data &= m_card->abcbus_xmemfl(offset);
+ }
+
+ return data;
+}
+
+READ8_MEMBER( abcbus_slot_device::xmemfl_r )
+{
+ return xmemfl_r(offset);
+}
+
+
+//-------------------------------------------------
+// xmemw_w -
+//-------------------------------------------------
+
+void abcbus_slot_device::xmemw_w(offs_t offset, UINT8 data)
+{
+ if (m_card != NULL)
+ {
+ m_card->abcbus_xmemw(offset, data);
+ }
+}
+
+WRITE8_MEMBER( abcbus_slot_device::xmemw_w )
+{
+ xmemw_w(offset, data);
+}
+
+
+//-------------------------------------------------
+// int_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( abcbus_slot_device::int_w )
+{
+ m_out_int_func(state);
+}
+
+
+//-------------------------------------------------
+// nmi_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( abcbus_slot_device::nmi_w )
+{
+ m_out_nmi_func(state);
+}
+
+
+//-------------------------------------------------
+// rdy_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( abcbus_slot_device::rdy_w )
+{
+ m_out_rdy_func(state);
+}
+
+
+//-------------------------------------------------
+// resin_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( abcbus_slot_device::resin_w )
+{
+ m_out_resin_func(state);
+}
+
+
+//-------------------------------------------------
+// SLOT_INTERFACE( abcbus_cards )
+//-------------------------------------------------
+
+SLOT_INTERFACE_START( abcbus_cards )
+ SLOT_INTERFACE("exp", ABC890)
+ SLOT_INTERFACE("exp3", ABC894)
+ SLOT_INTERFACE("hdc", ABC_HDC)
+ SLOT_INTERFACE("hdd", ABC850)
+ SLOT_INTERFACE("dos", ABC_DOS)
+ SLOT_INTERFACE("fd2", ABC_FD2)
+ SLOT_INTERFACE("sio", ABC_SIO)
+ SLOT_INTERFACE("slow", LUXOR_55_10828)
+ SLOT_INTERFACE("fast", LUXOR_55_21046)
+ SLOT_INTERFACE("uni800", ABC_UNI800)
+ SLOT_INTERFACE("slutprov", ABC_SLUTPROV)
+ SLOT_INTERFACE("turbo", TURBO_KONTROLLER)
+ SLOT_INTERFACE("xebec", ABC_XEBEC)
+SLOT_INTERFACE_END
diff --git a/src/mess/machine/abcbus.h b/src/mess/machine/abcbus.h
new file mode 100644
index 00000000000..5df9e04ad3b
--- /dev/null
+++ b/src/mess/machine/abcbus.h
@@ -0,0 +1,218 @@
+/**********************************************************************
+
+ Luxor ABC (Databoard 4680) Bus emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+
+ 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
+
+*/
+
+#pragma once
+
+#ifndef __ABCBUS__
+#define __ABCBUS__
+
+#include "emu.h"
+
+
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
+
+#define ABCBUS_TAG "bus"
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define ABCBUS_INTERFACE(_name) \
+ const abcbus_interface (_name) =
+
+
+#define MCFG_ABCBUS_SLOT_ADD(_tag, _config, _slot_intf, _def_slot, _def_inp) \
+ MCFG_DEVICE_ADD(_tag, ABCBUS_SLOT, 0) \
+ MCFG_DEVICE_CONFIG(_config) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false)
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> abcbus_interface
+
+struct abcbus_interface
+{
+ devcb_write_line m_out_int_cb;
+ devcb_write_line m_out_nmi_cb;
+ devcb_write_line m_out_rdy_cb;
+ devcb_write_line m_out_resin_cb;
+};
+
+
+// ======================> device_abcbus_card_interface
+
+class abcbus_slot_device;
+
+// class representing interface-specific live abcbus card
+class device_abcbus_card_interface : public device_slot_card_interface
+{
+ friend class abcbus_slot_device;
+
+public:
+ // construction/destruction
+ device_abcbus_card_interface(const machine_config &mconfig, device_t &device);
+ virtual ~device_abcbus_card_interface();
+
+ // required operation overrides
+ virtual void abcbus_cs(UINT8 data) = 0;
+
+ // optional operation overrides
+ virtual void abcbus_rst(int state) { };
+ virtual UINT8 abcbus_inp() { return 0xff; };
+ virtual void abcbus_utp(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) { };
+ virtual UINT8 abcbus_xmemfl(offs_t offset) { return 0xff; };
+ virtual void abcbus_xmemw(offs_t offset, UINT8 data) { };
+
+public:
+ abcbus_slot_device *m_bus;
+};
+
+
+// ======================> abcbus_slot_device
+
+class abcbus_slot_device : public device_t,
+ public device_slot_interface,
+ public abcbus_interface
+{
+public:
+ // construction/destruction
+ abcbus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // computer interface
+ void cs_w(UINT8 data);
+ UINT8 rst_r();
+ UINT8 inp_r();
+ void utp_w(UINT8 data);
+ UINT8 stat_r();
+ void c1_w(UINT8 data);
+ void c2_w(UINT8 data);
+ void c3_w(UINT8 data);
+ void c4_w(UINT8 data);
+ UINT8 xmemfl_r(offs_t offset);
+ void xmemw_w(offs_t offset, UINT8 data);
+
+ DECLARE_WRITE8_MEMBER( cs_w );
+ DECLARE_READ8_MEMBER( rst_r );
+ DECLARE_READ8_MEMBER( inp_r );
+ DECLARE_WRITE8_MEMBER( utp_w );
+ DECLARE_READ8_MEMBER( stat_r );
+ DECLARE_WRITE8_MEMBER( c1_w );
+ DECLARE_WRITE8_MEMBER( c2_w );
+ DECLARE_WRITE8_MEMBER( c3_w );
+ DECLARE_WRITE8_MEMBER( c4_w );
+ DECLARE_READ8_MEMBER( xmemfl_r );
+ DECLARE_WRITE8_MEMBER( xmemw_w );
+
+ // peripheral interface
+ DECLARE_WRITE_LINE_MEMBER( int_w );
+ DECLARE_WRITE_LINE_MEMBER( nmi_w );
+ DECLARE_WRITE_LINE_MEMBER( rdy_w );
+ DECLARE_WRITE_LINE_MEMBER( resin_w );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_config_complete();
+
+private:
+ devcb_resolved_write_line m_out_int_func;
+ devcb_resolved_write_line m_out_nmi_func;
+ devcb_resolved_write_line m_out_rdy_func;
+ devcb_resolved_write_line m_out_resin_func;
+
+ device_abcbus_card_interface *m_card;
+};
+
+
+// device type definition
+extern const device_type ABCBUS_SLOT;
+
+
+// ABC bus slot devices
+#include "machine/abc890.h"
+#include "machine/abc_dos.h"
+#include "machine/abc_fd2.h"
+#include "machine/abc_hdc.h"
+#include "machine/abc_uni800.h"
+#include "machine/abc_sio.h"
+#include "machine/abc_slutprov.h"
+#include "machine/abc_turbo.h"
+#include "machine/abc_xebec.h"
+#include "machine/lux10828.h"
+#include "machine/lux21046.h"
+
+SLOT_INTERFACE_EXTERN( abcbus_cards );
+
+
+
+#endif
diff --git a/src/mess/machine/ac1.c b/src/mess/machine/ac1.c
new file mode 100644
index 00000000000..6be53661798
--- /dev/null
+++ b/src/mess/machine/ac1.c
@@ -0,0 +1,121 @@
+/***************************************************************************
+
+ AC1 video driver by Miodrag Milanovic
+
+ 15/01/2009 Preliminary driver.
+
+****************************************************************************/
+
+#include "emu.h"
+#include "machine/z80pio.h"
+#include "imagedev/cassette.h"
+#include "includes/ac1.h"
+
+static READ8_DEVICE_HANDLER (ac1_port_b_r)
+{
+ ac1_state *state = device->machine().driver_data<ac1_state>();
+ UINT8 data = 0x7f;
+
+ if (state->m_cassette->input() > 0.03)
+ data |= 0x80;
+
+ return data;
+}
+
+#define BNOT(x) ((x) ? 0 : 1)
+
+static READ8_DEVICE_HANDLER (ac1_port_a_r)
+{
+ UINT8 line0 = device->machine().root_device().ioport("LINE0")->read();
+ UINT8 line1 = device->machine().root_device().ioport("LINE1")->read();
+ UINT8 line2 = device->machine().root_device().ioport("LINE2")->read();
+ UINT8 line3 = device->machine().root_device().ioport("LINE3")->read();
+ UINT8 line4 = device->machine().root_device().ioport("LINE4")->read();
+ UINT8 line5 = device->machine().root_device().ioport("LINE5")->read();
+ UINT8 line6 = device->machine().root_device().ioport("LINE6")->read();
+
+ UINT8 SH = BNOT(BIT(line6,0));
+ UINT8 CTRL = BNOT(BIT(line6,1));
+ UINT8 SPACE = BIT(line6,2);
+ UINT8 ENTER = BIT(line6,3);
+ UINT8 BACK = BIT(line6,4);
+
+ UINT8 all = line0 | line1 | line2 | line3 | line4 | line5;
+ UINT8 s1 = BNOT(BIT(all,0));UINT8 z1 = (line0 !=0) ? 0 : 1;
+ UINT8 s2 = BNOT(BIT(all,1));UINT8 z2 = (line1 !=0) ? 0 : 1;
+ UINT8 s3 = BNOT(BIT(all,2));UINT8 z3 = (line2 !=0) ? 0 : 1;
+ UINT8 s4 = BNOT(BIT(all,3));UINT8 z4 = (line3 !=0) ? 0 : 1;
+ UINT8 s5 = BNOT(BIT(all,4));UINT8 z5 = (line4 !=0) ? 0 : 1;
+ UINT8 s6 = BNOT(BIT(all,5));UINT8 z6 = (line5 !=0) ? 0 : 1;
+ UINT8 s7 = BNOT(BIT(all,6));
+ UINT8 s8 = BNOT(BIT(all,7));
+ UINT8 tast,td0,td1,td2,td3,td4,td5,td6,dg5;
+
+ /* Additional double keys */
+ if (SPACE) {
+ z1 = 0; s1 = 0; SH = 0;
+ }
+ if (ENTER) {
+ z4 = 0; s6 = 0; CTRL = 0;
+ }
+ if (BACK) {
+ z4 = 0; s1 = 0; CTRL = 0;
+ }
+
+ tast = BNOT(s1 & s2 & s3 & s4 & s5 &s6 & s7 & s8);
+ td0 = BNOT(s2 & s4 & s6 & s8);
+ td1 = BNOT(s3 & s4 & s7 & s8);
+ td2 = BNOT(s5 & s6 & s7 & s8);
+ td3 = BNOT(z2 & z4 & z6);
+ td4 = BNOT(BNOT(BNOT(z1 & z2) & SH) & z5 & z6);
+ dg5 = BNOT(z3 & z4 & z5 & z6);
+ td5 = BNOT(BNOT(dg5 & BNOT(SH)) & z1 & z2);
+ td6 = (dg5 & CTRL);
+ return td0 + (td1 << 1) +(td2 << 2) +(td3 << 3) +(td4 << 4) +(td5 << 5) +(td6 << 6) +(tast << 7);
+}
+
+static WRITE8_DEVICE_HANDLER (ac1_port_a_w)
+{
+}
+
+static WRITE8_DEVICE_HANDLER (ac1_port_b_w)
+{
+ /*
+
+ bit description
+
+ 0
+ 1 RTTY receive
+ 2 RTTY transmit
+ 3 RTTY PTT
+ 4
+ 5
+ 6 cassette out
+ 7 cassette in
+
+ */
+ ac1_state *state = device->machine().driver_data<ac1_state>();
+ state->m_cassette->output((data & 0x40) ? -1.0 : +1.0);
+}
+
+Z80PIO_INTERFACE( ac1_z80pio_intf )
+{
+ DEVCB_NULL, /* callback when change interrupt status */
+ DEVCB_HANDLER(ac1_port_a_r),
+ DEVCB_HANDLER(ac1_port_a_w),
+ DEVCB_NULL,
+ DEVCB_HANDLER(ac1_port_b_r),
+ DEVCB_HANDLER(ac1_port_b_w),
+ DEVCB_NULL
+};
+
+/* Driver initialization */
+DRIVER_INIT_MEMBER(ac1_state,ac1)
+{
+}
+
+MACHINE_RESET( ac1 )
+{
+ ac1_state *state = machine.driver_data<ac1_state>();
+ state->m_cassette = machine.device<cassette_image_device>(CASSETTE_TAG);
+}
diff --git a/src/mess/machine/advision.c b/src/mess/machine/advision.c
new file mode 100644
index 00000000000..36672d0c319
--- /dev/null
+++ b/src/mess/machine/advision.c
@@ -0,0 +1,176 @@
+/***************************************************************************
+
+ advision.c
+
+ Machine file to handle emulation of the AdventureVision.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/advision.h"
+#include "cpu/mcs48/mcs48.h"
+#include "sound/dac.h"
+
+/*
+ 8048 Ports:
+
+ P1 Bit 0..1 - RAM bank select
+ Bit 3..7 - Keypad input
+
+ P2 Bit 0..3 - A8-A11
+ Bit 4..7 - Sound control/Video write address
+
+ T1 Mirror sync pulse
+*/
+
+/* Machine Initialization */
+
+void advision_state::machine_start()
+{
+ /* configure EA banking */
+ membank("bank1")->configure_entry(0, memregion("bios")->base());
+ membank("bank1")->configure_entry(1, memregion(I8048_TAG)->base());
+ m_maincpu->memory().space(AS_PROGRAM)->install_readwrite_bank(0x0000, 0x03ff, "bank1");
+ membank("bank1")->set_entry(0);
+
+ /* allocate external RAM */
+ m_ext_ram = auto_alloc_array(machine(), UINT8, 0x400);
+}
+
+void advision_state::machine_reset()
+{
+ /* enable internal ROM */
+ device_set_input_line(m_maincpu, MCS48_INPUT_EA, CLEAR_LINE);
+ membank("bank1")->set_entry(0);
+
+ /* reset sound CPU */
+ device_set_input_line(m_soundcpu, INPUT_LINE_RESET, ASSERT_LINE);
+
+ m_rambank = 0x300;
+ m_frame_start = 0;
+ m_video_enable = 0;
+ m_sound_cmd = 0;
+}
+
+/* Bank Switching */
+
+WRITE8_MEMBER( advision_state::bankswitch_w )
+{
+ int ea = BIT(data, 2);
+
+ device_set_input_line(m_maincpu, MCS48_INPUT_EA, ea ? ASSERT_LINE : CLEAR_LINE);
+
+ membank("bank1")->set_entry(ea);
+
+ m_rambank = (data & 0x03) << 8;
+}
+
+/* External RAM */
+
+READ8_MEMBER( advision_state::ext_ram_r )
+{
+ UINT8 data = m_ext_ram[m_rambank + offset];
+
+ if (!m_video_enable)
+ {
+ /* the video hardware interprets reads as writes */
+ vh_write(data);
+ }
+
+ if (m_video_bank == 0x06)
+ {
+ device_set_input_line(m_soundcpu, INPUT_LINE_RESET, (data & 0x01) ? CLEAR_LINE : ASSERT_LINE);
+ }
+
+ return data;
+}
+
+WRITE8_MEMBER( advision_state::ext_ram_w )
+{
+ m_ext_ram[m_rambank + offset] = data;
+}
+
+/* Sound */
+
+READ8_MEMBER( advision_state::sound_cmd_r )
+{
+ return m_sound_cmd;
+}
+
+void advision_state::update_dac()
+{
+ if (m_sound_g == 0 && m_sound_d == 0)
+ m_dac->write_unsigned8(0xff);
+ else if (m_sound_g == 1 && m_sound_d == 1)
+ m_dac->write_unsigned8(0x80);
+ else
+ m_dac->write_unsigned8(0x00);
+}
+
+WRITE8_MEMBER( advision_state::sound_g_w )
+{
+ m_sound_g = data & 0x01;
+
+ update_dac();
+}
+
+WRITE8_MEMBER( advision_state::sound_d_w )
+{
+ m_sound_d = data & 0x01;
+
+ update_dac();
+}
+
+/* Video */
+
+WRITE8_MEMBER( advision_state::av_control_w )
+{
+ m_sound_cmd = data >> 4;
+
+ if ((m_video_enable == 0x00) && (data & 0x10))
+ {
+ vh_update(m_video_hpos);
+
+ m_video_hpos++;
+
+ if (m_video_hpos > 255)
+ {
+ m_video_hpos = 0;
+ logerror("HPOS OVERFLOW\n");
+ }
+ }
+
+ m_video_enable = data & 0x10;
+ m_video_bank = (data & 0xe0) >> 5;
+}
+
+READ8_MEMBER( advision_state::vsync_r )
+{
+ if (m_frame_start)
+ {
+ m_frame_start = 0;
+
+ return 0;
+ }
+ else
+ {
+ return 1;
+ }
+}
+
+/* Input */
+
+READ8_MEMBER( advision_state::controller_r )
+{
+ // Get joystick switches
+ UINT8 in = ioport("joystick")->read();
+ UINT8 data = in | 0x0f;
+
+ // Get buttons
+ if (in & 0x02) data = data & 0xf7; /* Button 3 */
+ if (in & 0x08) data = data & 0xcf; /* Button 1 */
+ if (in & 0x04) data = data & 0xaf; /* Button 2 */
+ if (in & 0x01) data = data & 0x6f; /* Button 4 */
+
+ return data & 0xf8;
+}
diff --git a/src/mess/machine/aim65.c b/src/mess/machine/aim65.c
new file mode 100644
index 00000000000..27756ef6377
--- /dev/null
+++ b/src/mess/machine/aim65.c
@@ -0,0 +1,419 @@
+/******************************************************************************
+
+ AIM65
+
+******************************************************************************/
+
+
+#include "includes/aim65.h"
+
+
+/******************************************************************************
+ Interrupt handling
+******************************************************************************/
+
+/* STEP/RUN
+ *
+ * Switch S2 (STEP/RUN) causes AIM 65 to operate either in the RUN mode or the
+ * single STEP mode. In the STEP mode, the NMI interrupt line is driven low
+ * when SYNC and O2 go high during instruction execution if the address lines
+ * are outside the A000-FFFF range. The NMI interrupt occurs on the high to
+ * low transition of the NMI line. The Monitor software will trace instructions
+ * and register, outside the Monitor instruction address range if the trace
+ * modes are selected and the NMI Interrupt Routine is not bypassed.
+ */
+
+
+
+/******************************************************************************
+ 6821 PIA
+******************************************************************************/
+
+/* PA0: A0 (Address)
+ * PA1: A1 (Address)
+ * PA2: CE1 (Chip enable)
+ * PA3: CE2 (Chip enable)
+ * PA4: CE3 (Chip enable)
+ * PA5: CE4 (Chip enable)
+ * PA6: CE5 (Chip enable)
+ * PA7: W (Write enable)
+ * PB0-6: D0-D6 (Data)
+ * PB7: CU (Cursor)
+ */
+
+static void dl1416_update(device_t *device, int index)
+{
+ aim65_state *state = device->machine().driver_data<aim65_state>();
+ dl1416_ce_w(device, state->m_pia_a & (0x04 << index));
+ dl1416_wr_w(device, BIT(state->m_pia_a, 7));
+ dl1416_cu_w(device, BIT(state->m_pia_b, 7));
+ dl1416_data_w(device, state->m_pia_a & 0x03, state->m_pia_b & 0x7f);
+}
+
+static void aim65_pia(running_machine &machine)
+{
+ dl1416_update(machine.device("ds1"), 0);
+ dl1416_update(machine.device("ds2"), 1);
+ dl1416_update(machine.device("ds3"), 2);
+ dl1416_update(machine.device("ds4"), 3);
+ dl1416_update(machine.device("ds5"), 4);
+}
+
+
+WRITE8_MEMBER( aim65_state::aim65_pia_a_w )
+{
+ m_pia_a = data;
+ aim65_pia(machine());
+}
+
+
+WRITE8_MEMBER( aim65_state::aim65_pia_b_w )
+{
+ m_pia_b = data;
+ aim65_pia(machine());
+}
+
+
+void aim65_update_ds1(device_t *device, int digit, int data)
+{
+ output_set_digit_value(0 + (digit ^ 3), data);
+}
+
+void aim65_update_ds2(device_t *device, int digit, int data)
+{
+ output_set_digit_value(4 + (digit ^ 3), data);
+}
+
+void aim65_update_ds3(device_t *device, int digit, int data)
+{
+ output_set_digit_value(8 + (digit ^ 3), data);
+}
+
+void aim65_update_ds4(device_t *device, int digit, int data)
+{
+ output_set_digit_value(12 + (digit ^ 3), data);
+}
+
+void aim65_update_ds5(device_t *device, int digit, int data)
+{
+ output_set_digit_value(16 + (digit ^ 3), data);
+}
+
+
+
+/******************************************************************************
+ 6532 RIOT
+******************************************************************************/
+
+
+READ8_MEMBER( aim65_state::aim65_riot_b_r )
+{
+ static const char *const keynames[] =
+ {
+ "keyboard_0", "keyboard_1", "keyboard_2", "keyboard_3",
+ "keyboard_4", "keyboard_5", "keyboard_6", "keyboard_7"
+ };
+
+ UINT8 row, data = 0xff;
+
+ /* scan keyboard rows */
+ for (row = 0; row < 8; row++)
+ {
+ if (!BIT(m_riot_port_a, row))
+ data &= ioport(keynames[row])->read();
+ }
+
+ return data;
+}
+
+
+WRITE8_MEMBER( aim65_state::aim65_riot_a_w )
+{
+ m_riot_port_a = data;
+}
+
+
+
+/***************************************************************************
+ DRIVER INIT
+***************************************************************************/
+
+MACHINE_START( aim65 )
+{
+ aim65_state *state = machine.driver_data<aim65_state>();
+ ram_device *ram = machine.device<ram_device>(RAM_TAG);
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ /* Init RAM */
+ space->install_ram(0x0000, ram->size() - 1, ram->pointer());
+
+ state->m_pb_save = 0;
+}
+
+
+/* RESET
+ *
+ * Pushbutton switch S1 initiates RESET of the AIM65 hardware and software.
+ * Timer Z4 holds the RES low for at least 15 ms from the time the pushbutton
+ * is released. RES is routed to the R6502 CPU, the Monitor R6522 (Z32), the
+ * Monitor R6532 RIOT (Z33), the user R6522 VIA (Z1), and the display R6520 PIA
+ * (U1). To initiate the device RESET function is also routed to the expansion
+ * connector for off-board RESET functions. The Monitor performs a software
+ * reset when the RES line goes high.
+ */
+
+
+/******************************************************************************
+ Cassette
+******************************************************************************/
+
+WRITE8_MEMBER( aim65_state::aim65_pb_w )
+{
+/*
+ d7 = cass out (both decks)
+ d5 = cass2 motor
+ d4 = cass1 motor
+ d2 = tty out (not emulated)
+ d0/1 = printer data (not emulated)
+*/
+
+ UINT8 bits = data ^ m_pb_save;
+ m_pb_save = data;
+
+ if (BIT(bits, 7))
+ {
+ m_cass1->output(BIT(data, 7) ? -1.0 : +1.0);
+ m_cass2->output(BIT(data, 7) ? -1.0 : +1.0);
+ }
+
+ if (BIT(bits, 5))
+ {
+ if (BIT(data, 5))
+ m_cass2->change_state(CASSETTE_MOTOR_DISABLED,CASSETTE_MASK_MOTOR);
+ else
+ m_cass2->change_state(CASSETTE_MOTOR_ENABLED,CASSETTE_MASK_MOTOR);
+ }
+
+ if (BIT(bits, 4))
+ {
+ if (BIT(data, 4))
+ m_cass1->change_state(CASSETTE_MOTOR_DISABLED,CASSETTE_MASK_MOTOR);
+ else
+ m_cass1->change_state(CASSETTE_MOTOR_ENABLED,CASSETTE_MASK_MOTOR);
+ }
+}
+
+
+READ8_MEMBER( aim65_state::aim65_pb_r )
+{
+/*
+ d7 = cassette in (deck 1)
+ d6 = tty in (not emulated)
+ d3 = kb/tty switch
+*/
+
+ UINT8 data = ioport("switches")->read();
+ data |= (m_cass1->input() > +0.03) ? 0x80 : 0;
+ data |= 0x40; // TTY must be H if not used.
+ data |= m_pb_save & 0x37;
+ return data;
+}
+
+
+/******************************************************************************
+ Printer
+******************************************************************************/
+
+#ifdef UNUSED_FUNCTION
+/*
+
+2012-01-24 Printer code removed [Robbbert]
+
+From here to the end is not compiled. It is the remnants of the old printer
+code. Have a look at version 0.114 or 0.115 for the original working code.
+
+I've left it here for the idly curious.
+
+The system sends out the pattern of dots to the 'dot-matrix' print-head.
+
+This is why we can't simply replace it with a Centronics-like 'Printer'
+device - the output will be gibberish.
+*/
+
+
+
+/*
+ aim65 thermal printer (20 characters)
+ 10 heat elements (place on 1 line, space between 2 characters(about 14dots))
+ (pa0..pa7,pb0,pb1 1 heat element on)
+
+ cb2 0 motor, heat elements on
+ cb1 output start!?
+ ca1 input
+
+ normally printer 5x7 characters
+ (horizontal movement limits not known, normally 2 dots between characters)
+
+ 3 dots space between lines?
+*/
+
+
+/* Part of aim65_pb_w
+
+ data &= 0x03;
+
+ if (m_flag_b == 0)
+ {
+ printerRAM[(m_printer_y * 20) + m_printer_x ] |= (data << 8);
+ m_flag_b = 1;
+ }
+*/
+
+
+/* Items for driver state
+
+ emu_timer *m_print_timer;
+ int m_printer_x;
+ int m_printer_y;
+ bool m_printer_dir;
+ bool m_flag_a;
+ bool m_flag_b;
+ bool m_printer_level;
+ UINT16 *m_printerRAM;
+*/
+
+
+/* Other items from H file
+VIDEO_START( aim65 );
+VIDEO_UPDATE( aim65 );
+*/
+
+
+/* From 6522 config
+DRIVER_MEMBER(aim65_state, aim65_pa_w), // out port A
+DRIVER_MEMBER(aim65_state, aim65_printer_on), // out CB2
+*/
+
+
+/* From Machine Config
+ MCFG_VIDEO_START(aim65)
+ MCFG_VIDEO_UPDATE(aim65)
+*/
+
+
+static TIMER_CALLBACK(aim65_printer_timer)
+{
+ aim65_state *state = machine.driver_data<aim65_state>();
+ via6522_device *via_0 = machine.device<via6522_device>("via6522_0");
+
+ via_0->write_cb1(state->m_printer_level);
+ via_0->write_cb1(!state->m_printer_level);
+ state->m_printer_level ^= 1;
+
+ if (state->m_printer_dir)
+ {
+ if (state->m_printer_x > 0)
+ state->m_printer_x--;
+ else
+ {
+ state->m_printer_dir = 0;
+ state->m_printer_x++;
+ state->m_printer_y++;
+ }
+ }
+ else
+ {
+ if (state->m_printer_x < 9)
+ state->m_printer_x++;
+ else
+ {
+ state->m_printer_dir = 1;
+ state->m_printer_x--;
+ state->m_printer_y++;
+ }
+ }
+
+ if (state->m_printer_y > 500) state->m_printer_y = 0;
+
+ state->m_flag_a=0;
+ state->m_flag_b=0;
+}
+
+
+WRITE8_MEMBER( aim65_state::aim65_printer_on )
+{
+ via6522_device *via_0 = machine().device<via6522_device>("via6522_0");
+ if (!data)
+ {
+ m_printer_x=0;
+ m_printer_y++;
+ if (m_printer_y > 500) m_printer_y = 0;
+ m_flag_a = m_flag_b=0;
+ via_0->write_cb1(0);
+ m_print_timer->adjust(attotime::zero, 0, attotime::from_usec(10));
+ m_printer_level = 1;
+ }
+ else
+ m_print_timer->reset();
+}
+
+
+WRITE8_MEMBER( aim65_state::aim65_pa_w )
+{
+// All bits are for printer data (not emulated)
+ if (m_flag_a == 0)
+ {
+ m_printerRAM[(m_printer_y * 20) + m_printer_x] |= data;
+ m_flag_a = 1;
+ }
+}
+
+VIDEO_START( aim65 )
+{
+ aim65_state *state = machine.driver_data<aim65_state>();
+ state->m_print_timer = machine.scheduler().timer_alloc(FUNC(aim65_printer_timer));
+ state->m_printerRAM = auto_alloc_array(machine, UINT16, (600 * 10 * 2) / 2);
+ memset(state->m_printerRAM, 0, videoram_size);
+ VIDEO_START_CALL(generic);
+ state->m_printer_x = 0;
+ state->m_printer_y = 0;
+ state->m_printer_dir = 0;
+ state->m_flag_a = 0;
+ state->m_flag_b = 0;
+ state->m_printer_level = 0;
+}
+
+SCREEN_UPDATE( aim65 )
+{
+ aim65_state *state = screen.machine().driver_data<aim65_state>();
+ /* Display printer output */
+ bool dir = 1;
+ UINT8 b,x,pen;
+ UINT16 y;
+
+ for (y = 0; y<500; y++)
+ {
+ for(x = 0; x< 10; x++)
+ {
+ if (dir == 1)
+ data = state->m_printerRAM[y * 10 + x];
+ else
+ data = state->m_printerRAM[(y * 10) + (9 - x)];
+
+
+ for (b = 0; b<10; b++)
+ {
+ pen = screen.machine().pens[BIT(data, 0) ? 2 : 0];
+ plot_pixel(bitmap,700 - ((b * 10) + x), y, pen);
+ data >>= 1;
+ }
+ }
+
+ dir ^= 1;
+ }
+ return 0;
+}
+
+
+#endif
+
diff --git a/src/mess/machine/amigacd.c b/src/mess/machine/amigacd.c
new file mode 100644
index 00000000000..c1463320f1f
--- /dev/null
+++ b/src/mess/machine/amigacd.c
@@ -0,0 +1,539 @@
+/***************************************************************************
+
+ Amiga CD-ROM controller emulation
+
+Notes:
+Many thanks to Toni Wilen for all the help and information about the
+DMAC controller.
+
+***************************************************************************/
+
+
+#include "emu.h"
+#include "includes/amiga.h"
+#include "amigacd.h"
+#include "machine/6525tpi.h"
+#include "machine/6526cia.h"
+#include "machine/wd33c93.h"
+#include "imagedev/chd_cd.h"
+#include "machine/matsucd.h"
+
+
+#define VERBOSE_DMAC 0
+
+#define LOG(x) do { if (VERBOSE_DMAC) logerror x; } while (0)
+
+/* constants */
+#define CD_SECTOR_TIME (1000/((300*1024)/2048)) /* 2X CDROM sector time in msec (300KBps) */
+
+/***************************************************************************
+
+ DMAC
+
+***************************************************************************/
+
+/*
+ * value to go into DAWR
+ */
+#define DAWR_ATZSC 3 /* according to A3000T service-manual */
+
+/*
+ * bits defined for CNTR
+ */
+#define CNTR_TCEN (1<<7) /* Terminal Count Enable */
+#define CNTR_PREST (1<<6) /* Perp Reset (not implemented :-((( ) */
+#define CNTR_PDMD (1<<5) /* Perp Device Mode Select (1=SCSI,0=XT/AT) */
+#define CNTR_INTEN (1<<4) /* Interrupt Enable */
+#define CNTR_DDIR (1<<3) /* Device Direction. 1==rd host, wr to perp */
+
+/*
+ * bits defined for ISTR
+ */
+#define ISTR_INTX (1<<8) /* XT/AT Interrupt pending */
+#define ISTR_INT_F (1<<7) /* Interrupt Follow */
+#define ISTR_INTS (1<<6) /* SCSI Peripheral Interrupt */
+#define ISTR_E_INT (1<<5) /* End-Of-Process Interrupt */
+#define ISTR_INT_P (1<<4) /* Interrupt Pending */
+#define ISTR_UE_INT (1<<3) /* Under-Run FIFO Error Interrupt */
+#define ISTR_OE_INT (1<<2) /* Over-Run FIFO Error Interrupt */
+#define ISTR_FF_FLG (1<<1) /* FIFO-Full Flag */
+#define ISTR_FE_FLG (1<<0) /* FIFO-Empty Flag */
+
+typedef struct
+{
+ UINT16 istr; /* Interrupt Status Register (R) */
+ UINT16 cntr; /* Control Register (RW) */
+ UINT32 wtc; /* Word Transfer Count Register (RW) */
+ UINT32 acr; /* Address Count Register (RW) */
+ UINT16 dawr; /* DACK Width Register (W) */
+ emu_timer *dma_timer;
+} _dmac_data;
+
+static _dmac_data dmac_data;
+
+static void check_interrupts( running_machine &machine )
+{
+ /* if interrupts are disabled, bail */
+ if ( (dmac_data.cntr & CNTR_INTEN) == 0 )
+ return;
+
+ /* if no interrupts are pending, bail */
+ if ( (dmac_data.istr & ISTR_INT_P) == 0 )
+ return;
+
+ /* otherwise, generate the IRQ */
+ amiga_custom_w(machine.device("maincpu")->memory().space(AS_PROGRAM), REG_INTREQ, 0x8000 | INTENA_PORTS, 0xffff);
+}
+
+static TIMER_CALLBACK(dmac_dma_proc)
+{
+ amiga_state *state = machine.driver_data<amiga_state>();
+ while( dmac_data.wtc > 0 )
+ {
+ UINT16 dat16;
+ UINT8 dat8;
+
+ if ( matsucd_get_next_byte( &dat8 ) < 0 )
+ break;
+
+ dat16 = dat8;
+
+ if ( matsucd_get_next_byte( &dat8 ) < 0 )
+ break;
+
+ dat16 <<= 8;
+ dat16 |= dat8;
+
+ (*state->m_chip_ram_w)(state, dmac_data.acr, dat16);
+
+ dmac_data.acr += 2;
+ dmac_data.wtc--;
+ }
+
+ if ( dmac_data.wtc > 0 )
+ {
+ matsucd_read_next_block();
+ dmac_data.dma_timer->adjust(attotime::from_msec( CD_SECTOR_TIME ));
+ }
+ else
+ {
+ dmac_data.istr |= ISTR_INT_P | ISTR_E_INT;
+ check_interrupts( machine );
+ }
+}
+
+static READ16_HANDLER( amiga_dmac_r )
+{
+ offset &= 0xff;
+
+ switch( offset )
+ {
+ case 0x20:
+ {
+ UINT8 v = dmac_data.istr;
+ LOG(( "DMAC: PC=%08x - ISTR Read(%04x)\n", cpu_get_pc(&space->device()), dmac_data.istr ));
+
+ dmac_data.istr &= ~0x0f;
+ return v;
+ }
+ break;
+
+ case 0x21:
+ {
+ LOG(( "DMAC: PC=%08x - CNTR Read(%04x)\n", cpu_get_pc(&space->device()), dmac_data.cntr ));
+ return dmac_data.cntr;
+ }
+ break;
+
+ case 0x40: /* wtc hi */
+ {
+ LOG(( "DMAC: PC=%08x - WTC HI Read\n", cpu_get_pc(&space->device()) ));
+ return (dmac_data.wtc >> 16);
+ }
+ break;
+
+ case 0x41: /* wtc lo */
+ {
+ LOG(( "DMAC: PC=%08x - WTC LO Read\n", cpu_get_pc(&space->device()) ));
+ return dmac_data.wtc;
+ }
+ break;
+
+ case 0x42: /* acr hi */
+ {
+ LOG(( "DMAC: PC=%08x - ACR HI Read\n", cpu_get_pc(&space->device()) ));
+ return (dmac_data.acr >> 16);
+ }
+ break;
+
+ case 0x43: /* acr lo */
+ {
+ LOG(( "DMAC: PC=%08x - ACR LO Read\n", cpu_get_pc(&space->device()) ));
+ return dmac_data.acr;
+ }
+ break;
+
+ case 0x48: /* wd33c93 SCSI expansion */
+ case 0x49:
+ {
+ LOG(( "DMAC: PC=%08x - WD33C93 Read(%d)\n", cpu_get_pc(&space->device()), offset & 1 ));
+ return 0x00; /* Not available without SCSI expansion */
+ }
+ break;
+
+ case 0x50:
+ {
+ LOG(( "DMAC: PC=%08x - CDROM RESP Read\n", cpu_get_pc(&space->device()) ));
+ return matsucd_response_r(space->machine());
+ }
+ break;
+
+ case 0x51: /* XT IO */
+ case 0x52:
+ case 0x53:
+ {
+ LOG(( "DMAC: PC=%08x - XT IO Read(%d)\n", cpu_get_pc(&space->device()), (offset & 3)-1 ));
+ return 0xff;
+ }
+ break;
+
+ case 0x58: /* TPI6525 */
+ 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:
+ {
+ device_t *tpi = space->machine().device("tpi6525");
+ LOG(( "DMAC: PC=%08x - TPI6525 Read(%d)\n", cpu_get_pc(&space->device()), (offset - 0x58) ));
+ return tpi6525_r(tpi, offset - 0x58);
+ }
+ break;
+
+ case 0x70: /* DMA start strobe */
+ {
+ LOG(( "DMAC: PC=%08x - DMA Start Strobe\n", cpu_get_pc(&space->device()) ));
+ dmac_data.dma_timer->adjust(attotime::from_msec( CD_SECTOR_TIME ));
+ }
+ break;
+
+ case 0x71: /* DMA stop strobe */
+ {
+ LOG(( "DMAC: PC=%08x - DMA Stop Strobe\n", cpu_get_pc(&space->device()) ));
+ dmac_data.dma_timer->reset( );
+ }
+ break;
+
+ case 0x72: /* Clear IRQ strobe */
+ {
+ LOG(( "DMAC: PC=%08x - IRQ Clear Strobe\n", cpu_get_pc(&space->device()) ));
+ dmac_data.istr &= ~ISTR_INT_P;
+ }
+ break;
+
+ case 0x74: /* Flush strobe */
+ {
+ LOG(( "DMAC: PC=%08x - Flush Strobe\n", cpu_get_pc(&space->device()) ));
+ dmac_data.istr |= ISTR_FE_FLG;
+ }
+ break;
+
+ default:
+ logerror( "DMAC-READ: PC=%08x, offset = %02x\n", cpu_get_pc(&space->device()), offset );
+ break;
+ }
+
+ return 0;
+}
+
+static WRITE16_HANDLER( amiga_dmac_w )
+{
+ offset &= 0xff;
+
+ switch( offset )
+ {
+ case 0x21: /* control write */
+ {
+ LOG(( "DMAC: PC=%08x - CNTR Write(%04x)\n", cpu_get_pc(&space->device()), data ));
+ dmac_data.cntr = data;
+ check_interrupts(space->machine());
+ }
+ break;
+
+ case 0x40: /* wtc hi */
+ {
+ LOG(( "DMAC: PC=%08x - WTC HI Write - data = %04x\n", cpu_get_pc(&space->device()), data ));
+ dmac_data.wtc &= 0x0000ffff;
+ dmac_data.wtc |= ((UINT32)data) << 16;
+ }
+ break;
+
+ case 0x41: /* wtc lo */
+ {
+ LOG(( "DMAC: PC=%08x - WTC LO Write - data = %04x\n", cpu_get_pc(&space->device()), data ));
+ dmac_data.wtc &= 0xffff0000;
+ dmac_data.wtc |= data;
+ }
+ break;
+
+ case 0x42: /* acr hi */
+ {
+ LOG(( "DMAC: PC=%08x - ACR HI Write - data = %04x\n", cpu_get_pc(&space->device()), data ));
+ dmac_data.acr &= 0x0000ffff;
+ dmac_data.acr |= ((UINT32)data) << 16;
+ }
+ break;
+
+ case 0x43: /* acr lo */
+ {
+ LOG(( "DMAC: PC=%08x - ACR LO Write - data = %04x\n", cpu_get_pc(&space->device()), data ));
+ dmac_data.acr &= 0xffff0000;
+ dmac_data.acr |= data;
+ }
+ break;
+
+ case 0x47: /* dawr */
+ {
+ LOG(( "DMAC: PC=%08x - DAWR Write - data = %04x\n", cpu_get_pc(&space->device()), data ));
+ dmac_data.dawr = data;
+ }
+ break;
+
+ case 0x48: /* wd33c93 SCSI expansion */
+ case 0x49:
+ {
+ LOG(( "DMAC: PC=%08x - WD33C93 Write(%d) - data = %04x\n", cpu_get_pc(&space->device()), offset & 1, data ));
+ /* Not available without SCSI expansion */
+ }
+ break;
+
+ case 0x50:
+ {
+ LOG(( "DMAC: PC=%08x - CDROM CMD Write - data = %04x\n", cpu_get_pc(&space->device()), data ));
+ matsucd_command_w(space->machine(), data );
+ }
+ break;
+
+ case 0x58: /* TPI6525 */
+ 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:
+ {
+ device_t *tpi = space->machine().device("tpi6525");
+ LOG(( "DMAC: PC=%08x - TPI6525 Write(%d) - data = %04x\n", cpu_get_pc(&space->device()), (offset - 0x58), data ));
+ tpi6525_w(tpi, offset - 0x58, data);
+ }
+ break;
+
+ case 0x70: /* DMA start strobe */
+ {
+ LOG(( "DMAC: PC=%08x - DMA Start Strobe\n", cpu_get_pc(&space->device()) ));
+ dmac_data.dma_timer->adjust(attotime::from_msec( CD_SECTOR_TIME ));
+ }
+ break;
+
+ case 0x71: /* DMA stop strobe */
+ {
+ LOG(( "DMAC: PC=%08x - DMA Stop Strobe\n", cpu_get_pc(&space->device()) ));
+ dmac_data.dma_timer->reset( );
+ }
+ break;
+
+ case 0x72: /* Clear IRQ strobe */
+ {
+ LOG(( "DMAC: PC=%08x - IRQ Clear Strobe\n", cpu_get_pc(&space->device()) ));
+ dmac_data.istr &= ~ISTR_INT_P;
+ }
+ break;
+
+ case 0x74: /* Flush Strobe */
+ {
+ LOG(( "DMAC: PC=%08x - Flush Strobe\n", cpu_get_pc(&space->device()) ));
+ dmac_data.istr |= ISTR_FE_FLG;
+ }
+ break;
+
+ default:
+ logerror( "DMAC-WRITE: PC=%08x, offset = %02x, data = %04x\n", cpu_get_pc(&space->device()), offset, data );
+ break;
+ }
+}
+
+/***************************************************************************
+
+ Autoconfig
+
+***************************************************************************/
+
+static void dmac_install(running_machine &machine, offs_t base)
+{
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ space->install_legacy_read_handler(base, base + 0xFFFF, FUNC(amiga_dmac_r));
+ space->install_legacy_write_handler(base, base + 0xFFFF, FUNC(amiga_dmac_w));
+}
+
+static void dmac_uninstall(running_machine &machine, offs_t base)
+{
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ space->unmap_readwrite(base, base + 0xFFFF);
+}
+
+static const amiga_autoconfig_device dmac_device =
+{
+ 0, /* link into free memory list */
+ 0, /* ROM vector offset valid */
+ 0, /* multiple devices on card */
+ 1, /* number of 64k pages */
+ 3, /* product number (DMAC) */
+ 0, /* prefer 8MB address space */
+ 0, /* can be shut up */
+ 0x0202, /* manufacturers number (Commodore) */
+ 0, /* serial number */
+ 0, /* ROM vector offset */
+ NULL, /* interrupt control read */
+ NULL, /* interrupt control write */
+ dmac_install, /* memory installation */
+ dmac_uninstall /* memory uninstallation */
+};
+
+/***************************************************************************
+
+ TPI6525
+
+***************************************************************************/
+
+READ8_DEVICE_HANDLER( amigacd_tpi6525_portc_r )
+{
+ int ret = 0;
+
+ if ( (tpi6525_get_ddr_c(device) & 0x04) == 0 ) /* if pin 2 is set to input */
+ {
+ ret |= matsucd_stch_r() ? 0x00 : 0x04; /* read status change signal */
+ }
+
+ if ( (tpi6525_get_ddr_c(device) & 0x08) == 0 ) /* if pin 3 is set to input */
+ ret |= matsucd_sten_r() ? 0x08 : 0x00; /* read enable signal */
+
+ return ret;
+}
+
+WRITE8_DEVICE_HANDLER( amigacd_tpi6525_portb_w )
+{
+ if ( tpi6525_get_ddr_b(device) & 0x01 ) /* if pin 0 is set to output */
+ matsucd_cmd_w( data & 1 ); /* write to the /CMD signal */
+
+ if ( tpi6525_get_ddr_b(device) & 0x02 ) /* if pin 1 is set to output */
+ matsucd_enable_w( data & 2 ); /* write to the /ENABLE signal */
+}
+
+static emu_timer *tp6525_delayed_timer;
+
+static TIMER_CALLBACK(tp6525_delayed_irq)
+{
+ amiga_state *state = machine.driver_data<amiga_state>();
+ (void)param;
+
+ if ( (CUSTOM_REG(REG_INTREQ) & INTENA_PORTS) == 0 )
+ {
+ amiga_custom_w(machine.device("maincpu")->memory().space(AS_PROGRAM), REG_INTREQ, 0x8000 | INTENA_PORTS, 0xffff);
+ }
+ else
+ {
+ tp6525_delayed_timer->adjust(attotime::from_msec(1));
+ }
+}
+
+static void amigacd_tpi6525_irq_trampoline(device_t *device, int level)
+{
+ amiga_state *state = device->machine().driver_data<amiga_state>();
+ LOG(( "TPI6525 Interrupt: level = %d\n", level ));
+
+ if ( level )
+ {
+ if ( (CUSTOM_REG(REG_INTREQ) & INTENA_PORTS) == 0 )
+ {
+ amiga_custom_w(device->machine().device("maincpu")->memory().space(AS_PROGRAM), REG_INTREQ, 0x8000 | INTENA_PORTS, 0xffff);
+ }
+ else
+ {
+ /* we *have to* deliver the irq, so if we can't, delay it and try again later */
+ tp6525_delayed_timer->adjust(attotime::from_msec(1));
+ }
+ }
+}
+
+WRITE_LINE_DEVICE_HANDLER( amigacd_tpi6525_irq )
+{
+ amigacd_tpi6525_irq_trampoline(device, state);
+}
+
+static void cdrom_status_enabled( running_machine &machine, int level )
+{
+ device_t *tpi = machine.device("tpi6525");
+
+ /* PC3 on the 6525 */
+ tpi6525_i3_w(tpi, level);
+}
+
+static void cdrom_status_change( running_machine &machine, int level )
+{
+ device_t *tpi = machine.device("tpi6525");
+
+ /* invert */
+ level = level ? 0 : 1;
+
+ /* PC2 on the 6525 */
+ tpi6525_i2_w(tpi, level);
+}
+
+static void cdrom_subcode_ready( running_machine &machine, int level )
+{
+ device_t *tpi = machine.device("tpi6525");
+
+ /* PC1 on the 6525 */
+ tpi6525_i1_w(tpi, level);
+}
+
+MACHINE_START( amigacd )
+{
+ /* initialize the dmac */
+ memset( &dmac_data, 0, sizeof( dmac_data ) );
+
+ dmac_data.dma_timer = machine.scheduler().timer_alloc(FUNC(dmac_dma_proc));
+ tp6525_delayed_timer = machine.scheduler().timer_alloc(FUNC(tp6525_delayed_irq));
+
+ /* set up DMAC with autoconfig */
+ amiga_add_autoconfig( machine, &dmac_device );
+
+ matsucd_init( machine.device<cdrom_image_device>("cdrom"), "cdda" );
+}
+
+MACHINE_RESET( amigacd )
+{
+ /* initialize the cdrom */
+ matsucd_set_status_enabled_callback( cdrom_status_enabled );
+ matsucd_set_status_changed_callback( cdrom_status_change );
+ matsucd_set_subcode_ready_callback( cdrom_subcode_ready );
+}
diff --git a/src/mess/machine/amigacd.h b/src/mess/machine/amigacd.h
new file mode 100644
index 00000000000..d2ed908a0fc
--- /dev/null
+++ b/src/mess/machine/amigacd.h
@@ -0,0 +1,14 @@
+#ifndef __AMIGACD_H__
+#define __AMIGACD_H__
+
+
+MACHINE_START( amigacd );
+MACHINE_RESET( amigacd );
+
+/* 6525tpi */
+READ8_DEVICE_HANDLER( amigacd_tpi6525_portc_r );
+WRITE8_DEVICE_HANDLER( amigacd_tpi6525_portb_w );
+WRITE_LINE_DEVICE_HANDLER( amigacd_tpi6525_irq );
+
+
+#endif /* __AMIGACD_H__ */
diff --git a/src/mess/machine/amigacrt.c b/src/mess/machine/amigacrt.c
new file mode 100644
index 00000000000..0298d617e9b
--- /dev/null
+++ b/src/mess/machine/amigacrt.c
@@ -0,0 +1,463 @@
+/***************************************************************************
+
+ Amiga cartridge emulation
+
+TODO:
+- Investigate why the AR2/3 sometimes garble the video on exit from the cart
+- Add Nordic Power and similar carts
+- Add HRTMon A1200 cart
+
+***************************************************************************/
+
+
+#include "emu.h"
+#include "includes/amiga.h"
+#include "cpu/m68000/m68000.h"
+#include "machine/6526cia.h"
+#include "machine/amigacrt.h"
+
+enum
+{
+ /* supported cartridges */
+ ACTION_REPLAY = 0,
+ ACTION_REPLAY_MKII,
+ ACTION_REPLAY_MKIII
+};
+
+typedef struct
+{
+ int cart_type;
+ int ar1_spurious;
+ UINT16 ar23_mode;
+} amigacrt_t;
+static amigacrt_t amigacrt;
+
+/***************************************************************************
+
+ Utilities
+
+***************************************************************************/
+
+static int check_kickstart_12_13( running_machine &machine, const char *cart_name )
+{
+ UINT16 * ksmem = (UINT16 *)(*machine.root_device().memregion( "user1" ));
+
+ if ( ksmem[2] == 0x00FC )
+ return 1;
+
+ logerror( "%s requires Kickstart version 1.2 or 1.3 - Cart not installed\n", cart_name );
+
+ return 0;
+}
+
+/***************************************************************************
+
+ Amiga Action Replay 1
+
+ Whenever you push the button, an NMI interrupt is generated.
+
+ The cartridge protects itself from being removed from memory by
+ generating an interrupt whenever either the spurious interrupt
+ vector is written at $60, or the nmi interrupt vector is written at
+ $7c. If the spurious interrupt vector at $60 is written, then
+ a NMI is generated, and the spurious irq vector is restored. If the
+ NMI vector at $7c is written, then a spurious interrupt is generated,
+ and the NMI vector is restored.
+
+ When breakpoints are set, the target address is replaced by a trap
+ instruction, and the original contents of the address are kept in
+ the cartridge's RAM. A trap handler is installed pointing to $40
+ in RAM, where code that clears memory address $60 followed by two
+ nops are written. There seems to be a small delay between the write
+ to $60 and until the actual NMI is generated, since the cart expects
+ the PC to be at $46 (at the second nop).
+
+***************************************************************************/
+
+static IRQ_CALLBACK(amiga_ar1_irqack)
+{
+ if ( irqline == 7 && amigacrt.ar1_spurious )
+ {
+ return M68K_INT_ACK_SPURIOUS;
+ }
+
+ return (24+irqline);
+}
+
+static TIMER_CALLBACK( amiga_ar1_delayed_nmi )
+{
+ (void)param;
+ cputag_set_input_line(machine, "maincpu", 7, PULSE_LINE);
+}
+
+static void amiga_ar1_nmi( running_machine &machine )
+{
+ amiga_state *state = machine.driver_data<amiga_state>();
+ /* get the cart's built-in ram */
+ UINT16 *ar_ram = (UINT16 *)machine.device("maincpu")->memory().space(AS_PROGRAM)->get_write_ptr(0x9fc000);
+
+ if ( ar_ram != NULL )
+ {
+ int i;
+
+ /* copy custom register values */
+ for( i = 0; i < 256; i++ )
+ ar_ram[0x1800+i] = CUSTOM_REG(i);
+
+ /* trigger NMI irq */
+ amigacrt.ar1_spurious = 0;
+ machine.scheduler().timer_set(machine.device<cpu_device>("maincpu")->cycles_to_attotime(28), FUNC(amiga_ar1_delayed_nmi));
+ }
+}
+
+static WRITE16_HANDLER( amiga_ar1_chipmem_w )
+{
+ amiga_state *state = space->machine().driver_data<amiga_state>();
+ int pc = cpu_get_pc(&space->device());
+
+ /* see if we're inside the AR1 rom */
+ if ( ((pc >> 16) & 0xff ) != 0xf0 )
+ {
+ /* if we're not, see if either the Spurious IRQ vector
+ or the NMI vector are being overwritten */
+ if ( offset == (0x60/2) || offset == (0x7c/2) )
+ {
+ /* trigger an NMI or spurious irq */
+ amigacrt.ar1_spurious = (offset == 0x60/2) ? 0 : 1;
+ space->machine().scheduler().timer_set(space->machine().device<cpu_device>("maincpu")->cycles_to_attotime(28), FUNC(amiga_ar1_delayed_nmi));
+ }
+ }
+
+ (*state->m_chip_ram_w)(state, offset * 2, data );
+}
+
+static void amiga_ar1_check_overlay( running_machine &machine )
+{
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x000000, 0x00007f, FUNC(amiga_ar1_chipmem_w));
+}
+
+static void amiga_ar1_init( running_machine &machine )
+{
+ amiga_state *state = machine.driver_data<amiga_state>();
+ void *ar_ram;
+
+ /* check kickstart version */
+ if ( !check_kickstart_12_13( machine, "Amiga Action Replay" ) )
+ {
+ amigacrt.cart_type = -1;
+ return;
+ }
+
+ /* setup the cart ram */
+ ar_ram = auto_alloc_array(machine, UINT8, 0x4000);
+ memset(ar_ram, 0, 0x4000);
+
+ /* Install ROM */
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0xf00000, 0xf7ffff, "bank2");
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0xf00000, 0xf7ffff);
+
+ /* Install RAM */
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(0x9fc000, 0x9fffff, "bank3");
+
+ /* Configure Banks */
+ state->membank("bank2")->set_base(machine.root_device().memregion("user2")->base());
+ state->membank("bank3")->set_base(ar_ram);
+
+ amigacrt.ar1_spurious = 0;
+
+ /* Install IRQ ACK callback */
+ device_set_irq_callback(machine.device("maincpu"), amiga_ar1_irqack);
+}
+
+/***************************************************************************
+
+ Amiga Action Replay MKII/MKIII
+
+ Whenever you push the button, an overlay of the cartridge appears
+ in RAM and an NMI interrupt is generated. Only reads are overlayed.
+ Writes go directly to chipmem (so that the CPU can write the stack
+ information for the NMI). Once the interrupt is taken, the cart
+ disables the ROM overlay and checks it's internal mode register
+ to see why it was invoked.
+
+ When a breakpoint is set the cart replaces the target instruction
+ with a trap, and adds a trap handler that it locates in the $100-$120
+ area. The handler simply has one instruction: TST.B $BFE001. This cia
+ access is monitored, and the conditions match (PC < 120 and a previous
+ command requested the monitoring of the cia) then the cart is invoked.
+
+***************************************************************************/
+
+static void amiga_ar23_freeze( running_machine &machine );
+
+static READ16_HANDLER( amiga_ar23_cia_r )
+{
+ int pc = cpu_get_pc(&space->device());
+
+ if ( ACCESSING_BITS_0_7 && offset == 2048 && pc >= 0x40 && pc < 0x120 )
+ {
+ amiga_ar23_freeze(space->machine());
+ }
+
+ return amiga_cia_r( space, offset, mem_mask );
+}
+
+static WRITE16_HANDLER( amiga_ar23_mode_w )
+{
+ if ( data & 2 )
+ {
+ space->install_legacy_read_handler(0xbfd000, 0xbfefff, FUNC(amiga_ar23_cia_r));
+ }
+ else
+ {
+ space->install_legacy_read_handler(0xbfd000, 0xbfefff, FUNC(amiga_cia_r));
+ }
+
+ amigacrt.ar23_mode = (data&0x3);
+ if ( amigacrt.ar23_mode == 0 )
+ amigacrt.ar23_mode = 1;
+
+}
+
+static READ16_HANDLER( amiga_ar23_mode_r )
+{
+ amiga_state *state = space->machine().driver_data<amiga_state>();
+ UINT16 *mem = (UINT16 *)(*state->memregion( "user2" ));
+
+ if ( ACCESSING_BITS_0_7 )
+ {
+ if ( offset < 2 )
+ return (mem[offset] | (amigacrt.ar23_mode&3));
+
+ if ( offset == 0x03 ) /* disable cart oberlay on chip mem */
+ {
+ UINT32 mirror_mask = state->m_chip_ram.bytes();
+
+ state->membank("bank1")->set_entry(0);
+
+ while( (mirror_mask<<1) < 0x100000 )
+ {
+ mirror_mask |= ( mirror_mask << 1 );
+ }
+
+ /* overlay disabled, map RAM on 0x000000 */
+ space->install_write_bank(0x000000, state->m_chip_ram.bytes() - 1, 0, mirror_mask, "bank1");
+ }
+ }
+
+ return mem[offset];
+}
+
+static WRITE16_HANDLER( amiga_ar23_chipmem_w )
+{
+ amiga_state *state = space->machine().driver_data<amiga_state>();
+ if ( offset == (0x08/2) )
+ {
+ if ( amigacrt.ar23_mode & 1 )
+ amiga_ar23_freeze(space->machine());
+ }
+
+ (*state->m_chip_ram_w)(state, offset * 2, data );
+}
+
+static void amiga_ar23_freeze( running_machine &machine )
+{
+ amiga_state *state = machine.driver_data<amiga_state>();
+ int pc = cpu_get_pc(machine.device("maincpu"));
+
+ /* only freeze if we're not inside the cart's ROM */
+ if ( ((pc >> 16) & 0xfe ) != 0x40 )
+ {
+ /* get the cart's built-in ram */
+ UINT16 *ar_ram = (UINT16 *)machine.device("maincpu")->memory().space(AS_PROGRAM)->get_write_ptr(0x440000);
+
+ if ( ar_ram != NULL )
+ {
+ int i;
+
+ for( i = 0; i < 0x100; i++ )
+ ar_ram[0x7800+i] = CUSTOM_REG(i);
+ }
+
+ /* overlay the cart rom's in chipram */
+ state->membank("bank1")->set_entry(2);
+
+ /* writes go to chipram */
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x000000, state->m_chip_ram.bytes() - 1, FUNC(amiga_ar23_chipmem_w));
+
+ /* trigger NMI irq */
+ cputag_set_input_line(machine, "maincpu", 7, PULSE_LINE);
+ }
+}
+
+static void amiga_ar23_nmi( running_machine &machine )
+{
+ amigacrt.ar23_mode = 0;
+ amiga_ar23_freeze(machine);
+}
+
+#if 0
+static WRITE16_HANDLER( amiga_ar23_custom_w )
+{
+ int pc = cpu_get_pc(&space->device());
+
+ /* see if we're inside the AR2 rom */
+ if ( ((pc >> 16) & 0xfe ) != 0x40 )
+ {
+ /* get the cart's built-in ram */
+ UINT16 *ar_ram = (UINT16 *)memory_get_write_ptr(0, AS_PROGRAM, 0x440000);
+
+ if ( ar_ram != NULL )
+ {
+ ar_ram[0x7800+offset] = data;
+ }
+ }
+
+ amiga_custom_w( offset, data, mem_mask );
+}
+
+static READ16_HANDLER( amiga_ar23_custom_r )
+{
+ UINT16 data = amiga_custom_r( offset, mem_mask );
+
+ int pc = cpu_get_pc(&space->device());
+
+ /* see if we're inside the AR2 rom */
+ if ( ((pc >> 16) & 0xfe ) != 0x40 )
+ {
+ /* get the cart's built-in ram */
+ UINT16 *ar_ram = (UINT16 *)memory_get_write_ptr(0, AS_PROGRAM, 0x440000);
+
+ if ( ar_ram != NULL )
+ {
+ ar_ram[0x7800+offset] = data;
+ }
+ }
+
+ return data;
+}
+#endif
+
+static void amiga_ar23_check_overlay( running_machine &machine )
+{
+ amigacrt.ar23_mode = 3;
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x000000, 0x00000f, FUNC(amiga_ar23_chipmem_w));
+}
+
+static void amiga_ar23_init( running_machine &machine, int ar3 )
+{
+ amiga_state *state = machine.driver_data<amiga_state>();
+ UINT32 mirror = 0x20000, size = 0x1ffff;
+ void *ar_ram;
+
+ /* check kickstart version */
+ if ( !check_kickstart_12_13( machine, "Action Replay MKII or MKIII" ) )
+ {
+ amigacrt.cart_type = -1;
+ return;
+ }
+
+ /* setup the cart ram */
+ ar_ram = auto_alloc_array_clear(machine, UINT8,0x10000);
+
+ if ( ar3 )
+ {
+ mirror = 0;
+ size = 0x3ffff;
+ }
+
+ /* Install ROM */
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0x400000, 0x400000+size, 0, mirror, "bank2");
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0x400000, 0x400000+size, 0, mirror);
+
+ /* Install RAM */
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0x440000, 0x44ffff, "bank3");
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_write_bank(0x440000, 0x44ffff, "bank3");
+
+ /* Install Custom chip monitor */
+// machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0xdff000, 0xdff1ff, FUNC(amiga_ar23_custom_r));
+// machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xdff000, 0xdff1ff, FUNC(amiga_ar23_custom_w));
+
+ /* Install status/mode handlers */
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x400000, 0x400007, 0, mirror, FUNC(amiga_ar23_mode_r));
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x400000, 0x400003, 0, mirror, FUNC(amiga_ar23_mode_w));
+
+ /* Configure Banks */
+ state->membank("bank2")->set_base(machine.root_device().memregion("user2")->base());
+ state->membank("bank3")->set_base(ar_ram);
+
+ state->membank("bank1")->configure_entries(0, 2, state->m_chip_ram, 0);
+ state->membank("bank1")->configure_entries(1, 2, machine.root_device().memregion("user1")->base(), 0);
+ state->membank("bank1")->configure_entries(2, 2, machine.root_device().memregion("user2")->base(), 0);
+
+ amigacrt.ar23_mode = 3;
+}
+
+/***************************************************************************
+
+ MAME/MESS hooks
+
+***************************************************************************/
+
+void amiga_cart_init( running_machine &machine )
+{
+ /* see what is there */
+ UINT16 *mem = (UINT16 *)(*machine.root_device().memregion( "user2" ));
+
+ amigacrt.cart_type = -1;
+
+ if ( mem != NULL )
+ {
+ if ( mem[0x00] == 0x1111 )
+ {
+ amigacrt.cart_type = ACTION_REPLAY;
+ amiga_ar1_init(machine);
+ }
+ else if ( mem[0x0C] == 0x4D6B )
+ {
+ amigacrt.cart_type = ACTION_REPLAY_MKII;
+ amiga_ar23_init(machine, 0);
+ }
+ else if ( mem[0x0C] == 0x4D4B )
+ {
+ amigacrt.cart_type = ACTION_REPLAY_MKIII;
+ amiga_ar23_init(machine, 1);
+ }
+ }
+}
+
+void amiga_cart_check_overlay( running_machine &machine )
+{
+ if ( amigacrt.cart_type < 0 )
+ return;
+
+ switch( amigacrt.cart_type )
+ {
+ case ACTION_REPLAY:
+ amiga_ar1_check_overlay(machine);
+ break;
+
+ case ACTION_REPLAY_MKII:
+ case ACTION_REPLAY_MKIII:
+ amiga_ar23_check_overlay(machine);
+ break;
+ }
+}
+
+void amiga_cart_nmi( running_machine &machine )
+{
+ if ( amigacrt.cart_type < 0 )
+ return;
+
+ switch( amigacrt.cart_type )
+ {
+ case ACTION_REPLAY:
+ amiga_ar1_nmi(machine);
+ break;
+
+ case ACTION_REPLAY_MKII:
+ case ACTION_REPLAY_MKIII:
+ amiga_ar23_nmi(machine);
+ break;
+ }
+}
diff --git a/src/mess/machine/amigacrt.h b/src/mess/machine/amigacrt.h
new file mode 100644
index 00000000000..6e603ed8b98
--- /dev/null
+++ b/src/mess/machine/amigacrt.h
@@ -0,0 +1,8 @@
+#ifndef AMIGACRT_H
+#define AMIGACRT_H
+
+void amiga_cart_init( running_machine &machine );
+void amiga_cart_check_overlay( running_machine &machine );
+void amiga_cart_nmi( running_machine &machine );
+
+#endif /* AMIGACRT_H */
diff --git a/src/mess/machine/amigakbd.c b/src/mess/machine/amigakbd.c
new file mode 100644
index 00000000000..15044cf7106
--- /dev/null
+++ b/src/mess/machine/amigakbd.c
@@ -0,0 +1,254 @@
+/***************************************************************************
+
+ Amiga keyboard controller emulation
+
+***************************************************************************/
+
+
+#include "emu.h"
+#include "includes/amiga.h"
+#include "amigakbd.h"
+#include "machine/6526cia.h"
+
+
+#define KEYBOARD_BUFFER_SIZE 256
+
+typedef struct
+{
+ UINT8 *buf;
+ int buf_pos;
+ int cur_pos;
+ emu_timer *timer;
+} amigakbd_t;
+static amigakbd_t kbd;
+
+static void kbd_sendscancode( running_machine &machine, UINT8 scancode )
+{
+ int j;
+ device_t *cia = machine.device("cia_0");
+
+ /* send over to the cia A */
+ for( j = 0; j < 8; j++ )
+ {
+ mos6526_cnt_w( cia, 0 ); /* lower cnt */
+ mos6526_sp_w( cia, BIT(scancode << j, 7) ); /* set the serial data */
+ mos6526_cnt_w( cia, 1 ); /* raise cnt */
+ }
+}
+
+static TIMER_CALLBACK( kbd_update_callback )
+{
+ UINT8 scancode;
+
+ (void)param;
+
+ /* if we don't have pending data, bail */
+
+ if ( kbd.buf_pos == kbd.cur_pos )
+ return;
+
+ /* fetch the next scan code and send it to the Amiga */
+ scancode = kbd.buf[kbd.cur_pos++];
+ kbd.cur_pos %= KEYBOARD_BUFFER_SIZE;
+ kbd_sendscancode( machine, scancode );
+
+ /* if we still have more data, schedule another update */
+ if ( kbd.buf_pos != kbd.cur_pos )
+ {
+ kbd.timer->adjust(machine.primary_screen->frame_period() / 4);
+ }
+}
+
+static INPUT_CHANGED( kbd_update )
+{
+ int index = (int)(FPTR)param, i;
+ UINT32 oldvalue = oldval * field.mask(), newvalue = newval * field.mask();
+ UINT32 delta = oldvalue ^ newvalue;
+
+ /* Special case Page UP, which we will use as Action Replay button */
+ if ( (index == 3) && ( delta & 0x80000000 ) && ( newvalue & 0x80000000 ) )
+ {
+ const amiga_machine_interface *amiga_intf = amiga_get_interface(field.machine());
+
+ if ( amiga_intf != NULL && amiga_intf->nmi_callback )
+ {
+ (*amiga_intf->nmi_callback)(field.machine());
+ }
+ }
+ else
+ {
+ int key_buf_was_empty = ( kbd.buf_pos == kbd.cur_pos ) ? 1 : 0;
+
+ for( i = 0; i < 32; i++ )
+ {
+ if ( delta & ( 1 << i ) )
+ {
+ int down = ( newvalue & ( 1 << i ) ) ? 0 : 1;
+ int scancode = ( ( (index*32)+i ) << 1 ) | down;
+ int amigacode = ~scancode;
+
+ /* add the keycode to the buffer */
+ kbd.buf[kbd.buf_pos++] = amigacode & 0xff;
+ kbd.buf_pos %= KEYBOARD_BUFFER_SIZE;
+ }
+ }
+
+ /* if the buffer was empty and we have new data, start a timer to send the keystrokes */
+ if ( key_buf_was_empty && ( kbd.buf_pos != kbd.cur_pos ) )
+ {
+ kbd.timer->adjust(field.machine().primary_screen->frame_period() / 4);
+ }
+ }
+}
+
+void amigakbd_init( running_machine &machine )
+{
+ /* allocate a keyboard buffer */
+ kbd.buf = auto_alloc_array(machine, UINT8, KEYBOARD_BUFFER_SIZE);
+ kbd.buf_pos = 0;
+ kbd.cur_pos = 0;
+ kbd.timer = machine.scheduler().timer_alloc(FUNC(kbd_update_callback));
+ kbd.timer->reset();
+}
+
+/*********************************************************************************************/
+
+/* Layout is for the US A500 keyboard */
+
+INPUT_PORTS_START( amiga_us_keyboard )
+ PORT_START("amiga_keyboard_0")
+ PORT_BIT( 0x00000001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') PORT_CHAR('~') // 00
+ PORT_BIT( 0x00000002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') // 01
+ PORT_BIT( 0x00000004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@') // 02
+ PORT_BIT( 0x00000008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') // 03
+ PORT_BIT( 0x00000010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') // 04
+ PORT_BIT( 0x00000020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') // 05
+ PORT_BIT( 0x00000040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^') // 06
+ PORT_BIT( 0x00000080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&') // 07
+ PORT_BIT( 0x00000100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*') // 08
+ PORT_BIT( 0x00000200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') // 09
+ PORT_BIT( 0x00000400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') // 0A
+ PORT_BIT( 0x00000800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_') // 0B
+ PORT_BIT( 0x00001000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+') // 0C
+ PORT_BIT( 0x00002000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_BACKSLASH2) PORT_CHAR('\\') PORT_CHAR('\xA6') // 0D
+ PORT_BIT( 0x00004000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 0) // 0E
+ PORT_BIT( 0x00008000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD)) // 0F
+ PORT_BIT( 0x00010000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') // 10
+ PORT_BIT( 0x00020000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') // 11
+ PORT_BIT( 0x00040000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') // 12
+ PORT_BIT( 0x00080000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') // 13
+ PORT_BIT( 0x00100000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') // 14
+ PORT_BIT( 0x00200000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') // 15
+ PORT_BIT( 0x00400000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') // 16
+ PORT_BIT( 0x00800000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') // 17
+ PORT_BIT( 0x01000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') // 18
+ PORT_BIT( 0x02000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') // 19
+ PORT_BIT( 0x04000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{') // 1A
+ PORT_BIT( 0x08000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}') // 1B
+ PORT_BIT( 0x10000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 0) // 1C
+ PORT_BIT( 0x20000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) // 1D
+ PORT_BIT( 0x40000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) // 1E
+ PORT_BIT( 0x80000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 0) PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD)) // 1F
+
+ PORT_START("amiga_keyboard_1")
+ PORT_BIT( 0x00000001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') // 20
+ PORT_BIT( 0x00000002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') // 21
+ PORT_BIT( 0x00000004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') // 22
+ PORT_BIT( 0x00000008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') // 23
+ PORT_BIT( 0x00000010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') // 24
+ PORT_BIT( 0x00000020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') // 25
+ PORT_BIT( 0x00000040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') // 26
+ PORT_BIT( 0x00000080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') // 27
+ PORT_BIT( 0x00000100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') // 28
+ PORT_BIT( 0x00000200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':') // 29
+ PORT_BIT( 0x00000400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('"') // 2A
+ PORT_BIT( 0x00000800, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 1) // 2B
+ PORT_BIT( 0x00001000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 1) // 2C
+ PORT_BIT( 0x00002000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD)) // 2D
+ PORT_BIT( 0x00004000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD)) // 2E
+ PORT_BIT( 0x00008000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD)) // 2F
+ PORT_BIT( 0x00010000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 1) // 30
+ PORT_BIT( 0x00020000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') // 31
+ PORT_BIT( 0x00040000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') // 32
+ PORT_BIT( 0x00080000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') // 33
+ PORT_BIT( 0x00100000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') // 34
+ PORT_BIT( 0x00200000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') // 35
+ PORT_BIT( 0x00400000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') // 36
+ PORT_BIT( 0x00800000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') // 37
+ PORT_BIT( 0x01000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<') // 38
+ PORT_BIT( 0x02000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>') // 39
+ PORT_BIT( 0x04000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') // 3A
+ PORT_BIT( 0x08000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 1) // 3B
+ PORT_BIT( 0x10000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD))// 3C
+ PORT_BIT( 0x20000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD)) // 3D
+ PORT_BIT( 0x40000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD)) // 3E
+ PORT_BIT( 0x80000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 1) PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD)) // 3F
+
+ PORT_START("amiga_keyboard_2")
+ PORT_BIT( 0x00000001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') // 40
+ PORT_BIT( 0x00000002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) // 41
+ PORT_BIT( 0x00000004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_TAB) PORT_CHAR('\t') // 42
+ PORT_BIT( 0x00000008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD)) // 43
+ PORT_BIT( 0x00000010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) // 44
+ PORT_BIT( 0x00000020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) // 45
+ PORT_BIT( 0x00000040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_DEL) PORT_CHAR(UCHAR_MAMEKEY(DEL)) // 46
+ PORT_BIT( 0x00000080, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 2) // 47
+ PORT_BIT( 0x00000100, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 2) // 48
+ PORT_BIT( 0x00000200, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 2) // 49
+ PORT_BIT( 0x00000400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD)) // 4A
+ PORT_BIT( 0x00000800, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 2) // 4B
+ PORT_BIT( 0x00001000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) // 4C
+ PORT_BIT( 0x00002000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) // 4D
+ PORT_BIT( 0x00004000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) // 4E
+ PORT_BIT( 0x00008000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) // 4F
+ PORT_BIT( 0x00010000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) // 50
+ PORT_BIT( 0x00020000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) // 51
+ PORT_BIT( 0x00040000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) // 52
+ PORT_BIT( 0x00080000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) // 53
+ PORT_BIT( 0x00100000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) // 54
+ PORT_BIT( 0x00200000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) // 55
+ PORT_BIT( 0x00400000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) // 56
+ PORT_BIT( 0x00800000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) // 57
+ PORT_BIT( 0x01000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9)) // 58
+ PORT_BIT( 0x02000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10)) // 59
+ PORT_BIT( 0x04000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 2) // 5A
+ PORT_BIT( 0x08000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 2) // 5B
+ PORT_BIT( 0x10000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_SLASH_PAD) PORT_CHAR(UCHAR_MAMEKEY(SLASH_PAD)) // 5C
+ PORT_BIT( 0x20000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_ASTERISK) PORT_CHAR(UCHAR_MAMEKEY(ASTERISK)) // 5D
+ PORT_BIT( 0x40000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(PLUS_PAD)) // 5E
+ PORT_BIT( 0x80000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 2) PORT_CODE(KEYCODE_INSERT) PORT_CHAR(UCHAR_MAMEKEY(INSERT)) // 5F
+
+ PORT_START("amiga_keyboard_3")
+ PORT_BIT( 0x00000001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 3) PORT_NAME("Shift (Left)") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) // 60
+ PORT_BIT( 0x00000002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 3) PORT_NAME("Shift (Right)") PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) // 61
+ PORT_BIT( 0x00000004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 3) PORT_NAME("Caps Lock") PORT_CODE(KEYCODE_CAPSLOCK) // 62
+ PORT_BIT( 0x00000008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 3) PORT_NAME("Ctrl") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL))// 63
+ PORT_BIT( 0x00000010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 3) PORT_NAME("Alt (Left)") PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_MAMEKEY(LALT)) // 64
+ PORT_BIT( 0x00000020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 3) PORT_NAME("Alt (Right)") PORT_CODE(KEYCODE_RALT) PORT_CHAR(UCHAR_MAMEKEY(RALT)) // 65
+ PORT_BIT( 0x00000040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 3) PORT_NAME("Amiga A (Left)") PORT_CODE(KEYCODE_LWIN) // 66
+ PORT_BIT( 0x00000080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 3) PORT_NAME("Amiga A (Right)") PORT_CODE(KEYCODE_RWIN) // 67
+ PORT_BIT( 0x00000100, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 68
+ PORT_BIT( 0x00000200, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 69
+ PORT_BIT( 0x00000400, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 6A
+ PORT_BIT( 0x00000800, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 6B
+ PORT_BIT( 0x00001000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 6C
+ PORT_BIT( 0x00002000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 6D
+ PORT_BIT( 0x00004000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 6E
+ PORT_BIT( 0x00008000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 6F
+ PORT_BIT( 0x00010000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 70
+ PORT_BIT( 0x00020000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 71
+ PORT_BIT( 0x00040000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 72
+ PORT_BIT( 0x00080000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 73
+ PORT_BIT( 0x00100000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 74
+ PORT_BIT( 0x00200000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 75
+ PORT_BIT( 0x00400000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 76
+ PORT_BIT( 0x00800000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 77
+ PORT_BIT( 0x01000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 78
+ PORT_BIT( 0x02000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 79
+ PORT_BIT( 0x04000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 7A
+ PORT_BIT( 0x08000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 7B
+ PORT_BIT( 0x10000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 7C
+ PORT_BIT( 0x20000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 7D
+ PORT_BIT( 0x40000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED(kbd_update, 3) // 7E
+ PORT_BIT( 0x80000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED(kbd_update, 3) PORT_CODE(KEYCODE_PGUP) // 7F NMI button
+INPUT_PORTS_END
diff --git a/src/mess/machine/amigakbd.h b/src/mess/machine/amigakbd.h
new file mode 100644
index 00000000000..627f6aa79b5
--- /dev/null
+++ b/src/mess/machine/amigakbd.h
@@ -0,0 +1,8 @@
+#ifndef AMIGAKBD_H
+#define AMIGAKBD_H
+
+void amigakbd_init( running_machine &machine );
+
+INPUT_PORTS_EXTERN( amiga_us_keyboard );
+
+#endif /* AMIGAKBD_H */
diff --git a/src/mess/machine/amstr_pc.c b/src/mess/machine/amstr_pc.c
new file mode 100644
index 00000000000..07bbe617099
--- /dev/null
+++ b/src/mess/machine/amstr_pc.c
@@ -0,0 +1,420 @@
+#include "emu.h"
+
+#include "machine/pit8253.h"
+#include "machine/pc_lpt.h"
+#include "machine/pcshare.h"
+#include "includes/amstr_pc.h"
+#include "includes/pc.h"
+#include "video/pc_vga.h"
+
+
+/* pc20 (v2)
+ fc078
+ fc102 color/mono selection
+ fc166
+ fc1b4
+ fd841 (output something)
+ ff17c (output something, read monitor type inputs)
+ fc212
+ fc26c
+ fc2df
+ fc3fe
+ fc0f4
+ fc432
+ fc49f
+ fc514
+ fc566
+ fc5db
+ fc622 in 3de
+
+port 0379 read
+port 03de write/read
+ */
+
+/* pc1512 (v1)
+ fc1b5
+ fc1f1
+ fc264
+ fc310
+ fc319
+ fc385
+ fc436
+ fc459
+ fc4cb
+ fc557
+ fc591
+ fc624
+ fc768
+ fc818
+ fc87d display amstrad ..
+ fca17 keyboard check
+ fca69
+ fd680
+ fd7f9
+ fca7b !keyboard interrupt routine for this check
+ */
+
+
+/* pc1640 (v3)
+ bios power up self test
+ important addresses
+
+ fc0c9
+ fc0f2
+ fc12e
+ fc193
+ fc20e
+ fc2c1
+ fc2d4
+
+
+ fc375
+ fc3ba
+ fc3e1
+ fc412
+ fc43c
+ fc47d
+ fc48f
+ fc51f
+ fc5a2
+ fc5dd mouse
+
+ fc1c0
+ fc5fa
+ the following when language selection not 0 (test for presence of 0x80000..0x9ffff ram)
+ fc60e
+ fc667
+ fc678
+ fc6e5
+ fc72e
+ fc78f
+ fc7cb ; coprocessor related
+ fc834
+ feda6 no problem with disk inserted
+
+ fca2a
+
+ cmos ram 28 0 amstrad pc1512 integrated cga
+ cmos ram 23 dipswitches?
+*/
+
+static struct {
+ struct {
+ UINT8 x,y; //byte clipping needed
+ } mouse;
+
+ // 64 system status register?
+ UINT8 port60;
+ UINT8 port61;
+ UINT8 port62;
+ UINT8 port65;
+
+ int dipstate;
+} pc1640={{0}, 0};
+
+/* test sequence in bios
+ write 00 to 65
+ write 30 to 61
+ read 62 and (0x10)
+ write 34 to 61
+ read 62 and (0x0f)
+ return or of the 2 62 reads
+
+ allows set of the original ibm pc "dipswitches"!!!!
+
+ 66 write gives reset?
+*/
+
+/* mouse x counter at 0x78 (read- writable)
+ mouse y counter at 0x7a (read- writable)
+
+ mouse button 1,2 keys
+ joystick (4 directions, 2 buttons) keys
+ these get value from cmos ram
+ 74 15 00 enter
+ 70 17 00 forward del
+ 77 1b 00 joystick button 1
+ 78 19 00 joystick button 2
+
+
+ 79 00 4d right
+ 7a 00 4b left
+ 7b 00 50 down
+ 7c 00 48 up
+
+ 7e 00 01 mouse button left
+ 7d 01 01 mouse button right
+*/
+
+WRITE8_HANDLER( pc1640_port60_w )
+{
+ switch (offset) {
+ case 1:
+ pc1640.port61=data;
+ if (data==0x30) pc1640.port62=(pc1640.port65&0x10)>>4;
+ else if (data==0x34) pc1640.port62=pc1640.port65&0xf;
+ pit8253_gate2_w(space->machine().device("pit8253"), BIT(data, 0));
+ pc_speaker_set_spkrdata( space->machine(), data & 0x02 );
+ pc_keyb_set_clock(data&0x40);
+ break;
+ case 4:
+ if (data&0x80) {
+ pc1640.port60=data^0x8d;
+ } else {
+ pc1640.port60=data;
+ }
+ break;
+ case 5:
+ // stores the configuration data for port 62 configuration dipswitch emulation
+ pc1640.port65=data;
+ break;
+ }
+
+ logerror("pc1640 write %.2x %.2x\n",offset,data);
+}
+
+
+READ8_HANDLER( pc1640_port60_r )
+{
+ int data=0;
+ switch (offset) {
+ case 0:
+ if (pc1640.port61&0x80)
+ data=pc1640.port60;
+ else
+ data = pc_keyb_read();
+ break;
+
+ case 1:
+ data = pc1640.port61;
+ break;
+
+ case 2:
+ data = pc1640.port62;
+ if (pit8253_get_output(space->machine().device("pit8253"), 2))
+ data |= 0x20;
+ break;
+ }
+ return data;
+}
+
+READ8_HANDLER( pc200_port378_r )
+{
+ device_t *lpt = space->machine().device("lpt_1");
+ UINT8 data = pc_lpt_r(lpt, offset);
+
+ if (offset == 1)
+ data = (data & ~7) | (space->machine().root_device().ioport("DSW0")->read() & 7);
+ if (offset == 2)
+ data = (data & ~0xe0) | (space->machine().root_device().ioport("DSW0")->read() & 0xc0);
+
+ return data;
+}
+
+READ8_HANDLER( pc200_port278_r )
+{
+ device_t *lpt = space->machine().device("lpt_2");
+ UINT8 data = pc_lpt_r(lpt, offset);
+
+ if (offset == 1)
+ data = (data & ~7) | (space->machine().root_device().ioport("DSW0")->read() & 7);
+ if (offset == 2)
+ data = (data & ~0xe0) | (space->machine().root_device().ioport("DSW0")->read() & 0xc0);
+
+ return data;
+}
+
+
+READ8_HANDLER( pc1640_port378_r )
+{
+ device_t *lpt = space->machine().device("lpt_1");
+ UINT8 data = pc_lpt_r(lpt, offset);
+
+ if (offset == 1)
+ data=(data & ~7) | (space->machine().root_device().ioport("DSW0")->read() & 7);
+ if (offset == 2)
+ {
+ switch (pc1640.dipstate)
+ {
+ case 0:
+ data = (data&~0xe0) | (space->machine().root_device().ioport("DSW0")->read() & 0xe0);
+ break;
+ case 1:
+ data = (data&~0xe0) | ((space->machine().root_device().ioport("DSW0")->read() & 0xe000)>>8);
+ break;
+ case 2:
+ data = (data&~0xe0) | ((space->machine().root_device().ioport("DSW0")->read() & 0xe00)>>4);
+ break;
+
+ }
+ }
+ return data;
+}
+
+READ8_HANDLER( pc1640_port3d0_r )
+{
+ if (offset==0xa) pc1640.dipstate=0;
+ return space->read_byte(0x3d0+offset);
+}
+
+READ8_HANDLER( pc1640_port4278_r )
+{
+ if (offset==2) pc1640.dipstate=1;
+ // read parallelport
+ return 0;
+}
+
+READ8_HANDLER( pc1640_port278_r )
+{
+ if ((offset==2)||(offset==0)) pc1640.dipstate=2;
+ // read parallelport
+ return 0;
+}
+
+READ8_HANDLER( pc1640_mouse_x_r )
+{
+ return pc1640.mouse.x - space->machine().root_device().ioport("pc_mouse_x")->read();
+}
+
+READ8_HANDLER( pc1640_mouse_y_r )
+{
+ return pc1640.mouse.y - space->machine().root_device().ioport("pc_mouse_y")->read();
+}
+
+WRITE8_HANDLER( pc1640_mouse_x_w )
+{
+ pc1640.mouse.x = data + space->machine().root_device().ioport("pc_mouse_x")->read();
+}
+
+WRITE8_HANDLER( pc1640_mouse_y_w )
+{
+ pc1640.mouse.y = data + space->machine().root_device().ioport("pc_mouse_y")->read();
+}
+
+INPUT_PORTS_START( amstrad_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)
+ PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1 !") PORT_CODE(KEYCODE_1)
+ PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2 @") PORT_CODE(KEYCODE_2)
+ PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3 #") PORT_CODE(KEYCODE_3)
+ PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4 $") PORT_CODE(KEYCODE_4)
+ PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("5 %") PORT_CODE(KEYCODE_5)
+ PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("6 ^") PORT_CODE(KEYCODE_6)
+ PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("7 &") PORT_CODE(KEYCODE_7)
+ PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("8 *") PORT_CODE(KEYCODE_8)
+ PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("9 (") PORT_CODE(KEYCODE_9)
+ PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("0 )") PORT_CODE(KEYCODE_0)
+ PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("- _") PORT_CODE(KEYCODE_MINUS)
+ PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("= +") PORT_CODE(KEYCODE_EQUALS)
+ PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("<--") PORT_CODE(KEYCODE_BACKSPACE)
+ PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Tab") PORT_CODE(KEYCODE_TAB)
+
+ PORT_START("pc_keyboard_1")
+ PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Q") PORT_CODE(KEYCODE_Q)
+ PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("W") PORT_CODE(KEYCODE_W)
+ PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("E") PORT_CODE(KEYCODE_E)
+ PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("R") PORT_CODE(KEYCODE_R)
+ PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("T") PORT_CODE(KEYCODE_T)
+ PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Y") PORT_CODE(KEYCODE_Y)
+ PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("U") PORT_CODE(KEYCODE_U)
+ PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("I") PORT_CODE(KEYCODE_I)
+ PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("O") PORT_CODE(KEYCODE_O)
+ PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("P") PORT_CODE(KEYCODE_P)
+ PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("[ {") PORT_CODE(KEYCODE_OPENBRACE)
+ PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("] }") PORT_CODE(KEYCODE_CLOSEBRACE)
+ PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Enter") PORT_CODE(KEYCODE_ENTER)
+ PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Ctrl") PORT_CODE(KEYCODE_LCONTROL)
+ PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("A") PORT_CODE(KEYCODE_A)
+ PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("S") PORT_CODE(KEYCODE_S)
+
+ PORT_START("pc_keyboard_2")
+ PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("D") PORT_CODE(KEYCODE_D)
+ PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F") PORT_CODE(KEYCODE_F)
+ PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("G") PORT_CODE(KEYCODE_G)
+ PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("H") PORT_CODE(KEYCODE_H)
+ PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("J") PORT_CODE(KEYCODE_J)
+ PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("K") PORT_CODE(KEYCODE_K)
+ PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("L") PORT_CODE(KEYCODE_L)
+ PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("; :") PORT_CODE(KEYCODE_COLON)
+ PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("' \"") PORT_CODE(KEYCODE_QUOTE)
+ PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("` ~") PORT_CODE(KEYCODE_TILDE)
+ PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("L-Shift") PORT_CODE(KEYCODE_LSHIFT)
+ PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("\\ |") PORT_CODE(KEYCODE_BACKSLASH)
+ PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Z") PORT_CODE(KEYCODE_Z)
+ PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("X") PORT_CODE(KEYCODE_X)
+ PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("C") PORT_CODE(KEYCODE_C)
+ PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("V") PORT_CODE(KEYCODE_V)
+
+ PORT_START("pc_keyboard_3")
+ PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("B") PORT_CODE(KEYCODE_B)
+ PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("N") PORT_CODE(KEYCODE_N)
+ PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("M") PORT_CODE(KEYCODE_M)
+ PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(", <") PORT_CODE(KEYCODE_COMMA)
+ PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(". >") PORT_CODE(KEYCODE_STOP)
+ PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("/ ?") PORT_CODE(KEYCODE_SLASH)
+ PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("R-Shift") PORT_CODE(KEYCODE_RSHIFT)
+ PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP * (PrtScr)") PORT_CODE(KEYCODE_ASTERISK)
+ PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Alt") PORT_CODE(KEYCODE_LALT)
+ PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Space") PORT_CODE(KEYCODE_SPACE)
+ PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Caps") PORT_CODE(KEYCODE_CAPSLOCK)
+ PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F1") PORT_CODE(KEYCODE_F1)
+ PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F2") PORT_CODE(KEYCODE_F2)
+ PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F3") PORT_CODE(KEYCODE_F3)
+ PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F4") PORT_CODE(KEYCODE_F4)
+ PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F5") PORT_CODE(KEYCODE_F5)
+
+ PORT_START("pc_keyboard_4")
+ PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F6") PORT_CODE(KEYCODE_F6)
+ PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F7") PORT_CODE(KEYCODE_F7)
+ PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F8") PORT_CODE(KEYCODE_F8)
+ PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F9") PORT_CODE(KEYCODE_F9)
+ PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F10") PORT_CODE(KEYCODE_F10)
+ PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("NumLock") PORT_CODE(KEYCODE_NUMLOCK)
+ PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ScrLock") PORT_CODE(KEYCODE_SCRLOCK)
+ PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 7 (Home)") PORT_CODE(KEYCODE_7_PAD) PORT_CODE(KEYCODE_HOME)
+ PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 8 (Up)") PORT_CODE(KEYCODE_8_PAD)
+ PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 9 (PgUp)") PORT_CODE(KEYCODE_9_PAD) PORT_CODE(KEYCODE_PGUP)
+ PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP -") PORT_CODE(KEYCODE_MINUS_PAD)
+ PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 4 (Left)") PORT_CODE(KEYCODE_4_PAD)
+ PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 5") PORT_CODE(KEYCODE_5_PAD)
+ PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 6 (Right)") PORT_CODE(KEYCODE_6_PAD)
+ PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP +") PORT_CODE(KEYCODE_PLUS_PAD)
+ PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 1 (End)") PORT_CODE(KEYCODE_1_PAD) PORT_CODE(KEYCODE_END)
+
+ PORT_START("pc_keyboard_5")
+ PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 2 (Down)") PORT_CODE(KEYCODE_2_PAD)
+ PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 3 (PgDn)") PORT_CODE(KEYCODE_3_PAD) PORT_CODE(KEYCODE_PGDN)
+ PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 0 (Ins)") PORT_CODE(KEYCODE_0_PAD) PORT_CODE(KEYCODE_INSERT)
+ PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP . (Del)") PORT_CODE(KEYCODE_DEL_PAD) PORT_CODE(KEYCODE_DEL)
+ PORT_BIT ( 0x0030, 0x0000, IPT_UNUSED )
+ PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("?(84/102)\\") PORT_CODE(KEYCODE_BACKSLASH2)
+ PORT_BIT ( 0xff80, 0x0000, IPT_UNUSED )
+
+ PORT_START("pc_keyboard_6")
+ PORT_BIT ( 0xffff, 0x0000, IPT_UNUSED )
+
+ PORT_START("pc_keyboard_7")
+ PORT_BIT ( 0x806e, 0x0000, IPT_UNUSED )
+ PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("-->")
+ PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("?Enter")
+ PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Amstrad Joystick Button 1") PORT_CODE(KEYCODE_RALT)
+ PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Amstrad Joystick Button 2") PORT_CODE(KEYCODE_RCONTROL)
+ PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Amstrad Joystick Right") PORT_CODE(KEYCODE_RIGHT)
+ PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Amstrad Joystick Left") PORT_CODE(KEYCODE_LEFT)
+ PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Amstrad Joystick Down") PORT_CODE(KEYCODE_DOWN)
+ PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Amstrad Joystick Up") PORT_CODE(KEYCODE_UP)
+ PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Amstrad Mouse Button left") PORT_CODE(KEYCODE_F11)
+ PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Amstrad Mouse Button right") PORT_CODE(KEYCODE_F12)
+
+ PORT_START("pc_mouse_misc")
+ PORT_BIT ( 0xffff, 0x0000, IPT_UNUSED )
+
+ PORT_START( "pc_mouse_x" ) /* Mouse - X AXIS */
+ PORT_BIT( 0xff, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1) PORT_REVERSE
+
+ PORT_START( "pc_mouse_y" ) /* Mouse - Y AXIS */
+ PORT_BIT( 0xff, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1)
+
+INPUT_PORTS_END
diff --git a/src/mess/machine/amstrad.c b/src/mess/machine/amstrad.c
new file mode 100644
index 00000000000..dfe7e5a5bce
--- /dev/null
+++ b/src/mess/machine/amstrad.c
@@ -0,0 +1,3307 @@
+/***************************************************************************
+
+ machine.c
+
+ Functions to emulate general aspects of the machine (RAM, ROM, interrupts,
+ I/O ports)
+
+Amstrad hardware consists of:
+
+- General Instruments AY-3-8912 (audio and keyboard scanning)
+- Intel 8255PPI (keyboard, access to AY-3-8912, cassette etc)
+- Z80A CPU
+- 765 FDC (disc drive interface)
+- "Gate Array" (custom chip by Amstrad controlling colour, mode,
+rom/ram selection
+
+
+On the Amstrad, any part of the 64k memory can be access by the video
+hardware (GA and CRTC - the CRTC specifies the memory address to access,
+and the GA fetches 2 bytes of data for each 1us cycle.
+
+The Z80 must also access the same ram.
+
+To maintain the screen display, the Z80 is halted on each memory access.
+
+The result is that timing for opcodes, appears to fall into a nice pattern,
+where the time for each opcode can be measured in NOP cycles. NOP cycles is
+the name I give to the time taken for one NOP command to execute.
+
+This happens to be 1us.
+
+From measurement, there are 64 NOPs per line, with 312 lines per screen.
+This gives a total of 19968 NOPs per frame.
+
+***************************************************************************/
+
+
+#include "emu.h"
+#include "cpu/z80/z80.h"
+#include "machine/i8255.h"
+#include "machine/mc146818.h"
+#include "machine/upd765.h"
+#include "machine/ctronics.h"
+#include "machine/cpc_rom.h"
+#include "machine/mface2.h"
+#include "imagedev/cassette.h"
+#include "imagedev/snapquik.h"
+#include "includes/amstrad.h"
+#include "sound/ay8910.h"
+#include "machine/ram.h"
+
+#define MANUFACTURER_NAME 0x07
+#define TV_REFRESH_RATE 0x10
+
+enum {
+ SYSTEM_CPC,
+ SYSTEM_ALESTE,
+ SYSTEM_PLUS,
+ SYSTEM_GX4000
+};
+
+
+/* originally from drivers/amstrad.c */
+// &ff,&77,&b3,&51,&a8,&d4,&62,&39,&9c,&46,&2b,&15,&8a,&cd,&ee
+// This is the sequence for unlocking the ASIC in the CPC+/GX4000
+// These are outed to port &bc00, after syncing the lock by outing a non-zero value then a zero to &bc00
+// To lock the ASIC again, repeat the sequence without the last &ee
+static const UINT8 asic_unlock_seq[15] =
+{
+ 0xff, 0x77, 0xb3, 0x51, 0xa8, 0xd4, 0x62, 0x39, 0x9c, 0x46, 0x2b, 0x15, 0x8a, 0xcd, 0xee
+};
+
+
+
+
+
+/* Ram configuration */
+
+/* pointers to current ram configuration selected for banks */
+
+/* the hardware allows selection of 256 ROMs. Rom 0 is usually BASIC and Rom 7 is AMSDOS */
+/* With the CPC hardware, if a expansion ROM is not connected, BASIC rom will be selected instead */
+/* data present on input of ppi, and data written to ppi output */
+#define amstrad_ppi_PortA 0
+#define amstrad_ppi_PortB 1
+#define amstrad_ppi_PortC 2
+
+
+
+/*------------------
+ - Ram Management -
+ ------------------*/
+/* There are 8 different ram configurations which work on the currently selected 64k logical block.
+ The following tables show the possible ram configurations :*/
+static const int RamConfigurations[8 * 4] =
+{
+ 0, 1, 2, 3, /* config 0 */
+ 0, 1, 2, 7, /* config 1 */
+ 4, 5, 6, 7, /* config 2 */
+ 0, 3, 2, 7, /* config 3 */
+ 0, 4, 2, 3, /* config 4 */
+ 0, 5, 2, 3, /* config 5 */
+ 0, 6, 2, 3, /* config 6 */
+ 0, 7, 2, 3 /* config 7 */
+};
+
+
+
+//static int amstrad_CRTC_CR = 0; /* CR = Cursor Enabled */
+
+/* this contains the colours in machine.pens form.*/
+/* this is updated from the eventlist and reflects the current state
+of the render colours - these may be different to the current colour palette values */
+/* colours can be changed at any time and will take effect immediatly */
+
+
+
+/* The Amstrad CPC has a fixed palette of 27 colours generated from 3 levels of Red, Green and Blue.
+The hardware allows selection of 32 colours, but these extra colours are copies of existing colours.*/
+
+static const rgb_t amstrad_palette[32] =
+{
+ MAKE_RGB(0x060, 0x060, 0x060), /* white */
+ MAKE_RGB(0x060, 0x060, 0x060), /* white */
+ MAKE_RGB(0x000, 0x0ff, 0x060), /* sea green */
+ MAKE_RGB(0x0ff, 0x0ff, 0x060), /* pastel yellow */
+ MAKE_RGB(0x000, 0x000, 0x060), /* blue */
+ MAKE_RGB(0x0ff, 0x000, 0x060), /* purple */
+ MAKE_RGB(0x000, 0x060, 0x060), /* cyan */
+ MAKE_RGB(0x0ff, 0x060, 0x060), /* pink */
+ MAKE_RGB(0x0ff, 0x000, 0x060), /* purple */
+ MAKE_RGB(0x0ff, 0x0ff, 0x060), /* pastel yellow */
+ MAKE_RGB(0x0ff, 0x0ff, 0x000), /* bright yellow */
+ MAKE_RGB(0x0ff, 0x0ff, 0x0ff), /* bright white */
+ MAKE_RGB(0x0ff, 0x000, 0x000), /* bright red */
+ MAKE_RGB(0x0ff, 0x000, 0x0ff), /* bright magenta */
+ MAKE_RGB(0x0ff, 0x060, 0x000), /* orange */
+ MAKE_RGB(0x0ff, 0x060, 0x0ff), /* pastel magenta */
+ MAKE_RGB(0x000, 0x000, 0x060), /* blue */
+ MAKE_RGB(0x000, 0x0ff, 0x060), /* sea green */
+ MAKE_RGB(0x000, 0x0ff, 0x000), /* bright green */
+ MAKE_RGB(0x000, 0x0ff, 0x0ff), /* bright cyan */
+ MAKE_RGB(0x000, 0x000, 0x000), /* black */
+ MAKE_RGB(0x000, 0x000, 0x0ff), /* bright blue */
+ MAKE_RGB(0x000, 0x060, 0x000), /* green */
+ MAKE_RGB(0x000, 0x060, 0x0ff), /* sky blue */
+ MAKE_RGB(0x060, 0x000, 0x060), /* magenta */
+ MAKE_RGB(0x060, 0x0ff, 0x060), /* pastel green */
+ MAKE_RGB(0x060, 0x0ff, 0x060), /* lime */
+ MAKE_RGB(0x060, 0x0ff, 0x0ff), /* pastel cyan */
+ MAKE_RGB(0x060, 0x000, 0x000), /* Red */
+ MAKE_RGB(0x060, 0x000, 0x0ff), /* mauve */
+ MAKE_RGB(0x060, 0x060, 0x000), /* yellow */
+ MAKE_RGB(0x060, 0x060, 0x0ff) /* pastel blue */
+};
+
+
+/* the green brightness is equal to the firmware colour index */
+static const rgb_t amstrad_green_palette[32] =
+{
+ MAKE_RGB(0x000, 0x07F, 0x000), /*13*/
+ MAKE_RGB(0x000, 0x07F, 0x000), /*13*/
+ MAKE_RGB(0x000, 0x0BA, 0x000), /*19*/
+ MAKE_RGB(0x000, 0x0F5, 0x000), /*25*/
+ MAKE_RGB(0x000, 0x009, 0x000), /*1*/
+ MAKE_RGB(0x000, 0x044, 0x000), /*7*/
+ MAKE_RGB(0x000, 0x062, 0x000), /*10*/
+ MAKE_RGB(0x000, 0x09C, 0x000), /*16*/
+ MAKE_RGB(0x000, 0x044, 0x000), /*7*/
+ MAKE_RGB(0x000, 0x0F5, 0x000), /*25*/
+ MAKE_RGB(0x000, 0x0EB, 0x000), /*24*/
+ MAKE_RGB(0x000, 0x0FF, 0x000), /*26*/
+ MAKE_RGB(0x000, 0x03A, 0x000), /*6*/
+ MAKE_RGB(0x000, 0x04E, 0x000), /*8*/
+ MAKE_RGB(0x000, 0x093, 0x000), /*15*/
+ MAKE_RGB(0x000, 0x0A6, 0x000), /*17*/
+ MAKE_RGB(0x000, 0x009, 0x000), /*1*/
+ MAKE_RGB(0x000, 0x0BA, 0x000), /*19*/
+ MAKE_RGB(0x000, 0x0B0, 0x000), /*18*/
+ MAKE_RGB(0x000, 0x0C4, 0x000), /*20*/
+ MAKE_RGB(0x000, 0x000, 0x000), /*0*/
+ MAKE_RGB(0x000, 0x013, 0x000), /*2*/
+ MAKE_RGB(0x000, 0x058, 0x000), /*9*/
+ MAKE_RGB(0x000, 0x06B, 0x000), /*11*/
+ MAKE_RGB(0x000, 0x027, 0x000), /*4*/
+ MAKE_RGB(0x000, 0x0D7, 0x000), /*22*/
+ MAKE_RGB(0x000, 0x0CD, 0x000), /*21*/
+ MAKE_RGB(0x000, 0x0E1, 0x000), /*23*/
+ MAKE_RGB(0x000, 0x01D, 0x000), /*3*/
+ MAKE_RGB(0x000, 0x031, 0x000), /*5*/
+ MAKE_RGB(0x000, 0x075, 0x000), /*12*/
+ MAKE_RGB(0x000, 0x089, 0x000) /*14*/
+};
+
+
+/*******************************************************************
+ Prototypes
+*******************************************************************/
+
+INLINE void amstrad_update_video( running_machine &machine );
+INLINE void amstrad_plus_update_video( running_machine &machine );
+static void amstrad_rethinkMemory(running_machine &machine);
+
+
+/* Initialise the palette */
+PALETTE_INIT( amstrad_cpc )
+{
+ palette_set_colors(machine, 0, amstrad_palette, ARRAY_LENGTH(amstrad_palette));
+}
+
+
+PALETTE_INIT( amstrad_cpc_green )
+{
+ palette_set_colors(machine, 0, amstrad_green_palette, ARRAY_LENGTH(amstrad_green_palette));
+}
+
+
+WRITE_LINE_DEVICE_HANDLER( aleste_interrupt )
+{
+ amstrad_state *drvstate = device->machine().driver_data<amstrad_state>();
+ if(state == CLEAR_LINE)
+ drvstate->m_aleste_fdc_int = 0;
+ else
+ drvstate->m_aleste_fdc_int = 1;
+}
+
+
+/* Some games set the 8255 to mode 1 and expect a strobe signal */
+/* on PC2. Apparently PC2 is always low on the CPC. ?!? */
+static TIMER_CALLBACK(amstrad_pc2_low)
+{
+ amstrad_state *state = machine.driver_data<amstrad_state>();
+ state->m_ppi->pc2_w(0);
+}
+
+
+/*************************************************************************/
+/* KC Compact
+
+The palette is defined by a colour rom. The only rom dump that exists (from the KC-Club webpage)
+is 2K, which seems correct. In this rom the same 32 bytes of data is repeated throughout the rom.
+
+When a I/O write is made to "Gate Array" to select the colour, Bit 7 and 6 are used by the
+"Gate Array" to define the function, bit 7 = 0, bit 6 = 1. In the Amstrad CPC, bits 4..0
+define the hardware colour number, but in the KC Compact, it seems bits 5..0
+define the hardware colour number allowing 64 colours to be chosen.
+
+It is possible therefore that the colour rom could be reprogrammed, so that other colour
+selections could be chosen allowing 64 different colours to be used. But this has not been tested
+and co
+
+colour rom byte:
+
+Bit Function
+7 not used
+6 not used
+5,4 Green value
+3,2 Red value
+1,0 Blue value
+
+Green value, Red value, Blue value: 0 = 0%, 01/10 = 50%, 11 = 100%.
+The 01 case is not used, it is unknown if this produces a different amount of colour.
+*/
+
+static unsigned char kccomp_get_colour_element(int colour_value)
+{
+ switch (colour_value)
+ {
+ case 0:
+ return 0x00;
+ case 1:
+ return 0x60;
+ case 2:
+ return 0x60;
+ case 3:
+ return 0xff;
+ }
+
+ return 0xff;
+}
+
+
+/* the colour rom has the same 32 bytes repeated, but it might be possible to put a new rom in
+with different data and be able to select the other entries - not tested on a real kc compact yet
+and not supported by this driver */
+PALETTE_INIT( kccomp )
+{
+ const UINT8 *color_prom = machine.root_device().memregion("proms")->base();
+ int i;
+
+ color_prom = color_prom+0x018000;
+
+ for (i=0; i<32; i++)
+ {
+ palette_set_color_rgb(machine, i,
+ kccomp_get_colour_element((color_prom[i]>>2) & 0x03),
+ kccomp_get_colour_element((color_prom[i]>>4) & 0x03),
+ kccomp_get_colour_element((color_prom[i]>>0) & 0x03));
+ }
+}
+
+
+/********************************************
+Amstrad Plus
+
+The Amstrad Plus has a 4096 colour palette
+*********************************************/
+
+PALETTE_INIT( amstrad_plus )
+{
+ int i;
+
+ palette_set_colors(machine, 0, amstrad_palette, sizeof(amstrad_palette) / 3);
+ for ( i = 0; i < 0x1000; i++ )
+ {
+ int r, g, b;
+
+ g = ( i >> 8 ) & 0x0f;
+ r = ( i >> 4 ) & 0x0f;
+ b = i & 0x0f;
+
+ r = ( r << 4 ) | ( r );
+ g = ( g << 4 ) | ( g );
+ b = ( b << 4 ) | ( b );
+
+ palette_set_color_rgb(machine, i, r, g, b);
+ }
+}
+
+
+PALETTE_INIT( aleste )
+{
+ int i;
+
+ /* CPC Colour data is stored in the colour ROM (RFCOLDAT.BIN) at 0x140-0x17f */
+ unsigned char* pal = machine.root_device().memregion("user4")->base();
+
+ for(i=0; i<32; i++)
+ {
+ int r,g,b;
+
+ b = (pal[0x140+i] >> 4) & 0x03;
+ g = (pal[0x140+i] >> 2) & 0x03;
+ r = pal[0x140+i] & 0x03;
+
+ r = (r << 6);
+ g = (g << 6);
+ b = (b << 6);
+
+ palette_set_color_rgb(machine, i, r, g, b);
+ }
+
+ /* MSX colour palette is 6-bit RGB */
+ for(i=0; i<64; i++)
+ {
+ int r,g,b;
+
+ r = (i >> 4) & 0x03;
+ g = (i >> 2) & 0x03;
+ b = i & 0x03;
+
+ r = (r << 6);
+ g = (g << 6);
+ b = (b << 6);
+
+ palette_set_color_rgb(machine, i+32, r, g, b);
+ }
+}
+
+
+static void amstrad_init_lookups( amstrad_state *state )
+{
+ int i;
+
+ for ( i = 0; i < 256; i++ )
+ {
+ state->m_mode0_lookup[i] = ( ( i & 0x80 ) >> 7 ) | ( ( i & 0x20 ) >> 3 ) | ( ( i & 0x08 ) >> 2 ) | ( ( i & 0x02 ) << 2 );
+ state->m_mode1_lookup[i] = ( ( i & 0x80 ) >> 7 ) | ( ( i & 0x08 ) >> 2 );
+ state->m_mode2_lookup[i] = ( ( i & 0x80 ) >> 7 );
+ }
+}
+
+
+/* Set the new screen mode (0,1,2,4) from the GateArray */
+static void amstrad_vh_update_mode( amstrad_state *state )
+{
+ if ( state->m_system_type == SYSTEM_PLUS || state->m_system_type == SYSTEM_GX4000 )
+ {
+ /* select a cpc plus mode */
+ switch ( state->m_gate_array.mrer & 0x03 )
+ {
+ case 0: /* Mode 0: 160x200, 16 colours */
+ state->m_gate_array.mode_lookup = state->m_mode0_lookup;
+ state->m_gate_array.max_colour_ticks = 4;
+ state->m_gate_array.ticks_increment = 1;
+ break;
+
+ case 1: /* Mode 1: 320x200, 4 colous */
+ state->m_gate_array.mode_lookup = state->m_mode1_lookup;
+ state->m_gate_array.max_colour_ticks = 2;
+ state->m_gate_array.ticks_increment = 1;
+ break;
+
+ case 2: /* Mode 2: 640x200, 2 colours */
+ state->m_gate_array.mode_lookup = state->m_mode2_lookup;
+ state->m_gate_array.max_colour_ticks = 1;
+ state->m_gate_array.ticks_increment = 1;
+ break;
+
+ case 3: /* Mode 3: 160x200, 4 colours */
+ state->m_gate_array.mode_lookup = state->m_mode0_lookup;
+ state->m_gate_array.max_colour_ticks = 4;
+ state->m_gate_array.ticks_increment = 1;
+ break;
+ }
+ }
+ else
+ {
+ if ( state->m_aleste_mode & 0x02 )
+ {
+ /* select an aleste mode */
+ switch ( state->m_gate_array.mrer & 0x03 )
+ {
+ case 0: /* Aleste Mode 0 (= Amstrad CPC mode 2): 640x200, 2 colours */
+ state->m_gate_array.mode_lookup = state->m_mode2_lookup;
+ state->m_gate_array.max_colour_ticks = 1;
+ state->m_gate_array.ticks_increment = 1;
+ break;
+
+ case 1: /* Aleste mode 1 (= Amstrad CPC mode 1): 320x200, 4 colours */
+ state->m_gate_array.mode_lookup = state->m_mode1_lookup;
+ state->m_gate_array.max_colour_ticks = 2;
+ state->m_gate_array.ticks_increment = 1;
+ break;
+
+ case 2: /* Aleste mode 2: 4 colours */
+ state->m_gate_array.mode_lookup = state->m_mode1_lookup;
+ state->m_gate_array.max_colour_ticks = 1;
+ state->m_gate_array.ticks_increment = 2;
+ break;
+
+ case 3: /* Aleste mode 3: 16 colours */
+ state->m_gate_array.mode_lookup = state->m_mode0_lookup;
+ state->m_gate_array.max_colour_ticks = 2;
+ state->m_gate_array.ticks_increment = 2;
+ break;
+ }
+ }
+ else
+ {
+ /* select an original cpc mode */
+ switch ( state->m_gate_array.mrer & 0x03 )
+ {
+ case 0: /* Mode 0: 160x200, 16 colours */
+ state->m_gate_array.mode_lookup = state->m_mode0_lookup;
+ state->m_gate_array.max_colour_ticks = 4;
+ state->m_gate_array.ticks_increment = 1;
+ break;
+
+ case 1: /* Mode 1: 320x200, 4 colous */
+ state->m_gate_array.mode_lookup = state->m_mode1_lookup;
+ state->m_gate_array.max_colour_ticks = 2;
+ state->m_gate_array.ticks_increment = 1;
+ break;
+
+ case 2: /* Mode 2: 640x200, 2 colours */
+ state->m_gate_array.mode_lookup = state->m_mode2_lookup;
+ state->m_gate_array.max_colour_ticks = 1;
+ state->m_gate_array.ticks_increment = 1;
+ break;
+
+ case 3: /* Mode 3: 160x200, 4 colours */
+ state->m_gate_array.mode_lookup = state->m_mode0_lookup;
+ state->m_gate_array.max_colour_ticks = 4;
+ state->m_gate_array.ticks_increment = 1;
+ break;
+ }
+ }
+ }
+}
+
+
+/*
+DMA commands
+
+0RDDh LOAD R,D Load 8 bit data D to PSG register R (0<=R<=15)
+1NNNh PAUSE N Pause for N prescaled ticks (0<N<=4095)
+2NNNh REPEAT N Set loop counter to N for this stream (0<N<=4095), and mark next instruction as loop start.
+3xxxh (reserved) Do not use
+4000h NOP No operation (64us idle)
+4001h LOOP If loop counter non zero, loop back to the first instruction after REPEAT instruction and decrement loop counter.
+4010h INT Interrupt the CPU
+4020h STOP Stop processing the sound list.
+*/
+
+static void amstrad_plus_dma_parse(running_machine &machine, int channel)
+{
+ amstrad_state *state = machine.driver_data<amstrad_state>();
+ unsigned short command;
+
+ if( state->m_asic.dma_addr[channel] & 0x01)
+ state->m_asic.dma_addr[channel]++; // align to even address
+
+ if ( state->m_asic.dma_pause[channel] != 0 )
+ { // do nothing, this channel is paused
+ state->m_asic.dma_prescaler[channel]--;
+ if ( state->m_asic.dma_prescaler[channel] == 0 )
+ {
+ state->m_asic.dma_pause[channel]--;
+ state->m_asic.dma_prescaler[channel] = state->m_asic.ram[0x2c02 + (4*channel)] + 1;
+ }
+ return;
+ }
+ command = (state->m_ram->pointer()[state->m_asic.dma_addr[channel]+1] << 8) + state->m_ram->pointer()[state->m_asic.dma_addr[channel]];
+// logerror("DMA #%i: address %04x: command %04x\n",channel,state->m_asic.dma_addr[channel],command);
+ switch (command & 0xf000)
+ {
+ case 0x0000: // Load PSG register
+ {
+ device_t *ay8910 = state->m_ay;
+ ay8910_address_w(ay8910, 0, (command & 0x0f00) >> 8);
+ ay8910_data_w(ay8910, 0, command & 0x00ff);
+ ay8910_address_w(ay8910, 0, state->m_prev_reg);
+ }
+ logerror("DMA %i: LOAD %i, %i\n",channel,(command & 0x0f00) >> 8, command & 0x00ff);
+ break;
+ case 0x1000: // Pause for n HSYNCs (0 - 4095)
+ state->m_asic.dma_pause[channel] = (command & 0x0fff) - 1;
+ logerror("DMA %i: PAUSE %i\n",channel,command & 0x0fff);
+ break;
+ case 0x2000: // Beginning of repeat loop
+ state->m_asic.dma_repeat[channel] = state->m_asic.dma_addr[channel];
+ state->m_asic.dma_loopcount[channel] = (command & 0x0fff);
+ logerror("DMA %i: REPEAT %i\n",channel,command & 0x0fff);
+ break;
+ case 0x4000: // Control functions
+ if (command & 0x01) // Loop back to last Repeat instruction
+ {
+ if (state->m_asic.dma_loopcount[channel] > 0)
+ {
+ state->m_asic.dma_addr[channel] = state->m_asic.dma_repeat[channel];
+ logerror("DMA %i: LOOP (%i left)\n",channel,state->m_asic.dma_loopcount[channel]);
+ state->m_asic.dma_loopcount[channel]--;
+ }
+ else
+ logerror("DMA %i: LOOP (end)\n",channel);
+ }
+ if (command & 0x10) // Cause interrupt
+ {
+ state->m_plus_irq_cause = channel * 2;
+ state->m_asic.ram[0x2c0f] |= (0x40 >> channel);
+ cputag_set_input_line(machine, "maincpu", 0, ASSERT_LINE);
+ logerror("DMA %i: INT\n",channel);
+ }
+ if (command & 0x20) // Stop processing on this channel
+ {
+ state->m_asic.dma_status &= ~(0x01 << channel);
+ logerror("DMA %i: STOP\n",channel);
+ }
+ break;
+ default:
+ logerror("DMA: Unknown DMA command - %04x - at address &%04x\n",command,state->m_asic.dma_addr[channel]);
+ }
+ state->m_asic.dma_addr[channel] += 2; // point to next DMA instruction
+}
+
+
+static void amstrad_plus_handle_dma(running_machine &machine)
+{
+ amstrad_state *state = machine.driver_data<amstrad_state>();
+ if ( state->m_asic.dma_status & 0x01 ) // DMA channel 0
+ amstrad_plus_dma_parse( machine, 0 );
+
+ if ( state->m_asic.dma_status & 0x02 ) // DMA channel 1
+ amstrad_plus_dma_parse( machine, 1 );
+
+ if ( state->m_asic.dma_status & 0x04 ) // DMA channel 2
+ amstrad_plus_dma_parse( machine, 2 );
+}
+
+static TIMER_CALLBACK(amstrad_video_update_timer)
+{
+ if(param == 1)
+ amstrad_plus_update_video(machine);
+ else
+ amstrad_update_video(machine);
+}
+
+/* Set the new colour from the GateArray */
+static void amstrad_vh_update_colour(running_machine &machine, int PenIndex, UINT16 hw_colour_index)
+{
+ amstrad_state *state = machine.driver_data<amstrad_state>();
+ if ( state->m_system_type == SYSTEM_PLUS || state->m_system_type == SYSTEM_GX4000 )
+ {
+ int val;
+
+ machine.scheduler().timer_set( attotime::from_usec(0), FUNC(amstrad_video_update_timer),1);
+
+ /* CPC+/GX4000 - normal palette changes through the Gate Array also makes the corresponding change in the ASIC palette */
+ val = (amstrad_palette[hw_colour_index] & 0xf00000) >> 16; /* red */
+ val |= (amstrad_palette[hw_colour_index] & 0x0000f0) >> 4; /* blue */
+ state->m_asic.ram[0x2400+PenIndex*2] = val;
+ val = (amstrad_palette[hw_colour_index] & 0x00f000) >> 12; /* green */
+ state->m_asic.ram[0x2401+PenIndex*2] = val;
+ }
+ else
+ {
+ machine.scheduler().timer_set( attotime::from_usec(0), FUNC(amstrad_video_update_timer),0);
+ }
+ state->m_GateArray_render_colours[PenIndex] = hw_colour_index;
+}
+
+
+static void aleste_vh_update_colour(running_machine &machine, int PenIndex, UINT16 hw_colour_index)
+{
+ amstrad_state *state = machine.driver_data<amstrad_state>();
+ machine.scheduler().timer_set( attotime::from_usec(0), FUNC(amstrad_video_update_timer),0);
+ state->m_GateArray_render_colours[PenIndex] = hw_colour_index+32;
+}
+
+
+INLINE void amstrad_gate_array_get_video_data( running_machine &machine )
+{
+ amstrad_state *state = machine.driver_data<amstrad_state>();
+ if ( state->m_aleste_mode & 0x02 )
+ state->m_gate_array.address = ( ( state->m_gate_array.ma & 0x2000 ) << 2 ) | ( ( state->m_gate_array.ra & 0x06 ) << 11 ) | ( ( state->m_gate_array.ra & 0x01 ) << 14 ) | ( ( state->m_gate_array.ma & 0x7ff ) << 1 );
+ else
+ state->m_gate_array.address = ( ( state->m_gate_array.ma & 0x3000 ) << 2 ) | ( ( state->m_gate_array.ra & 0x07 ) << 11 ) | ( ( state->m_gate_array.ma & 0x3ff ) << 1 );
+ state->m_gate_array.data = state->m_ram->pointer()[ state->m_gate_array.address ];
+ state->m_gate_array.colour = state->m_GateArray_render_colours[ state->m_gate_array.mode_lookup[state->m_gate_array.data] ];
+ state->m_gate_array.colour_ticks = state->m_gate_array.max_colour_ticks;
+ state->m_gate_array.ticks = 0;
+}
+
+
+INLINE void amstrad_update_video( running_machine &machine )
+{
+ amstrad_state *state = machine.driver_data<amstrad_state>();
+ attotime now = machine.time();
+
+
+ if ( state->m_gate_array.draw_p )
+ {
+ UINT32 cycles_passed = (now - state->m_gate_array.last_draw_time ).as_ticks(XTAL_16MHz);
+
+ while( cycles_passed )
+ {
+ if ( ! state->m_gate_array.de || ( ( state->m_aleste_mode & 0x02 ) && ! ( state->m_aleste_mode & 0x08 ) ) )
+ {
+ *state->m_gate_array.draw_p = state->m_GateArray_render_colours[ 16 ];
+ }
+ else
+ {
+ *state->m_gate_array.draw_p = state->m_gate_array.colour;
+ state->m_gate_array.colour_ticks--;
+ if ( ! state->m_gate_array.colour_ticks )
+ {
+ state->m_gate_array.data <<= 1;
+ state->m_gate_array.colour = state->m_GateArray_render_colours[ state->m_gate_array.mode_lookup[state->m_gate_array.data] ];
+ state->m_gate_array.colour_ticks = state->m_gate_array.max_colour_ticks;
+ }
+ state->m_gate_array.ticks += state->m_gate_array.ticks_increment;
+ switch( state->m_gate_array.ticks)
+ {
+ case 8:
+ state->m_gate_array.data = state->m_ram->pointer()[ state->m_gate_array.address + 1 ];
+ state->m_gate_array.colour = state->m_GateArray_render_colours[ state->m_gate_array.mode_lookup[state->m_gate_array.data] ];
+ break;
+ case 16:
+ state->m_gate_array.ma += 1; /* If we were synced with the 6845 mc6845_get_ma should return this value */
+ amstrad_gate_array_get_video_data( machine );
+ break;
+ }
+ }
+ state->m_gate_array.draw_p++;
+ cycles_passed--;
+ state->m_gate_array.line_ticks++;
+ if ( state->m_gate_array.line_ticks > state->m_gate_array.bitmap->width() )
+ {
+ state->m_gate_array.draw_p = NULL;
+ cycles_passed = 0;
+ }
+ }
+ }
+
+ state->m_gate_array.last_draw_time = now;
+}
+
+
+INLINE void amstrad_plus_gate_array_get_video_data( running_machine &machine )
+{
+ amstrad_state *state = machine.driver_data<amstrad_state>();
+ UINT16 caddr;
+ UINT16 ma = ( state->m_gate_array.ma - state->m_asic.split_ma_started ) + state->m_asic.split_ma_base;
+ UINT16 ra = state->m_gate_array.ra + ( ( state->m_asic.ram[0x2804] >> 4 ) & 0x07 );
+
+ if ( ra > 7 )
+ {
+ ma += state->m_asic.horiz_disp;
+ }
+ state->m_gate_array.address = ( ( ma & 0x3000 ) << 2 ) | ( ( state->m_gate_array.ra & 0x07 ) << 11 ) | ( ( ma & 0x3ff ) << 1 );
+ state->m_gate_array.data = state->m_ram->pointer()[ state->m_gate_array.address ];
+ caddr = 0x2400 + state->m_gate_array.mode_lookup[state->m_gate_array.data] * 2;
+ state->m_gate_array.colour = state->m_asic.ram[caddr] + ( state->m_asic.ram[caddr+1] << 8 );
+ state->m_gate_array.colour_ticks = state->m_gate_array.max_colour_ticks;
+ state->m_gate_array.ticks = 0;
+}
+
+
+INLINE void amstrad_plus_update_video( running_machine &machine )
+{
+ amstrad_state *state = machine.driver_data<amstrad_state>();
+ attotime now = machine.time();
+
+ if ( state->m_gate_array.draw_p )
+ {
+ UINT32 cycles_passed = (now - state->m_gate_array.last_draw_time ).as_ticks(XTAL_16MHz);
+
+ while( cycles_passed )
+ {
+ if ( ! state->m_gate_array.de )
+ {
+ *state->m_gate_array.draw_p = state->m_asic.ram[0x2420] + ( state->m_asic.ram[0x2421] << 8 );
+ }
+ else
+ {
+ *state->m_gate_array.draw_p = state->m_gate_array.colour;
+
+ if ( state->m_asic.hscroll )
+ {
+ state->m_asic.hscroll--;
+ if ( state->m_asic.hscroll == 0 )
+ amstrad_plus_gate_array_get_video_data( machine );
+ }
+ else
+ {
+ state->m_gate_array.colour_ticks--;
+ if ( ! state->m_gate_array.colour_ticks )
+ {
+ UINT16 caddr;
+
+ state->m_gate_array.data <<= 1;
+ caddr = 0x2400 + state->m_gate_array.mode_lookup[state->m_gate_array.data] * 2;
+ state->m_gate_array.colour = state->m_asic.ram[caddr] + ( state->m_asic.ram[caddr+1] << 8 );
+ state->m_gate_array.colour_ticks = state->m_gate_array.max_colour_ticks;
+ }
+ state->m_gate_array.ticks += state->m_gate_array.ticks_increment;
+ switch( state->m_gate_array.ticks)
+ {
+ case 8:
+ {
+ UINT16 caddr;
+
+ state->m_gate_array.data = state->m_ram->pointer()[ state->m_gate_array.address + 1 ];
+ caddr = 0x2400 + state->m_gate_array.mode_lookup[state->m_gate_array.data] * 2;
+ state->m_gate_array.colour = state->m_asic.ram[caddr] + ( state->m_asic.ram[caddr+1] << 8 );
+ }
+ break;
+ case 16:
+ state->m_gate_array.ma += 1; /* If we were synced with the 6845 mc6845_get_ma should return this value */
+ amstrad_plus_gate_array_get_video_data( machine );
+ break;
+ }
+ }
+ }
+ state->m_gate_array.draw_p++;
+ cycles_passed--;
+ state->m_gate_array.line_ticks++;
+ if ( state->m_gate_array.line_ticks > state->m_gate_array.bitmap->width() )
+ {
+ state->m_gate_array.draw_p = NULL;
+ cycles_passed = 0;
+ }
+ }
+ }
+
+ state->m_gate_array.last_draw_time = now;
+}
+
+
+INLINE void amstrad_plus_update_video_sprites( running_machine &machine )
+{
+ amstrad_state *state = machine.driver_data<amstrad_state>();
+ UINT16 *p = &state->m_gate_array.bitmap->pix16(state->m_gate_array.y, state->m_asic.h_start );
+ int i;
+
+ if ( state->m_gate_array.y < 0 )
+ return;
+
+ for ( i = 15 * 8; i >= 0; i -= 8 )
+ {
+ UINT8 xmag = ( state->m_asic.ram[ 0x2000 + i + 4 ] >> 2 ) & 0x03;
+ UINT8 ymag = state->m_asic.ram[ 0x2000 + i + 4 ] & 0x03;
+
+ /* Check if sprite is enabled */
+ if ( xmag && ymag )
+ {
+ INT16 spr_x = state->m_asic.ram[ 0x2000 + i ] + ( state->m_asic.ram[ 0x2001 + i ] << 8 );
+ INT16 spr_y = state->m_asic.ram[ 0x2002 + i ] + ( state->m_asic.ram[ 0x2003 + i ] << 8 );
+
+ xmag -= 1;
+ ymag -= 1;
+
+ /* Check if sprite would appear on this scanline */
+ if ( spr_y <= state->m_asic.vpos && state->m_asic.vpos < spr_y + ( 16 << ymag ) && spr_x < ( state->m_asic.h_end - state->m_asic.h_start ) && spr_x + ( 16 << xmag ) > 0 )
+ {
+ UINT16 spr_addr = i * 32 + ( ( ( state->m_asic.vpos - spr_y ) >> ymag ) * 16 );
+ int j, k;
+
+ for ( j = 0; j < 16; j++ )
+ {
+ for ( k = 0; k < ( 1 << xmag ); k++ )
+ {
+ INT16 x = spr_x + ( j << xmag ) + k;
+
+ if ( x >= 0 && x < ( state->m_asic.h_end - state->m_asic.h_start ) )
+ {
+ UINT8 spr_col = ( state->m_asic.ram[ spr_addr + j ] & 0x0f ) * 2;
+
+ if ( spr_col )
+ p[x] = state->m_asic.ram[ 0x2420 + spr_col ] + ( state->m_asic.ram[ 0x2421 + spr_col ] << 8 );
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+static WRITE_LINE_DEVICE_HANDLER( amstrad_hsync_changed )
+{
+ amstrad_state *drvstate = device->machine().driver_data<amstrad_state>();
+ amstrad_update_video(device->machine());
+
+ /* The gate array reacts to de-assertion of the hsycnc 6845 line */
+ if ( drvstate->m_gate_array.hsync && !state )
+ {
+ drvstate->m_gate_array.hsync_counter++;
+ /* Advance to next drawing line */
+ drvstate->m_gate_array.y++;
+ drvstate->m_gate_array.line_ticks = 0;
+ if ( drvstate->m_gate_array.y >= 0 && drvstate->m_gate_array.y < drvstate->m_gate_array.bitmap->height() )
+ {
+ drvstate->m_gate_array.draw_p = &drvstate->m_gate_array.bitmap->pix16(drvstate->m_gate_array.y);
+ }
+ else
+ {
+ drvstate->m_gate_array.draw_p = NULL;
+ }
+
+ if ( drvstate->m_gate_array.hsync_after_vsync_counter != 0 ) // counters still operate regardless of PRI state
+ {
+ drvstate->m_gate_array.hsync_after_vsync_counter--;
+
+ if (drvstate->m_gate_array.hsync_after_vsync_counter == 0)
+ {
+ if (drvstate->m_gate_array.hsync_counter >= 32)
+ {
+ cputag_set_input_line(device->machine(), "maincpu", 0, ASSERT_LINE);
+ }
+ drvstate->m_gate_array.hsync_counter = 0;
+ }
+ }
+
+ if ( drvstate->m_gate_array.hsync_counter >= 52 )
+ {
+ drvstate->m_gate_array.hsync_counter = 0;
+ cputag_set_input_line(device->machine(), "maincpu", 0, ASSERT_LINE);
+ }
+ }
+ drvstate->m_gate_array.hsync = state ? 1 : 0;
+}
+
+
+static WRITE_LINE_DEVICE_HANDLER( amstrad_plus_hsync_changed )
+{
+ amstrad_state *drvstate = device->machine().driver_data<amstrad_state>();
+ amstrad_plus_update_video(device->machine());
+
+ if ( drvstate->m_gate_array.hsync && !state )
+ {
+ drvstate->m_gate_array.hsync_counter++;
+ /* Advance to next drawing line */
+ drvstate->m_gate_array.y++;
+ drvstate->m_gate_array.line_ticks = 0;
+ if ( drvstate->m_gate_array.y >= 0 && drvstate->m_gate_array.y < drvstate->m_gate_array.bitmap->height() )
+ {
+ drvstate->m_gate_array.draw_p = &drvstate->m_gate_array.bitmap->pix16(drvstate->m_gate_array.y);
+ }
+ else
+ {
+ drvstate->m_gate_array.draw_p = NULL;
+ }
+
+ if ( drvstate->m_gate_array.hsync_after_vsync_counter != 0 ) // counters still operate regardless of PRI state
+ {
+ drvstate->m_gate_array.hsync_after_vsync_counter--;
+
+ if (drvstate->m_gate_array.hsync_after_vsync_counter == 0)
+ {
+ if (drvstate->m_gate_array.hsync_counter >= 32)
+ {
+ if( drvstate->m_asic.pri == 0 || drvstate->m_asic.enabled == 0)
+ {
+ cputag_set_input_line(device->machine(), "maincpu", 0, ASSERT_LINE);
+ }
+ }
+ drvstate->m_gate_array.hsync_counter = 0;
+ }
+ }
+
+ if ( drvstate->m_gate_array.hsync_counter >= 52 )
+ {
+ drvstate->m_gate_array.hsync_counter = 0;
+ if ( drvstate->m_asic.pri == 0 || drvstate->m_asic.enabled == 0 )
+ {
+ cputag_set_input_line(device->machine(), "maincpu", 0, ASSERT_LINE);
+ }
+ }
+
+ if ( drvstate->m_asic.enabled )
+ {
+ // CPC+/GX4000 Programmable Raster Interrupt (disabled if &6800 in ASIC RAM is 0)
+ if ( drvstate->m_asic.pri != 0 )
+ {
+ if ( drvstate->m_asic.pri == drvstate->m_asic.vpos - 1 )
+ {
+ logerror("PRI: triggered, scanline %d\n",drvstate->m_asic.pri);
+ cputag_set_input_line(device->machine(), "maincpu", 0, ASSERT_LINE);
+ drvstate->m_plus_irq_cause = 0x06; // raster interrupt vector
+ drvstate->m_gate_array.hsync_counter &= ~0x20; // ASIC PRI resets the MSB of the raster counter
+ }
+ }
+ // CPC+/GX4000 Split screen registers (disabled if &6801 in ASIC RAM is 0)
+ if(drvstate->m_asic.ram[0x2801] != 0)
+ {
+ if ( drvstate->m_asic.ram[0x2801] == drvstate->m_asic.vpos - 1 ) // split occurs here (hopefully)
+ {
+ logerror("SSCR: Split screen occurred at scanline %d\n",drvstate->m_asic.ram[0x2801]);
+ }
+ }
+ // CPC+/GX4000 DMA channels
+ amstrad_plus_handle_dma(device->machine()); // a DMA command is handled at the leading edge of HSYNC (every 64us)
+ if(drvstate->m_asic.de_start != 0)
+ drvstate->m_asic.vpos++;
+ }
+ }
+ drvstate->m_gate_array.hsync = state ? 1 : 0;
+}
+
+
+static WRITE_LINE_DEVICE_HANDLER( amstrad_vsync_changed )
+{
+ amstrad_state *drvstate = device->machine().driver_data<amstrad_state>();
+ amstrad_update_video(device->machine());
+
+ if ( ! drvstate->m_gate_array.vsync && state )
+ {
+ /* Reset the amstrad_CRTC_HS_After_VS_Counter */
+ drvstate->m_gate_array.hsync_after_vsync_counter = 3;
+
+ /* Start of new frame */
+ drvstate->m_gate_array.y = -1;
+ drvstate->m_asic.vpos = 1;
+ drvstate->m_asic.de_start = 0;
+ }
+
+ drvstate->m_gate_array.vsync = state ? 1 : 0;
+
+ /* Schedule a write to PC2 */
+ device->machine().scheduler().timer_set( attotime::zero, FUNC(amstrad_pc2_low));
+}
+
+
+static WRITE_LINE_DEVICE_HANDLER( amstrad_plus_vsync_changed )
+{
+ amstrad_state *drvstate = device->machine().driver_data<amstrad_state>();
+ amstrad_plus_update_video(device->machine());
+
+ if ( ! drvstate->m_gate_array.vsync && state )
+ {
+ /* Reset the amstrad_CRTC_HS_After_VS_Counter */
+ drvstate->m_gate_array.hsync_after_vsync_counter = 3;
+
+ /* Start of new frame */
+ drvstate->m_gate_array.y = -1;
+ drvstate->m_asic.vpos = 1;
+ drvstate->m_asic.de_start = 0;
+ }
+
+ drvstate->m_gate_array.vsync = state ? 1 : 0;
+
+ /* Schedule a write to PC2 */
+ device->machine().scheduler().timer_set( attotime::zero, FUNC(amstrad_pc2_low));
+}
+
+
+static WRITE_LINE_DEVICE_HANDLER( amstrad_de_changed )
+{
+ amstrad_state *drvstate = device->machine().driver_data<amstrad_state>();
+ amstrad_update_video(device->machine());
+
+ if ( ! drvstate->m_gate_array.de && state )
+ {
+ /* DE became active, store the starting MA and RA signals */
+ mc6845_device *mc6845 = drvstate->m_crtc;
+
+ drvstate->m_gate_array.ma = mc6845->get_ma();
+ drvstate->m_gate_array.ra = mc6845->get_ra();
+logerror("y = %d; ma = %02x; ra = %02x, address = %04x\n", drvstate->m_gate_array.y, drvstate->m_gate_array.ma, drvstate->m_gate_array.ra, ( ( drvstate->m_gate_array.ma & 0x3000 ) << 2 ) | ( ( drvstate->m_gate_array.ra & 0x07 ) << 11 ) | ( ( drvstate->m_gate_array.ma & 0x3ff ) << 1 ) );
+ amstrad_gate_array_get_video_data(device->machine());
+ drvstate->m_asic.de_start = 1;
+ }
+
+ drvstate->m_gate_array.de = state ? 1 : 0;
+}
+
+
+static WRITE_LINE_DEVICE_HANDLER( amstrad_plus_de_changed )
+{
+ amstrad_state *drvstate = device->machine().driver_data<amstrad_state>();
+ amstrad_plus_update_video(device->machine());
+
+ if ( ! drvstate->m_gate_array.de && state )
+ {
+ /* DE became active, store the starting MA and RA signals */
+ mc6845_device *mc6845 = drvstate->m_crtc;
+
+ drvstate->m_gate_array.ma = mc6845->get_ma();
+ drvstate->m_gate_array.ra = mc6845->get_ra();
+ drvstate->m_asic.h_start = drvstate->m_gate_array.line_ticks;
+ drvstate->m_asic.de_start = 1;
+
+ /* Start of screen */
+ if ( drvstate->m_asic.vpos == 1 )
+ {
+ drvstate->m_asic.split_ma_base = 0x0000;
+ drvstate->m_asic.split_ma_started = 0x0000;
+ }
+ /* Start of split screen section */
+ else if ( drvstate->m_asic.enabled && drvstate->m_asic.ram[0x2801] != 0 && drvstate->m_asic.ram[0x2801] == drvstate->m_asic.vpos - 1 )
+ {
+ drvstate->m_asic.split_ma_started = drvstate->m_gate_array.ma;
+ drvstate->m_asic.split_ma_base = ( drvstate->m_asic.ram[0x2802] << 8 ) | drvstate->m_asic.ram[0x2803];
+ }
+
+ drvstate->m_gate_array.colour = drvstate->m_asic.ram[0x2420] + ( drvstate->m_asic.ram[0x2421] << 8 );
+ drvstate->m_asic.hscroll = drvstate->m_asic.ram[0x2804] & 0x0f;
+
+ if ( drvstate->m_asic.hscroll == 0 )
+ amstrad_plus_gate_array_get_video_data(device->machine());
+ }
+
+ if ( drvstate->m_gate_array.de && ! state )
+ {
+ drvstate->m_asic.h_end = drvstate->m_gate_array.line_ticks;
+ amstrad_plus_update_video_sprites(device->machine());
+ }
+
+ drvstate->m_gate_array.de = state ? 1 : 0;
+}
+
+
+VIDEO_START( amstrad )
+{
+ amstrad_state *state = machine.driver_data<amstrad_state>();
+ //screen_device *screen = downcast<screen_device *>(machine.device("screen"));
+
+ amstrad_init_lookups(state);
+
+ state->m_gate_array.bitmap = auto_bitmap_ind16_alloc( machine, state->m_screen->width(), state->m_screen->height() );
+ state->m_gate_array.hsync_after_vsync_counter = 3;
+}
+
+
+SCREEN_UPDATE_IND16( amstrad )
+{
+ amstrad_state *state = screen.machine().driver_data<amstrad_state>();
+ copybitmap( bitmap, *state->m_gate_array.bitmap, 0, 0, 0, 0, cliprect );
+ return 0;
+}
+
+
+const mc6845_interface amstrad_mc6845_intf =
+{
+ NULL, /* screen name */
+ 16, /* number of pixels per video memory address */
+ NULL, /* begin_update */
+ NULL, /* update_row */
+ NULL, /* end_update */
+ DEVCB_LINE(amstrad_de_changed), /* on_de_changed */
+ DEVCB_NULL, /* on_cur_changed */
+ DEVCB_LINE(amstrad_hsync_changed), /* on_hsync_changed */
+ DEVCB_LINE(amstrad_vsync_changed), /* on_vsync_changed */
+ NULL
+};
+
+
+const mc6845_interface amstrad_plus_mc6845_intf =
+{
+ NULL, /* screen name */
+ 16, /* number of pixels per video memory address */
+ NULL, /* begin_update */
+ NULL, /* update_row */
+ NULL, /* end_update */
+ DEVCB_LINE(amstrad_plus_de_changed), /* on_de_changed */
+ DEVCB_NULL, /* on_cur_changed */
+ DEVCB_LINE(amstrad_plus_hsync_changed), /* on_hsync_changed */
+ DEVCB_LINE(amstrad_plus_vsync_changed), /* on_vsync_changed */
+ NULL
+};
+
+/* traverses the daisy-chain of expansion devices, looking for the specified device */
+static device_t* get_expansion_device(running_machine &machine, const char* tag)
+{
+ amstrad_state *state = machine.driver_data<amstrad_state>();
+ cpc_expansion_slot_device* exp_port = state->m_exp;
+
+ while(exp_port != NULL)
+ {
+ device_t* temp;
+
+ // first, check if this expansion port has the device we want attached
+ temp = exp_port->subdevice(tag);
+ if(temp != NULL)
+ return temp;
+
+ // if it's not what we're looking for, then check the expansion port on this expansion device. if it exists.
+ temp = dynamic_cast<device_t*>(exp_port->get_card_device());
+ if(temp == NULL)
+ return NULL; // no device attached
+ exp_port = temp->subdevice<cpc_expansion_slot_device>("exp");
+ if(exp_port == NULL)
+ return NULL; // we're at the end of the chain
+ }
+ return NULL;
+}
+
+WRITE_LINE_DEVICE_HANDLER(cpc_irq_w)
+{
+ cputag_set_input_line(device->machine(), "maincpu", 0, state);
+}
+
+WRITE_LINE_DEVICE_HANDLER(cpc_nmi_w)
+{
+ cputag_set_input_line(device->machine(), "maincpu", INPUT_LINE_NMI, state);
+}
+
+WRITE_LINE_DEVICE_HANDLER(cpc_romdis)
+{
+ amstrad_state *tstate = device->machine().driver_data<amstrad_state>();
+
+ tstate->m_gate_array.romdis = state;
+ amstrad_rethinkMemory(device->machine());
+}
+
+WRITE_LINE_DEVICE_HANDLER(cpc_romen)
+{
+ amstrad_state *tstate = device->machine().driver_data<amstrad_state>();
+
+ if(state != 0)
+ tstate->m_gate_array.mrer &= ~0x04;
+ else
+ tstate->m_gate_array.mrer |= 0x04;
+ amstrad_rethinkMemory(device->machine());
+}
+
+
+/*--------------------------
+ - Ram and Rom management -
+ --------------------------*/
+/*-----------------
+ - Set Lower Rom -
+ -----------------*/
+static void amstrad_setLowerRom(running_machine &machine)
+{
+ amstrad_state *state = machine.driver_data<amstrad_state>();
+ UINT8 *bank_base;
+
+ /* b2 : "1" Lower rom area disable or "0" Lower rom area enable */
+ if ( state->m_system_type == SYSTEM_CPC || state->m_system_type == SYSTEM_ALESTE )
+ {
+ if ((state->m_gate_array.mrer & (1<<2)) == 0 && state->m_gate_array.romdis == 0)
+ {
+ bank_base = &state->memregion("maincpu")->base()[0x010000];
+ }
+ else
+ {
+ if(state->m_aleste_mode & 0x04)
+ bank_base = state->m_Aleste_RamBanks[0];
+ else
+ bank_base = state->m_AmstradCPC_RamBanks[0];
+ }
+ state->membank("bank1")->set_base(bank_base);
+ state->membank("bank2")->set_base(bank_base+0x02000);
+ }
+ else // CPC+/GX4000
+ {
+ //address_space *space = state->m_maincpu->memory().space(AS_PROGRAM);
+
+/* if ( state->m_asic.enabled && ( state->m_asic.rmr2 & 0x18 ) == 0x18 )
+ {
+ space->install_read_handler(0x4000, 0x5fff, read8_delegate(FUNC(amstrad_state::amstrad_plus_asic_4000_r),state));
+ space->install_read_handler(0x6000, 0x7fff, read8_delegate(FUNC(amstrad_state::amstrad_plus_asic_6000_r),state));
+ space->install_write_handler(0x4000, 0x5fff, write8_delegate(FUNC(amstrad_state::amstrad_plus_asic_4000_w),state));
+ space->install_write_handler(0x6000, 0x7fff, write8_delegate(FUNC(amstrad_state::amstrad_plus_asic_6000_w),state));
+ }
+ else
+ {
+ space->install_read_bank(0x4000, 0x5fff, "bank3");
+ space->install_read_bank(0x6000, 0x7fff, "bank4");
+ space->install_write_bank(0x4000, 0x5fff, "bank11");
+ space->install_write_bank(0x6000, 0x7fff, "bank12");
+ }
+*/
+ if(state->m_AmstradCPC_RamBanks[0] != NULL)
+ {
+ state->membank("bank1")->set_base(state->m_AmstradCPC_RamBanks[0]);
+ state->membank("bank2")->set_base(state->m_AmstradCPC_RamBanks[0]+0x2000);
+ state->membank("bank3")->set_base(state->m_AmstradCPC_RamBanks[1]);
+ state->membank("bank4")->set_base(state->m_AmstradCPC_RamBanks[1]+0x2000);
+ state->membank("bank5")->set_base(state->m_AmstradCPC_RamBanks[2]);
+ state->membank("bank6")->set_base(state->m_AmstradCPC_RamBanks[2]+0x2000);
+ }
+
+ if ( (state->m_gate_array.mrer & (1<<2)) == 0 && state->m_gate_array.romdis == 0)
+ { // ASIC secondary lower ROM selection (bit 5: 1 = enabled)
+ if ( state->m_asic.enabled )
+ {
+// logerror("L-ROM: Lower ROM enabled, cart bank %i\n", state->m_asic.rmr2 & 0x07 );
+ bank_base = &machine.root_device().memregion("maincpu")->base()[0x4000 * ( state->m_asic.rmr2 & 0x07 )];
+ switch( state->m_asic.rmr2 & 0x18 )
+ {
+ case 0x00:
+// logerror("L-ROM: located at &0000\n");
+ state->membank("bank1")->set_base(bank_base);
+ state->membank("bank2")->set_base(bank_base+0x02000);
+ break;
+ case 0x08:
+// logerror("L-ROM: located at &4000\n");
+ state->membank("bank3")->set_base(bank_base);
+ state->membank("bank4")->set_base(bank_base+0x02000);
+ break;
+ case 0x10:
+// logerror("L-ROM: located at &8000\n");
+ state->membank("bank5")->set_base(bank_base);
+ state->membank("bank6")->set_base(bank_base+0x02000);
+ break;
+ case 0x18:
+// logerror("L-ROM: located at &0000, ASIC registers enabled\n");
+ state->membank("bank1")->set_base(bank_base);
+ state->membank("bank2")->set_base(bank_base+0x02000);
+ break;
+ }
+ }
+ else
+ {
+ state->membank( "bank1" )->set_base( machine.root_device().memregion( "maincpu" )->base() );
+ state->membank( "bank2" )->set_base( machine.root_device().memregion( "maincpu" )->base() + 0x2000 );
+ }
+ }
+ }
+}
+
+
+/*-----------------
+ - Set Upper Rom -
+ -----------------*/
+static void amstrad_setUpperRom(running_machine &machine)
+{
+ amstrad_state *state = machine.driver_data<amstrad_state>();
+ UINT8 *bank_base = NULL;
+
+ /* b3 : "1" Upper rom area disable or "0" Upper rom area enable */
+ if ( ! ( state->m_gate_array.mrer & 0x08 ) && state->m_gate_array.romdis == 0)
+ {
+ bank_base = state->m_Amstrad_ROM_Table[ state->m_gate_array.upper_bank ];
+ }
+ else
+ {
+ if(state->m_aleste_mode & 0x04)
+ bank_base = state->m_Aleste_RamBanks[3];
+ else
+ bank_base = state->m_AmstradCPC_RamBanks[3];
+ }
+
+ if (bank_base)
+ {
+ state->membank("bank7")->set_base(bank_base);
+ state->membank("bank8")->set_base(bank_base+0x2000);
+ }
+}
+
+
+/*--------------------------
+ - Ram and Rom management -
+ --------------------------*/
+
+/* simplified ram configuration - e.g. only correct for 128k machines
+
+RAM Expansion Bits
+ 7 6 5 4 3 2 1 0
+CPC6128 1 1 - - - s2 s1 s0
+Dk'tronics 256K Silicon Disk 1 1 1 b1 b0 b2 - -
+
+"-" - this bit is ignored. The value of this bit is not important.
+"0" - this bit must be set to "0"
+"1" - this bit must be set to "1"
+"b0,b1,b2" - this bit is used to define the logical 64k block that the ram configuration uses
+"s0,s1,s2" - this bit is used to define the ram configuration
+
+The CPC6128 has a 64k ram expansion built-in, giving 128K of RAM in this system.
+In the CPC464,CPC664 and KC compact if a ram expansion is not present, then writing to this port has no effect and the ram will be in the same arrangement as if configuration 0 had been selected.
+*/
+static void AmstradCPC_GA_SetRamConfiguration(running_machine &machine)
+{
+ amstrad_state *state = machine.driver_data<amstrad_state>();
+ int ConfigurationIndex = state->m_GateArray_RamConfiguration & 0x07;
+ int BankIndex,i;
+ unsigned char *BankAddr;
+
+/* if b5 = 0 */
+ if(((state->m_GateArray_RamConfiguration) & (1<<5)) == 0)
+ {
+ for (i=0;i<4;i++)
+ {
+ BankIndex = RamConfigurations[(ConfigurationIndex << 2) + i];
+ BankAddr = state->m_ram->pointer() + (BankIndex << 14);
+ state->m_Aleste_RamBanks[i] = BankAddr;
+ state->m_AmstradCPC_RamBanks[i] = BankAddr;
+ }
+ }
+ else
+ {/* Need to add the ram expansion configuration here ! */
+ }
+ amstrad_rethinkMemory(machine);
+}
+
+
+/* ASIC RAM */
+/*
+ ASIC RAM Layout. Always is mapped to &4000-&7fff
+
+ Hardware sprites: 16 sprites, 16x16, basic zooming, 15 colour (12-bit palette)
+ Pixel data is 0 - 15 for sprite pen number, low 4 bits
+ &4000 - &400f Pixel data for first line of first sprite
+ &4010 - &401f Pixel data for second line of first sprite
+ ... ...
+ &40f0 - &40ff Pixel data for last (16th) line of first sprite
+ ... ...
+ &4100 - &41ff Pixel data for second sprite
+ &4200 - &42ff Third sprite
+ ... ...
+ &4f00 - &4fff Pixel data for last (16th) sprite
+
+ &6000 - &607f Sprite properties (8 bytes each)
+ +0 Sprite X position LSB
+ +1 Sprite X position MSB
+ +2 Sprite Y position LSB (scanline)
+ +3 Sprite Y position MSB
+ +4 Sprite zoom - bits 3,2 X magnification, bits 1,0 Y magnification
+ Magnification: 00 = not displayed, 01 = x1, 10 = x2, 11 = x4
+
+ Palette: LSB first, presumably GGGGBBBBxxxxRRRR
+ &6400 - &641f Pen palette (12bpp, 2 bytes each, 16 total)
+ &6420 - &6421 Border palette (12bpp, 2 bytes)
+ &6422 - &643f Hardware sprite palette (12bpp, 2 bytes each, 15 total)
+
+ Programmable Raster Interrupt:
+ &6800 Scanline for IRQ to be triggered after
+ If 0, raster interrupts and DMA interrupts occur
+ Otherwise, the PRI interrupt is triggered only
+
+ Hardware split screen:
+ &6801 Scanline for split to occur at
+ &6802 LSB of screen address for split (like reg 12 of the 6845)
+ &6803 MSB of the above (like reg 13 of the 6845)
+
+ Soft Scroll Control Register:
+ &6804 bits 3-0 - horizontal delay in mode 2 pixels (shifts display to the right)
+ bits 6-4 - added to the 3 LSBs for the scanline address (shifts display up)
+ bit 7 - extends the border by two bytes (16 mode 2 pixels), masking the bad data from the horizontal scroll
+
+ Analogue paddle ports:
+ &6808 - &680f Analogue input, read-only, 6 bit
+
+ PSG DMA channels:
+ &6c00 DMA channel 0 address LSB
+ &6c01 DMA channel 0 address MSB
+ &6c02 DMA channel 0 prescaler
+ &6c03 unused
+ &6c04-7 DMA channel 1
+ &6c08-b DMA channel 2
+ &6c0f Control and Status register
+ bit 7 - raster interrupt
+ bit 6 - DMA channel 0 interrupt
+ bit 5 - DMA channel 1 interrupt
+ bit 4 - DMA channel 2 interrupt
+ bit 3 - unused (write 0)
+ bit 2 - DMA channel 2 enable
+ bit 1 - DMA channel 1 enable
+ bit 0 - DMA channel 0 enable
+
+ */
+
+WRITE8_MEMBER(amstrad_state::amstrad_plus_asic_4000_w)
+{
+// logerror("ASIC: Write to register at &%04x\n",offset+0x4000);
+ if ( m_asic.enabled && ( m_asic.rmr2 & 0x18 ) == 0x18 )
+ m_asic.ram[offset] = data & 0x0f;
+ else
+ {
+ UINT8* RAM = (UINT8*)membank("bank11")->base();
+ RAM[offset] = data;
+ }
+}
+
+
+WRITE8_MEMBER(amstrad_state::amstrad_plus_asic_6000_w)
+{
+ if ( m_asic.enabled && ( m_asic.rmr2 & 0x18 ) == 0x18 )
+ {
+ m_asic.ram[offset+0x2000] = data;
+ if(offset >= 0x0400 && offset < 0x440 && ( offset & 0x01 ) ) // ASIC palette
+ {
+ m_asic.ram[ offset + 0x2000 ] = data & 0x0f;
+ }
+ if(offset == 0x0800) // Programmable raster interrupt
+ {
+ // logerror("ASIC: Wrote %02x to PRI\n",data);
+ m_asic.pri = data;
+ }
+ if(offset >= 0x0801 && offset <= 0x0803) // Split screen registers
+ {
+ logerror("ASIC: Split screen at line %i, address &%04x\n",m_asic.ram[0x2801],m_asic.ram[0x2803] + (m_asic.ram[0x2802] << 8));
+ }
+ if(offset == 0x0804) // Soft scroll register
+ {
+ }
+ if(offset == 0x0805) // Interrupt vector register (for IM 2, used by Pang)
+ {
+ // high 5 bits go to interrupt vector
+ int vector;
+
+ if ( m_asic.enabled )
+ {
+ vector = (data & 0xf8) + (m_plus_irq_cause);
+ device_set_input_line_vector(m_maincpu, 0, vector);
+ logerror("ASIC: IM 2 vector write %02x, data = &%02x\n",vector,data);
+ }
+ m_asic.dma_clear = data & 0x01;
+ }
+ // DMA channels
+ switch(offset)
+ {
+ case 0x0c00:
+ case 0x0c01:
+ m_asic.dma_addr[0] = (m_asic.ram[0x2c01] << 8) + m_asic.ram[0x2c00];
+ m_asic.dma_status &= ~0x01;
+ logerror("ASIC: DMA 0 address set to &%04x\n",m_asic.dma_addr[0]);
+ break;
+ case 0x0c04:
+ case 0x0c05:
+ m_asic.dma_addr[1] = (m_asic.ram[0x2c05] << 8) + m_asic.ram[0x2c04];
+ m_asic.dma_status &= ~0x02;
+ logerror("ASIC: DMA 1 address set to &%04x\n",m_asic.dma_addr[1]);
+ break;
+ case 0x0c08:
+ case 0x0c09:
+ m_asic.dma_addr[2] = (m_asic.ram[0x2c09] << 8) + m_asic.ram[0x2c08];
+ m_asic.dma_status &= ~0x04;
+ logerror("ASIC: DMA 2 address set to &%04x\n",m_asic.dma_addr[2]);
+ break;
+ case 0x0c02:
+ m_asic.dma_prescaler[0] = data + 1;
+ logerror("ASIC: DMA 0 pause prescaler set to %i\n",data);
+ break;
+ case 0x0c06:
+ m_asic.dma_prescaler[1] = data + 1;
+ logerror("ASIC: DMA 1 pause prescaler set to %i\n",data);
+ break;
+ case 0x0c0a:
+ m_asic.dma_prescaler[2] = data + 1;
+ logerror("ASIC: DMA 2 pause prescaler set to %i\n",data);
+ break;
+ case 0x0c0f:
+ m_asic.dma_status = data;
+ logerror("ASIC: DMA status write - %02x\n",data);
+ if(data & 0x40)
+ {
+ logerror("ASIC: DMA 0 IRQ acknowledge\n");
+ cputag_set_input_line(machine(), "maincpu", 0, CLEAR_LINE);
+ m_plus_irq_cause = 0x06;
+ m_asic.ram[0x2c0f] &= ~0x40;
+ }
+ if(data & 0x20)
+ {
+ logerror("ASIC: DMA 1 IRQ acknowledge\n");
+ cputag_set_input_line(machine(), "maincpu", 0, CLEAR_LINE);
+ m_plus_irq_cause = 0x06;
+ m_asic.ram[0x2c0f] &= ~0x20;
+ }
+ if(data & 0x10)
+ {
+ logerror("ASIC: DMA 2 IRQ acknowledge\n");
+ cputag_set_input_line(machine(), "maincpu", 0, CLEAR_LINE);
+ m_plus_irq_cause = 0x06;
+ m_asic.ram[0x2c0f] &= ~0x10;
+ }
+ m_asic.ram[0x2c0f] = (m_asic.ram[0x2c0f] & 0xf8) | (data & 0x07);
+ break;
+ }
+ }
+ else
+ {
+ UINT8* RAM = (UINT8*)membank("bank12")->base();
+ RAM[offset] = data;
+ }
+}
+
+
+READ8_MEMBER(amstrad_state::amstrad_plus_asic_4000_r)
+{
+// logerror("RAM: read from &%04x\n",offset+0x4000);
+ if ( m_asic.enabled && ( m_asic.rmr2 & 0x18 ) == 0x18 )
+ return m_asic.ram[offset];
+ else
+ {
+ UINT8* RAM = (UINT8*)membank("bank3")->base();
+ return RAM[offset];
+ }
+}
+
+
+READ8_MEMBER(amstrad_state::amstrad_plus_asic_6000_r)
+{
+// logerror("RAM: read from &%04x\n",offset+0x6000);
+ if ( m_asic.enabled && ( m_asic.rmr2 & 0x18 ) == 0x18 )
+ {
+ // Analogue ports
+ if(offset == 0x0808)
+ {
+ return (ioport("analog1")->read() & 0x3f);
+ }
+ if(offset == 0x0809)
+ {
+ return (ioport("analog2")->read() & 0x3f);
+ }
+ if(offset == 0x080a)
+ {
+ return (ioport("analog3")->read() & 0x3f);
+ }
+ if(offset == 0x080b)
+ {
+ return (ioport("analog4")->read() & 0x3f);
+ }
+ if(offset == 0x080c || offset == 0x080e)
+ {
+ return 0x3f;
+ }
+ if(offset == 0x080d || offset == 0x080f)
+ {
+ return 0x00;
+ }
+ #if 0
+ if(offset == 0x0c0f) // DMA status and control
+ {
+ int result = 0;
+ if(m_plus_irq_cause == 0x00)
+ result |= 0x40;
+ if(m_plus_irq_cause == 0x02)
+ result |= 0x20;
+ if(m_plus_irq_cause == 0x04)
+ result |= 0x10;
+ if(m_plus_irq_cause == 0x06)
+ result |= 0x80;
+ return result;
+ }
+ #endif
+ return m_asic.ram[offset+0x2000];
+ }
+ else
+ {
+ UINT8* RAM = (UINT8*)membank("bank4")->base();
+ return RAM[offset];
+ }
+}
+
+
+/* used for loading snapshot only ! */
+static void AmstradCPC_PALWrite(running_machine &machine, int data)
+{
+ amstrad_state *state = machine.driver_data<amstrad_state>();
+ if ((data & 0x0c0)==0x0c0)
+ {
+ state->m_GateArray_RamConfiguration = data;
+ AmstradCPC_GA_SetRamConfiguration(machine);
+ }
+}
+
+
+/* -------------------
+ - the Gate Array -
+ -------------------
+The gate array is controlled by I/O. The recommended I/O port address is &7Fxx.
+The gate array is selected when bit 15 of the I/O port address is set to "0" and bit 14 of the I/O port address is set to "1".
+The values of the other bits are ignored.
+However, to avoid conflict with other devices in the system, these bits should be set to "1".
+
+The function to be performed is selected by writing data to the Gate-Array, bit 7 and 6 of the data define the function selected (see table below).
+It is not possible to read from the Gate-Array.
+
+Bit 7 Bit 6 Function
+0 0 Select pen
+0 1 Select colour for selected pen
+1 0 Select screen mode, rom configuration and interrupt control
+1 1 Ram Memory Management (note 1)
+
+Note 1 : This function is not available in the Gate-Array, but is performed by a device at the same I/O port address location. In the CPC464,CPC664 and KC compact, this function is performed in a memory-expansion (e.g. Dk'Tronics 64K Ram Expansion), if this expansion is not present then the function is not available. In the CPC6128, this function is performed by a PAL located on the main PCB, or a memory-expansion. In the 464+ and 6128+ this function is performed by the ASIC or a memory expansion. Please read the document on Ram Management for more information.*/
+
+
+static void amstrad_GateArray_write(running_machine &machine, UINT8 dataToGateArray)
+{
+ amstrad_state *state = machine.driver_data<amstrad_state>();
+/* Get Bit 7 and 6 of the dataToGateArray = Gate Array function selected */
+ switch ((dataToGateArray & 0xc0)>>6)
+ {
+/* Pen selection
+ -------------
+Bit Value Function Bit Value Function
+5 x not used 5 x not used
+4 1 Select border 4 0 Select pen
+3 x | ignored 3 x | Pen Number
+2 x | 2 x |
+1 x | 1 x |
+0 x | 0 x |
+*/
+ case 0x00:
+ /* Select Border Number, get b4 */
+ /* if b4 = 0 : Select Pen Number, get b3-b0 */
+ state->m_gate_array.pen_selected = ( dataToGateArray & 0x10 ) ? 0x10 : ( dataToGateArray & 0x0f );
+ break;
+
+/* Colour selection
+ ----------------
+Even though there is provision for 32 colours, only 27 are possible.
+The remaining colours are duplicates of those already in the colour palette.
+
+Bit Value Function
+5 x not used
+4 x | Colour number
+3 x |
+2 x |
+1 x |
+0 x |*/
+ case 0x01:
+ amstrad_vh_update_colour( machine, state->m_gate_array.pen_selected, (dataToGateArray & 0x1F));
+ break;
+
+/* Select screen mode and rom configuration
+ ----------------------------------------
+Bit Value Function
+5 x not used
+4 x Interrupt generation control
+3 1 Upper rom area disable or 0 Upper rom area enable
+2 1 Lower rom area disable or 0 Lower rom area enable
+1 x | Mode selection
+0 x |
+
+Screen mode selection : The settings for bits 1 and 0 and the corresponding screen mode are given in the table below.
+-----------------------
+b1 b0 Screen mode
+0 0 Mode 0, 160x200 resolution, 16 colours
+0 1 Mode 1, 320x200 resolution, 4 colours
+1 0 Mode 2, 640x200 resolution, 2 colours
+1 1 Mode 3, 160x200 resolution, 4 colours (note 1)
+
+This mode is not official. From the combinations possible, we can see that 4 modes can be defined, although the Amstrad only has 3. Mode 3 is similar to mode 0, because it has the same resolution, but it is limited to only 4 colours.
+Mode changing is synchronised with HSYNC. If the mode is changed, it will take effect from the next HSYNC.
+
+Rom configuration selection :
+-----------------------------
+Bit 2 is used to enable or disable the lower rom area. The lower rom area occupies memory addressess &0000-&3fff and is used to access the operating system rom. When the lower rom area is is enabled, reading from &0000-&3FFF will return data in the rom. When a value is written to &0000-&3FFF, it will be written to the ram underneath the rom. When it is disabled, data read from &0000-&3FFF will return the data in the ram.
+Similarly, bit 3 controls enabling or disabling of the upper rom area. The upper rom area occupies memory addressess &C000-&FFFF and is BASIC or any expansion roms which may be plugged into a rom board/box. See the document on upper rom selection for more details. When the upper rom area enabled, reading from &c000-&ffff, will return data in the rom. When data is written to &c000-&FFFF, it will be written to the ram at the same address as the rom. When the upper rom area is disabled, and data is read from &c000-&ffff the data returned will be the data in the ram.
+
+Bit 4 controls the interrupt generation. It can be used to delay interrupts.*/
+ case 0x02:
+ /* If bit 5 is enabled on a CPC Plus/GX4000 when the ASIC is unlocked, sets the lower ROM position and cart bank
+ b5 = 1, b4b3 = RAM position for lower ROM area and if the ASIC registers are visible at &4000,
+ b2b1b0 = cartridge bank to read from lower ROM area (0-7 only) */
+ if ( state->m_system_type == SYSTEM_PLUS || state->m_system_type == SYSTEM_GX4000 )
+ {
+ if ( state->m_asic.enabled && (dataToGateArray & 0x20) )
+ {
+ state->m_asic.rmr2 = dataToGateArray;
+ }
+ else
+ {
+ state->m_gate_array.mrer = dataToGateArray;
+ }
+ }
+ else
+ {
+ state->m_gate_array.mrer = dataToGateArray;
+ }
+
+ /* If bit 4 of the "Select screen mode and rom configuration" register of the Gate-Array is set to "1"
+ then the interrupt request is cleared and the 6-bit counter is reset to "0". */
+ if ( state->m_gate_array.mrer & 0x10 )
+ {
+ state->m_gate_array.hsync_counter = 0;
+ cputag_set_input_line(machine, "maincpu", 0, CLEAR_LINE);
+ }
+
+ /* b3b2 != 0 then change the state of upper or lower rom area and rethink memory */
+ amstrad_setLowerRom(machine);
+ amstrad_setUpperRom(machine);
+
+ /* b1b0 mode */
+ amstrad_vh_update_mode(state);
+
+ break;
+
+/* Ram Memory Management
+ ---------------------
+This function is not available in the Gate-Array, but is performed by a device at the same I/O port address location.
+In the CPC464,CPC664 and KC compact, this function is performed in a memory-expansion (e.g. Dk'Tronics 64K Ram Expansion), if this expansion is not present then the function is not available.
+In the CPC6128, this function is performed by a PAL located on the main PCB, or a memory-expansion.
+In the 464+ and 6128+ this function is performed by the ASIC or a memory expansion.
+*/
+ case 0x03:
+ state->m_GateArray_RamConfiguration = dataToGateArray;
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+WRITE8_MEMBER(amstrad_state::aleste_msx_mapper)
+{
+ int page = (offset & 0x0300) >> 8;
+ int ramptr = (data & 0x1f) * 0x4000;
+ int rampage = data & 0x1f;
+ int function = (data & 0xc0) >> 6;
+ UINT8 *ram = m_ram->pointer();
+
+ // It is assumed that functions are all mapped to each port &7cff-&7fff, and b8 and b9 are only used for RAM bank location
+ switch(function)
+ {
+ case 0: // Pen select (same as Gate Array?)
+ amstrad_GateArray_write(machine(), data);
+ break;
+ case 1: // Colour select (6-bit palette)
+ aleste_vh_update_colour( machine(), m_gate_array.pen_selected, data & 0x3f );
+ break;
+ case 2: // Screen mode, Upper/Lower ROM select
+ amstrad_GateArray_write(machine(), data);
+ break;
+ case 3: // RAM banks
+ switch(page)
+ {
+ case 0: /* 0x0000 - 0x3fff */
+ membank("bank1")->set_base(ram+ramptr);
+ membank("bank2")->set_base(ram+ramptr+0x2000);
+ membank("bank9")->set_base(ram+ramptr);
+ membank("bank10")->set_base(ram+ramptr+0x2000);
+ m_Aleste_RamBanks[0] = ram+ramptr;
+ m_aleste_active_page[0] = data;
+ logerror("RAM: RAM location 0x%06x (page %02x) mapped to 0x0000\n",ramptr,rampage);
+ break;
+ case 1: /* 0x4000 - 0x7fff */
+ membank("bank3")->set_base(ram+ramptr);
+ membank("bank4")->set_base(ram+ramptr+0x2000);
+ membank("bank11")->set_base(ram+ramptr);
+ membank("bank12")->set_base(ram+ramptr+0x2000);
+ m_Aleste_RamBanks[1] = ram+ramptr;
+ m_aleste_active_page[1] = data;
+ logerror("RAM: RAM location 0x%06x (page %02x) mapped to 0x4000\n",ramptr,rampage);
+ break;
+ case 2: /* 0x8000 - 0xbfff */
+ membank("bank5")->set_base(ram+ramptr);
+ membank("bank6")->set_base(ram+ramptr+0x2000);
+ membank("bank13")->set_base(ram+ramptr);
+ membank("bank14")->set_base(ram+ramptr+0x2000);
+ m_Aleste_RamBanks[2] = ram+ramptr;
+ m_aleste_active_page[2] = data;
+ logerror("RAM: RAM location 0x%06x (page %02x) mapped to 0x8000\n",ramptr,rampage);
+ break;
+ case 3: /* 0xc000 - 0xffff */
+ membank("bank7")->set_base(ram+ramptr);
+ membank("bank8")->set_base(ram+ramptr+0x2000);
+ membank("bank15")->set_base(ram+ramptr);
+ membank("bank16")->set_base(ram+ramptr+0x2000);
+ m_Aleste_RamBanks[3] = ram+ramptr;
+ m_aleste_active_page[3] = data;
+ logerror("RAM: RAM location 0x%06x (page %02x) mapped to 0xc000\n",ramptr,rampage);
+ break;
+ }
+ break;
+ }
+}
+
+
+/* CRTC Differences
+ ----------------
+The following tables list the functions that can be accessed for each type:
+
+Type 0
+b1 b0 Function Read/Write
+0 0 Select internal 6845 register Write Only
+0 1 Write to selected internal 6845 register Write Only
+1 0 - -
+1 1 Read from selected internal 6845 register Read only
+
+Type 1
+b1 b0 Function Read/Write
+0 0 Select internal 6845 register Write Only
+0 1 Write to selected internal 6845 register Write Only
+1 0 Read Status Register Read Only
+1 1 Read from selected internal 6845 register Read only
+
+Type 2
+b1 b0 Function Read/Write
+0 0 Select internal 6845 register Write Only
+0 1 Write to selected internal 6845 register Write Only
+1 0 - -
+1 1 Read from selected internal 6845 register Read only
+
+Type 3 and 4
+b1 b0 Function Read/Write
+0 0 Select internal 6845 register Write Only
+0 1 Write to selected internal 6845 register Write Only
+1 0 Read from selected internal 6845 register Read Only
+1 1 Read from selected internal 6845 register Read only
+*/
+
+/* I/O port allocation
+ -------------------
+
+Many thanks to Mark Rison for providing the original information. Thankyou to Richard Wilson for his discoveries concerning RAM management I/O decoding.
+
+This document will explain the decoding of the I/O ports. The port address is not decoded fully which means a hardware device can be accessed through more than one address, in addition, using some addressess can access more than one element of the hardware at the same time. The CPC IN/OUT design differs from the norm in that port numbers are defined using 16 bits, as opposed to the traditional 8 bits.
+
+IN r,(C)/OUT (C),r instructions: Bits b15-b8 come from the B register, bits b7-b0 come from "r"
+IN A,(n)/OUT (n),A instructions: Bits b15-b8 come from the A register, bits b7-b0 come from "n"
+Listed below are the internal hardware devices and the bit fields to which they respond. In the table:
+
+"-" means this bit is ignored,
+"0" means the bit must be set to "0" for the hardware device to respond,
+"1" means the bit must be set to "1" for the hardware device to respond.
+"r1" and "r0" mean a bit used to define a register
+
+Hardware device Read/Write Port bits
+ b15 b14 b13 b12 b11 b10 b9 b8 b7 b6 b5 b4 b3 b2 b1 b0
+Gate-Array Write Only 0 1 - - - - - - - - - - - - - -
+RAM Configuration Write Only 0 - - - - - - - - - - - - - - -
+CRTC Read/Write - 0 - - - - r1 r0 - - - - - - - -
+ROM select Write only - - 0 - - - - - - - - - - - - -
+Printer port Write only - - - 0 - - - - - - - - - - - -
+8255 PPI Read/Write - - - - 0 - r1 r0 - - - - - - - -
+Expansion Peripherals Read/Write - - - - - 0 - - - - - - - - - -
+
+*/
+
+READ8_MEMBER(amstrad_state::amstrad_cpc_io_r)
+{
+ device_t *fdc = m_fdc;
+ mc6845_device *mc6845 = m_crtc;
+
+ unsigned char data = 0xFF;
+ unsigned int r1r0 = (unsigned int)((offset & 0x0300) >> 8);
+// m6845_personality_t crtc_type;
+ int page;
+
+// crtc_type = ioport("crtc"->read_safe(0));
+// m6845_set_personality(crtc_type);
+
+ if(m_aleste_mode & 0x04)
+ {
+ if ((offset & (1<<15)) == 0) // Aleste Mapper is readable?
+ {
+ page = (offset & 0x0300) >> 8;
+ data = m_aleste_active_page[page];
+ return data;
+ }
+ }
+
+ /* if b14 = 0 : CRTC Read selected */
+ if ((offset & (1<<14)) == 0)
+ {
+ switch(r1r0)
+ {
+ case 0x02:
+ data = mc6845->status_r( space, 0 );
+#if 0
+ /* CRTC Type 1 : Read Status Register
+ CRTC Type 3 or 4 : Read from selected internal 6845 register */
+ switch(crtc_type) {
+ case M6845_PERSONALITY_UM6845R:
+ data = amstrad_CRTC_CR; /* Read Status Register */
+ break;
+ case M6845_PERSONALITY_AMS40489:
+ case M6845_PERSONALITY_PREASIC:
+ data = m6845_register_r(0);
+ break;
+ default:
+ break;
+ }
+#endif
+ break;
+ case 0x03:
+ /* All CRTC type : Read from selected internal 6845 register Read only */
+ data = mc6845->register_r( space, (offs_t)0 );
+ break;
+ }
+ }
+
+/* if b11 = 0 : 8255 PPI Read selected - bits 9 and 8 then define the PPI function access as shown below:
+
+b9 b8 | PPI Function Read/Write status
+0 0 | Port A data Read/Write
+0 1 | Port B data Read/Write
+1 0 | Port C data Read/Write
+1 1 | Control Write Only
+*/
+ if ((offset & (1<<11)) == 0)
+ {
+ if (r1r0 < 0x03 )
+ data = m_ppi->read(space, r1r0);
+ }
+
+/* if b10 = 0 : Expansion Peripherals Read selected
+
+bits b7-b5 are used to select an expansion peripheral. Again, this is done by resetting the peripheral's bit:
+Bit | Device
+b7 | FDC
+b6 | Reserved (was it ever used?)
+b5 | Serial port
+
+In the case of the FDC, bits b8 and b0 are used to select the specific mode of operation; all the other bits (b9,b4-b1) are ignored:
+b8 b0 Function Read/Write state
+0 0 FDD motor control Write Only
+0 1 not used N/A
+1 0 Main Status register of FDC (MSR) Read Only
+1 1 Data register of FDC Read/Write
+
+If b10 is reset but none of b7-b5 are reset, user expansion peripherals are selected.
+The exception is the case where none of b7-b0 are reset (i.e. port &FBFF), which causes the expansion peripherals to reset.
+ */
+ if ( m_system_type != SYSTEM_GX4000 )
+ {
+ if ( ( offset & (1<<10) ) == 0 )
+ {
+ if ( ( offset & (1<<10) ) == 0 )
+ {
+ int b8b0 = ( ( offset & (1<<8) ) >> (8 - 1) ) | ( offset & 0x01 );
+
+ switch (b8b0)
+ {
+ case 0x02:
+ data = upd765_status_r(fdc, 0);
+ break;
+ case 0x03:
+ data = upd765_data_r(fdc, 0);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ return data;
+}
+
+
+// Handler for checking the ASIC unlocking sequence
+void amstrad_state::amstrad_plus_seqcheck(int data)
+{
+ if(data == 0 && m_prev_data != 0)
+ {
+ m_asic.seqptr = 0; // non-zero value followed by zero will sync the locking mechanism
+ }
+ if(data == asic_unlock_seq[m_asic.seqptr])
+ {
+ m_asic.seqptr++;
+ if ( m_asic.seqptr == 14 && m_asic.enabled )
+ {
+ logerror("SYS: ASIC locked\n");
+ m_asic.enabled = 0;
+ }
+ if ( m_asic.seqptr >= 15 ) // end of sequence
+ {
+ logerror("SYS: ASIC unlocked\n");
+ m_asic.enabled = 1;
+ }
+ }
+ m_prev_data = data;
+}
+
+/* Offset handler for write */
+WRITE8_MEMBER(amstrad_state::amstrad_cpc_io_w)
+{
+ device_t *fdc = m_fdc;
+ mc6845_device *mc6845 = m_crtc;
+ cpc_multiface2_device* mface2;
+
+ if ((offset & (1<<15)) == 0)
+ {
+ if(m_aleste_mode & 0x04) // Aleste mode
+ {
+ aleste_msx_mapper(space, offset, data);
+ }
+ else
+ {
+ /* if b15 = 0 and b14 = 1 : Gate-Array Write Selected*/
+ if ((offset & (1<<14)) != 0)
+ amstrad_GateArray_write(machine(), data);
+
+ /* if b15 = 0 : RAM Configuration Write Selected*/
+ AmstradCPC_GA_SetRamConfiguration(machine());
+ }
+ }
+
+ /*The Gate-Array and CRTC can't be selected simultaneously, which would otherwise cause potential display corruption.*/
+ /* if b14 = 0 : CRTC Write Selected*/
+ if ((offset & (1<<14)) == 0)
+ {
+ switch ((offset & 0x0300) >> 8) // r1r0
+ {
+ case 0x00: /* Select internal 6845 register Write Only */
+ mc6845->address_w( space, 0, data );
+ if ( m_system_type == SYSTEM_PLUS || m_system_type == SYSTEM_GX4000 )
+ amstrad_plus_seqcheck(data);
+
+ /* printer port d7 */
+ if (data == 0x0c && m_system_type == SYSTEM_PLUS)
+ m_printer_bit8_selected = TRUE;
+
+ m_asic.addr_6845 = data;
+ break;
+ case 0x01: /* Write to selected internal 6845 register Write Only */
+ if ( m_system_type == SYSTEM_PLUS || m_system_type == SYSTEM_GX4000 )
+ machine().scheduler().timer_set( attotime::from_usec(0), FUNC(amstrad_video_update_timer),1);
+ else
+ machine().scheduler().timer_set( attotime::from_usec(0), FUNC(amstrad_video_update_timer),0);
+ mc6845->register_w( space, 0, data );
+
+ /* printer port bit 8 */
+ if (m_printer_bit8_selected && m_system_type == SYSTEM_PLUS)
+ {
+ centronics_device *printer = m_centronics;
+ printer->d7_w(BIT(data, 3));
+ m_printer_bit8_selected = FALSE;
+ }
+
+ if ( m_asic.addr_6845 == 0x01 )
+ m_asic.horiz_disp = data;
+
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* ROM select before GateArrayWrite ?*/
+ /* b13 = 0 : ROM select Write Selected*/
+ if ((offset & (1<<13)) == 0)
+ {
+ m_gate_array.upper_bank = data;
+ amstrad_setUpperRom(machine());
+ }
+
+ /* b12 = 0 : Printer port Write Selected*/
+ if(m_system_type != SYSTEM_GX4000)
+ {
+ if ((offset & (1<<12)) == 0)
+ {
+ centronics_device *printer = m_centronics;
+
+ /* CPC has a 7-bit data port, bit 8 is the STROBE signal */
+ printer->write(space, 0, data & 0x7f);
+ printer->strobe_w(BIT(data, 7));
+ }
+ }
+
+ /* if b11 = 0 : 8255 PPI Write selected - bits 9 and 8 then define the PPI function access as shown below:
+ b9 b8 | PPI Function Read/Write status
+ 0 0 | Port A data Read/Write
+ 0 1 | Port B data Read/Write
+ 1 0 | Port C data Read/Write
+ 1 1 | Control Write Only
+ */
+ if ((offset & (1<<11)) == 0)
+ {
+ unsigned int Index = ((offset & 0x0300) >> 8);
+
+ m_ppi->write(space, Index, data);
+ }
+
+ /* if b10 = 0 : Expansion Peripherals Write selected */
+ if ((offset & (1<<10)) == 0)
+ {
+/* bits b7-b5 are used to select an expansion peripheral. This is done by resetting the peripheral's bit:
+Bit | Device
+b7 | FDC
+b6 | Reserved (was it ever used?)
+b5 | Serial port
+
+In the case of the FDC, bits b8 and b0 are used to select the specific mode of operation;
+all the other bits (b9,b4-b1) are ignored:
+b8 b0 Function Read/Write state
+0 0 FDD motor control Write Only
+0 1 not used N/A
+1 0 Main Status register of FDC (MSR) Read Only
+1 1 Data register of FDC Read/Write
+
+If b10 is reset but none of b7-b5 are reset, user expansion peripherals are selected.
+The exception is the case where none of b7-b0 are reset (i.e. port &FBFF), which causes the expansion peripherals to reset.
+*/
+ if(m_system_type != SYSTEM_GX4000)
+ {
+ if ((offset & (1<<7)) == 0)
+ {
+ unsigned int b8b0 = ((offset & 0x0100) >> (8 - 1)) | (offset & 0x01);
+
+ switch (b8b0)
+ {
+ case 0x00:
+ /* 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_mon_w(floppy_get_device(machine(), 0), !BIT(data, 0));
+ floppy_mon_w(floppy_get_device(machine(), 1), !BIT(data, 0));
+ floppy_drive_set_ready_state(floppy_get_device(machine(), 0), 1,1);
+ floppy_drive_set_ready_state(floppy_get_device(machine(), 1), 1,1);
+ break;
+
+ case 0x03: /* Write Data register of FDC */
+ upd765_data_w(fdc, 0,data);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ /* Aleste Extend Port:
+ D0 - VRAM Bank 0/1 (64K)
+ D1 - MODE 0-Norm ,1-High resolution
+ D2 - MAPMOD 0-Amstrad ,1-Yamaha mapper
+ D3 - MAP Page 0/1 (256K)
+ D4 - 580WI53
+ D5 - 0-AY8910 ,1-512WI1 */
+ if(offset == 0xfabf)
+ {
+ m_aleste_mode = data;
+ logerror("EXTEND: Port &FABF write 0x%02x\n",data);
+ mc6845->set_clock( ( m_aleste_mode & 0x02 ) ? ( XTAL_16MHz / 8 ) : ( XTAL_16MHz / 16 ) );
+ }
+
+ mface2 = dynamic_cast<cpc_multiface2_device*>(get_expansion_device(machine(),"multiface2"));
+ if(mface2 != NULL)
+ {
+ if(mface2->multiface_io_write(offset, data) != 0)
+ amstrad_rethinkMemory(machine());
+ }
+}
+
+
+/* load CPCEMU style snapshots */
+static void amstrad_handle_snapshot(running_machine &machine, unsigned char *pSnapshot)
+{
+ amstrad_state *state = machine.driver_data<amstrad_state>();
+ address_space* space = state->m_maincpu->memory().space(AS_PROGRAM);
+ mc6845_device *mc6845 = state->m_crtc;
+ device_t *ay8910 = state->m_ay;
+ int RegData;
+ int i;
+
+ /* init Z80 */
+ RegData = (pSnapshot[0x011] & 0x0ff) | ((pSnapshot[0x012] & 0x0ff)<<8);
+ cpu_set_reg(state->m_maincpu, Z80_AF, RegData);
+
+ RegData = (pSnapshot[0x013] & 0x0ff) | ((pSnapshot[0x014] & 0x0ff)<<8);
+ cpu_set_reg(state->m_maincpu, Z80_BC, RegData);
+
+ RegData = (pSnapshot[0x015] & 0x0ff) | ((pSnapshot[0x016] & 0x0ff)<<8);
+ cpu_set_reg(state->m_maincpu, Z80_DE, RegData);
+
+ RegData = (pSnapshot[0x017] & 0x0ff) | ((pSnapshot[0x018] & 0x0ff)<<8);
+ cpu_set_reg(state->m_maincpu, Z80_HL, RegData);
+
+ RegData = (pSnapshot[0x019] & 0x0ff) ;
+ cpu_set_reg(state->m_maincpu, Z80_R, RegData);
+
+ RegData = (pSnapshot[0x01a] & 0x0ff);
+ cpu_set_reg(state->m_maincpu, Z80_I, RegData);
+
+ if ((pSnapshot[0x01b] & 1)==1)
+ {
+ cpu_set_reg(state->m_maincpu, Z80_IFF1, (UINT64)1);
+ }
+ else
+ {
+ cpu_set_reg(state->m_maincpu, Z80_IFF1, (UINT64)0);
+ }
+
+ if ((pSnapshot[0x01c] & 1)==1)
+ {
+ cpu_set_reg(state->m_maincpu, Z80_IFF2, (UINT64)1);
+ }
+ else
+ {
+ cpu_set_reg(state->m_maincpu, Z80_IFF2, (UINT64)0);
+ }
+
+ RegData = (pSnapshot[0x01d] & 0x0ff) | ((pSnapshot[0x01e] & 0x0ff)<<8);
+ cpu_set_reg(state->m_maincpu, Z80_IX, RegData);
+
+ RegData = (pSnapshot[0x01f] & 0x0ff) | ((pSnapshot[0x020] & 0x0ff)<<8);
+ cpu_set_reg(state->m_maincpu, Z80_IY, RegData);
+
+ RegData = (pSnapshot[0x021] & 0x0ff) | ((pSnapshot[0x022] & 0x0ff)<<8);
+ cpu_set_reg(state->m_maincpu, Z80_SP, RegData);
+ cpu_set_reg(state->m_maincpu, STATE_GENSP, RegData);
+
+ RegData = (pSnapshot[0x023] & 0x0ff) | ((pSnapshot[0x024] & 0x0ff)<<8);
+
+ cpu_set_reg(state->m_maincpu, Z80_PC, RegData);
+// cpu_set_reg(state->m_maincpu, REG_SP, RegData);
+
+ RegData = (pSnapshot[0x025] & 0x0ff);
+ cpu_set_reg(state->m_maincpu, Z80_IM, RegData);
+
+ RegData = (pSnapshot[0x026] & 0x0ff) | ((pSnapshot[0x027] & 0x0ff)<<8);
+ cpu_set_reg(state->m_maincpu, Z80_AF2, RegData);
+
+ RegData = (pSnapshot[0x028] & 0x0ff) | ((pSnapshot[0x029] & 0x0ff)<<8);
+ cpu_set_reg(state->m_maincpu, Z80_BC2, RegData);
+
+ RegData = (pSnapshot[0x02a] & 0x0ff) | ((pSnapshot[0x02b] & 0x0ff)<<8);
+ cpu_set_reg(state->m_maincpu, Z80_DE2, RegData);
+
+ RegData = (pSnapshot[0x02c] & 0x0ff) | ((pSnapshot[0x02d] & 0x0ff)<<8);
+ cpu_set_reg(state->m_maincpu, Z80_HL2, RegData);
+
+ /* init GA */
+ for (i=0; i<17; i++)
+ {
+ amstrad_GateArray_write(machine, i);
+
+ amstrad_GateArray_write(machine, ((pSnapshot[0x02f + i] & 0x01f) | 0x040));
+ }
+
+ amstrad_GateArray_write(machine, pSnapshot[0x02e] & 0x01f);
+
+ amstrad_GateArray_write(machine, ((pSnapshot[0x040] & 0x03f) | 0x080));
+
+ AmstradCPC_PALWrite(machine, ((pSnapshot[0x041] & 0x03f) | 0x0c0));
+
+ /* init CRTC */
+ for (i=0; i<18; i++)
+ {
+ mc6845->address_w( *space, 0, i );
+ mc6845->register_w( *space, 0, pSnapshot[0x043+i] & 0xff );
+ }
+
+ mc6845->address_w( *space, 0, i );
+
+ /* upper rom selection */
+ state->m_gate_array.upper_bank = pSnapshot[0x055];
+
+ /* PPI */
+ state->m_ppi->write(*space, 3, pSnapshot[0x059] & 0x0ff);
+
+ state->m_ppi->write(*space, 0, pSnapshot[0x056] & 0x0ff);
+ state->m_ppi->write(*space, 1, pSnapshot[0x057] & 0x0ff);
+ state->m_ppi->write(*space, 2, pSnapshot[0x058] & 0x0ff);
+
+ /* PSG */
+ for (i=0; i<16; i++)
+ {
+ ay8910_address_w(ay8910, 0, i);
+ ay8910_data_w(ay8910, 0, pSnapshot[0x05b + i] & 0x0ff);
+ }
+
+ ay8910_address_w(ay8910, 0, pSnapshot[0x05a]);
+
+ {
+ int MemSize;
+ int MemorySize;
+
+ MemSize = (pSnapshot[0x06b] & 0x0ff) | ((pSnapshot[0x06c] & 0x0ff)<<8);
+
+ if (MemSize==128)
+ {
+ MemorySize = 128*1024;
+ }
+ else
+ {
+ MemorySize = 64*1024;
+ }
+
+ memcpy(state->m_ram->pointer(), &pSnapshot[0x0100], MemorySize);
+ }
+ amstrad_rethinkMemory(machine);
+}
+
+
+/* sets up for a machine reset
+All hardware is reset and the firmware is completely initialized
+Once all tables and jumpblocks have been set up,
+control is passed to the default entry in rom 0*/
+static void amstrad_reset_machine(running_machine &machine)
+{
+ amstrad_state *state = machine.driver_data<amstrad_state>();
+ /* enable lower rom (OS rom) */
+ amstrad_GateArray_write(machine, 0x089);
+
+ /* set ram config 0 */
+ amstrad_GateArray_write(machine, 0x0c0);
+
+ // Get manufacturer name and TV refresh rate from PCB link (dipswitch for mess emulation)
+ state->m_ppi_port_inputs[amstrad_ppi_PortB] = (((machine.root_device().ioport("solder_links")->read()&MANUFACTURER_NAME)<<1) | (machine.root_device().ioport("solder_links")->read()&TV_REFRESH_RATE));
+
+ if ( state->m_system_type == SYSTEM_PLUS || state->m_system_type == SYSTEM_GX4000 )
+ memset(state->m_asic.ram,0,16384); // clear ASIC RAM
+}
+
+
+/*------------------
+ - Rethink Memory -
+ ------------------*/
+static void amstrad_rethinkMemory(running_machine &machine)
+{
+ amstrad_state *state = machine.driver_data<amstrad_state>();
+ cpc_multiface2_device* mface2;
+ /* the following is used for banked memory read/writes and for setting up
+ * opcode and opcode argument reads */
+
+ /* bank 0 - 0x0000..0x03fff */
+ amstrad_setLowerRom(machine);
+
+ /* bank 1 - 0x04000..0x07fff */
+ if ( state->m_system_type == SYSTEM_CPC || state->m_system_type == SYSTEM_ALESTE || state->m_asic.enabled == 0 )
+ {
+ if(state->m_aleste_mode & 0x04)
+ {
+ state->membank("bank3")->set_base(state->m_Aleste_RamBanks[1]);
+ state->membank("bank4")->set_base(state->m_Aleste_RamBanks[1]+0x2000);
+ /* bank 2 - 0x08000..0x0bfff */
+ state->membank("bank5")->set_base(state->m_Aleste_RamBanks[2]);
+ state->membank("bank6")->set_base(state->m_Aleste_RamBanks[2]+0x2000);
+ }
+ else
+ {
+ state->membank("bank3")->set_base(state->m_AmstradCPC_RamBanks[1]);
+ state->membank("bank4")->set_base(state->m_AmstradCPC_RamBanks[1]+0x2000);
+ /* bank 2 - 0x08000..0x0bfff */
+ state->membank("bank5")->set_base(state->m_AmstradCPC_RamBanks[2]);
+ state->membank("bank6")->set_base(state->m_AmstradCPC_RamBanks[2]+0x2000);
+ }
+ }
+ else
+ amstrad_setLowerRom(machine);
+
+ /* bank 3 - 0x0c000..0x0ffff */
+ amstrad_setUpperRom(machine);
+
+ /* other banks */
+ if(state->m_aleste_mode & 0x04)
+ {
+ state->membank("bank9")->set_base(state->m_Aleste_RamBanks[0]);
+ state->membank("bank10")->set_base(state->m_Aleste_RamBanks[0]+0x2000);
+ state->membank("bank11")->set_base(state->m_Aleste_RamBanks[1]);
+ state->membank("bank12")->set_base(state->m_Aleste_RamBanks[1]+0x2000);
+ state->membank("bank13")->set_base(state->m_Aleste_RamBanks[2]);
+ state->membank("bank14")->set_base(state->m_Aleste_RamBanks[2]+0x2000);
+ state->membank("bank15")->set_base(state->m_Aleste_RamBanks[3]);
+ state->membank("bank16")->set_base(state->m_Aleste_RamBanks[3]+0x2000);
+ }
+ else
+ {
+ state->membank("bank9")->set_base(state->m_AmstradCPC_RamBanks[0]);
+ state->membank("bank10")->set_base(state->m_AmstradCPC_RamBanks[0]+0x2000);
+ state->membank("bank11")->set_base(state->m_AmstradCPC_RamBanks[1]);
+ state->membank("bank12")->set_base(state->m_AmstradCPC_RamBanks[1]+0x2000);
+ state->membank("bank13")->set_base(state->m_AmstradCPC_RamBanks[2]);
+ state->membank("bank14")->set_base(state->m_AmstradCPC_RamBanks[2]+0x2000);
+ state->membank("bank15")->set_base(state->m_AmstradCPC_RamBanks[3]);
+ state->membank("bank16")->set_base(state->m_AmstradCPC_RamBanks[3]+0x2000);
+ }
+
+ /* multiface hardware enabled? */
+ mface2 = dynamic_cast<cpc_multiface2_device*>(get_expansion_device(machine,"multiface2"));
+ if(mface2 != NULL)
+ {
+ if (mface2->multiface_hardware_enabled())
+ {
+ if((state->m_gate_array.mrer & 0x04) == 0)
+ mface2->multiface_rethink_memory();
+ }
+ }
+}
+
+
+static void kccomp_reset_machine(running_machine &machine)
+{
+ /* enable lower rom (OS rom) */
+ amstrad_GateArray_write(machine, 0x089);
+
+ /* set ram config 0 */
+ amstrad_GateArray_write(machine, 0x0c0);
+}
+
+
+SCREEN_VBLANK( amstrad )
+{
+ // rising edge
+ if (vblank_on)
+ {
+ cpc_multiface2_device* mface2 = dynamic_cast<cpc_multiface2_device*>(get_expansion_device(screen.machine(),"multiface2"));
+
+ if(mface2 != NULL)
+ {
+ mface2->check_button_state();
+ }
+ }
+}
+
+
+/* ---------------------------------------
+ - 27.05.2004 - PSG function selection -
+ ---------------------------------------
+The databus of the PSG is connected to PPI Port A.
+Data is read from/written to the PSG through this port.
+
+The PSG function, defined by the BC1,BC2 and BDIR signals, is controlled by bit 7 and bit 6 of PPI Port C.
+
+PSG function selection:
+-----------------------
+Function
+
+BDIR = PPI Port C Bit 7 and BC1 = PPI Port C Bit 6
+
+PPI Port C Bit | PSG Function
+BDIR BC1 |
+0 0 | Inactive
+0 1 | Read from selected PSG register. When function is set, the PSG will make the register data available to PPI Port A
+1 0 | Write to selected PSG register. When set, the PSG will take the data at PPI Port A and write it into the selected PSG register
+1 1 | Select PSG register. When set, the PSG will take the data at PPI Port A and select a register
+*/
+/* PSG function selected */
+static void update_psg(running_machine &machine)
+{
+ amstrad_state *state = machine.driver_data<amstrad_state>();
+ address_space *space = state->m_maincpu->memory().space(AS_PROGRAM);
+ device_t *ay8910 = state->m_ay;
+ mc146818_device *rtc = state->m_rtc;
+
+ if(state->m_aleste_mode & 0x20) // RTC selected
+ {
+ switch(state->m_aleste_rtc_function)
+ {
+ case 0x02: // AS
+ rtc->write(*space, 0,state->m_ppi_port_outputs[amstrad_ppi_PortA]);
+ break;
+ case 0x04: // DS write
+ rtc->write(*space, 1,state->m_ppi_port_outputs[amstrad_ppi_PortA]);
+ break;
+ case 0x05: // DS read
+ state->m_ppi_port_inputs[amstrad_ppi_PortA] = rtc->read(*space, 1);
+ break;
+ }
+ return;
+ }
+ switch (state->m_Psg_FunctionSelected)
+ {
+ case 0:
+ {/* Inactive */
+ } break;
+ case 1:
+ {/* b6 = 1 ? : Read from selected PSG register and make the register data available to PPI Port A */
+ state->m_ppi_port_inputs[amstrad_ppi_PortA] = ay8910_r(ay8910, 0);
+ }
+ break;
+ case 2:
+ {/* b7 = 1 ? : Write to selected PSG register and write data to PPI Port A */
+ ay8910_data_w(ay8910, 0, state->m_ppi_port_outputs[amstrad_ppi_PortA]);
+ }
+ break;
+ case 3:
+ {/* b6 and b7 = 1 ? : The register will now be selected and the user can read from or write to it. The register will remain selected until another is chosen.*/
+ ay8910_address_w(ay8910, 0, state->m_ppi_port_outputs[amstrad_ppi_PortA]);
+ state->m_prev_reg = state->m_ppi_port_outputs[amstrad_ppi_PortA];
+ }
+ break;
+ default:
+ {
+ } break;
+ }
+}
+
+
+/* Read/Write 8255 PPI port A (connected to AY-3-8912 databus) */
+READ8_DEVICE_HANDLER ( amstrad_ppi_porta_r )
+{
+ amstrad_state *state = device->machine().driver_data<amstrad_state>();
+ update_psg(device->machine());
+ return state->m_ppi_port_inputs[amstrad_ppi_PortA];
+}
+
+
+WRITE8_DEVICE_HANDLER ( amstrad_ppi_porta_w )
+{
+ amstrad_state *state = device->machine().driver_data<amstrad_state>();
+ state->m_ppi_port_outputs[amstrad_ppi_PortA] = data;
+ update_psg(device->machine());
+}
+
+
+/* - Read PPI Port B -
+ -------------------
+Bit Description
+7 Cassette read data
+6 Parallel/Printer port ready signal ("1" = not ready, "0" = Ready)
+5 /EXP signal on expansion port (note 6)
+4 50/60 Hz (link on PCB. For this MESS driver I have used the dipswitch feature) (note 5)
+3 | PCB links to define manufacturer name. For this MESS driver I have used the dipswitch feature. (note 1) (note 4)
+2 | (note 2)
+1 | (note 3)
+0 VSYNC State from 6845. "1" = VSYNC active, "0" = VSYNC inactive
+
+Note:
+
+1 On CPC464,CPC664,CPC6128 and GX4000 this is LK3 on the PCB. On the CPC464+ and CPC6128+ this is LK103 on the PCB. On the KC compact this is "1".
+2 On CPC464,CPC664,CPC6128 and GX4000 this is LK2 on the PCB. On the CPC464+ and CPC6128+ this is LK102 on the PCB. On the KC compact this is "0".
+3 On CPC464,CPC664,CPC6128 and GX4000 this is LK1 on the PCB. On the CPC464+ and CPC6128+ this is LK101 on the PCB. On the KC compact this is /TEST signal from the expansion port.
+4 On the CPC464,CPC664,CPC6128,CPC464+,CPC6128+ and GX4000 bits 3,2 and 1 define the manufacturer name. See below to see the options available. The manufacturer name is defined on the PCB and cannot be changed through software.
+5 On the CPC464,CPC664,CPC6128,CPC464+,CPC6128+ and GX4000 bit 4 defines the Screen refresh frequency. "1" = 50 Hz, "0" = 60 Hz. This is defined on the PCB and cannot be changed with software. On the KC compact bit 4 is "1"
+6 This bit is connected to /EXP signal on the expansion port.
+ On the KC Compact this bit is used to define bit 7 of the printer data.
+ On the CPC, it is possible to use this bit to define bit 7 of the printer data, so a 8-bit printer port is made, with a hardware modification,
+ On the CPC this can be used by a expansion device to report it's presence. "1" = device connected, "0" = device not connected. This is not always used by all expansion devices.
+*/
+
+
+READ8_DEVICE_HANDLER (amstrad_ppi_portb_r)
+{
+ amstrad_state *state = device->machine().driver_data<amstrad_state>();
+ int data = 0;
+/* Set b7 with cassette tape input */
+ if(state->m_system_type != SYSTEM_GX4000)
+ {
+ if (state->m_cassette->input() > 0.03)
+ {
+ data |= (1<<7);
+ }
+ }
+/* Set b6 with Parallel/Printer port ready */
+ if(state->m_system_type != SYSTEM_GX4000)
+ {
+ centronics_device *printer = state->m_centronics;
+ data |= printer->busy_r() << 6;
+ }
+/* Set b4-b1 50Hz/60Hz state and manufacturer name defined by links on PCB */
+ data |= (state->m_ppi_port_inputs[amstrad_ppi_PortB] & 0x1e);
+
+/* Set b0 with VSync state from the CRTC */
+ data |= state->m_gate_array.vsync;
+
+ if(state->m_aleste_mode & 0x04)
+ {
+ if(state->m_aleste_fdc_int == 0)
+ data &= ~0x02;
+ else
+ data |= 0x02;
+ }
+
+logerror("amstrad_ppi_portb_r\n");
+ /* Schedule a write to PC2 */
+ device->machine().scheduler().timer_set( attotime::zero, FUNC(amstrad_pc2_low));
+
+ return data;
+}
+
+
+/* 26-May-2005 - PPI Port C
+ -----------------------
+Bit Description Usage
+7 PSG BDIR | PSG function selection
+6 PSG BC1 |
+5 Cassette Write data
+4 Cassette Motor Control set bit to "1" for motor on, or "0" for motor off
+3 | Keyboard line Select keyboard line to be scanned (0-15)
+2 |
+1 |
+0 |*/
+
+/* previous_ppi_portc_w value */
+
+WRITE8_DEVICE_HANDLER ( amstrad_ppi_portc_w )
+{
+ amstrad_state *state = device->machine().driver_data<amstrad_state>();
+ int changed_data;
+
+ state->m_previous_ppi_portc_w = state->m_ppi_port_outputs[amstrad_ppi_PortC];
+/* Write the data to Port C */
+ changed_data = state->m_previous_ppi_portc_w^data;
+
+ state->m_ppi_port_outputs[amstrad_ppi_PortC] = data;
+
+/* get b7 and b6 (PSG Function Selected */
+ state->m_Psg_FunctionSelected = ((data & 0xC0)>>6);
+
+ /* MC146818 function */
+ state->m_aleste_rtc_function = data & 0x07;
+
+ /* Perform PSG function */
+ update_psg(device->machine());
+
+ /* b5 Cassette Write data */
+ if(state->m_system_type != SYSTEM_GX4000)
+ {
+ if ((changed_data & 0x20) != 0)
+ {
+ state->m_cassette->output(((data & 0x20) ? -1.0 : +1.0));
+ }
+ }
+
+ /* b4 Cassette Motor Control */
+ if(state->m_system_type != SYSTEM_GX4000)
+ {
+ if ((changed_data & 0x10) != 0)
+ {
+ state->m_cassette->change_state(
+ ((data & 0x10) ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED),
+ CASSETTE_MASK_MOTOR);
+ }
+ }
+}
+
+
+/* Additional notes for the AY-3-8912 in the CPC design
+Port A of the AY-3-8912 is connected to the keyboard.
+The data for a selected keyboard line can be read through Port A, as long as it is defined as input.
+The operating system and I believe all programs assume this port has been defined as input. (NWC has found a bug in the Multiface 2 software. The Multiface does not reprogram the input/output state of the AY-3-8912's registers, therefore if port A is programmed as output, the keyboard will be unresponsive and it will not be possible to use the Multiface functions.)
+When port B is defined as input (bit 7 of register 7 is set to "0"), a read of this port will return &FF.
+*/
+
+/* read PSG port A */
+READ8_MEMBER(amstrad_state::amstrad_psg_porta_read)
+{
+ /* Read CPC Keyboard
+ If keyboard matrix line 11-14 are selected, the byte is always &ff.
+ After testing on a real CPC, it is found that these never change, they always return &FF. */
+
+ static const char *const keynames[] = {
+ "keyboard_row_0", "keyboard_row_1", "keyboard_row_2", "keyboard_row_3", "keyboard_row_4",
+ "keyboard_row_5", "keyboard_row_6", "keyboard_row_7", "keyboard_row_8", "keyboard_row_9",
+ "keyboard_row_10"
+ };
+
+ if ( ( m_ppi_port_outputs[amstrad_ppi_PortC] & 0x0F ) > 10)
+ {
+ return 0xFF;
+ }
+ else
+ {
+ if(m_aleste_mode == 0x08 && ( m_ppi_port_outputs[amstrad_ppi_PortC] & 0x0F ) == 10)
+ return 0xff;
+
+ return machine().root_device().ioport(keynames[m_ppi_port_outputs[amstrad_ppi_PortC] & 0x0F])->read_safe(0) & 0xFF;
+ }
+}
+
+
+/* called when cpu acknowledges int */
+/* reset top bit of interrupt line counter */
+/* this ensures that the next interrupt is no closer than 32 lines */
+static IRQ_CALLBACK(amstrad_cpu_acknowledge_int)
+{
+ amstrad_state *state = device->machine().driver_data<amstrad_state>();
+ // DMA interrupts can be automatically cleared if bit 0 of &6805 is set to 0
+ if( state->m_asic.enabled && state->m_plus_irq_cause != 0x06 && state->m_asic.dma_clear & 0x01)
+ {
+ logerror("IRQ: Not cleared, IRQ was called by DMA [%i]\n",state->m_plus_irq_cause);
+ state->m_asic.ram[0x2c0f] &= ~0x80; // not a raster interrupt, so this bit is reset
+ return (state->m_asic.ram[0x2805] & 0xf8) | state->m_plus_irq_cause;
+ }
+ cputag_set_input_line(device->machine(),"maincpu", 0, CLEAR_LINE);
+ state->m_gate_array.hsync_counter &= 0x1F;
+ if ( state->m_asic.enabled )
+ {
+ if(state->m_plus_irq_cause == 6) // bit 7 is set "if last interrupt acknowledge cycle was caused by a raster interrupt"
+ state->m_asic.ram[0x2c0f] |= 0x80;
+ else
+ {
+ state->m_asic.ram[0x2c0f] &= ~0x80;
+ state->m_asic.ram[0x2c0f] &= (0x40 >> state->m_plus_irq_cause/2);
+ }
+ return (state->m_asic.ram[0x2805] & 0xf8) | state->m_plus_irq_cause;
+ }
+ return 0xFF;
+}
+
+
+/* the following timings have been measured! */
+static const UINT8 amstrad_cycle_table_op[256] = {
+ 4, 12, 8, 8, 4, 4, 8, 4, 4, 12, 8, 8, 4, 4, 8, 4,
+ 12, 12, 8, 8, 4, 4, 8, 4, 12, 12, 8, 8, 4, 4, 8, 4,
+ 8, 12, 20, 8, 4, 4, 8, 4, 8, 12, 20, 8, 4, 4, 8, 4,
+ 8, 12, 16, 8, 12, 12, 12, 4, 8, 12, 16, 8, 4, 4, 8, 4,
+ 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
+ 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
+ 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
+ 8, 8, 8, 8, 8, 8, 4, 8, 4, 4, 4, 4, 4, 4, 8, 4,
+ 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
+ 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
+ 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
+ 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
+ 8, 12, 12, 12, 12, 16, 8, 16, 8, 12, 12, 4, 12, 20, 8, 16,
+ 8, 12, 12, 12, 12, 16, 8, 16, 8, 4, 12, 12, 12, 4, 8, 16,
+ 8, 12, 12, 24, 12, 16, 8, 16, 8, 4, 12, 4, 12, 4, 8, 16,
+ 8, 12, 12, 4, 12, 16, 8, 16, 8, 8, 12, 4, 12, 4, 8, 16
+};
+
+static const UINT8 amstrad_cycle_table_cb[256]=
+{
+ 4, 4, 4, 4, 4, 4, 12, 4, 4, 4, 4, 4, 4, 4, 12, 4,
+ 4, 4, 4, 4, 4, 4, 12, 4, 4, 4, 4, 4, 4, 4, 12, 4,
+ 4, 4, 4, 4, 4, 4, 12, 4, 4, 4, 4, 4, 4, 4, 12, 4,
+ 4, 4, 4, 4, 4, 4, 12, 4, 4, 4, 4, 4, 4, 4, 12, 4,
+ 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
+ 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
+ 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
+ 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
+ 4, 4, 4, 4, 4, 4, 12, 4, 4, 4, 4, 4, 4, 4, 12, 4,
+ 4, 4, 4, 4, 4, 4, 12, 4, 4, 4, 4, 4, 4, 4, 12, 4,
+ 4, 4, 4, 4, 4, 4, 12, 4, 4, 4, 4, 4, 4, 4, 12, 4,
+ 4, 4, 4, 4, 4, 4, 12, 4, 4, 4, 4, 4, 4, 4, 12, 4,
+ 4, 4, 4, 4, 4, 4, 12, 4, 4, 4, 4, 4, 4, 4, 12, 4,
+ 4, 4, 4, 4, 4, 4, 12, 4, 4, 4, 4, 4, 4, 4, 12, 4,
+ 4, 4, 4, 4, 4, 4, 12, 4, 4, 4, 4, 4, 4, 4, 12, 4,
+ 4, 4, 4, 4, 4, 4, 12, 4, 4, 4, 4, 4, 4, 4, 12, 4
+};
+
+static const UINT8 amstrad_cycle_table_ed[256]=
+{
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 12, 12, 12, 20, 4, 12, 4, 8, 12, 12, 12, 20, 4, 12, 4, 8,
+ 12, 12, 12, 20, 4, 12, 4, 8, 12, 12, 12, 20, 4, 12, 4, 8,
+ 12, 12, 12, 20, 4, 12, 4, 16, 12, 12, 12, 20, 4, 12, 4, 16,
+ 12, 12, 12, 20, 4, 12, 4, 4, 12, 12, 12, 20, 4, 12, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 16, 12, 16, 16, 4, 4, 4, 4, 16, 12, 16, 16, 4, 4, 4, 4,
+ 16, 12, 16, 16, 4, 4, 4, 4, 16, 12, 16, 16, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
+};
+
+static const UINT8 amstrad_cycle_table_xy[256]=
+{
+ 4, 12, 8, 8, 4, 4, 8, 4, 4, 12, 8, 8, 4, 4, 8, 4,
+ 12, 12, 8, 8, 4, 4, 8, 4, 12, 12, 8, 8, 4, 4, 8, 4,
+ 8, 12, 20, 8, 4, 4, 8, 4, 8, 12, 20, 8, 4, 4, 8, 4,
+ 8, 12, 16, 8, 20, 20, 20, 4, 8, 12, 16, 8, 4, 4, 8, 4,
+ 4, 4, 4, 4, 4, 4, 16, 4, 4, 4, 4, 4, 4, 4, 16, 4,
+ 4, 4, 4, 4, 4, 4, 16, 4, 4, 4, 4, 4, 4, 4, 16, 4,
+ 4, 4, 4, 4, 4, 4, 16, 4, 4, 4, 4, 4, 4, 4, 16, 4,
+ 16, 16, 16, 16, 16, 16, 4, 16, 4, 4, 4, 4, 4, 4, 16, 4,
+ 4, 4, 4, 4, 4, 4, 16, 4, 4, 4, 4, 4, 4, 4, 16, 4,
+ 4, 4, 4, 4, 4, 4, 16, 4, 4, 4, 4, 4, 4, 4, 16, 4,
+ 4, 4, 4, 4, 4, 4, 16, 4, 4, 4, 4, 4, 4, 4, 16, 4,
+ 4, 4, 4, 4, 4, 4, 16, 4, 4, 4, 4, 4, 4, 4, 16, 4,
+ 8, 12, 12, 12, 12, 16, 8, 16, 8, 12, 12, 4, 12, 20, 8, 16,
+ 8, 12, 12, 12, 12, 16, 8, 16, 8, 4, 12, 12, 12, 4, 8, 16,
+ 8, 12, 12, 24, 12, 16, 8, 16, 8, 4, 12, 4, 12, 4, 8, 16,
+ 8, 12, 12, 4, 12, 16, 8, 16, 8, 8, 12, 4, 12, 4, 8, 16
+};
+
+static const UINT8 amstrad_cycle_table_xycb[256]=
+{
+ 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,
+ 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,
+ 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, 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, 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
+};
+
+static const UINT8 amstrad_cycle_table_ex[256]=
+{
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 4, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0,
+ 4, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 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, 8, 4, 4, 0, 0, 0, 0, 4, 8, 4, 4, 0, 0, 0, 0,
+ 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0,
+ 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0,
+ 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0,
+ 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0
+};
+
+static void amstrad_common_init(running_machine &machine)
+{
+ amstrad_state *state = machine.driver_data<amstrad_state>();
+ address_space *space = state->m_maincpu->memory().space(AS_PROGRAM);
+ device_t* romexp;
+ rom_image_device* romimage;
+ char str[20];
+ int x;
+
+ state->m_aleste_mode = 0;
+
+ state->m_gate_array.mrer = 0;
+ state->m_gate_array.vsync = 0;
+ state->m_gate_array.hsync = 0;
+ state->m_GateArray_RamConfiguration = 0;
+ state->m_gate_array.hsync_counter = 2;
+
+ space->install_read_bank(0x0000, 0x1fff, "bank1");
+ space->install_read_bank(0x2000, 0x3fff, "bank2");
+
+ space->install_read_bank(0x4000, 0x5fff, "bank3");
+ space->install_read_bank(0x6000, 0x7fff, "bank4");
+
+ space->install_read_bank(0x8000, 0x9fff, "bank5");
+ space->install_read_bank(0xa000, 0xbfff, "bank6");
+
+ space->install_read_bank(0xc000, 0xdfff, "bank7");
+ space->install_read_bank(0xe000, 0xffff, "bank8");
+
+ space->install_write_bank(0x0000, 0x1fff, "bank9");
+ space->install_write_bank(0x2000, 0x3fff, "bank10");
+
+ space->install_write_bank(0x4000, 0x5fff, "bank11");
+ space->install_write_bank(0x6000, 0x7fff, "bank12");
+
+ space->install_write_bank(0x8000, 0x9fff, "bank13");
+ space->install_write_bank(0xa000, 0xbfff, "bank14");
+
+ space->install_write_bank(0xc000, 0xdfff, "bank15");
+ space->install_write_bank(0xe000, 0xffff, "bank16");
+
+ /* Set up ROMs, if we have an expansion device connected */
+ romexp = get_expansion_device(machine,"rom");
+ if(romexp)
+ {
+ for(x=0;x<6;x++)
+ {
+ sprintf(str,"rom%i",x+1);
+ romimage = romexp->subdevice<rom_image_device>(str);
+ if(romimage->base() != NULL)
+ {
+ state->m_Amstrad_ROM_Table[x+1] = romimage->base();
+ }
+ }
+ }
+
+ state->m_maincpu->reset();
+ if ( state->m_system_type == SYSTEM_CPC || state->m_system_type == SYSTEM_ALESTE )
+ device_set_input_line_vector(state->m_maincpu, 0, 0xff);
+ else
+ device_set_input_line_vector(state->m_maincpu, 0, 0x00);
+
+ /* The opcode timing in the Amstrad is different to the opcode
+ timing in the core for the Z80 CPU.
+
+ The Amstrad hardware issues a HALT for each memory fetch.
+ This has the effect of stretching the timing for Z80 opcodes,
+ so that they are all multiple of 4 T states long. All opcode
+ timings are a multiple of 1us in length. */
+
+ /* Using the cool code Juergen has provided, I will override
+ the timing tables with the values for the amstrad */
+ z80_set_cycle_tables(state->m_maincpu,
+ (const UINT8*)amstrad_cycle_table_op,
+ (const UINT8*)amstrad_cycle_table_cb,
+ (const UINT8*)amstrad_cycle_table_ed,
+ (const UINT8*)amstrad_cycle_table_xy,
+ (const UINT8*)amstrad_cycle_table_xycb,
+ (const UINT8*)amstrad_cycle_table_ex);
+
+ /* Juergen is a cool dude! */
+ device_set_irq_callback(state->m_maincpu, amstrad_cpu_acknowledge_int);
+}
+
+static TIMER_CALLBACK( cb_set_resolution )
+{
+ amstrad_state *state = machine.driver_data<amstrad_state>();
+// screen_device *screen = downcast<screen_device *>(state->m_screen);
+ rectangle visarea;
+ attoseconds_t refresh;
+ int height;
+
+ if ( machine.root_device().ioport( "solder_links" )->read() & 0x10 )
+ {
+ /* PAL */
+ visarea.set(0, 64 + 640 + 64 - 1, 34, 34 + 15 + 242 + 15 - 1);
+ height = 312;
+ }
+ else
+ {
+ /* NTSC */
+ visarea.set(0, 64 + 640 + 64 - 1, 16, 16 + 15 + 200 + 15 - 1);
+ height = 262;
+ }
+ refresh = HZ_TO_ATTOSECONDS( XTAL_16MHz ) * 1024 * height;
+ state->m_screen->configure( 1024, height, visarea, refresh );
+}
+
+
+MACHINE_START( amstrad )
+{
+ amstrad_state *state = machine.driver_data<amstrad_state>();
+ state->m_system_type = SYSTEM_CPC;
+}
+
+
+MACHINE_RESET( amstrad )
+{
+ amstrad_state *state = machine.driver_data<amstrad_state>();
+ int i;
+ UINT8 *rom = state->memregion("maincpu")->base();
+
+ for (i=0; i<256; i++)
+ {
+ state->m_Amstrad_ROM_Table[i] = &rom[0x014000];
+ }
+
+ state->m_Amstrad_ROM_Table[7] = &rom[0x018000];
+ amstrad_common_init(machine);
+ amstrad_reset_machine(machine);
+// amstrad_init_palette(machine);
+
+ state->m_gate_array.de = 0;
+ state->m_gate_array.draw_p = NULL;
+ state->m_gate_array.hsync = 0;
+ state->m_gate_array.vsync = 0;
+
+ machine.scheduler().timer_set( attotime::zero, FUNC(cb_set_resolution));
+}
+
+
+MACHINE_START( plus )
+{
+ amstrad_state *state = machine.driver_data<amstrad_state>();
+ state->m_asic.ram = state->memregion("user1")->base(); // 16kB RAM for ASIC, memory-mapped registers.
+ state->m_system_type = SYSTEM_PLUS;
+}
+
+
+MACHINE_RESET( plus )
+{
+ amstrad_state *state = machine.driver_data<amstrad_state>();
+ address_space *space = state->m_maincpu->memory().space(AS_PROGRAM);
+ int i;
+ UINT8 *rom = state->memregion("maincpu")->base();
+
+ for (i=0; i<128; i++) // fill ROM table
+ {
+ state->m_Amstrad_ROM_Table[i] = &rom[0x4000]; // BASIC in system cart
+ }
+ for(i=128;i<160;i++)
+ {
+ state->m_Amstrad_ROM_Table[i] = &rom[(i-128)*0x4000];
+ }
+ state->m_Amstrad_ROM_Table[7] = &rom[0xc000]; // AMSDOS in system cart
+
+ state->m_asic.enabled = 0;
+ state->m_asic.seqptr = 0;
+ state->m_asic.pri = 0; // disable PRI
+ state->m_asic.dma_status = 0; // disable all DMA channels
+ state->m_asic.dma_addr[0] = 0;
+ state->m_asic.dma_prescaler[0] = 0;
+ state->m_asic.dma_addr[1] = 0;
+ state->m_asic.dma_prescaler[1] = 0;
+ state->m_asic.dma_addr[2] = 0;
+ state->m_asic.dma_prescaler[2] = 0;
+ state->m_asic.dma_clear = 1; // by default, DMA interrupts must be cleared by writing to the DSCR (&6c0f)
+ state->m_plus_irq_cause = 6;
+
+ amstrad_common_init(machine);
+ amstrad_reset_machine(machine);
+ state->m_asic.ram[0x2805] = 0x01; // interrupt vector is undefined at startup, except that bit 0 is always 1.
+ AmstradCPC_GA_SetRamConfiguration(machine);
+ amstrad_GateArray_write(machine, 0x081); // Epyx World of Sports requires upper ROM to be enabled by default
+
+ space->install_read_handler(0x4000, 0x5fff, read8_delegate(FUNC(amstrad_state::amstrad_plus_asic_4000_r),state));
+ space->install_read_handler(0x6000, 0x7fff, read8_delegate(FUNC(amstrad_state::amstrad_plus_asic_6000_r),state));
+ space->install_write_handler(0x4000, 0x5fff, write8_delegate(FUNC(amstrad_state::amstrad_plus_asic_4000_w),state));
+ space->install_write_handler(0x6000, 0x7fff, write8_delegate(FUNC(amstrad_state::amstrad_plus_asic_6000_w),state));
+
+ // multiface_init();
+ machine.scheduler().timer_set( attotime::zero, FUNC(cb_set_resolution));
+}
+
+MACHINE_START( gx4000 )
+{
+ amstrad_state *state = machine.driver_data<amstrad_state>();
+ state->m_asic.ram = state->memregion("user1")->base(); // 16kB RAM for ASIC, memory-mapped registers.
+ state->m_system_type = SYSTEM_GX4000;
+}
+
+MACHINE_RESET( gx4000 )
+{
+ amstrad_state *state = machine.driver_data<amstrad_state>();
+ address_space *space = state->m_maincpu->memory().space(AS_PROGRAM);
+ int i;
+ UINT8 *rom = state->memregion("maincpu")->base();
+
+ for (i=0; i<128; i++) // fill ROM table
+ {
+ state->m_Amstrad_ROM_Table[i] = &rom[0x4000];
+ }
+ for(i=128;i<160;i++)
+ {
+ state->m_Amstrad_ROM_Table[i] = &rom[(i-128)*0x4000];
+ }
+ state->m_Amstrad_ROM_Table[7] = &rom[0xc000];
+
+ state->m_asic.enabled = 0;
+ state->m_asic.seqptr = 0;
+ state->m_asic.pri = 0; // disable PRI
+ state->m_asic.dma_status = 0; // disable all DMA channels
+ state->m_asic.dma_addr[0] = 0;
+ state->m_asic.dma_prescaler[0] = 0;
+ state->m_asic.dma_addr[1] = 0;
+ state->m_asic.dma_prescaler[1] = 0;
+ state->m_asic.dma_addr[2] = 0;
+ state->m_asic.dma_prescaler[2] = 0;
+ state->m_asic.dma_clear = 1; // by default, DMA interrupts must be cleared by writing to the DSCR (&6c0f)
+ state->m_plus_irq_cause = 6;
+
+ amstrad_common_init(machine);
+ amstrad_reset_machine(machine);
+ state->m_asic.ram[0x2805] = 0x01; // interrupt vector is undefined at startup, except that bit 0 is always 1.
+ AmstradCPC_GA_SetRamConfiguration(machine);
+ amstrad_GateArray_write(machine, 0x081); // Epyx World of Sports requires upper ROM to be enabled by default
+ // multiface_init();
+ space->install_read_handler(0x4000, 0x5fff, read8_delegate(FUNC(amstrad_state::amstrad_plus_asic_4000_r),state));
+ space->install_read_handler(0x6000, 0x7fff, read8_delegate(FUNC(amstrad_state::amstrad_plus_asic_6000_r),state));
+ space->install_write_handler(0x4000, 0x5fff, write8_delegate(FUNC(amstrad_state::amstrad_plus_asic_4000_w),state));
+ space->install_write_handler(0x6000, 0x7fff, write8_delegate(FUNC(amstrad_state::amstrad_plus_asic_6000_w),state));
+
+ machine.scheduler().timer_set( attotime::zero, FUNC(cb_set_resolution));
+}
+
+MACHINE_START( kccomp )
+{
+ amstrad_state *state = machine.driver_data<amstrad_state>();
+ state->m_system_type = SYSTEM_CPC;
+}
+
+
+MACHINE_RESET( kccomp )
+{
+ amstrad_state *state = machine.driver_data<amstrad_state>();
+ int i;
+ UINT8 *rom = state->memregion("maincpu")->base();
+
+ for (i=0; i<256; i++)
+ {
+ state->m_Amstrad_ROM_Table[i] = &rom[0x014000];
+ }
+
+ amstrad_common_init(machine);
+ kccomp_reset_machine(machine);
+
+ /* bit 1 = /TEST. When 0, KC compact will enter data transfer
+ sequence, where another system using the expansion port signals
+ DATA2,DATA1, /STROBE and DATA7 can transfer 256 bytes of program.
+ When the program has been transfered, it will be executed. This
+ is not supported in the driver */
+ /* bit 3,4 are tied to +5V, bit 2 is tied to 0V */
+ state->m_ppi_port_inputs[amstrad_ppi_PortB] = (1<<4) | (1<<3) | 2;
+}
+
+
+MACHINE_START( aleste )
+{
+ amstrad_state *state = machine.driver_data<amstrad_state>();
+ state->m_system_type = SYSTEM_ALESTE;
+}
+
+MACHINE_RESET( aleste )
+{
+ amstrad_state *state = machine.driver_data<amstrad_state>();
+ int i;
+ UINT8 *rom = state->memregion("maincpu")->base();
+
+ for (i=0; i<256; i++)
+ {
+ state->m_Amstrad_ROM_Table[i] = &rom[0x014000];
+ }
+
+ state->m_Amstrad_ROM_Table[3] = &rom[0x01c000]; // MSX-DOS / BIOS
+ state->m_Amstrad_ROM_Table[7] = &rom[0x018000]; // AMSDOS
+ amstrad_common_init(machine);
+ amstrad_reset_machine(machine);
+
+ machine.scheduler().timer_set( attotime::zero, FUNC(cb_set_resolution));
+}
+
+
+/* load snapshot */
+SNAPSHOT_LOAD(amstrad)
+{
+ UINT8 *snapshot;
+
+ /* get file size */
+ if (snapshot_size < 8)
+ return IMAGE_INIT_FAIL;
+
+ snapshot = (UINT8 *)malloc(snapshot_size);
+ if (!snapshot)
+ return IMAGE_INIT_FAIL;
+
+ /* read whole file */
+ image.fread(snapshot, snapshot_size);
+
+ if (memcmp(snapshot, "MV - SNA", 8))
+ {
+ free(snapshot);
+ return IMAGE_INIT_FAIL;
+ }
+
+ amstrad_handle_snapshot(image.device().machine(), snapshot);
+ free(snapshot);
+ return IMAGE_INIT_PASS;
+}
+
+
+DEVICE_IMAGE_LOAD(amstrad_plus_cartridge)
+{
+ // load CPC Plus / GX4000 cartridge image
+ // Format is RIFF: RIFF header chunk contains "AMS!"
+ // Chunks should be 16k, but may vary
+ // Chunks labeled 'cb00' represent Cartridge block 0, and is loaded to &0000-&3fff
+ // 'cb01' represent Cartridge block 1, and is loaded to &4000-&7fff
+ // ... and so on.
+
+ UINT32 size, offset = 0;
+ UINT8 *temp_copy;
+ unsigned char header[12]; // RIFF chunk
+ char chunkid[4]; // chunk ID (4 character code - cb00, cb01, cb02... upto cb31 (max 512kB), other chunks are ignored)
+ char chunklen[4]; // chunk length (always little-endian)
+ int chunksize; // chunk length, calcaulated from the above
+ int ramblock; // 16k RAM block chunk is to be loaded in to
+ unsigned int bytes_to_read; // total bytes to read, as mame_feof doesn't react to EOF without trying to go past it.
+ unsigned char* mem = image.device().machine().root_device().memregion("maincpu")->base();
+
+ if (image.software_entry() == NULL)
+ {
+ size = image.length();
+ temp_copy = auto_alloc_array(image.device().machine(), UINT8, size);
+ if (image.fread(temp_copy, size) != size)
+ {
+ logerror("IMG: failed to read from cart image\n");
+ auto_free(image.device().machine(), temp_copy);
+ return IMAGE_INIT_FAIL;
+ }
+ }
+ else
+ {
+ size= image.get_software_region_length("rom");
+ temp_copy = auto_alloc_array(image.device().machine(), UINT8, size);
+ memcpy(temp_copy, image.get_software_region("rom"), size);
+ }
+
+ logerror("IMG: loading CPC+ cartridge file\n");
+ // load RIFF chunk
+ memcpy(header, temp_copy, 12);
+ offset += 12;
+
+ if (strncmp((char *)header, "RIFF", 4) != 0)
+ {
+ logerror("IMG: raw CPC+ cartridge file\n");
+ offset -= 12; // no header, so we go back to the start of the file
+
+ // not an RIFF format file, assume raw binary (*.bin)
+ while (offset < size)
+ {
+ memcpy(mem + offset, temp_copy + offset, 0x4000);
+
+ if ((size - offset) < 0x4000)
+ {
+ logerror("BIN: block %i loaded is smaller than 16kB in size\n", offset / 0x4000);
+ auto_free(image.device().machine(), temp_copy);
+ return IMAGE_INIT_FAIL;
+ }
+ offset += 0x4000;
+ }
+ }
+ else if (image.software_entry() == NULL) // we have no CPR carts in our gx4000 softlist
+ {
+ // Is RIFF format (*.cpr)
+ if (strncmp((char*)(header + 8), "AMS!", 4) != 0)
+ {
+ logerror("CPR: not an Amstrad CPC cartridge image\n");
+ auto_free(image.device().machine(), temp_copy);
+ return IMAGE_INIT_FAIL;
+ }
+
+ bytes_to_read = header[4] + (header[5] << 8) + (header[6] << 16)+ (header[7] << 24);
+ bytes_to_read -= 4; // account for AMS! header
+ logerror("CPR: Data to read: %i bytes\n", bytes_to_read);
+ // read some chunks
+ while (bytes_to_read > 0)
+ {
+ memcpy(chunkid, temp_copy + offset, 4);
+ bytes_to_read -= 4;
+ offset += 4;
+
+ memcpy(chunklen, temp_copy + offset, 4);
+ bytes_to_read -= 4;
+ offset += 4;
+
+ // calculate little-endian value, just to be sure
+ chunksize = chunklen[0] + (chunklen[1] << 8) + (chunklen[2] << 16) + (chunklen[3] << 24);
+
+ if (strncmp(chunkid, "cb", 2) == 0)
+ {
+ // load chunk into RAM
+ // find out what block this is
+ ramblock = (chunkid[2] - 0x30) * 10;
+ ramblock += chunkid[3] - 0x30;
+ logerror("CPR: Loading chunk into RAM block %i ['%4s']\n", ramblock, chunkid);
+
+ if(ramblock >= 0 && ramblock < 32)
+ {
+ // clear RAM block
+ memset(mem + 0x4000 * ramblock, 0, 0x4000);
+
+ // load block into ROM area
+ if (chunksize > 16384)
+ chunksize = 16384;
+
+ memcpy(mem + 0x4000 * ramblock, temp_copy + offset, chunksize);
+ bytes_to_read -= chunksize;
+ offset += chunksize;
+ logerror("CPR: Loaded %i-byte chunk into RAM block %i\n", chunksize, ramblock);
+ }
+ }
+ else
+ {
+ logerror("CPR: Unknown chunk '%4s', skipping %i bytes\n", chunkid, chunksize);
+ if (chunksize != 0)
+ {
+ bytes_to_read -= chunksize;
+ offset += chunksize;
+ }
+ }
+ }
+ }
+ else // CPR carts in our softlist
+ {
+ logerror("Gamelist cart in RIFF format\n");
+ auto_free(image.device().machine(), temp_copy);
+ return IMAGE_INIT_FAIL;
+ }
+
+ auto_free(image.device().machine(), temp_copy);
+ return IMAGE_INIT_PASS;
+}
+
+
+#if 0
+static DEVICE_IMAGE_LOAD( aleste )
+{
+ if (device_load_basicdsk_floppy(image)==IMAGE_INIT_PASS)
+ {
+ basicdsk_set_geometry(image, 80, 2, 9, 512, 0x01, 0, FALSE);
+ return IMAGE_INIT_PASS;
+ }
+ return IMAGE_INIT_FAIL;
+}
+#endif
diff --git a/src/mess/machine/ap2_lang.c b/src/mess/machine/ap2_lang.c
new file mode 100644
index 00000000000..5601cb42da5
--- /dev/null
+++ b/src/mess/machine/ap2_lang.c
@@ -0,0 +1,122 @@
+/*********************************************************************
+
+ ap2_lang.c
+
+ Implementation of the Apple II Language Card
+
+*********************************************************************/
+
+#include "emu.h"
+#include "includes/apple2.h"
+#include "ap2_lang.h"
+
+
+/***************************************************************************
+ PARAMETERS
+***************************************************************************/
+
+#define LOG_LANGCARD 0
+
+
+
+/***************************************************************************
+ CORE IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ apple2_langcard_touch - device read callback
+-------------------------------------------------*/
+
+static void apple2_langcard_touch(device_t *device, 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_setvar(device->machine(), val, mask);
+}
+
+
+
+/*-------------------------------------------------
+ apple2_langcard_r - device read callback
+-------------------------------------------------*/
+
+READ8_DEVICE_HANDLER(apple2_langcard_r)
+{
+ apple2_langcard_touch(device, offset);
+ return 0x00;
+}
+
+
+
+/*-------------------------------------------------
+ apple2_langcard_w - device read callback
+-------------------------------------------------*/
+
+WRITE8_DEVICE_HANDLER(apple2_langcard_w)
+{
+ apple2_langcard_touch(device, offset);
+}
+
+
+
+/*-------------------------------------------------
+ DEVICE_START(apple2_langcard) - device start
+ function
+-------------------------------------------------*/
+
+static DEVICE_START(apple2_langcard)
+{
+ /* nothing to do */
+}
+
+
+
+/*-------------------------------------------------
+ DEVICE_GET_INFO(apple2_langcard) - device get info
+ function
+-------------------------------------------------*/
+
+DEVICE_GET_INFO(apple2_langcard)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = 1; break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(apple2_langcard); break;
+ case DEVINFO_FCT_STOP: /* Nothing */ break;
+ case DEVINFO_FCT_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "Apple II Language Card"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "Apple II Language Card"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(APPLE2_LANGCARD, apple2_langcard);
diff --git a/src/mess/machine/ap2_lang.h b/src/mess/machine/ap2_lang.h
new file mode 100644
index 00000000000..38a14ac029c
--- /dev/null
+++ b/src/mess/machine/ap2_lang.h
@@ -0,0 +1,35 @@
+/*********************************************************************
+
+ ap2_lang.h
+
+ Implementation of the Apple II Language Card
+
+*********************************************************************/
+
+#ifndef __AP2_LANG__
+#define __AP2_LANG__
+
+#include "emu.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+DECLARE_LEGACY_DEVICE(APPLE2_LANGCARD, apple2_langcard);
+
+#define MCFG_APPLE2_LANGCARD_ADD(_tag) \
+ MCFG_DEVICE_ADD((_tag), APPLE2_LANGCARD, 0)
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+/* slot read function */
+READ8_DEVICE_HANDLER(apple2_langcard_r);
+
+/* slot write function */
+WRITE8_DEVICE_HANDLER(apple2_langcard_w);
+
+#endif /* __AP2_LANG__ */
diff --git a/src/mess/machine/ap2_slot.c b/src/mess/machine/ap2_slot.c
new file mode 100644
index 00000000000..6c76bc7e361
--- /dev/null
+++ b/src/mess/machine/ap2_slot.c
@@ -0,0 +1,233 @@
+/*********************************************************************
+
+ ap2_slot.c
+
+ Implementation of Apple II device slots
+
+*********************************************************************/
+
+#include "ap2_slot.h"
+#include "includes/apple2.h"
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _apple2_slot_token apple2_slot_token;
+struct _apple2_slot_token
+{
+ device_t *slot_device;
+};
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+INLINE void assert_valid(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == APPLE2_SLOT);
+}
+
+
+
+INLINE const apple2_slot_config *get_config(device_t *device)
+{
+ assert_valid(device);
+ return (const apple2_slot_config *) downcast<const legacy_device_base *>(device)->inline_config();
+}
+
+
+
+INLINE apple2_slot_token *get_token(device_t *device)
+{
+ assert_valid(device);
+ return (apple2_slot_token *) downcast<legacy_device_base *>(device)->token();
+}
+
+
+
+/***************************************************************************
+ CORE IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ apple2_slot - looks up a slot
+-------------------------------------------------*/
+
+device_t *apple2_slot(running_machine &machine, int slotnum)
+{
+ char buffer[7];
+
+ assert((slotnum >= 0) && (slotnum <= 7));
+ snprintf(buffer, ARRAY_LENGTH(buffer), "slot_%d", slotnum);
+
+ return machine.device(buffer);
+}
+
+
+
+/*-------------------------------------------------
+ DEVICE_START(apple2_slot) - device start
+ function
+-------------------------------------------------*/
+
+static DEVICE_START(apple2_slot)
+{
+ const apple2_slot_config *config = get_config(device);
+ apple2_slot_token *token = get_token(device);
+
+ if (config->tag != NULL)
+ {
+ /* locate the device */
+ token->slot_device = device->machine().device(config->tag);
+
+ assert(token->slot_device != NULL);
+ }
+ else
+ {
+ token->slot_device = NULL;
+ }
+}
+
+
+
+/*-------------------------------------------------
+ apple2_slot_r - slot read function
+-------------------------------------------------*/
+
+READ8_DEVICE_HANDLER(apple2_slot_r)
+{
+ UINT8 result = 0x00;
+ const apple2_slot_config *config = get_config(device);
+ apple2_slot_token *token = get_token(device);
+
+ /* do we actually have a device, and can we read? */
+ if ((token->slot_device != NULL) && (config->rh != NULL))
+ {
+ result = (*config->rh)(token->slot_device, offset);
+ }
+
+ return result;
+}
+
+
+
+/*-------------------------------------------------
+ apple2_slot_w - slot write function
+-------------------------------------------------*/
+
+WRITE8_DEVICE_HANDLER(apple2_slot_w)
+{
+ const apple2_slot_config *config = get_config(device);
+ apple2_slot_token *token = get_token(device);
+
+ /* do we actually have a device, and can we read? */
+ if ((token->slot_device != NULL) && (config->wh != NULL))
+ {
+ (*config->wh)(token->slot_device, offset, data);
+ }
+}
+
+/*-------------------------------------------------
+ apple2_c800_slot_r - slot read function
+-------------------------------------------------*/
+
+READ8_DEVICE_HANDLER(apple2_c800_slot_r)
+{
+ UINT8 result = 0x00;
+ const apple2_slot_config *config = get_config(device);
+ apple2_slot_token *token = get_token(device);
+
+ /* do we actually have a device, and can we read? */
+ if ((token->slot_device != NULL) && (config->rhc800 != NULL))
+ {
+ result = (*config->rhc800)(token->slot_device, offset);
+ }
+
+ return result;
+}
+
+/*-------------------------------------------------
+ apple2_c800_slot_w - slot write function
+-------------------------------------------------*/
+
+WRITE8_DEVICE_HANDLER(apple2_c800_slot_w)
+{
+ const apple2_slot_config *config = get_config(device);
+ apple2_slot_token *token = get_token(device);
+
+ /* do we actually have a device, and can we read? */
+ if ((token->slot_device != NULL) && (config->whc800 != NULL))
+ {
+ (*config->whc800)(token->slot_device, offset, data);
+ }
+}
+
+/*-------------------------------------------------
+ apple2_slot_ROM_w - slot ROM read function
+-------------------------------------------------*/
+READ8_DEVICE_HANDLER(apple2_slot_ROM_r)
+{
+ const apple2_slot_config *config = get_config(device);
+ apple2_slot_token *token = get_token(device);
+
+ /* do we actually have a device, and can we read? */
+ if ((token->slot_device != NULL) && (config->rhcnxx != NULL))
+ {
+ return (*config->rhcnxx)(token->slot_device, offset);
+ }
+
+ if (config->slotnum > 0)
+ {
+ return apple2_slotram_r(device->machine(), config->slotnum, offset + ((config->slotnum-1)<<8));
+ }
+
+ return apple2_getfloatingbusvalue(device->machine());
+}
+
+/*-------------------------------------------------
+ apple2_slot_ROM_w - slot ROM write function
+-------------------------------------------------*/
+
+WRITE8_DEVICE_HANDLER(apple2_slot_ROM_w)
+{
+ const apple2_slot_config *config = get_config(device);
+ apple2_slot_token *token = get_token(device);
+
+ /* do we actually have a device, and can we write? */
+ if ((token->slot_device != NULL) && (config->whcnxx != NULL))
+ {
+ (*config->whcnxx)(token->slot_device, offset, data);
+ }
+}
+
+/*-------------------------------------------------
+ DEVICE_GET_INFO(apple2_slot) - device get info
+ function
+-------------------------------------------------*/
+
+DEVICE_GET_INFO(apple2_slot)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(apple2_slot_token); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = sizeof(apple2_slot_config); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(apple2_slot); break;
+ case DEVINFO_FCT_STOP: /* Nothing */ break;
+ case DEVINFO_FCT_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "Apple II Slot"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "Apple II Slot"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(APPLE2_SLOT, apple2_slot);
diff --git a/src/mess/machine/ap2_slot.h b/src/mess/machine/ap2_slot.h
new file mode 100644
index 00000000000..3a9ffacb33b
--- /dev/null
+++ b/src/mess/machine/ap2_slot.h
@@ -0,0 +1,85 @@
+/*********************************************************************
+
+ ap2_slot.h
+
+ Implementation of Apple II device slots
+
+*********************************************************************/
+
+#ifndef __AP2_SLOT__
+#define __AP2_SLOT__
+
+#include "emu.h"
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+DECLARE_LEGACY_DEVICE(APPLE2_SLOT, apple2_slot);
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _apple2_slot_config apple2_slot_config;
+struct _apple2_slot_config
+{
+ const char *tag;
+ int slotnum; // slot number
+
+ read8_device_func rh; // C0nX I/O space (DEVSEL)
+ write8_device_func wh;
+
+ read8_device_func rhcnxx; // CnXX ROM space (IOSEL)
+ write8_device_func whcnxx;
+
+ read8_device_func rhc800; // C800 ROM extension space (IOSTB)
+ write8_device_func whc800;
+};
+
+
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+#define MCFG_APPLE2_SLOT_ADD(_slot_number, _slot_device_tag, _rh, _wh, _rhc800, _whc800, _rhcnxx, _whcnxx) \
+ MCFG_DEVICE_ADD("slot_" #_slot_number, APPLE2_SLOT, 0) \
+ MCFG_DEVICE_CONFIG_DATAPTR(apple2_slot_config, tag, _slot_device_tag) \
+ MCFG_DEVICE_CONFIG_DATA32(apple2_slot_config, slotnum, _slot_number) \
+ MCFG_DEVICE_CONFIG_DATAPTR(apple2_slot_config, rh, _rh) \
+ MCFG_DEVICE_CONFIG_DATAPTR(apple2_slot_config, wh, _wh) \
+ MCFG_DEVICE_CONFIG_DATAPTR(apple2_slot_config, rhc800, _rhc800) \
+ MCFG_DEVICE_CONFIG_DATAPTR(apple2_slot_config, whc800, _whc800) \
+ MCFG_DEVICE_CONFIG_DATAPTR(apple2_slot_config, rhcnxx, _rhcnxx) \
+ MCFG_DEVICE_CONFIG_DATAPTR(apple2_slot_config, whcnxx, _whcnxx) \
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+/* slot read function */
+READ8_DEVICE_HANDLER(apple2_slot_r);
+
+/* slot write function */
+WRITE8_DEVICE_HANDLER(apple2_slot_w);
+
+/* slot ROM read function */
+READ8_DEVICE_HANDLER(apple2_slot_ROM_r);
+
+/* slot ROM write function */
+WRITE8_DEVICE_HANDLER(apple2_slot_ROM_w);
+
+/* slot extended ROM read function */
+READ8_DEVICE_HANDLER(apple2_c800_slot_r);
+
+/* slot extended ROM write function */
+WRITE8_DEVICE_HANDLER(apple2_c800_slot_w);
+
+/* slot device lookup */
+device_t *apple2_slot(running_machine &machine, int slotnum);
+
+#endif /* __AP2_SLOT__ */
diff --git a/src/mess/machine/apollo.c b/src/mess/machine/apollo.c
new file mode 100644
index 00000000000..199317a285b
--- /dev/null
+++ b/src/mess/machine/apollo.c
@@ -0,0 +1,1475 @@
+/*
+ * apollo.c - Apollo DS3500 CPU Board
+ *
+ * Created on: Jan 20, 2011
+ * Author: Hans Ostermeyer
+ *
+ * Released for general non-commercial use under the MAME license
+ * Visit http://mamedev.org for licensing and usage restrictions.
+ *
+ * Contains:
+ * - apollo_config.c - APOLLO DS3500 configuration
+ * - apollo_csr.c - APOLLO DS3500 CPU Control and Status registers
+ * - apollo_dma.c - APOLLO DS3500 DMA controllers
+ * - apollo_pic.c - APOLLO DS3500 PIC8259 controllers
+ * - apollo_ptm.c - APOLLO DS3500 Programmable Timer 6840
+ * - apollo_rtc.c - APOLLO DS3500 RTC MC146818
+ * - apollo_sio.c - APOLLO DS3500 SIO
+ * - apollo_sio2.c - APOLLO DS3500 SIO2
+ * - apollo_fdc.c - APOLLO DS3500 Floppy disk controller
+ *
+ * see also:
+ * - http://www.bitsavers.org/pdf/apollo/008778-03_DOMAIN_Series_3000_4000_Technical_Reference_Aug87.pdf
+ * - http://www.freescale.com/files/32bit/doc/inactive/MC68681UM.pdf
+ *
+ */
+
+#include "includes/apollo.h"
+#include "machine/apollo_kbd.h"
+#include "machine/omti8621.h"
+#include "machine/sc499.h"
+#include "machine/3c505.h"
+
+#include "machine/6840ptm.h"
+#include "machine/68681.h"
+#include "machine/8237dma.h"
+#include "machine/mc146818.h"
+#include "machine/pic8259.h"
+
+#include "machine/pc_fdc.h"
+#include "formats/basicdsk.h"
+
+#include "cpu/m68000/m68000.h"
+//#include "cpu/m68000/m68kcpu.h"
+
+#include "emuopts.h"
+
+#if defined(APOLLO_FOR_LINUX)
+#include <fcntl.h>
+#include <unistd.h>
+#endif
+
+#define APOLLO_IRQ_VECTOR 0xa0
+#define APOLLO_IRQ_PTM 0
+#define APOLLO_IRQ_SIO1 1
+#define APOLLO_IRQ_PIC_SLAVE 3
+#define APOLLO_IRQ_CTAPE 5
+#define APOLLO_IRQ_FDC 6
+#define APOLLO_IRQ_RTC 8 // DN3000 only
+#define APOLLO_IRQ_SIO2 8 // DN3500
+#define APOLLO_IRQ_ETH2 9
+#define APOLLO_IRQ_ETH1 10
+#define APOLLO_IRQ_DIAG 13
+#define APOLLO_IRQ_WIN1 14
+
+#define APOLLO_DMA_ETH1 6
+#define APOLLO_DMA_ETH2 3
+
+//##########################################################################
+// machine/apollo_config.c - APOLLO DS3500 configuration
+//##########################################################################
+
+#undef VERBOSE
+#define VERBOSE 0
+
+static UINT16 config = 0;
+
+/***************************************************************************
+ apollo_config - check configuration setting
+ ***************************************************************************/
+
+int apollo_config(int mask)
+{
+ return config & mask ? 1 : 0;
+}
+
+/***************************************************************************
+ Input Ports
+ ***************************************************************************/
+
+INPUT_PORTS_START( apollo_config )
+ PORT_START( "apollo_config" )
+ PORT_CONFNAME(APOLLO_CONF_SERVICE_MODE, 0x00, "Normal/Service" )
+ PORT_CONFSETTING(0x00, "Service" )
+ PORT_CONFSETTING(APOLLO_CONF_SERVICE_MODE, "Normal " )
+
+ PORT_CONFNAME(APOLLO_CONF_GERMAN_KBD, 0x00, "German Keyboard")
+ PORT_CONFSETTING(0x00, DEF_STR ( Off ) )
+ PORT_CONFSETTING(APOLLO_CONF_GERMAN_KBD, DEF_STR ( On ) )
+
+ PORT_CONFNAME(APOLLO_CONF_DATE_1990, 0x00, "20 Years Ago ...")
+ PORT_CONFSETTING(0x00, DEF_STR ( Off ) )
+ PORT_CONFSETTING(APOLLO_CONF_DATE_1990, DEF_STR ( On ) )
+
+ PORT_CONFNAME(APOLLO_CONF_NODE_ID, 0x00, "Node ID from Disk")
+ PORT_CONFSETTING(0x00, DEF_STR ( Off ) )
+ PORT_CONFSETTING(APOLLO_CONF_NODE_ID, DEF_STR ( On ) )
+
+ PORT_CONFNAME(APOLLO_CONF_IDLE_SLEEP, 0x00, "Idle Sleep")
+ PORT_CONFSETTING(0x00, DEF_STR ( Off ) )
+ PORT_CONFSETTING(APOLLO_CONF_IDLE_SLEEP, DEF_STR ( On ) )
+
+ PORT_CONFNAME(APOLLO_CONF_TRAP_TRACE, 0x00, "Trap Trace")
+ PORT_CONFSETTING(0x00, DEF_STR ( Off ) )
+ PORT_CONFSETTING(APOLLO_CONF_TRAP_TRACE, DEF_STR ( On ) )
+
+ PORT_CONFNAME(APOLLO_CONF_FPU_TRACE, 0x00, "FPU Trace")
+ PORT_CONFSETTING(0x00, DEF_STR ( Off ) )
+ PORT_CONFSETTING(APOLLO_CONF_FPU_TRACE, DEF_STR ( On ) )
+
+ PORT_CONFNAME(APOLLO_CONF_DISK_TRACE, 0x00, "Disk Trace")
+ PORT_CONFSETTING(0x00, DEF_STR ( Off ) )
+ PORT_CONFSETTING(APOLLO_CONF_DISK_TRACE, DEF_STR ( On ) )
+
+ PORT_CONFNAME(APOLLO_CONF_NET_TRACE, 0x00, "Network Trace")
+ PORT_CONFSETTING(0x00, DEF_STR ( Off ) )
+ PORT_CONFSETTING(APOLLO_CONF_NET_TRACE, DEF_STR ( On ) )
+INPUT_PORTS_END
+
+/*-------------------------------------------------
+ device start callback
+ -------------------------------------------------*/
+
+static DEVICE_START(apollo_config)
+{
+ DLOG1(("start apollo_config"));
+}
+
+/*-------------------------------------------------
+ device reset callback
+ -------------------------------------------------*/
+
+static DEVICE_RESET(apollo_config)
+{
+ DLOG1(("reset apollo_config"));
+ // load configuration
+ config = device->machine().root_device().ioport("apollo_config")->read();
+}
+
+/*-------------------------------------------------
+ device get info callback
+ -------------------------------------------------*/
+
+static DEVICE_GET_INFO(apollo_config)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(apollo_config); break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(apollo_config);break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "Apollo Configuration");break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "Configuration"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break;
+ }
+}
+
+static DECLARE_LEGACY_DEVICE(APOLLO_CONF, apollo_config);
+
+DEFINE_LEGACY_DEVICE(APOLLO_CONF, apollo_config);
+
+//##########################################################################
+// machine/apollo_csr.c - APOLLO DS3500 CPU Control and Status registers
+//##########################################################################
+
+#undef VERBOSE
+#define VERBOSE 0
+
+#define CPU_CONTROL_REGISTER_ADDRESS 0x010100
+
+static UINT16 cpu_status_register = APOLLO_CSR_SR_BIT15 | APOLLO_CSR_SR_SERVICE;
+static UINT16 cpu_control_register = 0x0000;
+
+/*-------------------------------------------------
+ apollo_csr_get/set_servicemode
+ -------------------------------------------------*/
+
+static int apollo_csr_get_servicemode()
+{
+
+ return cpu_status_register & APOLLO_CSR_SR_SERVICE ? 0 : 1;
+}
+
+static void apollo_csr_set_servicemode(int mode)
+{
+ apollo_csr_set_status_register(1, mode ? APOLLO_CSR_SR_SERVICE : 0);
+}
+
+UINT16 apollo_csr_get_control_register(void)
+{
+ return cpu_control_register;
+}
+
+UINT16 apollo_csr_get_status_register(void)
+{
+ return cpu_status_register;
+}
+
+void apollo_csr_set_status_register(UINT16 mask, UINT16 data)
+{
+ UINT16 new_value = (cpu_status_register & ~mask) | (data & mask);
+
+ if (new_value != cpu_status_register)
+ {
+ cpu_status_register = new_value;
+ LOG1(("#### setting CPU Status Register with data=%04x & %04x to %04x", data, mask, cpu_status_register));
+ }
+}
+
+/*-------------------------------------------------
+ DN3000/DN3500 CPU Status Register at 0x8000/0x10000
+ -------------------------------------------------*/
+
+WRITE16_MEMBER(apollo_state::apollo_csr_status_register_w){
+ // To clear bus timeouts or parity conditions from status register,
+ // write to the status register. This register is readonly.
+ // in DN3500 bit 15 is always set (undocumented !?)
+ cpu_status_register &= (APOLLO_CSR_SR_BIT15 | APOLLO_CSR_SR_FP_TRAP | APOLLO_CSR_SR_SERVICE);
+ SLOG1(("writing CPU Status Register at offset %X = %04x & %04x (%04x)", offset, data, mem_mask, cpu_status_register));
+}
+
+READ16_MEMBER(apollo_state::apollo_csr_status_register_r){
+ SLOG2(("reading CPU Status Register at offset %X = %04x & %04x", offset, cpu_status_register, mem_mask));
+ return cpu_status_register & mem_mask;
+}
+
+/*-------------------------------------------------
+ DN3000/DN3500 CPU Control Register at 0x8100/0x10100
+ -------------------------------------------------*/
+
+WRITE16_MEMBER(apollo_state::apollo_csr_control_register_w)
+{
+ int leds;
+
+ if ((mem_mask & APOLLO_CSR_CR_FPU_TRAP_ENABLE) == 0)
+ {
+ // FPU Trap enable not involved
+ }
+ else if (((data ^ cpu_control_register) & APOLLO_CSR_CR_FPU_TRAP_ENABLE) == 0)
+ {
+ // FPU Trap enable remains unchanged
+ }
+ else if ((data & APOLLO_CSR_CR_FPU_TRAP_ENABLE) == 0)
+ {
+ // enable FPU (i.e. FPU opcodes in CPU)
+ apollo_set_cpu_has_fpu(&space.device(), 1);
+ }
+ else
+ {
+ // disable FPU (i.e. FPU opcodes in CPU)
+ apollo_set_cpu_has_fpu(&space.device(), 0);
+
+ if (!apollo_is_dn3000())
+ {
+ // hack: set APOLLO_CSR_SR_FP_TRAP in cpu status register for /sau7/self_test
+ // APOLLO_CSR_SR_FP_TRAP in status register should be set by next fmove instruction
+ // cpu_status_register |= APOLLO_CSR_SR_FP_TRAP;
+ }
+ }
+
+ cpu_control_register = (cpu_control_register & ~mem_mask) | (data & mem_mask);
+
+ output_set_value("internal_led_1", (cpu_control_register >> 15) & 1);
+ output_set_value("internal_led_2", (cpu_control_register >> 14) & 1);
+ output_set_value("internal_led_3", (cpu_control_register >> 13) & 1);
+ output_set_value("internal_led_4", (cpu_control_register >> 12) & 1);
+ output_set_value("external_led_a", (cpu_control_register >> 11) & 1);
+ output_set_value("external_led_b", (cpu_control_register >> 10) & 1);
+ output_set_value("external_led_c", (cpu_control_register >> 9) & 1);
+ output_set_value("external_led_d", (cpu_control_register >> 8) & 1);
+
+ leds = ((cpu_control_register >> 8) & 0xff) ^ 0xff;
+
+ SLOG1(("writing CPU Control Register at offset %X = %04x & %04x (%04x - %d%d%d%d %d%d%d%d)",
+ offset, data, mem_mask, cpu_control_register,
+ (leds >> 3) & 1,(leds >> 2) & 1, (leds >> 1) & 1, (leds >> 0) & 1,
+ (leds >> 7) & 1,(leds >> 6) & 1, (leds >> 5) & 1, (leds >> 4) & 1 ));
+
+ if (data & APOLLO_CSR_CR_RESET_DEVICES)
+ {
+ // FIXME: reset all devices (but not SIO lines!)
+ }
+}
+
+READ16_MEMBER(apollo_state::apollo_csr_control_register_r)
+{
+ SLOG1(("reading CPU Control Register at offset %X = %04x & %04x", offset, cpu_control_register, mem_mask));
+ return cpu_control_register & mem_mask;
+}
+
+//##########################################################################
+// machine/apollo_dma.c - APOLLO DS3500 DMA
+//##########################################################################
+
+#undef VERBOSE
+#define VERBOSE 0
+
+static UINT16 address_translation_map[0x400];
+
+static UINT16 dma_page_register[16] =
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+static const UINT8 channel2page_register[8] = { 7, 3, 1, 2, 0, 11, 9, 10};
+
+static UINT8 dn3000_dma_channel1 = 1; // 1 = memory/ctape, 2 = floppy dma channel
+static UINT8 dn3000_dma_channel2 = 5; // 5 = memory dma channel
+
+INLINE device_t *get_device_dma8237_1(device_t *device) {
+ return device->machine().driver_data<apollo_state>()->dma8237_1;
+}
+
+INLINE device_t *get_device_dma8237_2(device_t *device) {
+ return device->machine().driver_data<apollo_state>()->dma8237_2;
+}
+
+static void apollo_dma_fdc_drq(device_t *device, int state) {
+ DLOG2(("apollo_dma_fdc_drq: state=%x", state));
+ i8237_dreq2_w(get_device_dma8237_1(device), state);
+}
+
+static void apollo_dma_ctape_drq(device_t *device, int state) {
+ DLOG1(("apollo_dma_ctape_drq: state=%x", state));
+ i8237_dreq1_w(get_device_dma8237_1(device), state);
+}
+
+/*-------------------------------------------------
+ DN3000/DN3500 DMA Controller 1 at 0x9000/0x10c00
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(apollo_state::apollo_dma_1_w){
+ SLOG1(("apollo_dma_1_w: writing DMA Controller 1 at offset %02x = %02x", offset, data));
+ i8237_w(get_device_dma8237_1(&space.device()), offset, data);
+}
+
+READ8_MEMBER(apollo_state::apollo_dma_1_r){
+ UINT8 data = i8237_r(get_device_dma8237_1(&space.device()), offset);
+ SLOG1(("apollo_dma_1_r: reading DMA Controller 1 at offset %02x = %02x", offset, data));
+ return data;
+}
+
+/*-------------------------------------------------
+ DN3000/DN3500 DMA Controller 2 at 0x9100/0x10d00
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(apollo_state::apollo_dma_2_w){
+ SLOG1(("apollo_dma_2_w: writing DMA Controller 2 at offset %02x = %02x", offset/2, data));
+ i8237_w(get_device_dma8237_2(&space.device()), offset / 2, data);
+}
+
+READ8_MEMBER(apollo_state::apollo_dma_2_r){
+ UINT8 data = i8237_r(get_device_dma8237_2(&space.device()), offset / 2);
+ SLOG1(("apollo_dma_2_r: reading DMA Controller 2 at offset %02x = %02x", offset/2, data));
+ return data;
+}
+
+/***************************************************************************
+ DN3000 DMA Page Register at 0x9200
+ ***************************************************************************/
+
+WRITE8_MEMBER(apollo_state::apollo_dma_page_register_w){
+ dma_page_register[offset & 0x0f] = data;
+ SLOG1(("writing DMA Page Register at offset %02x = %02x", offset, data));
+}
+
+READ8_MEMBER(apollo_state::apollo_dma_page_register_r){
+ UINT8 data = dma_page_register[offset & 0x0f];
+ SLOG1(("reading DMA Page Register at offset %02x = %02x", offset, data));
+ return data;
+}
+
+/*-------------------------------------------------
+ DN3500 Address Translation Map at 0x017000
+ -------------------------------------------------*/
+
+WRITE16_MEMBER(apollo_state::apollo_address_translation_map_w){
+ address_translation_map[offset & 0x3ff] = data;
+ SLOG2(("writing Address Translation Map at offset %02x = %04x", offset, data));
+}
+
+READ16_MEMBER(apollo_state::apollo_address_translation_map_r){
+ UINT16 data = address_translation_map[offset & 0x3ff];
+ SLOG2(("reading Address Translation Map at offset %02x = %04x", offset, data));
+ return data;
+}
+
+READ8_MEMBER(apollo_state::apollo_dma_read_byte){
+ UINT8 data;
+ offs_t page_offset;
+
+ if (apollo_is_dn3000()) {
+ page_offset = dma_page_register[channel2page_register[dn3000_dma_channel1]] << 16;
+ } else {
+ // FIXME: address_translation_map[0x200] ?
+ page_offset = (((offs_t) address_translation_map[0x200 + (offset >> 10)]) << 10) & 0x7FFFFC00;
+ offset &= 0x3ff;
+ }
+
+ data = space.read_byte(page_offset + offset);
+
+ if (VERBOSE > 1 || offset < 4 || (offset & 0xff) == 0 || (offset & 0xff) == 0xff)
+ {
+ SLOG1(("dma read byte at offset %x+%03x = %02x", page_offset, offset, data));
+ }
+
+ return data;
+}
+
+WRITE8_MEMBER(apollo_state::apollo_dma_write_byte){
+ offs_t page_offset;
+ if (apollo_is_dn3000()) {
+ page_offset = dma_page_register[channel2page_register[dn3000_dma_channel1]] << 16;
+ } else {
+ // FIXME: address_translation_map[0x200] ?
+ page_offset = (((offs_t) address_translation_map[0x200 + (offset >> 10)]) << 10) & 0x7FFFFC00;
+ offset &= 0x3ff;
+ }
+ // FIXME: MSB not available, writing only LSB
+ space.write_byte(page_offset + offset, data);
+
+ if (VERBOSE > 1 || offset < 4 || (offset & 0xff) == 0 || (offset & 0xff) == 0xff)
+ {
+ SLOG1(("dma write byte at offset %x+%03x = %02x", page_offset, offset , data));
+ }
+}
+
+READ8_MEMBER(apollo_state::apollo_dma_read_word){
+ UINT16 data;
+ offs_t page_offset;
+
+ if (apollo_is_dn3000()) {
+ page_offset = dma_page_register[channel2page_register[dn3000_dma_channel2]] << 16;
+ page_offset &= 0xfffe0000;
+ offset <<= 1;
+ } else {
+ // FIXME: address_translation_map[0x200] ?
+ page_offset = (((offs_t) address_translation_map[0x200 + (offset >> 9)]) << 10) & 0x7FFFFC00;
+ offset = (offset << 1) & 0x3ff;
+ }
+
+ data = space.read_byte(page_offset + offset);
+
+ SLOG1(("dma read word at offset %x+%03x = %04x", page_offset, offset , data));
+ // FIXME: MSB will get lost
+ return data;
+}
+
+WRITE8_MEMBER(apollo_state::apollo_dma_write_word){
+ offs_t page_offset;
+
+ SLOG1(("dma write word at offset %x = %02x", offset, data));
+
+ if (apollo_is_dn3000()) {
+ page_offset = dma_page_register[channel2page_register[dn3000_dma_channel2]] << 16;
+ page_offset &= 0xfffe0000;
+ offset <<= 1;
+ } else {
+ // FIXME: address_translation_map[0x200] ?
+ page_offset
+ = (((offs_t) address_translation_map[0x200 + (offset >> 9)])
+ << 10) & 0x7FFFFC00;
+ offset = (offset << 1) & 0x3ff;
+ }
+
+ space.write_byte(page_offset + offset, data);
+ SLOG1(("dma write word at offset %x+%03x = %02x", page_offset, offset, data));
+}
+
+static READ8_DEVICE_HANDLER( apollo_dma8237_ctape_dack_r ) {
+
+ UINT8 data = sc499_dack_r(&device->machine());
+ DLOG2(("dma ctape dack read %02x",data));
+
+ // hack for DN3000: select appropriate DMA channel No.
+ dn3000_dma_channel1 = 1; // 1 = ctape, 2 = floppy dma channel
+
+ return data;
+}
+
+static WRITE8_DEVICE_HANDLER( apollo_dma8237_ctape_dack_w ) {
+ DLOG2(("dma ctape dack write %02x", data));
+ sc499_dack_w(&device->machine(), data);
+
+ // hack for DN3000: select appropriate DMA channel No.
+ // Note: too late for this byte, but next bytes will be ok
+ dn3000_dma_channel1 = 1; // 1 = ctape, 2 = floppy dma channel
+}
+
+static READ8_DEVICE_HANDLER( apollo_dma8237_fdc_dack_r ) {
+ UINT8 data = pc_fdc_dack_r(device->machine());
+ // DLOG2(("dma fdc dack read %02x",data));
+
+ // hack for DN3000: select appropriate DMA channel No.
+ dn3000_dma_channel1 = 2; // 1 = ctape, 2 = floppy dma channel
+
+ return data;
+}
+
+static WRITE8_DEVICE_HANDLER( apollo_dma8237_fdc_dack_w ) {
+ // DLOG2(("dma fdc dack write %02x", data));
+ pc_fdc_dack_w(device->machine(), data);
+
+ // hack for DN3000: select appropriate DMA channel No.
+ // Note: too late for this byte, but next bytes will be ok
+ dn3000_dma_channel1 = 2; // 1 = ctape, 2 = floppy dma channel
+}
+
+static READ8_DEVICE_HANDLER( apollo_dma8237_wdc_dack_r ) {
+ UINT8 data = 0xff; // omti8621_dack_r(device->machine);
+ DLOG1(("dma wdc dack read %02x (not used, not emulated!)",data));
+ return data;
+}
+
+static WRITE8_DEVICE_HANDLER( apollo_dma8237_wdc_dack_w ) {
+ DLOG1(("dma wdc dack write %02x (not used, not emulated!)", data));
+// omti8621_dack_w(device->machine, data);
+}
+
+static WRITE_LINE_DEVICE_HANDLER( apollo_dma8237_out_eop ) {
+ DLOG1(("dma out eop state %02x", state));
+ pc_fdc_set_tc_state(device->machine(), state ? 0 : 1);
+ sc499_set_tc_state(&device->machine(), state);
+}
+
+static WRITE_LINE_DEVICE_HANDLER( apollo_dma_1_hrq_changed ) {
+ // DLOG2(("dma 1 hrq changed state %02x", state));
+ i8237_dreq0_w(get_device_dma8237_2(device), state);
+
+ /* Assert HLDA */
+ i8237_hlda_w(device, state);
+
+ // cascade mode?
+ // i8237_hlda_w(get_device_dma8237_2(device), state);
+}
+
+static WRITE_LINE_DEVICE_HANDLER( apollo_dma_2_hrq_changed ) {
+ // DLOG2(("dma 2 hrq changed state %02x", state));
+ cputag_set_input_line(device->machine(), MAINCPU, INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE);
+
+ /* Assert HLDA */
+ i8237_hlda_w(device, state);
+}
+
+static I8237_INTERFACE( apollo_dma8237_1_config )
+{
+ DEVCB_LINE(apollo_dma_1_hrq_changed),
+ DEVCB_LINE(apollo_dma8237_out_eop),
+ DEVCB_DRIVER_MEMBER(apollo_state, apollo_dma_read_byte),
+ DEVCB_DRIVER_MEMBER(apollo_state, apollo_dma_write_byte),
+ { DEVCB_NULL, DEVCB_HANDLER(apollo_dma8237_ctape_dack_r), DEVCB_HANDLER(apollo_dma8237_fdc_dack_r), DEVCB_NULL},
+ { DEVCB_NULL, DEVCB_HANDLER(apollo_dma8237_ctape_dack_w), DEVCB_HANDLER(apollo_dma8237_fdc_dack_w), DEVCB_NULL},
+ { DEVCB_NULL, DEVCB_NULL, DEVCB_NULL, DEVCB_NULL}
+};
+
+static I8237_INTERFACE( apollo_dma8237_2_config )
+{
+ DEVCB_LINE(apollo_dma_2_hrq_changed),
+ DEVCB_NULL,
+ DEVCB_DRIVER_MEMBER(apollo_state, apollo_dma_read_word),
+ DEVCB_DRIVER_MEMBER(apollo_state, apollo_dma_write_word),
+ { DEVCB_NULL, DEVCB_NULL, DEVCB_NULL, DEVCB_HANDLER(apollo_dma8237_wdc_dack_r)},
+ { DEVCB_NULL, DEVCB_NULL, DEVCB_NULL, DEVCB_HANDLER(apollo_dma8237_wdc_dack_w)},
+ { DEVCB_NULL, DEVCB_NULL, DEVCB_NULL, DEVCB_NULL}
+};
+
+//##########################################################################
+// machine/apollo_pic.c - APOLLO DS3500 PIC 8259 controllers
+//##########################################################################
+
+#undef VERBOSE
+#define VERBOSE 0
+
+INLINE device_t *get_pic8259_master(device_t *device) {
+ return device->machine().driver_data<apollo_state>()->pic8259_master;
+}
+
+INLINE device_t *get_pic8259_slave(device_t *device) {
+ return device->machine().driver_data<apollo_state>()->pic8259_slave;
+}
+
+/*-------------------------------------------------
+ Interrupt Controller 8259 PIC #1 at 0x9400/0x11000
+ -------------------------------------------------*/
+
+WRITE8_DEVICE_HANDLER(apollo_pic8259_master_w ) {
+ DLOG1(("writing %s at offset %X = %02x", device->tag(), offset, data));
+ pic8259_w(device, offset, data);
+}
+
+READ8_DEVICE_HANDLER( apollo_pic8259_master_r ) {
+ UINT8 data = pic8259_r(device, offset);
+ DLOG1(("reading %s at offset %X = %02x", device->tag(), offset, data));
+ return data;
+}
+
+/*-------------------------------------------------
+ Interrupt Controller 8259 PIC #2 at 0x9500/0x11100
+ -------------------------------------------------*/
+
+WRITE8_DEVICE_HANDLER(apollo_pic8259_slave_w ) {
+ DLOG1(("writing %s at offset %X = %02x", device->tag(), offset, data));
+ pic8259_w(device, offset, data);
+}
+
+READ8_DEVICE_HANDLER( apollo_pic8259_slave_r ) {
+ UINT8 data = pic8259_r(device, offset);
+ DLOG1(("reading %s at offset %X = %02x", device->tag(), offset, data));
+ return data;
+}
+
+static void apollo_pic_set_irq_line(device_t *device, int irq, int state) {
+ // don't log PTM interrupts
+ if (irq != APOLLO_IRQ_PTM) {
+ DLOG1(("apollo_pic_set_irq_line: irq=%d state=%d", irq, state));
+ }
+
+ switch (irq) {
+ case 0: pic8259_ir0_w(get_pic8259_master(device), state); break;
+ case 1: pic8259_ir1_w(get_pic8259_master(device), state); break;
+ case 2: pic8259_ir2_w(get_pic8259_master(device), state); break;
+ case 3: pic8259_ir3_w(get_pic8259_master(device), state); break;
+ case 4: pic8259_ir4_w(get_pic8259_master(device), state); break;
+ case 5: pic8259_ir5_w(get_pic8259_master(device), state); break;
+ case 6: pic8259_ir6_w(get_pic8259_master(device), state); break;
+ case 7: pic8259_ir7_w(get_pic8259_master(device), state); break;
+
+ case 8: pic8259_ir0_w(get_pic8259_slave(device), state); break;
+ case 9: pic8259_ir1_w(get_pic8259_slave(device), state); break;
+ case 10: pic8259_ir2_w(get_pic8259_slave(device), state); break;
+ case 11: pic8259_ir3_w(get_pic8259_slave(device), state); break;
+ case 12: pic8259_ir4_w(get_pic8259_slave(device), state); break;
+ case 13: pic8259_ir5_w(get_pic8259_slave(device), state); break;
+ case 14: pic8259_ir6_w(get_pic8259_slave(device), state); break;
+ case 15: pic8259_ir7_w(get_pic8259_slave(device), state); break;
+ }
+}
+
+IRQ_CALLBACK(apollo_pic_acknowledge) {
+ UINT32 vector = pic8259_acknowledge(get_pic8259_master(device));
+ if ((vector & 0x0f) == APOLLO_IRQ_PIC_SLAVE) {
+ vector = pic8259_acknowledge(get_pic8259_slave(device));
+ }
+
+ // don't log ptm interrupts
+ if (vector != APOLLO_IRQ_VECTOR+APOLLO_IRQ_PTM) {
+ DLOG1(("apollo_pic_acknowledge: irq=%d vector=%x", vector & 0x0f, vector));
+ }
+
+ if (apollo_is_dn3000()) {
+ apollo_csr_set_status_register(APOLLO_CSR_SR_INTERRUPT_PENDING, 0);
+ } else {
+ // clear bit Interrupt Pending in Cache Status Register
+ apollo_set_cache_status_register(0x10, 0x00);
+ }
+ return vector;
+}
+
+/*************************************************************
+ * pic8259 configuration
+ *************************************************************/
+
+static WRITE_LINE_DEVICE_HANDLER( apollo_pic8259_master_set_int_line ) {
+ static int interrupt_line = -1;
+ if (state != interrupt_line) {
+ DLOG1(("apollo_pic8259_master_set_int_line: %x", state));
+ }
+ interrupt_line = state;
+
+ if (apollo_is_dn3000()) {
+ apollo_csr_set_status_register(APOLLO_CSR_SR_INTERRUPT_PENDING,
+ state ? APOLLO_CSR_SR_INTERRUPT_PENDING : 0);
+ } else {
+ // set bit Interrupt Pending in Cache Status Register
+ apollo_set_cache_status_register(0x10, state ? 0x10 : 0x00);
+ }
+
+ cputag_set_input_line_and_vector(device->machine(), MAINCPU, M68K_IRQ_6,state ? ASSERT_LINE : CLEAR_LINE, M68K_INT_ACK_AUTOVECTOR);
+}
+
+static WRITE_LINE_DEVICE_HANDLER( apollo_pic8259_slave_set_int_line ) {
+ static int interrupt_line = -1;
+ if (state != interrupt_line) {
+ DLOG1(("apollo_pic8259_slave_set_int_line: %x", state));
+ interrupt_line = state;
+ apollo_pic_set_irq_line(device, 3, state);
+ }
+}
+
+static const struct pic8259_interface apollo_pic8259_master_config = {
+ DEVCB_LINE(apollo_pic8259_master_set_int_line) };
+
+static const struct pic8259_interface apollo_pic8259_slave_config = {
+ DEVCB_LINE(apollo_pic8259_slave_set_int_line) };
+
+//##########################################################################
+// machine/apollo_ptm.c - APOLLO DS3500 Programmable Timer 6840
+//##########################################################################
+
+#undef VERBOSE
+#define VERBOSE 0
+
+static emu_timer* ptm_timer;
+static UINT32 ptm_counter = 0;
+
+static TIMER_CALLBACK(apollo_ptm_timer_callback)
+{
+ ptm6840_device *device = downcast<ptm6840_device *>((device_t *) ptr);
+
+ ptm_counter++;
+ device->set_c1( 1);
+ device->set_c1( 0);
+ device->set_c2(ptm_counter & 1);
+
+ if ((ptm_counter & 1) == 0)
+ {
+ device->set_c3((ptm_counter >> 1) & 1);
+ }
+
+ if (ptm_counter % 250000 == 0)
+ {
+ DLOG2(("apollo_ptm_timer_callback: %d", ptm_counter / 250000));
+ }
+}
+
+static WRITE_LINE_DEVICE_HANDLER( apollo_ptm_irq_function ) {
+ DLOG1(("apollo_ptm_irq_function: state=%d", state ));
+
+// ptm6840_device *ptm = device->machine().device<ptm6840_device>(APOLLO_PTM_TAG);
+
+ apollo_pic_set_irq_line(device, APOLLO_IRQ_PTM, state);
+}
+
+// Timer 1's input is a 250-kHz (4-microsecond period) signal.
+// Timer 2's input is a 125-kHz (8-microsecond period) signal.
+// Timer 3's input is a 62.5-kHz (16-microsecond period) signal.
+// The Timer 3 input may be prescaled to make the effective input signal have a 128-microsecond period.
+
+static const ptm6840_interface apollo_ptm_config = {
+ 0,
+ { 250000, 125000, 62500 },
+ { DEVCB_NULL, DEVCB_NULL, DEVCB_NULL },
+ DEVCB_LINE(apollo_ptm_irq_function)
+};
+
+static DEVICE_START( apollo_ptm )
+{
+ DLOG1(("start apollo_ptm"));
+ // allocate and start ptm timer
+ ptm_timer = device->machine().scheduler().timer_alloc(FUNC(apollo_ptm_timer_callback), device);
+ ptm_timer->adjust( attotime::zero, 0, attotime::from_usec(4));
+}
+
+static DEVICE_RESET( apollo_ptm )
+{
+ DLOG1(("reset apollo_ptm"));
+ device->reset();
+}
+
+READ8_DEVICE_HANDLER(apollo_ptm_r) {
+ UINT8 data =downcast<ptm6840_device *>((device_t *) device)->read(offset / 2);
+
+ // prevent excessive logging
+ static UINT8 previous = 255;
+ if (offset / 2 != 1 || data != previous) {
+ DLOG1(("apollo_ptm_read reg %x returned %02x", offset/2, data ));
+ if (offset / 2 == 1) {
+ previous = data;
+ }
+ }
+ return data;
+}
+
+WRITE8_DEVICE_HANDLER(apollo_ptm_w) {
+ DLOG1(("apollo_ptm_write reg %x with %02x", offset/2, data ));
+ downcast<ptm6840_device *>((device_t *) device)->write(offset / 2, data);
+}
+
+//##########################################################################
+// machine/apollo_rtc.c - APOLLO DS3500 RTC MC146818
+//##########################################################################
+
+#undef VERBOSE
+#define VERBOSE 0
+
+/***************************************************************************
+ DN3000/DN3500 Realtime Calendar MC146818 at 0x8900/0x10900
+ ***************************************************************************/
+
+static DEVICE_RESET( apollo_rtc ) {
+ address_space *space = device->machine().device(MAINCPU)->memory().space(AS_PROGRAM);
+ apollo_state *state = device->machine().driver_data<apollo_state>();
+ UINT8 year = state->apollo_rtc_r(*space, 9);
+
+ // change year according to configuration settings
+ if (year < 20 && apollo_config(APOLLO_CONF_DATE_1990))
+ {
+ year+=80;
+ state->apollo_rtc_w(*space, 9, year);
+ }
+ else if (year >= 80 && !apollo_config(APOLLO_CONF_DATE_1990))
+ {
+ year -=80;
+ state->apollo_rtc_w(*space, 9, year);
+ }
+
+ //SLOG1(("reset apollo_rtc year=%d", year));
+}
+
+WRITE8_MEMBER(apollo_state::apollo_rtc_w)
+{
+ mc146818_device *rtc = machine().device<mc146818_device> (APOLLO_RTC_TAG);
+ rtc->write(space, 0, offset);
+ rtc->write(space, 1, data);
+ if (offset >= 0x0b && offset <= 0x0c)
+ {
+ SLOG2(("writing MC146818 at offset %02x = %02x", offset, data));
+ }
+}
+
+READ8_MEMBER(apollo_state::apollo_rtc_r)
+{
+ UINT8 data;
+ mc146818_device *rtc = machine().device<mc146818_device> (APOLLO_RTC_TAG);
+ rtc->write(space, 0, offset);
+ data = rtc->read(space, 1);
+ if (offset >= 0x0b && offset <= 0x0c)
+ {
+ SLOG2(("reading MC146818 at offset %02x = %02x", offset, data));
+ }
+ return data;
+}
+
+static TIMER_CALLBACK( apollo_rtc_timer )
+{
+ apollo_state *state = machine.driver_data<apollo_state>();
+ address_space *space = machine.device(MAINCPU)->memory().space(AS_PROGRAM);
+
+ // FIXME: reading register 0x0c will clear all interrupt flags
+ if ((state->apollo_rtc_r(*space, 0x0c) & 0x80))
+ {
+ //SLOG2(("apollo_rtc_timer - set_irq_line %d", APOLLO_IRQ_RTC));
+ apollo_pic_set_irq_line(&space->device(), APOLLO_IRQ_RTC, 1);
+ }
+}
+
+//##########################################################################
+// machine/apollo_sio.c - APOLLO DS3500 SIO
+//##########################################################################
+
+#undef VERBOSE
+#define VERBOSE 0
+
+#define SIO_SLEEP_DELAY_TIME 30000 // ms
+
+static int isInitialized = 0;
+static int input_from_stdin = 0;
+
+static UINT8 sio_input_data = 0xff;
+static UINT8 sio_output_data = 0xff;
+
+static emu_timer *kbd_timer;
+static int sleep_time = 0;
+
+static int sio_irq_line = 0;
+
+static UINT8 sio_csrb = 0;
+
+/*-------------------------------------------------
+ sio_sleep - sleep to reduce the CPU usage
+ -------------------------------------------------*/
+
+// we reduce the CPU usage, if SRB is being polled for input
+// but only as long as the transmitter is empty and ready
+// and the initial delay time has passed w/o IO
+
+static void sio_sleep(int delay) {
+ if (!apollo_config(APOLLO_CONF_IDLE_SLEEP)) {
+ // nothing to do; sleeping is not enabled
+ } else if (delay <= 0) {
+ //reset the sleep delay time
+ if (sleep_time > 0) {
+ LOG2(("sio_sleep: sleeping stopped"))
+ sleep_time = 0;
+ }
+ } else if (sleep_time < delay) {
+ // sleep delay pending (i.e. don't sleep)
+ sleep_time++;
+ } else {
+ if (sleep_time == delay) {
+ LOG2(("sio_sleep: sleeping started after %d ms",sleep_time));
+ sleep_time++;
+ }
+ // Note: ticks_per_second/100 will sleep for 6 ms (= 4-10 ms)
+ osd_sleep(osd_ticks_per_second() / 50);
+ }
+}
+
+/*-------------------------------------------------
+ apollo_sio_rx_data - get character from keyboard/stdin
+ -------------------------------------------------*/
+
+void apollo_sio_rx_data(device_t* device, int ch, UINT8 data) {
+ // omit logging for channel 1
+ if (ch == 0) {
+ DLOG1(("apollo_sio_rx_data ch=%d <- data=%02x", ch, data ));
+ }
+
+ if (ch == 1 && !isInitialized && data == '\r' && apollo_csr_get_servicemode()) {
+ // force baudrate recognition
+ data = 0xff;
+ isInitialized = 1;
+ }
+
+ duart68681_rx_data(device, ch, data);
+}
+
+/*-------------------------------------------------
+ apollo_sio_tx_data - put character to display/stdout
+ -------------------------------------------------*/
+
+static void apollo_sio_tx_data(device_t *device, int channel, UINT8 data) {
+ if (channel == 0) {
+ DLOG1(("apollo_sio_tx_data ch=%d -> data=%02x", channel, data ));
+ device_t *keyboard = device->machine().device( APOLLO_KBD_TAG );
+ if (keyboard != NULL) {
+ apollo_kbd_getchar(keyboard, data);
+ }
+ } else if (channel == 1) {
+ DLOG2(("apollo_sio_tx_data ch=%d -> data=%02x", channel, data ));
+
+ if (data != '\r') {
+ // output data to stdout
+ putchar(data);
+ fflush(stdout);
+
+ if (apollo_is_dsp3x00()) {
+ // output data to terminal emulator
+ apollo_terminal_write(data);
+ }
+ }
+ }
+}
+
+/*-------------------------------------------------
+ sio configuration
+ -------------------------------------------------*/
+
+static void sio_irq_handler(device_t *device, int state, UINT8 vector) {
+ DLOG2(("sio_irq_handler: vector=%02x", vector ));
+ apollo_pic_set_irq_line(device, APOLLO_IRQ_SIO1, state);
+ sio_irq_line = 1;
+}
+
+static UINT8 sio_input(device_t *device) {
+ // necessary for DN3000?
+ // sio_input_data = sio_input_data ? 0 : 0x0f;
+ DLOG2(("reading 2681 input: %02x", sio_input_data ));
+ return sio_input_data;
+}
+
+static void sio_output(device_t *device, UINT8 data) {
+ DLOG1(("writing 2681 output: %02x", data ));
+
+ if ((data & 0x80) != (sio_output_data & 0x80)) {
+ apollo_pic_set_irq_line(device, APOLLO_IRQ_DIAG, (data & 0x80) ? 1 : 0);
+ sio_output_data = data;
+ }
+}
+
+const duart68681_config apollo_sio_config = {
+ sio_irq_handler,
+ apollo_sio_tx_data,
+ sio_input,
+ sio_output
+};
+
+/*-------------------------------------------------
+ DN3000/DS3500 SIO at 0x8400/0x10400
+ -------------------------------------------------*/
+
+READ8_DEVICE_HANDLER(apollo_sio_r) {
+ static int last_read8_offset[2] = { -1, -1 };
+ static int last_read8_value[2] = { -1, -1 };
+
+ 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" };
+
+ int data = duart68681_r(device, offset / 2);
+
+ if (sio_irq_line) {
+ apollo_pic_set_irq_line(device, APOLLO_IRQ_SIO1, 0);
+ sio_irq_line = 0;
+ }
+
+ switch (offset / 2) {
+ case 0x0b: /* RHRB */
+ if (data == 0x0d && sio_csrb == 0x77) {
+ // special for MD command SK (Select keyboard) with baudrate set to 2000
+ data = 0xff;
+ }
+ break;
+ }
+
+ // omit logging if sio is being polled from the boot rom
+ if ((offset != last_read8_offset[1] || data != last_read8_value[1])
+ && (offset != last_read8_offset[0] || data != last_read8_value[0])) {
+ last_read8_offset[0] = last_read8_offset[1];
+ last_read8_value[0] = last_read8_value[1];
+ last_read8_offset[1] = offset;
+ last_read8_value[1] = data;
+ DLOG2(("reading 2681 reg %x (%s) returned %02x",
+ offset, duart68681_reg_read_names[offset/2], data ));
+ }
+
+ return data;
+}
+
+WRITE8_DEVICE_HANDLER(apollo_sio_w)
+{
+ 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" };
+
+ if (sio_irq_line) {
+ apollo_pic_set_irq_line(device, APOLLO_IRQ_SIO1, 0);
+ sio_irq_line = 0;
+ }
+
+ // don't log THRB
+ if (offset != 0x17) {
+ DLOG2(("writing 2681 reg %x (%s) with %02x", offset, duart68681_reg_write_names[(offset/2) & 15], data ));
+ }
+
+ switch (offset / 2) {
+ case 0x09: /* CSRB */
+ // remember CSRB to handle MD command SK on DSP3x00
+ sio_csrb = data;
+ break;
+ case 0x0b: /* THRB */
+ // stop sleeping
+ sio_sleep(0);
+ break;
+ case 0x0d: /* OPCR */
+ if ((data & 0x0c) == 0x04) {
+ // Unhandled OPCR value; used for RAM refresh circuit
+ // ignore value; omit error message
+ data &= ~0x0c;
+ }
+ break;
+ }
+ duart68681_w(device, offset / 2, data);
+}
+
+/*-------------------------------------------------
+ kbd tty timer callback
+ -------------------------------------------------*/
+
+static TIMER_CALLBACK(kbd_timer_callback)
+{
+
+#if defined(APOLLO_FOR_LINUX)
+ device_t *device = (device_t *) ptr;
+ UINT8 data;
+
+#define SRA 0x01
+#define SRB 0x09
+
+ if (!(duart68681_r(device, SRB) & 0x02))
+ {
+ // Channel B FIFO not yet full (STATUS_FIFO_FULL)
+ if (read(STDIN_FILENO, &data, 1) == 1)
+ {
+ apollo_sio_rx_data(device, 1, data == '\n' ? '\r' : data);
+ input_from_stdin = 1;
+ // stop sleeping to reduce CPU usage
+ sio_sleep(0);
+ }
+ else if (input_from_stdin && (duart68681_r(device, SRB) & 0x0c) == 0x0c)
+ {
+ // we reduce the CPU usage, if SRB is being polled for input
+ // but only as long as the transmitter is empty and ready
+ // and the initial delay time has has passed
+ sio_sleep(SIO_SLEEP_DELAY_TIME);
+ }
+ }
+#endif
+
+ // The counter/timer on the SIO chip is used for the refresh count.
+ // This is set up in the timer mode to produce a square wave output on output OP3.
+ // The period of the output is 15 microseconds.
+
+ // toggle memory refresh counter
+ sio_input_data ^= 0x01;
+}
+
+/*-------------------------------------------------
+ device start callback
+ -------------------------------------------------*/
+
+static DEVICE_START(apollo_sio)
+{
+ kbd_timer = device->machine().scheduler().timer_alloc(FUNC(kbd_timer_callback), device);
+}
+
+/*-------------------------------------------------
+ device reset callback
+ -------------------------------------------------*/
+
+static DEVICE_RESET(apollo_sio)
+{
+ DLOG1(("reset apollo_sio"));
+
+ isInitialized = 0;
+ input_from_stdin = 0;
+ sleep_time = 0;
+ sio_input_data = apollo_get_ram_config_byte();
+ sio_output_data = 0xff;
+
+#if defined(APOLLO_FOR_LINUX)
+ // FIXME: unavailable in mingw
+ // set stdin to nonblocking to allow polling in sio_poll_rxb
+ fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK);
+#endif
+
+ // start the keyboard timer
+ kbd_timer->adjust( attotime::zero, 0, attotime::from_msec(1));
+}
+
+//##########################################################################
+// machine/apollo_sio2.c - APOLLO DS3500 SIO2
+//##########################################################################
+
+#undef VERBOSE
+#define VERBOSE 0
+
+/*-------------------------------------------------
+ sio2 configuration (DN3500 only)
+ -------------------------------------------------*/
+
+static void sio2_irq_handler(device_t *device, int state, UINT8 vector)
+{
+ DLOG1(("sio2_irq_handler: vector=%02x", vector ));
+ apollo_pic_set_irq_line(device, APOLLO_IRQ_SIO2, state);
+}
+
+static void sio2_tx_data(device_t *device, int channel, UINT8 data)
+{
+ DLOG1(("apollo_sio2_tx_data ch=%d -> data=%02x", channel, data ));
+}
+
+static UINT8 sio2_input(device_t *device)
+{
+ UINT8 data = 0x00;
+ DLOG1(("reading 2681 input: %02x", data ));
+ return data;
+}
+
+static void sio2_output(device_t *device, UINT8 data)
+{
+ DLOG1(("writing 2681 output: %02x", data ));
+}
+
+const duart68681_config apollo_sio2_config = {
+ sio2_irq_handler,
+ sio2_tx_data,
+ sio2_input,
+ sio2_output
+};
+
+/*-------------------------------------------------
+ DN3500 SIO2 at 0x10500
+ -------------------------------------------------*/
+
+READ8_DEVICE_HANDLER(apollo_sio2_r)
+{
+ 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" };
+
+ apollo_pic_set_irq_line(device, APOLLO_IRQ_SIO2, 0);
+
+ int data = duart68681_r(device, offset / 2);
+
+ DLOG2(("reading 2681 reg %x (%s) returned %02x",
+ offset, duart68681_reg_read_names[offset/2], data ));
+ return data;
+}
+
+WRITE8_DEVICE_HANDLER(apollo_sio2_w)
+{
+ 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" };
+
+ DLOG2(("writing 2681 reg %x (%s) with %02x", offset, duart68681_reg_write_names[(offset/2) & 15], data ));
+
+ apollo_pic_set_irq_line(device, APOLLO_IRQ_SIO2, 0);
+
+ switch (offset / 2) {
+ case 0x04: /* ACR */
+ if (data == 0x80) {
+ // FIXME: unhandled ACR value
+ // data = 0xe0;
+ }
+ break;
+ }
+
+ duart68681_w(device, offset / 2, data);
+}
+
+/*-------------------------------------------------
+ device start callback
+ -------------------------------------------------*/
+
+static DEVICE_START(apollo_sio2)
+{
+ DLOG1(("start apollo_sio2"));
+}
+
+/*-------------------------------------------------
+ device reset callback
+ -------------------------------------------------*/
+
+static DEVICE_RESET(apollo_sio2)
+{
+ DLOG1(("reset apollo_sio2"));
+}
+
+//##########################################################################
+// machine/apollo_fdc.c - APOLLO DS3500 Floppy disk controller
+//##########################################################################
+
+#undef VERBOSE
+#define VERBOSE 0
+
+static device_t *apollo_fdc_device = NULL;
+
+static LEGACY_FLOPPY_OPTIONS_START( apollo )
+ LEGACY_FLOPPY_OPTION( img2d, "afd", "Apollo floppy disk image", basicdsk_identify_default, basicdsk_construct_default, NULL,
+ HEADS([2])
+ TRACKS([77])
+ SECTORS([8])
+ SECTOR_LENGTH([1024])
+ FIRST_SECTOR_ID([1]))
+ LEGACY_FLOPPY_OPTIONS_END0
+
+static const floppy_interface apollo_fdc_floppy_config = { //
+ DEVCB_NULL, //
+ DEVCB_NULL, //
+ DEVCB_NULL, //
+ DEVCB_NULL, //
+ DEVCB_NULL, //
+ FLOPPY_STANDARD_5_25_DSHD, //
+ LEGACY_FLOPPY_OPTIONS_NAME(apollo), //
+ NULL, //
+ NULL //
+};
+
+/*************************************
+ * Floppy Disk Controller
+ *************************************/
+
+static void apollo_fdc_interrupt(running_machine &machine, int state) {
+ apollo_pic_set_irq_line( machine.firstcpu, APOLLO_IRQ_FDC, state);
+}
+
+static void apollo_fdc_dma_drq(running_machine &machine, int state) {
+ apollo_dma_fdc_drq(machine.firstcpu, state);
+}
+
+static device_t *apollo_fdc_get_image(running_machine &machine,
+ int floppy_index) {
+ return floppy_get_device(machine, 0);
+}
+
+static device_t * apollo_fdc_get_device(running_machine &machine) {
+ return apollo_fdc_device;
+}
+
+static const struct pc_fdc_interface apollo_fdc_interface = {
+ apollo_fdc_interrupt, //
+ apollo_fdc_dma_drq, //
+ apollo_fdc_get_image, //
+ apollo_fdc_get_device //
+};
+
+/*-------------------------------------------------
+ FDC upd765 at 0x5f800 - 0x5f807
+ -------------------------------------------------*/
+
+static DEVICE_START( apollo_fdc ) {
+ DLOG1(("device_start_apollo_fdc"));
+ apollo_fdc_device = device;
+ pc_fdc_init(device->machine(), &apollo_fdc_interface);
+}
+
+static DEVICE_RESET( apollo_fdc ) {
+ DLOG1(("device_reset_apollo_fdc"));
+ pc_fdc_reset(device->machine());
+}
+
+WRITE8_MEMBER(apollo_state::apollo_fdc_w){
+ SLOG1(("writing FDC upd765 at offset %X = %02x", offset, data));
+ pc_fdc_w(&space, offset, data);
+}
+
+READ8_MEMBER(apollo_state::apollo_fdc_r){
+ UINT8 data = pc_fdc_r(&space, offset);
+ SLOG1(("reading FDC upd765 at offset %X = %02x", offset, data));
+ return data;
+}
+
+/***************************************************************************
+ DN3500 3c505 DEVICE Configuration
+ ***************************************************************************/
+
+static void apollo_3c505_set_irq(device_t *device, int state) {
+ // DLOG2(("apollo_3c505_interrupt: state=%x", state ));
+ apollo_pic_set_irq_line(device->machine().firstcpu, APOLLO_IRQ_ETH1, state);
+}
+
+static int apollo_3c505_tx_data(device_t *device,
+ const UINT8 tx_data_buffer[], int tx_data_length) {
+
+ // transmit all transmitted packets to the apollo_netserver
+ apollo_netserver_receive(device, tx_data_buffer, tx_data_length);
+
+ // transmit all transmitted packets to the host ethernet (ignore any errors)
+ return apollo_eth_transmit(device, tx_data_buffer, tx_data_length);
+}
+
+static int apollo_3c505_setfilter(device_t *device, int node_id)
+{
+ return apollo_eth_setfilter(device, node_id);
+}
+
+static int apollo_3c505_rx_data(device_t *device,
+ const UINT8 rx_data_buffer[], int rx_data_length) {
+
+ // transmit all received packets to the threecom3c505 receiver
+ return threecom3c505_receive(device, rx_data_buffer, rx_data_length);
+}
+
+static void apollo_3c505_tx_init(device_t *device) {
+
+ apollo_eth_init(device, apollo_3c505_rx_data);
+
+ // setup to receive all packets from the apollo_netserver
+ apollo_netserver_init(device->machine().options().media_path(), apollo_3c505_rx_data);
+}
+
+static THREECOM3C505_INTERFACE(apollo_3c505_config) = {
+ apollo_3c505_set_irq,
+ apollo_3c505_tx_init,
+ apollo_3c505_tx_data,
+ apollo_3c505_setfilter
+};
+
+/***************************************************************************
+ DN3500 OMTI 8621 DEVICE Configuration
+ ***************************************************************************/
+
+static void apollo_wdc_set_irq(const running_machine *machine, int state) {
+// FIXME:
+// MLOG2(("apollo_wdc_set_irq: state=%x", state ));
+ apollo_pic_set_irq_line(machine->firstcpu, APOLLO_IRQ_WIN1, state);
+}
+
+static const omti8621_config apollo_wdc_config = {
+ apollo_wdc_set_irq
+};
+
+/***************************************************************************
+ DN3500 Cartridge Tape DEVICE Configuration
+ ***************************************************************************/
+
+static void apollo_ctape_set_irq(const device_t *device, int state) {
+ DLOG2(("apollo_ctape_set_irq: state=%x", state ));
+ apollo_pic_set_irq_line(device->machine().firstcpu, APOLLO_IRQ_CTAPE, state);
+}
+
+
+static void apollo_ctape_dma_drq(const device_t *device, int state) {
+ DLOG2(("apollo_ctape_dma_drq: state=%x", state ));
+ apollo_dma_ctape_drq(device->machine().firstcpu, state);
+}
+
+static const sc499_interface apollo_ctape_config = {
+ apollo_ctape_set_irq,
+ apollo_ctape_dma_drq,
+};
+
+//##########################################################################
+// machine/apollo.c - APOLLO DS3500 CPU Board
+//##########################################################################
+
+#undef VERBOSE
+#define VERBOSE 0
+
+MACHINE_CONFIG_FRAGMENT( apollo )
+ // configuration MUST be reset first !
+ MCFG_DEVICE_ADD(APOLLO_CONF_TAG, APOLLO_CONF, 0)
+
+ MCFG_I8237_ADD( APOLLO_DMA1_TAG, XTAL_14_31818MHz/3, apollo_dma8237_1_config )
+ MCFG_I8237_ADD( APOLLO_DMA2_TAG, XTAL_14_31818MHz/3, apollo_dma8237_2_config )
+ MCFG_PIC8259_ADD( APOLLO_PIC1_TAG, apollo_pic8259_master_config )
+ MCFG_PIC8259_ADD( APOLLO_PIC2_TAG, apollo_pic8259_slave_config )
+ MCFG_PTM6840_ADD(APOLLO_PTM_TAG, apollo_ptm_config)
+ MCFG_MC146818_ADD( APOLLO_RTC_TAG, MC146818_UTC )
+ MCFG_DUART68681_ADD( APOLLO_SIO_TAG, XTAL_3_6864MHz, apollo_sio_config )
+ MCFG_DUART68681_ADD( APOLLO_SIO2_TAG, XTAL_3_6864MHz, apollo_sio2_config )
+
+ MCFG_UPD765A_ADD(APOLLO_FDC_TAG, pc_fdc_upd765_connected_1_drive_interface)
+ MCFG_LEGACY_FLOPPY_DRIVE_ADD(FLOPPY_0, apollo_fdc_floppy_config)
+
+ MCFG_OMTI8621_ADD(APOLLO_WDC_TAG, apollo_wdc_config)
+ MCFG_SC499_ADD(APOLLO_CTAPE_TAG, apollo_ctape_config)
+ MCFG_THREECOM3C505_ADD(APOLLO_ETH_TAG, apollo_3c505_config)
+MACHINE_CONFIG_END
+
+DRIVER_INIT_MEMBER(apollo_state,apollo)
+{
+ //MLOG1(("driver_init_apollo"));
+}
+
+MACHINE_START( apollo )
+{
+ MLOG1(("machine_start_apollo"));
+
+ device_start_apollo_fdc (machine.device(APOLLO_FDC_TAG));
+ device_start_apollo_ptm (machine.device(APOLLO_PTM_TAG) );
+ device_start_apollo_sio(machine.device(APOLLO_SIO_TAG));
+ device_start_apollo_sio2(machine.device(APOLLO_SIO2_TAG));
+
+ if (apollo_is_dn3000())
+ {
+ MLOG1(("faking mc146818 interrupts (DN3000 only)"));
+ // fake mc146818 interrupts (DN3000 only)
+ machine.scheduler().timer_pulse(attotime::from_hz(2), FUNC(apollo_rtc_timer));
+ }
+}
+
+MACHINE_RESET( apollo )
+{
+ apollo_state *st = machine.driver_data<apollo_state>();
+ MLOG1(("machine_reset_apollo"));
+
+ st->dma8237_1 = machine.device(APOLLO_DMA1_TAG);
+ st->dma8237_2 = machine.device(APOLLO_DMA2_TAG);
+ st->pic8259_master = machine.device(APOLLO_PIC1_TAG);
+ st->pic8259_slave = machine.device(APOLLO_PIC2_TAG);
+
+ // set configuration
+ apollo_csr_set_servicemode(apollo_config(APOLLO_CONF_SERVICE_MODE));
+
+ device_reset_apollo_ptm(machine.device(APOLLO_PTM_TAG));
+ device_reset_apollo_rtc(machine.device(APOLLO_RTC_TAG));
+ device_reset_apollo_sio(machine.device(APOLLO_SIO_TAG));
+ device_reset_apollo_sio2(machine.device(APOLLO_SIO2_TAG));
+ device_reset_apollo_fdc(apollo_fdc_device);
+}
diff --git a/src/mess/machine/apollo_dbg.c b/src/mess/machine/apollo_dbg.c
new file mode 100644
index 00000000000..6e8cbcae5f1
--- /dev/null
+++ b/src/mess/machine/apollo_dbg.c
@@ -0,0 +1,1185 @@
+/*
+ * debug/apollo.c - APOLLO DN3500/DN3000 debug functions
+ *
+ * Created on: Nov. 21, 2010
+ * Author: Hans Ostermeyer
+ *
+ * Released for general non-commercial use under the MAME license
+ * Visit http://mamedev.org for licensing and usage restrictions.
+ *
+ */
+
+#define VERBOSE 1
+
+#include "includes/apollo.h"
+#include "cpu/m68000/m68kcpu.h"
+
+//------------------------------------------------------
+// TRAP 0
+//------------------------------------------------------
+
+static const char* trap0[] = {
+/* 0x00 */NULL, NULL,
+/* 0x01 */"FIM_$GET_FIM_ADDR", "",
+/* 0x02 */NULL, NULL,
+/* 0x03 */"DTTY_$RELOAD_FONT", "",
+/* 0x04 */"FILE_$UNLOCK_ALL", "",
+/* 0x05 */NULL, NULL,
+/* 0x06 */NULL, NULL,
+/* 0x07 */"PROC2_$MY_PID", "",
+/* 0x08 */"SMD_$OP_WAIT_U", "",
+/* 0x09 */"TPAD_$RE_RANGE", "",
+/* 0x0a */NULL, NULL,
+/* 0x0b */NULL, NULL,
+/* 0x0c */NULL, NULL,
+/* 0x0d */"ACL_$UP", "",
+/* 0x0e */"ACL_$DOWN", "",
+/* 0x0f */NULL, NULL,
+/* 0x10 */"TPAD_$INQ_DTYPE", "",
+/* 0x11 */NULL, NULL,
+/* 0x12 */"CACHE_$CLEAR", "",
+/* 0x13 */"RIP_$ANNOUNCE_NS", "",
+/* 0x14 */NULL, NULL,
+/* 0x15 */NULL, NULL,
+/* 0x16 */NULL, NULL,
+/* 0x17 */NULL, NULL,
+/* 0x18 */"PROC2_$DELIVER_PENDING", "",
+/* 0x19 */"PROC2_$COMPLETE_FORK", "",
+/* 0x1a */"PACCT_$STOP", "",
+/* 0x1b */"PACCT_$ON", "",
+/* 0x1c */"ACL_$GET_LOCAL_LOCKSMITH", "",
+/* 0x1d */"ACL_$IS_SUSER", "",
+/* 0x1e */NULL, NULL,
+/* 0x1f */"SMD_$N_DEVICES", "",
+/* 0x20 */"PROC1_$GET_MAXID", "",
+/* 0x21 */"THREAD_$DELETE", "",
+/* 0x22 */"THREAD_$SELF_OS", "",
+/* 0x23 */"THREAD_$NUMBER_THREADS", "",
+/* 0x24 */"ACL_$GET_PROTECT_OPTION", "",
+/* 0x25 */"ACL_$PROTECT_CHECK", "",
+/* 0x26 */"THREAD_$YIELD", "" };
+
+//------------------------------------------------------
+// TRAP1
+//------------------------------------------------------
+
+static const char* trap1[] = {
+/* 0x00 */NULL, NULL,
+/* 0x01 */NULL, NULL,
+/* 0x02 */"FIM_$INSTALL", "x",
+/* 0x03 */"NETWORK_$READ_SERVICE", "x",
+/* 0x04 */"PROC1_$GET_CPUT", "x",
+/* 0x05 */"SET_LITES_LOC", "x",
+/* 0x06 */"TIME_$CLOCK", "x",
+/* 0x07 */"ASKNODE_$READ_FAILURE_REC", "x",
+/* 0x08 */"CAL_$APPLY_LOCAL_OFFSET", "x",
+/* 0x09 */"CAL_$GET_INFO", "x",
+/* 0x0a */"CAL_$GET_LOCAL_TIME", "x",
+/* 0x0b */"CAL_$REMOVE_LOCAL_OFFSET", "x",
+/* 0x0c */"CAL_$SET_DRIFT", "x",
+/* 0x0d */"DISK_$GET_ERROR_INFO", "x",
+/* 0x0e */NULL, NULL,
+/* 0x0f */"MSG_$CLOSE", "x",
+/* 0x10 */"PROC2_$WHO_AM_I", "u",
+/* 0x11 */"SMD_$CLEAR_KBD_CURSOR", "x",
+/* 0x12 */NULL, NULL,
+/* 0x13 */NULL, NULL,
+/* 0x14 */"SMD_$SEND_RESPONSE", "x",
+/* 0x15 */"SMD_$STOP_TP_CURSOR", "x",
+/* 0x16 */NULL, NULL,
+/* 0x17 */NULL, NULL,
+/* 0x18 */"SMD_$UNMAP_DISPLAY_U", "x",
+/* 0x19 */"UID_$GEN", "x",
+/* 0x1a */"TONE_$TIME", "x",
+/* 0x1b */"SMD_$INQ_DISP_TYPE", "x",
+/* 0x1c */NULL, NULL,
+/* 0x1d */NULL, NULL,
+/* 0x1e */NULL, NULL,
+/* 0x1f */"TPAD_$SET_CURSOR", "x",
+/* 0x20 */NULL, NULL,
+/* 0x21 */NULL, NULL,
+/* 0x22 */"NAME_$GET_WDIR_UID", "u",
+/* 0x23 */"NAME_$GET_NDIR_UID", "u",
+/* 0x24 */"NAME_$GET_ROOT_UID", "u",
+/* 0x25 */"NAME_$GET_NODE_UID", "u",
+/* 0x26 */"NAME_$GET_NODE_DATA_UID", "u",
+/* 0x27 */"NAME_$GET_CANNED_ROOT_UID", "u",
+/* 0x28 */"MSG_$GET_MY_NET", "x",
+/* 0x29 */"MSG_$GET_MY_NODE", "x",
+/* 0x2a */NULL, NULL,
+/* 0x2b */NULL, NULL,
+/* 0x2c */NULL, NULL,
+/* 0x2d */NULL, NULL,
+/* 0x2e */NULL, NULL,
+/* 0x2f */NULL, NULL,
+/* 0x30 */"GPU_$INIT", "x",
+/* 0x31 */NULL, NULL,
+/* 0x32 */"SMD_$INIT_STATE", "x",
+/* 0x33 */"SMD_$CLR_TRK_RECT", "x",
+/* 0x34 */"PROC2_$GET_SIG_MASK", "x",
+/* 0x35 */"FIM_$FRESTORE", "x",
+/* 0x36 */"TIME_$GET_TIME_OF_DAY", "x",
+/* 0x37 */"PROC1_$GET_LOADAV", "x",
+/* 0x38 */"PROC2_$GET_BOOT_FLAGS", "x",
+/* 0x39 */NULL, NULL,
+/* 0x3a */"PROC2_$SET_TTY", "x",
+/* 0x3b */"OS_$SHUTDOWN", "x",
+/* 0x3c */"PBU_$FAULTED_UNITS", "x",
+/* 0x3d */"PROC2_$GET_CPU_USAGE", "x",
+/* 0x3e */NULL, NULL,
+/* 0x3f */NULL, NULL,
+/* 0x40 */NULL, NULL,
+/* 0x41 */"TIME_$GET_ADJUST", "x",
+/* 0x42 */"FILE_$SYNC", "x",
+/* 0x43 */"XPAGE_$IS_MAPPED", "x",
+/* 0x44 */"THREAD_$SUSPEND_FOR_FORK", "x",
+/* 0x45 */"THREAD_$RESUME_FOR_FORK", "x" };
+
+//------------------------------------------------------
+// TRAP2
+//------------------------------------------------------
+
+static const char* trap2[] = {
+/* 0x00 */NULL, NULL,
+/* 0x01 */NULL, NULL,
+/* 0x02 */"FILE_$DELETE", "x,x",
+/* 0x03 */"EC2_$WAKEUP", "x,x",
+/* 0x04 */NULL, NULL,
+/* 0x05 */"ACL_$GET_SID", "x,x",
+/* 0x06 */"FILE_$MK_PERMANENT", "x,x",
+/* 0x07 */"FILE_$UNLOCK_VOL", "x,x",
+/* 0x08 */"CAL_$READ_TIMEZONE", "x,x",
+/* 0x09 */"CAL_$SEC_TO_CLOCK", "x,x",
+/* 0x0a */"CAL_$WRITE_TIMEZONE", "x,x",
+/* 0x0b */"DISK_$UNASSIGN", "x,x",
+/* 0x0c */"FILE_$FORCE_UNLOCK", "x,x",
+/* 0x0d */"FILE_$FW_FILE", "x,x",
+/* 0x0e */"FILE_$MK_IMMUTABLE", "x,x",
+/* 0x0f */"FILE_$PURIFY", "x,x",
+/* 0x10 */"GET_BUILD_TIME", "x,x",
+/* 0x11 */NULL, NULL,
+/* 0x12 */NULL, NULL,
+/* 0x13 */"MSG_$ALLOCATE", "x,x",
+/* 0x14 */"MSG_$OPEN", "x,x",
+/* 0x15 */"MSG_$WAIT", "x,x",
+/* 0x16 */NULL, NULL,
+/* 0x17 */NULL, NULL,
+/* 0x18 */"PBU_$DEVICE_INTERRUPTING", "x,x",
+/* 0x19 */"PBU_$DISABLE_DEVICE", "x,x",
+/* 0x1a */"PBU_$ENABLE_DEVICE", "x,x",
+/* 0x1b */"PBU_$FREE_MAP", "x,x",
+/* 0x1c */"PROC2_$QUIT", "x,x",
+/* 0x1d */"PROC2_$RESUME", "x,x",
+/* 0x1e */"PROC2_$SUSPEND", "x,x",
+/* 0x1f */NULL, NULL,
+/* 0x20 */NULL, NULL,
+/* 0x21 */NULL, NULL,
+/* 0x22 */NULL, NULL,
+/* 0x23 */NULL, NULL,
+/* 0x24 */NULL, NULL,
+/* 0x25 */NULL, NULL,
+/* 0x26 */"SMD_$MAP_DISPLAY_U", "x,x",
+/* 0x27 */"SMD_$MOVE_KBD_CURSOR", "x,x",
+/* 0x28 */NULL, NULL,
+/* 0x29 */"SMD_$RETURN_DISPLAY", "x,x",
+/* 0x2a */NULL, NULL,
+/* 0x2b */NULL, NULL,
+/* 0x2c */NULL, NULL,
+/* 0x2d */NULL, NULL,
+/* 0x2e */"PEB_$GET_INFO", "x,x",
+/* 0x2f */NULL, NULL,
+/* 0x30 */"EC2_$GET_VAL", "x,x",
+/* 0x31 */"AST_$ADD_ASTES", "x,x",
+/* 0x32 */"PBU_$DISSOC", "x,x",
+/* 0x33 */"PROC2_$MAKE_ORPHAN", "x,x",
+/* 0x34 */"FILE_$DELETE_FORCE", "x,x",
+/* 0x35 */"FILE_$DELETE_WHEN_UNLOCKED", "x,x",
+/* 0x36 */"FILE_$MK_TEMPORARY", "x,x",
+/* 0x37 */NULL, NULL,
+/* 0x38 */NULL, NULL,
+/* 0x39 */NULL, NULL,
+/* 0x3a */NULL, NULL,
+/* 0x3b */"SMD_$INQ_KBD_CURSOR", "x,x",
+/* 0x3c */"ACL_$ENTER_SUBS", "u,x",
+/* 0x3d */NULL, NULL,
+/* 0x3e */NULL, NULL,
+/* 0x3f */NULL, NULL,
+/* 0x40 */NULL, NULL,
+/* 0x41 */NULL, NULL,
+/* 0x42 */"FILE_$DELETE_FORCE_WHEN_UNLOCKED", "x,x",
+/* 0x43 */NULL, NULL,
+/* 0x44 */"CT_$ACQUIRE", "x,x",
+/* 0x45 */"HINT_$ADD", "x,x",
+/* 0x46 */"DIR_$FIX_DIR", "x,x",
+/* 0x47 */"NAME_$SET_WDIRUS", "u,x",
+/* 0x48 */"NAME_$SET_NDIRUS", "u,x",
+/* 0x49 */NULL, NULL,
+/* 0x4a */NULL, NULL,
+/* 0x4b */"MSG_$CLOSEI", "x,x",
+/* 0x4c */"NETWORK_$ADD_PAGE_SERVERS", "x,x",
+/* 0x4d */"NETWORK_$ADD_REQUEST_SERVERS", "x,x",
+/* 0x4e */"ACL_$ADD_PROJ", "x,x",
+/* 0x4f */"ACL_$DELETE_PROJ", "x,x",
+/* 0x50 */NULL, NULL,
+/* 0x51 */NULL, NULL,
+/* 0x52 */"SMD_$SET_TP_REPORTING", "x,x",
+/* 0x53 */"SMD_$DISABLE_TRACKING", "x,x",
+/* 0x54 */NULL, NULL,
+/* 0x55 */NULL, NULL,
+/* 0x56 */NULL, NULL,
+/* 0x57 */NULL, NULL,
+/* 0x58 */"HINT_$ADDI", "x,x",
+/* 0x59 */NULL, NULL,
+/* 0x5a */NULL, NULL,
+/* 0x5b */"PBU_$ALLOCATE_EC", "x,x",
+/* 0x5c */"SMD_$SET_DISP_UNIT", "x,x",
+/* 0x5d */"SMD_$VIDEO_CTL", "x,x",
+/* 0x5e */"SMD_$SET_CURSOR_POS", "x,x",
+/* 0x5f */"TERM_$SEND_KBD_STRING", "x,x",
+/* 0x60 */"AUDIT_$CONTROL", "x,x",
+/* 0x61 */"PROC2_$SIGBLOCK", "x,x",
+/* 0x62 */"PROC2_$SIGSETMASK", "x,x",
+/* 0x63 */"PROC2_$SIGPAUSE", "x,x",
+/* 0x64 */"ACL_$FIPS_CTL", "x,x",
+/* 0x65 */"AS_$GET_ADDR", "x,x",
+/* 0x66 */"PROC2_$GET_ASID", "x,x",
+/* 0x67 */"TTY_$K_FLUSH_INPUT", "x,x",
+/* 0x68 */"TTY_$K_FLUSH_OUTPUT", "x,x",
+/* 0x69 */"TTY_$K_DRAIN_OUTPUT", "x,x",
+/* 0x6a */"PROC2_$DEBUG", "x,x",
+/* 0x6b */"PROC2_$UNDEBUG", "x,x",
+/* 0x6c */"ACL_$DEF_ACLDATA", "x,x",
+/* 0x6d */"PROC2_$OVERRIDE_DEBUG", "x,x",
+/* 0x6e */"TIME_$SET_TIME_OF_DAY", "x,x",
+/* 0x6f */"CAL_$DECODE_TIME", "x,x",
+/* 0x70 */"ACL_$INHERIT_SUBSYS", "x,x",
+/* 0x71 */"ACL_$SET_LOCAL_LOCKSMITH", "x,x",
+/* 0x72 */NULL, NULL,
+/* 0x73 */"SMD_$DISSOC", "x,x",
+/* 0x74 */"SMD_$BUSY_WAIT", "x,x",
+/* 0x75 */"TTY_$K_OLD_RESET", "x,x",
+/* 0x76 */NULL, NULL,
+/* 0x77 */NULL, NULL,
+/* 0x78 */NULL, NULL,
+/* 0x79 */"SCSI_$ABORT_OPERATION", "x,x",
+/* 0x7a */"SCSI_$RELEASE", "x,x",
+/* 0x7b */"SCSI_$RESET_DEVICE", "x,x",
+/* 0x7c */NULL, NULL,
+/* 0x7d */"TPAD_$RE_RANGE_UNIT", "x,x",
+/* 0x7e */"DISK_$FORMAT_WHOLE", "x,x",
+/* 0x7f */NULL, NULL,
+/* 0x80 */NULL, NULL,
+/* 0x81 */NULL, NULL,
+/* 0x82 */NULL, NULL,
+/* 0x83 */NULL, NULL,
+/* 0x84 */"SMD_$SEND_UNIT_RESPONSE", "x,x",
+/* 0x85 */NULL, NULL,
+/* 0x86 */"MST_$FW_XTAL", "x,x",
+/* 0x87 */"THREAD_$TERMINATE", "x,x",
+/* 0x88 */"THREAD_$TERMINATE_ALL", "u,x",
+/* 0x89 */"THREAD_$SUSPEND", "x,x",
+/* 0x8a */"THREAD_$RESUME", "x,x",
+/* 0x8b */"THREAD_$HANDLE_SIGNALS", "x,x",
+/* 0x8c */"THREAD_$ABORT", "x,x",
+/* 0x8d */"ACL_$SET_PROTECT_OPTION", "x,x",
+/* 0x8e */"TTY_$K_SUSPEND_INPUT", "x,x",
+/* 0x8f */"TTY_$K_RESUME_INPUT", "x,x",
+/* 0x90 */"TTY_$K_SUSPEND_OUTPUT", "x,x",
+/* 0x91 */"TTY_$K_RESUME_OUTPUT", "x,x" };
+
+//------------------------------------------------------
+// TRAP3
+//------------------------------------------------------
+
+static const char* trap3[] = {
+/* 0x00 */"PBU2_$DMA_STOP", "x,x,x",
+/* 0x01 */NULL, NULL,
+/* 0x02 */"FILE_$CREATE", "x,x,x",
+/* 0x03 */"FILE_$UNLOCK", "u,x,x",
+/* 0x04 */"FILE_$TRUNCATE", "u,x,x",
+/* 0x05 */"MST_$UNMAPS", "x,x,x",
+/* 0x06 */"VFMT_$WRITE", "s,x,x",
+/* 0x07 */"FILE_$ATTRIBUTES", "x,x,x",
+/* 0x08 */"FILE_$SET_LEN", "x,x,x",
+/* 0x09 */"FILE_$SET_TYPE", "x,x,x",
+/* 0x0a */NULL, NULL,
+/* 0x0b */NULL, NULL,
+/* 0x0c */NULL, NULL,
+/* 0x0d */NULL, NULL,
+/* 0x0e */"NETWORK_$SET_SERVICE", "x,x,x",
+/* 0x0f */"ASKNODE_$WHO", "s,x,x",
+/* 0x10 */"FILE_$ACT_ATTRIBUTES", "x,x,x",
+/* 0x11 */"FILE_$LOCATE", "x,x,x",
+/* 0x12 */"FILE_$NEIGHBORS", "x,x,x",
+/* 0x13 */"FILE_$READ_LOCK_ENTRYU", "x,x,x",
+/* 0x14 */"FILE_$SET_ACL", "x,x,x",
+/* 0x15 */"FILE_$SET_DIRPTR", "x,x,x",
+/* 0x16 */"FILE_$SET_TROUBLE", "x,x,x",
+/* 0x17 */NULL, NULL,
+/* 0x18 */NULL, NULL,
+/* 0x19 */NULL, NULL,
+/* 0x1a */NULL, NULL,
+/* 0x1b */NULL, NULL,
+/* 0x1c */"PBU_$DMA_STOP", "x,x,x",
+/* 0x1d */"PBU_$SETDOWN", "x,x,x",
+/* 0x1e */"PBU_$SETUP", "x,x,x",
+/* 0x1f */"PROC2_$LIST", "x,x,x",
+/* 0x20 */"FIM_$SINGLE_STEP", "x,x,x",
+/* 0x21 */"SMD_$ASSOC", "x,x,x",
+/* 0x22 */"SMD_$BORROW_DISPLAY", "x,x,x",
+/* 0x23 */NULL, NULL,
+/* 0x24 */NULL, NULL,
+/* 0x25 */"SMD_$SET_TP_CURSOR", "x,x,x",
+/* 0x26 */"TIME_$WAIT", "x,x,x",
+/* 0x27 */"RINGLOG_$CNTL", "x,x,x",
+/* 0x28 */"SMD_$ALLOC_HDM", "x,x,x",
+/* 0x29 */"SMD_$FREE_HDM", "x,x,x",
+/* 0x2a */NULL, NULL,
+/* 0x2b */"OS_$GET_EC", "x,x,x",
+/* 0x2c */"TIME_$GET_EC", "x,x,x",
+/* 0x2d */NULL, NULL,
+/* 0x2e */"PROC2_$UPID_TO_UID", "x,u,x",
+/* 0x2f */"MSG_$GET_EC", "x,x,x",
+/* 0x30 */"DISK_$AS_OPTIONS", "x,x,x",
+/* 0x31 */"SMD_$GET_EC", "x,x,x",
+/* 0x32 */"NAME_$SET_ACL", "x,x,x",
+/* 0x33 */"FILE_$SET_REFCNT", "x,x,x",
+/* 0x34 */NULL, NULL,
+/* 0x35 */"PROC1_$GET_INFO", "x,x,x",
+/* 0x36 */NULL, NULL,
+/* 0x37 */NULL, NULL,
+/* 0x38 */NULL, NULL,
+/* 0x39 */NULL, NULL,
+/* 0x3a */NULL, NULL,
+/* 0x3b */NULL, NULL,
+/* 0x3c */"AS_$GET_INFO", "x,x,x",
+/* 0x3d */"FILE_$SET_DTM", "x,x,x",
+/* 0x3e */"FILE_$SET_DTU", "x,x,x",
+/* 0x3f */NULL, NULL,
+/* 0x40 */"LOG_$READ", "x,x,x",
+/* 0x41 */"PROC2_$SET_PGROUP", "x,x,x",
+/* 0x42 */"SMD_$SET_BLANK_TIMEOUT", "x,x,x",
+/* 0x43 */"SMD_$INQ_BLANK_TIMEOUT", "x,x,x",
+/* 0x44 */"FILE_$REMOVE_WHEN_UNLOCKED", "x,x,x",
+/* 0x45 */"CT_$RELEASE", "x,x,x",
+/* 0x46 */"PROC2_$UPGID_TO_UID", "x,x,x",
+/* 0x47 */"TIME_$GET_ITIMER", "x,x,x",
+/* 0x48 */"DIR_$SET_DAD", "x,x,x",
+/* 0x49 */NULL, NULL,
+/* 0x4a */NULL, NULL,
+/* 0x4b */NULL, NULL,
+/* 0x4c */NULL, NULL,
+/* 0x4d */NULL, NULL,
+/* 0x4e */NULL, NULL,
+/* 0x4f */"RIP_$TABLE", "x,x,x",
+/* 0x50 */"FILE_$LOCATEI", "x,x,x",
+/* 0x51 */"MSG_$OPENI", "x,x,x",
+/* 0x52 */"MSG_$ALLOCATEI", "x,x,x",
+/* 0x53 */"MSG_$WAITI", "x,x,x",
+/* 0x54 */"ACL_$SET_PROJ_LIST", "x,x,x",
+/* 0x55 */"ACL_$GET_RE_SIDS", "x,x,x",
+/* 0x56 */NULL, NULL,
+/* 0x57 */"MSG_$SET_HPIPC", "x,x,x",
+/* 0x58 */"DIR_$VALIDATE_ROOT_ENTRY", "x,x,x",
+/* 0x59 */"SMD_$ENABLE_TRACKING", "x,x,x",
+/* 0x5a */"FILE_$READ_LOCK_ENTRYUI", "x,x,x",
+/* 0x5b */NULL, NULL,
+/* 0x5c */"ROUTE_$SERVICE", "x,x,x",
+/* 0x5d */NULL, NULL,
+/* 0x5e */NULL, NULL,
+/* 0x5f */NULL, NULL,
+/* 0x60 */"PBU_$ADVANCE_EC", "x,x,x",
+/* 0x61 */"PBU_$RELEASE_EC", "x,x,x",
+/* 0x62 */NULL, NULL,
+/* 0x63 */"SMD_$GET_IDM_EVENT", "x,x,x",
+/* 0x64 */"MSG_$TEST_FOR_MESSAGE", "x,x,x",
+/* 0x65 */"SMD_$ADD_TRK_RECT", "x,x,x",
+/* 0x66 */"SMD_$DEL_TRK_RECT", "x,x,x",
+/* 0x67 */"SMD_$SET_KBD_TYPE", "x,x,x",
+/* 0x68 */NULL, NULL,
+/* 0x69 */"FILE_$SET_AUDITED", "x,x,x",
+/* 0x6a */"PROC2_$ACKNOWLEDGE", "x,x,x",
+/* 0x6b */"PROC2_$GET_MY_UPIDS", "x,x,x",
+/* 0x6c */"TTY_$K_INQ_INPUT_FLAGS", "x,x,x",
+/* 0x6d */"TTY_$K_INQ_OUTPUT_FLAGS", "x,x,x",
+/* 0x6e */"TTY_$K_INQ_ECHO_FLAGS", "x,x,x",
+/* 0x6f */"TTY_$K_SET_INPUT_BREAK_MODE", "x,x,x",
+/* 0x70 */"TTY_$K_INQ_INPUT_BREAK_MODE", "x,x,x",
+/* 0x71 */"TTY_$K_SET_PGROUP", "x,x,x",
+/* 0x72 */"TTY_$K_INQ_PGROUP", "x,x,x",
+/* 0x73 */"TTY_$K_SIMULATE_TERMINAL_INPUT", "x,x,x",
+/* 0x74 */"TTY_$K_INQ_FUNC_ENABLED", "x,x,x",
+/* 0x75 */"SIO_$K_TIMED_BREAK", "x,x,x",
+/* 0x76 */"FILE_$SET_DEVNO", "x,x,x",
+/* 0x77 */"XPD_$SET_PTRACE_OPTS", "x,x,x",
+/* 0x78 */"XPD_$INQ_PTRACE_OPTS", "x,x,x",
+/* 0x79 */"FILE_$SET_MAND_LOCK", "x,x,x",
+/* 0x7a */"TIME_$SET_CPU_LIMIT", "x,x,x",
+/* 0x7b */"CAL_$WEEKDAY", "x,x,x",
+/* 0x7c */"SIO_$K_SIGNAL_WAIT", "x,x,x",
+/* 0x7d */"TERM_$SET_DISCIPLINE", "x,x,x",
+/* 0x7e */"PROC2_$SET_SERVER", "x,x,x",
+/* 0x7f */"PACCT_$START", "x,x,x",
+/* 0x80 */"FILE_$SET_DTU_F", "x,x,x",
+/* 0x81 */"PROC2_$PGUID_TO_UPGID", "x,x,x",
+/* 0x82 */"TERM_$INQ_DISCIPLINE", "x,x,x",
+/* 0x83 */"PBU_$DMA_STATUS", "x,x,x",
+/* 0x84 */NULL, NULL,
+/* 0x85 */"MST_$UNMAPS_AND_FREE_AREA", "x,x,x",
+/* 0x86 */"SMD_$ASSOC_CSRS", "x,x,x",
+/* 0x87 */"SMD_$INQ_DISP_INFO", "x,x,x",
+/* 0x88 */"SMD_$INQ_DISP_UID", "x,x,x",
+/* 0x89 */"SMD_$DISPLAY_LOGO", "x,x,x",
+/* 0x8a */"TERM_$SET_REAL_LINE_DISCIPLINE", "x,x,x",
+/* 0x8b */"TIME_$ADJUST_TIME_OF_DAY", "x,x,x",
+/* 0x8c */"PROC2_$UID_TO_UPID", "x,x,x",
+/* 0x8d */"PROC2_$SET_SESSION_ID", "x,x,x",
+/* 0x8e */"SMD_$GET_UNIT_EVENT", "x,x,x",
+/* 0x8f */"TPAD_$SET_UNIT_CURSOR", "x,x,x",
+/* 0x90 */"TPAD_$SET_PUNCH_IMPACT", "x,x,x",
+/* 0x91 */"TPAD_$INQ_PUNCH_IMPACT", "x,x,x",
+/* 0x92 */"TTY_$K_INQ_SESSION_ID", "x,x,x",
+/* 0x93 */"TTY_$K_SET_SESSION_ID", "x,x,x",
+/* 0x94 */NULL, NULL,
+/* 0x95 */NULL, NULL,
+/* 0x96 */NULL, NULL,
+/* 0x97 */NULL, NULL,
+/* 0x98 */"SMD_$SHARE_DEVICE", "x,x,x",
+/* 0x99 */"SMD_$SET_UNIT_CURSOR_POS", "x,x,x",
+/* 0x9a */"SMD_$CLR_AND_LOAD_TRK_RECT", "x,x,x",
+/* 0x9b */"PROC2_$GET_PARM", "x,x,x",
+/* 0x9c */NULL, NULL,
+/* 0x9d */NULL, NULL,
+/* 0x9e */NULL, NULL,
+/* 0x9f */"FILE_$CW_READ", "x,x,x",
+/* 0xa0 */"FILE_$CW_WRITE", "x,x,x",
+/* 0xa1 */"MST_$TRUNC_XTAL", "x,x,x",
+/* 0xa2 */"MST_$SET_LEN_XTAL", "x,x,x",
+/* 0xa3 */"THREAD_$CREATE", "x,x,x",
+/* 0xa4 */"THREAD_$CLEANUP", "x,x,x",
+/* 0xa5 */"THREAD_$SET_INH_PTR", "x,x,x",
+/* 0xa6 */"SMD_$BORROW_DISPLAY_AND_KBD", "x,x,x",
+/* 0xa7 */"THREAD_$CLEANUP_ALL", "x,x,x",
+/* 0xa8 */"DIR_$ADD_MOUNT", "x,x,x",
+/* 0xa9 */"DIR_$REMOVE_MOUNT", "x,x,x",
+/* 0xaa */NULL, NULL,
+/* 0xab */"TTY_$K_RESET", "x,x,x",
+/* 0xac */"MST_$SHADOW_MAP", "x,x,x",
+/* 0xad */NULL, NULL };
+
+//------------------------------------------------------
+// TRAP4
+//------------------------------------------------------
+
+static const char* trap4[] = {
+/* 0x00 */NULL, NULL,
+/* 0x01 */"MST_$SET_GUARD", "u,x,x,x",
+/* 0x02 */"MST_$UNMAP_GLOBAL", "u,x,x,x",
+/* 0x03 */"MST_$GET_UID", "x,u,x,x",
+/* 0x04 */"EC2_$WAIT", "x,x,x,x",
+/* 0x05 */"FILE_$READ_LOCK_ENTRY", "x,x,x,x",
+/* 0x06 */"MST_$UNMAP", "u,x,x,x",
+/* 0x07 */"MST_$GROW_AREA", "x,x,x,x",
+/* 0x08 */NULL, NULL,
+/* 0x09 */NULL, NULL,
+/* 0x0a */NULL, NULL,
+/* 0x0b */NULL, NULL,
+/* 0x0c */"TERM_$CONTROL", "x,x,x,x",
+/* 0x0d */"TERM_$READ", "x,s,x,x",
+/* 0x0e */"TERM_$WRITE", "x,x,x,x",
+/* 0x0f */"DISK_$FORMAT", "x,x,x,x",
+/* 0x10 */"DISK_$LV_ASSIGN", "x,x,x,x",
+/* 0x11 */"FILE_$FW_PARTIAL", "x,x,x,x",
+/* 0x12 */NULL, NULL,
+/* 0x13 */NULL, NULL,
+/* 0x14 */NULL, NULL,
+/* 0x15 */NULL, NULL,
+/* 0x16 */NULL, NULL,
+/* 0x17 */NULL, NULL,
+/* 0x18 */NULL, NULL,
+/* 0x19 */NULL, NULL,
+/* 0x1a */NULL, NULL,
+/* 0x1b */NULL, NULL,
+/* 0x1c */NULL, NULL,
+/* 0x1d */NULL, NULL,
+/* 0x1e */NULL, NULL,
+/* 0x1f */NULL, NULL,
+/* 0x20 */NULL, NULL,
+/* 0x21 */NULL, NULL,
+/* 0x22 */NULL, NULL,
+/* 0x23 */"PBU_$WAIT", "x,x,x,x",
+/* 0x24 */"PBU_$GET_PTR", "x,x,x,x",
+/* 0x25 */"PCHIST_$CNTL", "x,x,x,x",
+/* 0x26 */"PROC2_$GET_INFO", "u,x,x,x",
+/* 0x27 */NULL, NULL,
+/* 0x28 */NULL, NULL,
+/* 0x29 */NULL, NULL,
+/* 0x2a */"SMD_$SIGNAL", "x,x,x,x",
+/* 0x2b */NULL, NULL,
+/* 0x2c */NULL, NULL,
+/* 0x2d */"TERM_$INQUIRE", "x,x,x,x",
+/* 0x2e */NULL, NULL,
+/* 0x2f */NULL, NULL,
+/* 0x30 */NULL, NULL,
+/* 0x31 */"TERM_$GET_EC", "x,x,x,x",
+/* 0x32 */NULL, NULL,
+/* 0x33 */"PBU_$GET_EC", "x,x,x,x",
+/* 0x34 */NULL, NULL,
+/* 0x35 */NULL, NULL,
+/* 0x36 */NULL, NULL,
+/* 0x37 */NULL, NULL,
+/* 0x38 */"TERM_$READ_COND", "x,x,x,x",
+/* 0x39 */NULL, NULL,
+/* 0x3a */NULL, NULL,
+/* 0x3b */"PBU2_$WIRE", "x,x,x,x",
+/* 0x3c */"PROC2_$SET_NAME", "x,x,x,x",
+/* 0x3d */"PROC2_$SET_PRIORITY", "x,x,x,x",
+/* 0x3e */"PROC2_$GET_EC", "u,x,x,x",
+/* 0x3f */"PROC2_$LIST_PGROUP", "x,x,x,x",
+/* 0x40 */NULL, NULL,
+/* 0x41 */NULL, NULL,
+/* 0x42 */NULL, NULL,
+/* 0x43 */"CT_$CONTROL", "x,x,x,x",
+/* 0x44 */"CT_$WAIT", "x,x,x,x",
+/* 0x45 */"DIR_$DROP_DIRU", "x,x,x,x",
+/* 0x46 */"DIR_$SET_DEFAULT_ACL", "x,x,x,x",
+/* 0x47 */"DIR_$GET_DEFAULT_ACL", "x,x,x,x",
+/* 0x48 */"NAME_$READ_DIRS_PS", "x,x,x,x",
+/* 0x49 */NULL, NULL,
+/* 0x4a */"ACL_$GET_PROJ_LIST", "x,x,x,x",
+/* 0x4b */"MST_$CHANGE_RIGHTS", "x,x,x,x",
+/* 0x4c */NULL, NULL,
+/* 0x4d */"FILE_$READ_LOCK_ENTRYI", "x,x,x,x",
+/* 0x4e */"ROUTE_$INCOMING", "x,x,x,x",
+/* 0x4f */NULL, NULL,
+/* 0x50 */"SMD_$INQ_KBD_TYPE", "x,x,x,x",
+/* 0x51 */"ROUTE_$GET_EC", "x,x,x,x",
+/* 0x52 */NULL, NULL,
+/* 0x53 */"SMD_$DM_COND_EVENT_WAIT", "x,x,x,x",
+/* 0x54 */"DISK_$READ_MFG_BADSPOTS", "x,x,x,x",
+/* 0x55 */"DISK_$GET_MNT_INFO", "x,x,x,x",
+/* 0x56 */"PROC2_$SET_SIG_MASK", "x,x,x,x",
+/* 0x57 */"PROC2_$SIGRETURN", "x,x,x,x",
+/* 0x58 */"PROC2_$WAIT", "x,x,x,x",
+/* 0x59 */"PROC2_$SIGNAL", "x,x,x,x",
+/* 0x5a */"PROC2_$SIGNAL_PGROUP", "x,x,x,x",
+/* 0x5b */"PROC2_$GET_CR_REC", "x,x,x,x",
+/* 0x5c */"TTY_$K_SET_FUNC_CHAR", "x,x,x,x",
+/* 0x5d */"TTY_$K_INQ_FUNC_CHAR", "x,x,x,x",
+/* 0x5e */"TTY_$K_SET_INPUT_FLAG", "x,x,x,x",
+/* 0x5f */"TTY_$K_SET_OUTPUT_FLAG", "x,x,x,x",
+/* 0x60 */"TTY_$K_SET_ECHO_FLAG", "x,x,x,x",
+/* 0x61 */"TTY_$K_ENABLE_FUNC", "x,x,x,x",
+/* 0x62 */"SIO_$K_SET_PARAM", "x,x,x,x",
+/* 0x63 */"SIO_$K_INQ_PARAM", "x,x,x,x",
+/* 0x64 */"FILE_$SET_MGR_ATTR", "x,x,x,x",
+/* 0x65 */"XPD_$GET_REGISTERS", "x,x,x,x",
+/* 0x66 */"XPD_$PUT_REGISTERS", "x,x,x,x",
+/* 0x67 */"FILE_$RESERVE", "u,x,x,x",
+/* 0x68 */NULL, NULL,
+/* 0x69 */"ACL_$GET_RES_SIDS", "x,x,x,x",
+/* 0x6a */"FILE_$FW_PAGES", "x,x,x,x",
+/* 0x6b */"PROC2_$SET_ACCT_INFO", "s,x,x,x",
+/* 0x6c */"FILE_$IMPORT_LK", "x,x,x,x",
+/* 0x6d */"FILE_$UNLOCK_D", "u,x,x,x",
+/* 0x6e */"FILE_$SET_LEN_D", "x,x,x,x",
+/* 0x6f */"FILE_$TRUNCATE_D", "x,x,x,x",
+/* 0x70 */"FILE_$SET_DTM_F", "x,x,x,x",
+/* 0x71 */"TTY_$K_SET_FLAG", "x,x,x,x",
+/* 0x72 */NULL, NULL,
+/* 0x73 */"MST_$UNMAP_AND_FREE_AREA", "x,x,x,x",
+/* 0x74 */NULL, NULL,
+/* 0x75 */"PROC2_$NAME_TO_UID", "S,w,u,x",
+/* 0x76 */NULL, NULL,
+/* 0x77 */NULL, NULL,
+/* 0x78 */NULL, NULL,
+/* 0x79 */"SCSI_$GET_EC", "x,x,x,x",
+/* 0x7a */"SCSI_$GET_INFO", "x,x,x,x",
+/* 0x7b */"SCSI_$SETUP", "x,x,x,x",
+/* 0x7c */"SCSI_$WIRE", "x,x,x,x",
+/* 0x7d */"MSG_$SHARE_SOCKET", "x,x,x,x",
+/* 0x7e */"TTY_$K_INQ_DELAY", "x,x,x,x",
+/* 0x7f */"TTY_$K_SET_DELAY", "x,x,x,x",
+/* 0x80 */NULL, NULL,
+/* 0x81 */NULL, NULL,
+/* 0x82 */"PROC2_$PGROUP_INFO", "x,x,x,x",
+/* 0x83 */"PROC2_$SET_PARM", "x,x,x,x",
+/* 0x84 */NULL, NULL,
+/* 0x85 */NULL, NULL,
+/* 0x86 */"XPAGE_$PAGER_RENDEZVOUS", "x,x,x,x",
+/* 0x87 */"FILE_$SET_DEVNO32", "x,x,x,x",
+/* 0x88 */"MST_$SET_LIMIT", "x,x,x,x",
+/* 0x89 */"THREAD_$SET_PRIORITY", "x,x,x,x",
+/* 0x8a */"THREAD_$INFO", "x,x,x,x",
+/* 0x8b */"TTY_$K_SET_DELAY_STYLE", "x,x,x,x",
+/* 0x8c */"TTY_$K_INQ_DELAY_STYLE", "x,x,x,x" };
+
+//------------------------------------------------------
+// TRAP5
+//------------------------------------------------------
+
+static const char* trap5[] = {
+/* 0x00 */NULL, NULL,
+/* 0x01 */"MST_$MAP_AREA", "x,x,x,u,x",
+/* 0x02 */NULL, NULL,
+/* 0x03 */NULL, NULL,
+/* 0x04 */NULL, NULL,
+/* 0x05 */"ACL_$RIGHTS", "x,x,x,x,x",
+/* 0x06 */NULL, NULL,
+/* 0x07 */"ASKNODE_$INFO", "x,x,x,x,x",
+/* 0x08 */"DISK_$AS_READ", "x,x,x,x,x",
+/* 0x09 */"DISK_$AS_WRITE", "x,x,x,x,x",
+/* 0x0a */NULL, NULL,
+/* 0x0b */NULL, NULL,
+/* 0x0c */NULL, NULL,
+/* 0x0d */NULL, NULL,
+/* 0x0e */NULL, NULL,
+/* 0x0f */NULL, NULL,
+/* 0x10 */NULL, NULL,
+/* 0x11 */"PBU_$GET_DCTE", "x,x,x,x,x",
+/* 0x12 */"PBU_$READ_CSR", "x,x,x,x,x",
+/* 0x13 */"PBU_$CONTROL", "x,x,x,x,x",
+/* 0x14 */"PBU2_$WIRE_MAP", "x,x,x,x,x",
+/* 0x15 */"PBU_$WRITE_CSR", "x,x,x,x,x",
+/* 0x16 */"TPAD_$INQUIRE", "x,x,x,x,x",
+/* 0x17 */"TPAD_$SET_MODE", "x,x,x,x,x",
+/* 0x18 */"VFMT_$MAIN", "x,x,x,x,x",
+/* 0x19 */"VOLX_$GET_INFO", "x,x,x,x,x",
+/* 0x1a */"VTOC_$GET_UID", "x,x,x,x,x",
+/* 0x1b */"NETLOG_$CNTL", "x,x,x,x,x",
+/* 0x1c */"PROC2_$GET_UPIDS", "x,x,x,x,x",
+/* 0x1d */NULL, NULL,
+/* 0x1e */NULL, NULL,
+/* 0x1f */"PBU2_$ALLOCATE_MAP", "x,x,x,x,x",
+/* 0x20 */"PBU2_$MAP", "x,x,x,x,x",
+/* 0x21 */"PBU2_$UNMAP", "x,x,x,x,x",
+/* 0x22 */"PBU2_$UNWIRE", "x,x,x,x,x",
+/* 0x23 */"MST_$GET_UID_ASID", "x,x,x,x,x",
+/* 0x24 */"MST_$INVALIDATE", "x,x,u,x,x",
+/* 0x25 */"FILE_$INVALIDATE", "x,x,x,x,x",
+/* 0x26 */NULL, NULL,
+/* 0x27 */NULL, NULL,
+/* 0x28 */NULL, NULL,
+/* 0x29 */"MST_$SET_TOUCH_AHEAD_CNT", "x,x,x,x,x",
+/* 0x2a */"OS_$CHKSUM", "x,x,x,x,x",
+/* 0x2b */"FILE_$GET_SEGMENT_MAP", "x,x,x,x,x",
+/* 0x2c */NULL, NULL,
+/* 0x2d */"PBU2_$ASSOC", "x,x,x,x,x",
+/* 0x2e */"FILE_$UNLOCK_PROC", "x,x,x,x,x",
+/* 0x2f */"CT_$READ", "x,x,x,x,x",
+/* 0x30 */"CT_$WRITE", "x,x,x,x,x",
+/* 0x31 */"DIR_$ADDU", "u,S,w,u,x",
+/* 0x32 */"DIR_$DROPU", "x,x,x,x,x",
+/* 0x33 */"DIR_$CREATE_DIRU", "x,x,x,x,x",
+/* 0x34 */"DIR_$ADD_BAKU", "x,x,x,x,x",
+/* 0x35 */NULL, NULL,
+/* 0x36 */NULL, NULL,
+/* 0x37 */NULL, NULL,
+/* 0x38 */"DIR_$ADD_HARD_LINKU", "x,x,x,x,x",
+/* 0x39 */NULL, NULL,
+/* 0x3a */"RIP_$UPDATE", "x,x,x,x,x",
+/* 0x3b */"DIR_$DROP_LINKU", "x,x,x,x,x",
+/* 0x3c */"ACL_$CHECK_RIGHTS", "x,x,x,x,x",
+/* 0x3d */"DIR_$DROP_HARD_LINKU", "x,x,x,x,x",
+/* 0x3e */"ROUTE_$OUTGOING", "x,x,x,x,x",
+/* 0x3f */NULL, NULL,
+/* 0x40 */NULL, NULL,
+/* 0x41 */NULL, NULL,
+/* 0x42 */"NET_$GET_INFO", "x,x,x,x,x",
+/* 0x43 */"DIR_$GET_ENTRYU", "x,x,x,x,x",
+/* 0x44 */"AUDIT_$LOG_EVENT", "x,x,x,x,x",
+/* 0x45 */"FILE_$SET_PROT", "x,x,x,x,x",
+/* 0x46 */"TTY_$K_GET", "x,x,s,x,x",
+/* 0x47 */"TTY_$K_PUT", "x,x,S,w,x",
+/* 0x48 */"PROC2_$ALIGN_CTL", "x,x,x,x,x",
+/* 0x49 */NULL, NULL,
+/* 0x4a */"XPD_$READ_PROC", "x,x,x,x,x",
+/* 0x4b */"XPD_$WRITE_PROC", "x,x,x,x,x",
+/* 0x4c */"DIR_$SET_DEF_PROTECTION", "x,x,x,x,x",
+/* 0x4d */"DIR_$GET_DEF_PROTECTION", "x,x,x,x,x",
+/* 0x4e */"ACL_$COPY", "u,u,x,x,x",
+/* 0x4f */"ACL_$CONVERT_FUNKY_ACL", "x,x,x,x,x",
+/* 0x50 */"DIR_$SET_PROTECTION", "x,x,x,x,x",
+/* 0x51 */"FILE_$OLD_AP", "x,x,x,x,x",
+/* 0x52 */"ACL_$SET_RE_ALL_SIDS", "x,x,x,x,x",
+/* 0x53 */"ACL_$GET_RE_ALL_SIDS", "x,x,x,x,x",
+/* 0x54 */"FILE_$EXPORT_LK", "x,x,x,x,x",
+/* 0x55 */"FILE_$CHANGE_LOCK_D", "x,x,x,x,x",
+/* 0x56 */"XPD_$READ_PROC_ASYNC", "x,x,x,x,x",
+/* 0x57 */NULL, NULL,
+/* 0x58 */"SMD_$MAP_DISPLAY_MEMORY", "x,x,x,x,x",
+/* 0x59 */NULL, NULL,
+/* 0x5a */NULL, NULL,
+/* 0x5b */NULL, NULL,
+/* 0x5c */NULL, NULL,
+/* 0x5d */"SCSI_$UNWIRE", "x,x,x,x,x",
+/* 0x5e */"SMD_$UNMAP_DISPLAY_MEMORY", "x,x,x,x,x",
+/* 0x5f */"SMD_$SET_COLOR_TABLE", "x,x,x,x,x",
+/* 0x60 */"RIP_$TABLE_D", "x,x,x,x,x",
+/* 0x61 */NULL, NULL,
+/* 0x62 */"SMD_$DEVICE_INFO", "x,x,x,x,x",
+/* 0x63 */NULL, NULL,
+/* 0x64 */NULL, NULL,
+/* 0x65 */"THREAD_$GET_STATE", "x,x,x,p,x",
+/* 0x66 */"THREAD_$SET_STATE", "x,x,x,p,x",
+/* 0x67 */"THREAD_$SET_STACK", "x,u,x,x,x",
+/* 0x68 */NULL, NULL };
+
+//------------------------------------------------------
+// TRAP7
+//------------------------------------------------------
+
+static const char* trap7[] = {
+/* 0x00 */"FILE_$LOCK", "u,x,x,x,x,x,x",
+/* 0x01 */"VFMT_$WRITE", "s,x,x,x,x,x,x",
+/* 0x02 */"MST_$MAP_AREA_AT", "x,x,x,x,x,x,x",
+/* 0x03 */NULL, NULL,
+/* 0x04 */NULL, NULL,
+/* 0x05 */NULL, NULL,
+/* 0x06 */NULL, NULL,
+/* 0x07 */NULL, NULL,
+/* 0x08 */NULL, NULL,
+/* 0x09 */NULL, NULL,
+/* 0x0a */NULL, NULL,
+/* 0x0b */NULL, NULL,
+/* 0x0c */NULL, NULL,
+/* 0x0d */"VFMT_$ENCODE/VFMT_$FORMAT", "x,x,x,x,x,x,x",
+/* 0x0e */"VFMT_$ENCODE/VFMT_$FORMAT", "x,x,x,x,x,x,x",
+/* 0x0f */"STOP_$WATCH", "x,x,x,x,x,x,x",
+/* 0x10 */NULL, NULL,
+/* 0x11 */NULL, NULL,
+/* 0x12 */"ASKNODE_$GET_INFO", "x,x,x,x,x,x,x",
+/* 0x13 */"DISK_$DIAG_IO", "x,x,x,x,x,x,x",
+/* 0x14 */NULL, NULL,
+/* 0x15 */NULL, NULL,
+/* 0x16 */NULL, NULL,
+/* 0x17 */"CT_$DIAG", "x,x,x,x,x,x,x",
+/* 0x18 */"TIME_$SET_ITIMER", "x,x,x,x,x,x,x",
+/* 0x19 */"OSINFO_$GET_STATS", "x,x,x,x,x,x,x",
+/* 0x1a */"DIR_$CNAMEU", "x,x,x,x,x,x,x",
+/* 0x1b */"DIR_$DELETE_FILEU", "u,S,w,x,x,x,x",
+/* 0x1c */"DIR_$ADD_LINKU", "x,x,x,x,x,x,x",
+/* 0x1d */NULL, NULL,
+/* 0x1e */NULL, NULL,
+/* 0x1f */NULL, NULL,
+/* 0x20 */NULL, NULL,
+/* 0x21 */"ASKNODE_$WHO_REMOTE", "x,x,x,x,x,x,x",
+/* 0x22 */"MST_$REMAP", "x,x,x,x,x,x,x",
+/* 0x23 */"DIR_$ROOT_ADDU", "x,x,x,x,x,x,x",
+/* 0x24 */NULL, NULL,
+/* 0x25 */NULL, NULL,
+/* 0x26 */NULL, NULL,
+/* 0x27 */NULL, NULL,
+/* 0x28 */"ASKNODE_$WHO_NOTOPO", "x,x,x,x,x,x,x",
+/* 0x29 */"NET_$OPEN", "x,x,x,x,x,x,x",
+/* 0x2a */"NET_$CLOSE", "x,x,x,x,x,x,x",
+/* 0x2b */"NET_$IOCTL", "x,x,x,x,x,x,x",
+/* 0x2c */"DIR_$FIND_UID", "u,u,x,S,w,x,x",
+/* 0x2d */"FILE_$GET_ATTRIBUTES", "u,x,x,x,x,x,-",
+/* 0x2e */NULL, NULL,
+/* 0x2f */"PCHIST_$UNIX_PROFIL_CNTL", "x,x,x,x,x,x,x",
+/* 0x30 */"XPD_$RESTART", "x,x,x,x,x,x,x",
+/* 0x31 */"FILE_$GET_ATTR_INFO", "u,x,x,x,x,x,p",
+/* 0x32 */"ACL_$PRIM_CREATE", "x,x,x,x,x,x,x",
+/* 0x33 */"PROC2_$GET_REGS", "x,x,x,x,x,x,x",
+/* 0x34 */"ACL_$CONVERT_TO_9ACL", "x,x,x,x,x,x,x",
+/* 0x35 */"ACL_$SET_RES_ALL_SIDS", "x,x,x,x,x,x,x",
+/* 0x36 */"ACL_$GET_RES_ALL_SIDS", "x,x,x,x,x,x,x",
+/* 0x37 */"FILE_$LOCK_D", "u,x,x,x,x,x,p",
+/* 0x38 */"FILE_$CREATE_IT", "x,x,u,x,u,x,u",
+/* 0x39 */"ACL_$RIGHTS_CHECK", "x,x,x,x,x,x,x",
+/* 0x3a */"RIP_$UPDATE_D", "x,x,x,x,x,x,x",
+/* 0x3b */"VOLX_$SWAPON", "x,x,x,x,x,x,x",
+/* 0x3c */"MST_$ADDMAP", "x,x,x,x,x,x,x", };
+
+//------------------------------------------------------
+// TRAP8
+//------------------------------------------------------
+
+static const char* trap8[] = {
+
+/* 0x00 - 0x07 */"MST_$MAP", "u,x,x,x,x,x,x",
+/* 0x01 - 0x08 */"MST_$MAP_AT", "x,u,x,x,x,x,x,x",
+/* 0x02 - 0x07 */"MST_$MAP_GLOBAL", "u,x,x,x,x,x,x",
+/* 0x03 - 0x0A */"VFMT_$WRITE", "s,x,x,x,x,x,x,x,x,x",
+/* 0x04 - 0x06 */"VOLX_$DISMOUNT", "x,x,x,x,x,x",
+/* 0x05 - 0x06 */"VOLX_$GET_UIDS", "x,x,x,x,x,x",
+/* 0x06 - 0x07 */NULL, NULL,
+/* 0x07 - 0x07 */"DISK_$PV_ASSIGN", "x,x,x,x,x,x,x",
+/* 0x08 - 0x0B */"MSG_$RCV", "x,x,x,x,x,x,x,x,x,x,x",
+/* 0x09 - 0x10 */"MSG_$SAR", "x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x",
+/* 0x0a - 0x0A */"MSG_$SEND", "x,x,x,x,x,x,x,x,x,x",
+/* 0x0b - 0x06 */NULL, NULL,
+/* 0x0c - 0x07 */"SMD_$LOAD_CRSR_BITMAP", "x,x,x,x,x,x,x",
+/* 0x0d - 0x07 */"SMD_$READ_CRSR_BITMAP", "x,x,x,x,x,x,x",
+/* 0x0e - 0x0D */"VFMT_$ENCODE/VFMT_$FORMAT", "s,x,x,x,x,x,x,x,x,x,x,x,x",
+/* 0x0f - 0x08 */"VFMT_$ENCODE/VFMT_$FORMAT", "s,x,x,x,x,x,x,x",
+/* 0x10 - 0x0D */"VFMT_$ENCODE/VFMT_$FORMAT", "s,x,x,x,x,x,x,x,x,x,x,x,x",
+/* 0x11 - 0x08 */"VFMT_$ENCODE/VFMT_$FORMAT", "s,x,x,x,x,x,x,x",
+/* 0x12 - 0x06 */"CAL_$WRITE_CALENDAR", "x,x,x,x,x,x",
+/* 0x13 - 0x08 */"MSG_$RCV_CONTIG", "x,x,x,x,x,x,x,x",
+/* 0x14 - 0x06 */"OSINFO_$GET_MMAP", "x,x,x,x,x,x",
+/* 0x15 - 0x06 */"ASKNODE_$INTERNET_INFO", "x,x,x,x,x,x",
+/* 0x16 - 0x07 */"MST_$GET_VA_INFO", "x,x,x,x,x,x,x",
+/* 0x17 - 0x0D */"MSG_$SENDI", "x,x,x,x,x,x,x,x,x,x,x,x,x",
+/* 0x18 - 0x0F */"MSG_$RCVI", "x,x,x,x,x,x,x,x,x,x,x,x,x,x,x",
+/* 0x19 - 0x0C */"MSG_$RCV_CONTIGI", "x,x,x,x,x,x,x,x,x,x,x,x",
+/* 0x1a - 0x11 */"MSG_$SARI", "x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x",
+/* 0x1b - 0x06 */NULL, NULL,
+/* 0x1c - 0x0E */"MSG_$SEND_HW", "x,x,x,x,x,x,x,x,x,x,x,x,x,x",
+/* 0x1d - 0x07 */"PBU_$WIRE_SPECIAL", "x,x,x,x,x,x,x",
+/* 0x1e - 0x06 */"PBU_$DMA_START", "x,x,x,x,x,x",
+/* 0x1f - 0x08 */NULL, NULL,
+/* 0x20 - 0x07 */"MST_$MAP_TOP", "x,x,x,x,x,x,x",
+/* 0x21 - 0x08 */"NET_$SEND", "x,x,x,x,x,x,x,x",
+/* 0x22 - 0x08 */"NET_$RCV", "x,x,x,x,x,x,x,x",
+/* 0x23 - 0x08 */"DIR_$DIR_READU", "u,S,w,x,x,x,x,x",
+/* 0x24 - 0x07 */"DIR_$READ_LINKU", "x,x,x,x,x,x,x",
+/* 0x25 - 0x07 */"PBU2_$DMA_START", "x,x,x,x,x,x,x",
+/* 0x26 - 0x09 */NULL, NULL,
+/* 0x27 - 0x09 */NULL, NULL,
+/* 0x28 - 0x07 */"PROC2_$COMPLETE_VFORK", "x,x,x,x,x,x,x",
+/* 0x29 - 0x07 */NULL, NULL,
+/* 0x2a - 0x06 */NULL, NULL,
+/* 0x2b - 0x0A */"DIR_$RESOLVE", "S,w,u,u,x,x,x,x,x,x",
+/* 0x2c - 0x08 */"VOLX_$MOUNT", "x,x,x,x,x,x,x,x",
+/* 0x2d - 0x06 */"ACL_$IMAGE", "x,x,x,x,x,x",
+/* 0x2e - 0x09 */"DISK_$PV_ASSIGN_N", "x,x,x,x,x,x,x,x,x",
+/* 0x2f - 0x07 */"DISK_$AS_XFER_MULTI", "x,x,x,x,x,x,x",
+/* 0x30 - 0x07 */"PROC2_$FORK", "x,x,x,x,x,x,x",
+/* 0x31 - 0x06 */"SCSI_$DO_COMMAND", "x,x,x,x,x,x",
+/* 0x32 - 0x07 */"SCSI_$WAIT", "x,x,x,x,x,x,x",
+/* 0x33 - 0x0A */"PROC2_$CREATE", "x,x,x,x,x,x,x,x,x,x",
+/* 0x34 - 0x06 */"TPAD_$SET_UNIT_MODE", "x,x,x,x,x,x",
+/* 0x35 - 0x06 */"TPAD_$INQUIRE_UNIT", "x,x,x,x,x,x",
+/* 0x36 - 0x0B */"SCSI_$DO_SYS_DEVICE_CMD", "x,x,x,x,x,x,x,x,x,x,x",
+/* 0x37 - 0x0D */"MSG_$RCV_HW", "x,x,x,x,x,x,x,x,x,x,x,x,x",
+/* 0x38 - 0x06 */"VOLX_$VOL_INFO", "x,x,x,x,x,x",
+/* 0x39 - 0x08 */"MST_$MAP_XTAL", "x,x,x,x,x,x,x,x",
+/* 0x3a - 0x08 */"MST_$MAP_U", "x,u,x,x,x,x,x,x",
+/* 0x3b - 0x06 */"MST_$GET_INFO_BY_VA", "x,x,x,x,x,x",
+/* 0x3c - 0x06 */"VOLX_$QUOTA_CONTROL", "x,x,x,x,x,x",
+/* 0x3d - 0x06 */"VOLX_$READ_QUOTA_TABLE", "x,x,x,x,x,x",
+/* 0x3e - 0x06 */"THREAD_$LIST", "x,x,x,x,x,x",
+/* 0x3f - 0x07 */"SCSI_$DO_COMMAND_2", "x,x,x,x,x,x,x" };
+
+// get parameter string for parameter type and value at addr
+
+static const char *get_param(m68ki_cpu_core *m68k, UINT32 addr, char type)
+{
+ UINT32 value = ~0;
+
+ // FIXME:
+ static char sb[256];
+
+ int i;
+ char ch;
+ int maxlen = sizeof(sb) - 2;
+ UINT32 value1;
+
+ sb[0] = 0;
+
+ if (!m68k->mmu_tmp_buserror_occurred)
+ {
+ value = m68k->memory.read32(addr);
+ if (!m68k->mmu_tmp_buserror_occurred && (value != ~0))
+ {
+ switch (type)
+ {
+ case 'S': // string w/o terminating 0
+ value1 = m68k->memory.read32(addr + 4);
+ if (!m68k->mmu_tmp_buserror_occurred && (value1 != ~0))
+ {
+ maxlen = m68k->memory.read16(value1);
+ if (maxlen > sizeof(sb) - 2)
+ {
+ maxlen = sizeof(sb) - 2;
+ }
+ }
+ case 's': // string
+ i = 0;
+ sb[i++] = '"';
+ while (i <= maxlen && (ch = m68k->memory.read8(value++)) != 0
+ && !m68k->mmu_tmp_buserror_occurred)
+ {
+ sb[i++] = ch < 32 ? '.' : ch;
+ }
+ sb[i++] = '"';
+ sb[i] = 0;
+ break;
+ case 'b': // byte (1 byte)
+ sprintf(sb, "0x%x", m68k->memory.read8(value));
+ break;
+ case 'p': // pointer
+ sprintf(sb, "0x%x", value);
+ break;
+ case 'w': // word (2 byte)
+ sprintf(sb, "0x%x", m68k->memory.read16(value));
+ break;
+ case 'x': // default (hex 32 bit)
+ sprintf(sb, "0x%x", m68k->memory.read32(value));
+ break;
+ case 'u': // uid
+ sprintf(sb, "%08x.%08x", m68k->memory.read32(value),
+ m68k->memory.read32(value + 4));
+ break;
+ default:
+ sprintf(sb, "%c", type);
+ break;
+ }
+ }
+ m68k->mmu_tmp_buserror_occurred = 0;
+ }
+ return sb;
+}
+
+// get the svc call string
+
+static const char* get_svc_call(m68ki_cpu_core *m68k, int trap_no,
+ int trap_code, char *sb)
+{
+ UINT32 sp = REG_A(m68k)[7];
+ UINT32 pa;
+ const char * name = NULL;
+ const char * param = NULL;
+
+ switch (trap_no)
+ {
+ case 0:
+ if (trap_no < sizeof(trap0) / 8)
+ {
+ name = trap0[trap_code * 2];
+ param = trap0[trap_code * 2 + 1];
+ }
+ break;
+ case 1:
+ if (trap_no < sizeof(trap1) / 8)
+ {
+ name = trap1[trap_code * 2];
+ param = trap1[trap_code * 2 + 1];
+ }
+ break;
+ case 2:
+ if (trap_no < sizeof(trap2) / 8)
+ {
+ name = trap2[trap_code * 2];
+ param = trap2[trap_code * 2 + 1];
+ }
+ break;
+ case 3:
+ if (trap_no < sizeof(trap3) / 8)
+ {
+ name = trap3[trap_code * 2];
+ param = trap3[trap_code * 2 + 1];
+ }
+ break;
+ case 4:
+ if (trap_no < sizeof(trap4) / 8)
+ {
+ name = trap4[trap_code * 2];
+ param = trap4[trap_code * 2 + 1];
+ }
+ break;
+ case 5:
+ if (trap_no < sizeof(trap5) / 8)
+ {
+ name = trap5[trap_code * 2];
+ param = trap5[trap_code * 2 + 1];
+ }
+ break;
+ case 7:
+ if (trap_no < sizeof(trap7) / 8)
+ {
+ name = trap7[trap_code * 2];
+ param = trap7[trap_code * 2 + 1];
+ }
+ break;
+ case 8:
+ if (trap_no < sizeof(trap8) / 8)
+ {
+ name = trap8[trap_code * 2];
+ param = trap8[trap_code * 2 + 1];
+ }
+ break;
+ }
+
+ sb[0] = '\0';
+
+ if (name == NULL)
+ {
+ strcat(sb, "???");
+ }
+ else
+ {
+ strcat(sb, name);
+ if (param != NULL)
+ {
+ int i;
+ strcat(sb, "(");
+ for (i = 0, pa = sp + 4; param[i] != '\0'; i++)
+ {
+ switch (param[i])
+ {
+ case ',':
+ strcat(sb, ", ");
+ pa += 4;
+ break;
+ default:
+ strcat(sb, get_param(m68k, pa, param[i]));
+ break;
+ }
+ }
+ strcat(sb, ")");
+ }
+ }
+ return sb;
+}
+
+static const char * disassemble(m68ki_cpu_core *m68k, offs_t pc, char* sb)
+{
+ UINT8 oprom[10];
+ UINT8 opram[10];
+ UINT32 options = 0;
+
+ // remember bus error state
+ UINT32 tmp_buserror_occurred = m68k->mmu_tmp_buserror_occurred;
+ UINT32 tmp_buserror_address = m68k->mmu_tmp_buserror_address;
+
+ m68k->mmu_tmp_buserror_occurred = 0;
+ m68k->mmu_tmp_rw = 1;
+
+ int i;
+ for (i = 0; i < sizeof(oprom); i++)
+ {
+ oprom[i] = opram[i] = m68k->memory.read8(pc + i);
+ if (m68k->mmu_tmp_buserror_occurred)
+ {
+
+ sprintf(sb, "- (apollo_disassemble failed at %08x)", pc + i);
+
+ // restore previous bus error state
+ m68k->mmu_tmp_buserror_occurred = tmp_buserror_occurred;
+ m68k->mmu_tmp_buserror_address = tmp_buserror_address;
+
+ return sb;
+ }
+ }
+ m68k->device->disassemble(sb, pc, oprom, opram, options);
+
+ // restore previous bus error state
+ m68k->mmu_tmp_buserror_occurred = tmp_buserror_occurred;
+ m68k->mmu_tmp_buserror_address = tmp_buserror_address;
+
+ return sb;
+}
+
+static const UINT16 *get_data(m68ki_cpu_core *m68k, offs_t addr)
+{
+ static UINT16 data[4];
+
+ // remember bus error state
+ UINT32 tmp_buserror_occurred = m68k->mmu_tmp_buserror_occurred;
+ UINT32 tmp_buserror_address = m68k->mmu_tmp_buserror_address;
+
+ m68k->mmu_tmp_buserror_occurred = 0;
+ m68k->mmu_tmp_rw = 1;
+
+ int i;
+ for (i = 0; i < sizeof(data); i += 2)
+ {
+ data[i/2] = m68k->memory.read16(addr + i);
+ }
+
+ // restore previous bus error state
+ m68k->mmu_tmp_buserror_occurred = tmp_buserror_occurred;
+ m68k->mmu_tmp_buserror_address = tmp_buserror_address;
+
+ return data;
+}
+
+//-------------------------------------------------
+// instruction_hook - should be called by the CPU core
+// before executing each instruction
+//-------------------------------------------------
+
+int apollo_debug_instruction_hook(device_t *device, offs_t curpc)
+{
+ // trap data remembered for next rte
+ static struct {
+ UINT32 pc;
+ UINT32 sp;
+ UINT16 trap_no;
+ UINT16 trap_code;
+ } trap = { 0, 0, 0, 0 };
+
+ if (apollo_config( APOLLO_CONF_TRAP_TRACE | APOLLO_CONF_FPU_TRACE))
+ {
+ UINT32 ppc_save;
+ UINT16 ir;
+ m68ki_cpu_core *m68k = (m68ki_cpu_core *) downcast<legacy_cpu_device *> (device)->token();
+ m68k->mmu_tmp_buserror_occurred = 0;
+
+ /* Read next instruction */
+ ir = (m68k->pref_addr == REG_PC(m68k)) ? m68k->pref_data : m68k->memory.readimm16(REG_PC(m68k));
+
+ // apollo_cpu_context expects the PC of current opcode in REG_PPC (not the previous PC)
+ ppc_save = REG_PPC(m68k);
+ REG_PPC(m68k) = REG_PC(m68k);
+
+ if (m68k->mmu_tmp_buserror_occurred)
+ {
+ m68k->mmu_tmp_buserror_occurred = 0;
+ // give up
+ }
+ else if ((ir & 0xff00) == 0xf200 && (apollo_config( APOLLO_CONF_FPU_TRACE)))
+ {
+ char sb[256];
+ LOG(("%s sp=%08x FPU: %x %s", apollo_cpu_context(device->machine().firstcpu),
+ REG_A(m68k)[7], ir, disassemble(m68k, REG_PC(m68k), sb)));
+ }
+ else if (!m68k->pmmu_enabled)
+ {
+ // skip
+ }
+ else if (ir == 0x4e73) // RTE
+ {
+ const UINT16 *data = get_data(m68k, REG_A(m68k)[7]);
+ if ( REG_USP(m68k) == 0 && (data[0] & 0x2000) == 0) {
+ LOG(("%s sp=%08x RTE: sr=%04x pc=%04x%04x v=%04x usp=%08x",
+ apollo_cpu_context(device->machine().firstcpu),
+ REG_A(m68k)[7], data[0], data[1], data[2], data[3], REG_USP(m68k)));
+ }
+ }
+ else if ((ir & 0xfff0) == 0x4e40 && (ir & 0x0f) <= 8 && apollo_config(APOLLO_CONF_TRAP_TRACE))
+ {
+ // trap n
+ trap.pc = REG_PC(m68k);
+ trap.sp = REG_A(m68k)[7];
+ trap.trap_no = ir & 0x0f;
+ trap.trap_code = REG_D(m68k)[0] & 0xffff;
+
+ char sb[1000];
+ LOG(("%s sp=%08x Domain/OS SVC: trap %x 0x%02x: %s",
+ apollo_cpu_context(device->machine().firstcpu), trap.sp,
+ trap.trap_no, trap.trap_code,
+ get_svc_call(m68k, trap.trap_no, trap.trap_code, sb)));
+
+ }
+ else if (trap.pc == REG_PC(m68k) - 2 && trap.sp == REG_A(m68k)[7])
+ {
+ // rte
+ char sb[1000];
+ LOG(("%s sp=%08x Domain/OS SVC: %s D0=0x%x",
+ apollo_cpu_context(device->machine().firstcpu), trap.sp,
+ get_svc_call(m68k, trap.trap_no, trap.trap_code, sb), REG_D(m68k)[0]));
+
+ trap.pc = 0;
+ trap.sp = 0;
+ trap.trap_no = 0;
+ trap.trap_code = 0;
+ }
+ // restore previous PC
+ REG_PPC(m68k) = ppc_save;
+ }
+ return 0;
+}
diff --git a/src/mess/machine/apollo_eth.c b/src/mess/machine/apollo_eth.c
new file mode 100644
index 00000000000..059a50efddd
--- /dev/null
+++ b/src/mess/machine/apollo_eth.c
@@ -0,0 +1,355 @@
+/*
+ * apollo_eth.c - APOLLO ethernet proxy
+ *
+ * Created on: Sep 19, 2011
+ * Author: Hans Ostermeyer
+ *
+ * Released for general non-commercial use under the MAME license
+ * Visit http://mamedev.org for licensing and usage restrictions.
+ *
+ * see also:
+ * http://www.linuxjournal.com/article/4659
+ *
+ *
+ * TODO:
+ * Scrap this unportable stuff, make 3c505 use the core Ethernet layer directly like the 3c503.
+ *
+ */
+
+#define VERBOSE 0
+
+#include "includes/apollo.h"
+
+#if !defined(APOLLO_FOR_LINUX)
+
+int apollo_eth_transmit(device_t *device, const UINT8 data[], int length)
+{
+ return 1;
+}
+
+int apollo_eth_setfilter(device_t *device, int node_id)
+{
+ return 0;
+}
+
+void apollo_eth_init(device_t *device, apollo_eth_receive rx_data)
+{
+}
+
+#else /* defined(APOLLO_FOR_LINUX) */
+
+#include "machine/3c505.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <netpacket/packet.h>
+#include <net/ethernet.h>
+#include <sys/ioctl.h>
+#include <linux/if.h>
+#include <linux/filter.h>
+#include <netinet/in.h>
+
+#define ETH_BUFFER_SIZE 2048
+
+// TODO: should be configurable
+#define ETH_INTERFACE_NAME "eth0"
+//#define ETH_INTERFACE_NAME "vmnet0"
+
+static const char *eth_if_name;
+static int eth_if_index = -1;
+static int eth_socket = -1;
+static UINT8 eth_hw_address[ETHERNET_ADDR_SIZE];
+
+static apollo_eth_receive rx_callback = NULL;
+
+/***************************************************************************
+ log data
+ ***************************************************************************/
+
+static void log_data(const device_t *device, const char *type,
+ const UINT8 *data, int data_length) {
+ if (VERBOSE > 0) {
+ int i;
+ logerror("%s - %s: %s (length=%2x)", apollo_cpu_context(
+ device->machine().firstcpu), device->tag(), type, data_length);
+ for (i = 0; i < data_length; i++) {
+ logerror(" %02x", data[i]);
+ }
+ logerror("\n");
+ }
+}
+
+/***************************************************************************
+ apollo_eth_receive_packet
+ ***************************************************************************/
+
+static int apollo_eth_receive_packet(device_t *device)
+{
+ u_char rx_buffer[ETH_BUFFER_SIZE];
+ int packet_len;
+
+ do
+ {
+ packet_len = recv(eth_socket, rx_buffer, sizeof(rx_buffer), MSG_TRUNC);
+ } while (packet_len == -1 && errno == EINTR);
+
+ /* Check if an error occurred */
+ if (packet_len == -1)
+ {
+ switch (errno)
+ {
+ case EAGAIN:
+ return 0; /* no packet there */
+
+ case ENETDOWN:
+ // The device on which we're capturing went away.
+ DLOG1(("apollo_eth_receive_packet: the interface went down (error %d - %s)", errno, strerror(errno)));
+ return -1;
+
+ default:
+ DLOG(("apollo_eth_receive_packet: recv failed (error %d - %s)", errno, strerror(errno)));
+ return -1;
+ }
+ }
+ else if (packet_len > sizeof(rx_buffer))
+ {
+ DLOG(("apollo_eth_receive_packet: data size (%d) exceeds rx buffer size (%d)!!!", packet_len, sizeof(rx_buffer)));
+ return -1;
+ }
+
+ log_data(device, "apollo_eth_receive_packet", rx_buffer, packet_len);
+
+ /* Call the user supplied callback function */
+ if (rx_callback != NULL)
+ {
+ // threecom3c505_receive(device, tx_data_buffer, tx_data_length);
+ (*rx_callback)(device, rx_buffer, packet_len);
+ }
+
+ return 1;
+}
+
+/***************************************************************************
+ receive_interrupt
+ ***************************************************************************/
+
+static TIMER_CALLBACK(receive_interrupt)
+{
+ device_t *device = (device_t *) ptr;
+
+ /*
+ * Save the socket's current mode, and put it in non-blocking mode;
+ * we drain it by reading packets until we get an error
+ * (which is normally a "nothing more to be read" error).
+ */
+ int save_mode = fcntl(eth_socket, F_GETFL, 0);
+ if (save_mode == -1)
+ {
+ DLOG(("receive_interrupt: fcntl failed (error %d - %s)", errno, strerror(errno)))
+ }
+ else if (fcntl(eth_socket, F_SETFL, save_mode | O_NONBLOCK) < 0)
+ {
+ DLOG(("receive_interrupt: fcntl failed (error %d - %s)", errno, strerror(errno)))
+ }
+ else
+ {
+ int i = 0;
+ while (apollo_eth_receive_packet(device) > 0 && i++ < 4)
+ ;
+
+ fcntl(eth_socket, F_SETFL, save_mode);
+ }
+
+ machine.scheduler().timer_set(attotime::from_msec(1), FUNC(receive_interrupt), 0, device);
+}
+
+/***************************************************************************
+ apollo_eth_transmit - transmit an packet to the ethernet
+ ***************************************************************************/
+
+int apollo_eth_transmit(device_t *device, const UINT8 data[], int length) {
+
+ if (eth_socket != -1)
+ {
+ if (memcmp(data, eth_hw_address, ETHERNET_ADDR_SIZE) == 0)
+ {
+ // destination ethernet address is my own mac address
+ // TODO: should send data to "eth0"
+ }
+
+ if (send(eth_socket, data, length, 0) == -1) {
+ DLOG(("apollo_eth_transmit: send failed with error %d (%s)", errno, strerror(errno)));
+ } else {
+ log_data(device, "apollo_eth_transmit", data, length);
+ }
+ }
+
+ return 1;
+}
+
+/***************************************************************************
+ apollo_eth_setfilter - set the socket filter
+ ***************************************************************************/
+
+int apollo_eth_setfilter(device_t *device, int node_id)
+{
+ /*
+ tcpdump -i eth0 -dd ether dst 08:00:1e:01:ae:a5 or ether dst 09:00:1e:00:00:00 or ether dst 09:00:1e:00:00:01 or ether broadcast
+
+ (000) ld [2]
+ (001) jeq #0x1e01aea5 jt 2 jf 4
+ (002) ldh [0]
+ (003) jeq #0x800 jt 11 jf 12
+ (004) jeq #0x1e000000 jt 6 jf 5
+ (005) jeq #0x1e000001 jt 6 jf 8
+ (006) ldh [0]
+ (007) jeq #0x900 jt 11 jf 12
+ (008) jeq #0xffffffff jt 9 jf 12
+ (009) ldh [0]
+ (010) jeq #0xffff jt 11 jf 12
+ (011) ret #65535
+ (012) ret #0
+ */
+ static struct sock_filter bpf_code[]= {
+ { 0x20, 0, 0, 0x00000002 },
+ { 0x15, 0, 2, 0x1e01aea5 },
+ { 0x28, 0, 0, 0x00000000 },
+ { 0x15, 7, 8, 0x00000800 },
+ { 0x15, 1, 0, 0x1e000000 },
+ { 0x15, 0, 2, 0x1e000001 },
+ { 0x28, 0, 0, 0x00000000 },
+ { 0x15, 3, 4, 0x00000900 },
+ { 0x15, 0, 3, 0xffffffff },
+ { 0x28, 0, 0, 0x00000000 },
+ { 0x15, 0, 1, 0x0000ffff },
+ { 0x6, 0, 0, 0x0000ffff },
+ { 0x6, 0, 0, 0x00000000 }
+ };
+
+ if (eth_socket != -1)
+ {
+ struct sock_fprog filter;
+ filter.len = sizeof(bpf_code) / sizeof(sock_filter);
+ filter.filter = bpf_code;
+
+ // set node id in filter
+ bpf_code[1].k = (bpf_code[1].k & 0xff000000) | (node_id & 0x00ffffff);
+
+ /* Attach the filter to the socket */
+ if (setsockopt(eth_socket, SOL_SOCKET, SO_ATTACH_FILTER, &filter,
+ sizeof(filter)) < 0)
+ {
+ DLOG(("apollo_eth_setfilter: failed with error %d (%s)", errno, strerror(errno)));
+ return 0;
+ }
+ else
+ {
+ DLOG1(("apollo_eth_setfilter: set filter for node id %x", node_id & 0x00ffffff));
+ }
+ }
+ return 1;
+}
+
+/***************************************************************************
+ apollo_eth_init - specify node id and transmitter call back function
+ ***************************************************************************/
+
+void apollo_eth_init(device_t *device, apollo_eth_receive rx_data)
+{
+ rx_callback = rx_data;
+
+ eth_if_name = ETH_INTERFACE_NAME;
+ eth_if_index = -1;
+ memset(eth_hw_address, 0 , sizeof(eth_hw_address));
+
+ // Note: Only processes with effective UID 0 or the CAP_NET_RAW capability may open packet sockets.
+ // see also: man 7 packet
+
+ eth_socket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+ if (eth_socket == -1)
+ {
+ if (errno == EPERM)
+ {
+ DLOG(("apollo_eth_init: %s - Ethernet access disabled", strerror(errno)));
+ }
+ else
+ {
+ DLOG1(("apollo_eth_init: socket failed (error %d - %s)", errno, strerror(errno)));
+ }
+ }
+ else
+ {
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, eth_if_name, sizeof(ifr.ifr_name));
+
+ // Get interface index
+ if (ioctl(eth_socket, SIOCGIFINDEX, &ifr) == -1)
+ {
+ DLOG(("apollo_eth_init: interface %s not found (error %d - %s)", eth_if_name, errno, strerror(errno)));
+ close(eth_socket);
+ eth_socket = -1;
+ }
+ else
+ {
+ eth_if_index = ifr.ifr_ifindex;
+
+ // Get hardware address
+ memset(&ifr, 0, sizeof(ifr));
+ (void) strncpy(ifr.ifr_name, eth_if_name, sizeof(ifr.ifr_name));
+ if (ioctl(eth_socket, SIOCGIFHWADDR, (char *) &ifr) < 0)
+ {
+ DLOG(("apollo_eth_init: SIOCGIFHWADDR failed for %s (error %d - %s)", eth_if_name, errno, strerror(errno)));
+ }
+ else
+ {
+ memcpy(eth_hw_address, ifr.ifr_hwaddr.sa_data, sizeof(eth_hw_address));
+ }
+
+ struct sockaddr_ll sll;
+ memset(&sll, 0, sizeof(sll));
+ sll.sll_family = AF_PACKET;
+ sll.sll_ifindex = eth_if_index;
+ sll.sll_protocol = htons(ETH_P_ALL);
+
+ if (bind(eth_socket, (struct sockaddr *) &sll, sizeof(sll)) == -1)
+ {
+ DLOG(("apollo_eth_init: bind to interface %s failed (error %d - %s)", eth_if_name, errno, strerror(errno)));
+ close(eth_socket);
+ eth_socket = -1;
+ }
+ else
+ {
+ struct packet_mreq mr;
+ memset(&mr, 0, sizeof(mr));
+ mr.mr_ifindex = eth_if_index;
+ mr.mr_type = PACKET_MR_PROMISC;
+ if (setsockopt(eth_socket, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mr, sizeof(mr)) == -1)
+ {
+ DLOG(("apollo_eth_init: failed to set promiscuous mode (error %d - %s)", errno, strerror(errno)));
+ close(eth_socket);
+ eth_socket = -1;
+ }
+ else
+ {
+ // Set the socket buffer size to the specified value.
+ // by default request 2M for the ring buffer
+ int rx_bufsize = 2*1024*1024;
+ if (setsockopt(eth_socket, SOL_SOCKET, SO_RCVBUF, &rx_bufsize, sizeof(rx_bufsize)) == -1)
+ {
+ DLOG(("apollo_eth_init: failed to set buffer size (error %d - %s)", errno, strerror(errno)));
+ close(eth_socket);
+ eth_socket = -1;
+ }
+ else
+ {
+ device->machine().scheduler().timer_set(attotime::from_msec(1), FUNC(receive_interrupt), 0, device);
+ }
+ }
+ }
+ }
+ }
+}
+#endif /* defined(APOLLO_FOR_LINUX) */
diff --git a/src/mess/machine/apollo_kbd.c b/src/mess/machine/apollo_kbd.c
new file mode 100644
index 00000000000..6141d20ae50
--- /dev/null
+++ b/src/mess/machine/apollo_kbd.c
@@ -0,0 +1,1182 @@
+/*
+ * apollo_kbd.c - Apollo keyboard and mouse emulation
+ *
+ * Created on: Dec 27, 2010
+ * Author: Hans Ostermeyer
+ *
+ * Released for general non-commercial use under the MAME license
+ * Visit http://mamedev.org for licensing and usage restrictions.
+ *
+ * see also http://www.bitsavers.org/pdf/apollo/008778-03_DOMAIN_Series_3000_4000_Technical_Reference_Aug87.pdf
+ *
+ */
+
+#define VERBOSE 0
+
+#include "machine/apollo_kbd.h"
+#include "sound/beep.h"
+
+#if defined(APOLLO_FOR_LINUX)
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+// on linux we may attach a real Apollo keyboard at /dev/ttyS0
+#include <termios.h>
+#include <sys/ioctl.h>
+#define KBD_TTY_NAME "/dev/ttyS0"
+#endif
+
+#define LOG(x) { logerror ("%s apollo_kbd: ", m_device->cpu_context()); logerror x; logerror ("\n"); }
+#define LOG1(x) { if (VERBOSE > 0) LOG(x)}
+#define LOG2(x) { if (VERBOSE > 1) LOG(x)}
+
+#define MAP_APOLLO_KEYS 1
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+//const device_type APOLLO_KBD = apollo_kbd_device_config::static_alloc_device_config;
+
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
+
+#define KBD_MODE_0_COMPATIBILITY 0
+#define KBD_MODE_1_KEYSTATE 1
+#define KBD_MODE_2_RELATIVE_CURSOR_CONTROL 2
+#define KBD_MODE_3_ABSOLUTE_CURSOR_CONTROL 3
+
+#define CODE_TABLE_DOWN_CODE 0
+#define CODE_TABLE_UP_CODE 1
+#define CODE_TABLE_UNSHIFTED_CODE 2
+#define CODE_TABLE_SHIFTED_CODE 3
+#define CODE_TABLE_CONTROL_CODE 4
+#define CODE_TABLE_CAPS_LOCK_CODE 5
+#define CODE_TABLE_UP_TRANS_CODE 6
+#define CODE_TABLE_AUTO_REPEAT_CODE 7
+#define CODE_TABLE_ENTRY_SIZE 8
+
+#define NOP 0
+#define No 0
+#define Yes 1
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+// device type definition
+const device_type APOLLO_KBD = &device_creator<apollo_kbd_device>;
+
+//-------------------------------------------------
+// apollo_kbd_device - constructor
+//-------------------------------------------------
+
+apollo_kbd_device::apollo_kbd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, APOLLO_KBD, "Apollo Keyboard", tag, owner, clock)
+{
+ memset(static_cast<apollo_kbd_interface *>(this), 0, sizeof(apollo_kbd_interface));
+}
+
+//-------------------------------------------------
+// static_set_interface - set the interface struct
+//-------------------------------------------------
+
+void apollo_kbd_device::static_set_interface(device_t &device, const apollo_kbd_interface &interface)
+{
+ apollo_kbd_device &kbd = downcast<apollo_kbd_device &>(device);
+
+ static_cast<apollo_kbd_interface &>(kbd) = interface;
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void apollo_kbd_device::device_start()
+{
+ m_device = this;
+ LOG1(("start apollo_kbd"));
+
+ m_beeper.start(this);
+ m_mouse.start(this);
+ m_tx_fifo.start(this);
+ m_keyboard_tty.start(this);
+
+ m_timer = machine().scheduler().timer_alloc(FUNC(static_poll_callback), this);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void apollo_kbd_device::device_reset()
+{
+ LOG1(("reset apollo_kbd"));
+
+ m_beeper.reset();
+ m_mouse.reset();
+ m_tx_fifo.reset();
+ m_keyboard_tty.reset();
+
+ // init keyboard
+ m_loopback_mode = 1;
+ m_mode = KBD_MODE_0_COMPATIBILITY;
+ m_delay = 500;
+ m_repeat = 33;
+ m_last_pressed = 0;
+ memset(m_keytime, 0, sizeof(m_keytime));
+ memset(m_keyon, 0, sizeof(m_keyon));
+
+ // start timer
+ m_timer->adjust( attotime::zero, 0, attotime::from_msec(5)); // every 5ms
+}
+
+/***************************************************************************
+ cpu_context - return a string describing the current CPU context
+ ***************************************************************************/
+
+const char *apollo_kbd_device::cpu_context()
+{
+ static char statebuf[64]; /* string buffer containing state description */
+
+ device_t *cpu = machine().firstcpu;
+ 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_get_previouspc(cpu), tag());
+ }
+ else
+ {
+ sprintf(statebuf, "%d.%03d", s, ms);
+ }
+ return statebuf;
+}
+
+//**************************************************************************
+// Beeper
+//**************************************************************************
+
+apollo_kbd_device::beeper::beeper() :
+ m_device(NULL),
+ m_beeper(NULL),
+ m_timer(NULL)
+{
+}
+
+void apollo_kbd_device::beeper::start(apollo_kbd_device *device)
+{
+ m_device = device;
+ LOG2(("start apollo_kbd::beeper"));
+ m_beeper = m_device->machine().device("beep");
+ m_timer = m_device->machine().scheduler().timer_alloc(FUNC(static_beeper_callback), this);
+}
+
+void apollo_kbd_device::beeper::reset()
+{
+ LOG2(("reset apollo_kbd::beeper"));
+ on();
+}
+
+void apollo_kbd_device::beeper::off()
+{
+ beep_set_state(m_beeper, 0);
+}
+
+void apollo_kbd_device::beeper::on()
+{
+ if (keyboard_has_beeper())
+ {
+ beep_set_frequency(m_beeper, 1000);
+ beep_set_state(m_beeper, 1);
+ m_timer->adjust( attotime::from_msec(10), 0, attotime::zero);
+ }
+}
+
+int apollo_kbd_device::beeper::keyboard_has_beeper()
+{
+ return m_device->apollo_kbd_has_beeper ?
+ (m_device->apollo_kbd_has_beeper)(m_device, 0) : 0;
+}
+
+void apollo_kbd_device::beeper::beeper_callback()
+{
+ off();
+}
+
+TIMER_CALLBACK( apollo_kbd_device::beeper::static_beeper_callback )
+{
+ reinterpret_cast<beeper *> (ptr)->beeper_callback();
+}
+
+//**************************************************************************
+// Mouse
+//**************************************************************************
+
+apollo_kbd_device::mouse::mouse() :
+ m_device(NULL)
+{
+}
+
+void apollo_kbd_device::mouse::start(apollo_kbd_device *device)
+{
+ m_device = device;
+ LOG2(("start apollo_kbd::mouse"));
+}
+
+void apollo_kbd_device::mouse::reset()
+{
+ LOG2(("reset apollo_kbd::mouse"));
+
+ m_last_b = -1;
+ m_last_x = 0;
+ m_last_y = 0;
+ m_tx_pending = 0;
+}
+
+void apollo_kbd_device::mouse::read_mouse()
+{
+ if (m_tx_pending > 0)
+ {
+ m_tx_pending -= 5;
+ }
+ else
+ {
+ int b = m_device->machine().root_device().ioport("mouse1")->read();
+ int x = m_device->machine().root_device().ioport("mouse2")->read();
+ int y = m_device->machine().root_device().ioport("mouse3")->read();
+
+ if (m_last_b < 0)
+ {
+ m_last_b = b;
+ m_last_x = x;
+ m_last_y = y;
+ }
+ else if (b != m_last_b || x != m_last_x || y != m_last_y)
+ {
+ int dx = x - m_last_x;
+ int dy = y - m_last_y;
+ UINT8 mouse_data[4];
+ int mouse_data_size;
+
+ LOG2(("read_mouse: b=%02x x=%04x y=%04x dx=%d dy=%d", b, x, y, dx, dy));
+
+ if (m_device->m_mode == KBD_MODE_0_COMPATIBILITY)
+ {
+ mouse_data[0] = 0xdf;
+ mouse_data[1] = 0xf0 ^ b;
+ mouse_data[2] = dx;
+ mouse_data[3] = -dy;
+ mouse_data_size = 4;
+ }
+ else
+ {
+ if (m_device->m_mode != KBD_MODE_2_RELATIVE_CURSOR_CONTROL)
+ {
+ m_device->set_mode(KBD_MODE_2_RELATIVE_CURSOR_CONTROL);
+ }
+
+ mouse_data[0] = 0xf0 ^ b;
+ mouse_data[1] = dx;
+ mouse_data[2] = -dy;
+ mouse_data_size = 3;
+ }
+
+ if (m_device->m_tx_fifo.putdata(mouse_data, mouse_data_size))
+ {
+ // mouse data submitted; update current mouse state
+ m_last_b = b;
+ m_last_x = x;
+ m_last_y = y;
+ }
+ m_tx_pending = 100; // mouse data packet will take 50 ms
+ }
+ }
+}
+
+//**************************************************************************
+// tx fifo
+//**************************************************************************
+
+apollo_kbd_device::tx_fifo::tx_fifo() :
+ m_device(NULL),
+ m_timer(NULL)
+{
+}
+
+void apollo_kbd_device::tx_fifo::start(apollo_kbd_device *device)
+{
+ m_device = device;
+ LOG2(("start apollo_kbd::tx_fifo"));
+ m_timer = m_device->machine().scheduler().timer_alloc(FUNC(static_timer_callback), this);
+}
+
+void apollo_kbd_device::tx_fifo::reset()
+{
+ LOG2(("reset apollo_kbd::tx_fifo"));
+
+ memset(fifo, 0, sizeof(fifo));
+ m_read_ptr = 0;
+ m_write_ptr = 0;
+ m_char_count = 0;
+ m_tx_pending = 0;
+ m_baud_rate = 1200;
+
+ // reset timer
+ m_timer->adjust(attotime::never, 0);
+}
+
+UINT8 apollo_kbd_device::tx_fifo::getchar()
+{
+ UINT8 data;
+
+ if (m_char_count == 0)
+ {
+ LOG(("apollo_kbd FIFO underflow"));
+ data = 0x0;
+ }
+ else
+ {
+ data = fifo[m_read_ptr++];
+ if (m_read_ptr == TX_FIFO_SIZE)
+ {
+ m_read_ptr = 0;
+ }
+ m_char_count--;
+ }
+ return data;
+}
+
+void apollo_kbd_device::tx_fifo::putchar(UINT8 data)
+{
+ if (m_char_count >= TX_FIFO_SIZE)
+ {
+ LOG(("apollo_kbd FIFO overflow"));
+ }
+ else
+ {
+ fifo[m_write_ptr++] = data;
+ if (m_write_ptr == TX_FIFO_SIZE)
+ {
+ m_write_ptr = 0;
+ }
+ m_char_count++;
+ if ( m_tx_pending == 0)
+ {
+ flush();
+ }
+ }
+}
+
+int apollo_kbd_device::tx_fifo::putdata(const UINT8 *data, int data_length)
+{
+ if (m_char_count + data_length >= TX_FIFO_SIZE-5)
+ {
+ // tx fifo is full
+ return 0;
+ }
+ else
+ {
+ while (data_length-- > 0) {
+ putchar(*data++);
+ }
+ return 1;
+ }
+}
+
+void apollo_kbd_device::tx_fifo::flush()
+{
+ if (m_char_count > 0)
+ {
+ m_tx_pending = 1;
+
+ if (m_device->apollo_kbd_putchar)
+ (m_device->apollo_kbd_putchar)(m_device, 0, getchar());
+ // 11 = one start, 8 data, one parity (even), one stop bit
+ m_timer->adjust(attotime::from_hz(m_baud_rate / 11), 0);
+ }
+ else
+ {
+ m_tx_pending = 0;
+// m_timer->adjust(attotime::never, 0);
+ }
+}
+
+void apollo_kbd_device::tx_fifo::timer_callback()
+{
+ flush();
+}
+
+TIMER_CALLBACK( apollo_kbd_device::tx_fifo::static_timer_callback )
+{
+ reinterpret_cast<apollo_kbd_device::tx_fifo *> (ptr)->timer_callback();
+}
+
+//**************************************************************************
+// Real Apollo keyboard connected at the keyboard tty (i.e. /dev/ttyS0)
+//**************************************************************************
+
+apollo_kbd_device::keyboard_tty::keyboard_tty() :
+ m_device(NULL),
+ m_tty_name(NULL),
+ m_tty_fd(-1),
+ m_connected(0)
+{
+}
+
+void apollo_kbd_device::keyboard_tty::start(apollo_kbd_device *device)
+{
+ m_device = device;
+ LOG2(("start apollo_kbd::keyboard_tty"));
+#if defined(KBD_TTY_NAME)
+ m_tty_name = KBD_TTY_NAME;
+#endif
+}
+
+void apollo_kbd_device::keyboard_tty::reset()
+{
+ LOG2(("reset apollo_kbd::keyboard_tty"));
+
+ m_connected = 0;
+
+#if defined(KBD_TTY_NAME)
+ /* Open the tty line */
+ m_tty_fd = open(m_tty_name, 2);
+ if (m_tty_fd < 0)
+ {
+ LOG1(("failed to open %s", m_tty_name));
+ }
+ else
+ {
+ int serial;
+ struct termios tty_mode;
+
+ // set nonblocking mode
+ fcntl(m_tty_fd, F_SETFL, fcntl(m_tty_fd, F_GETFL) | O_NONBLOCK);
+
+ tcgetattr(m_tty_fd, &tty_mode);
+ tty_mode.c_iflag = INPCK;
+ tty_mode.c_oflag = 0;
+ tty_mode.c_cflag = B1200 | CS8 | CREAD | HUPCL | PARENB | CLOCAL;
+ tty_mode.c_lflag = 0;
+ tty_mode.c_cc[VTIME] = 0;
+ tty_mode.c_cc[VMIN] = 1;
+ tcsetattr(m_tty_fd, TCSANOW, &tty_mode);
+
+ ioctl(m_tty_fd, TIOCMGET, &serial);
+
+ if ((serial & TIOCM_RTS) && !(serial & TIOCM_CTS))
+ {
+ // Apollo keyboard not connected
+ close(m_tty_fd);
+ m_tty_fd = -1;
+ m_connected = 0;
+ }
+ else
+ {
+ LOG1(("opened %s with RTS=%d CTS=%d", m_tty_name,
+ serial & TIOCM_RTS ? 1 : 0, serial & TIOCM_CTS ? 1 : 0 ));
+ }
+ }
+#endif
+}
+
+int apollo_kbd_device::keyboard_tty::isConnected()
+{
+ return m_connected;
+}
+
+int apollo_kbd_device::keyboard_tty::getchar()
+{
+#if defined(KBD_TTY_NAME)
+ UINT8 data;
+ if (m_tty_fd < 0 || read(m_tty_fd, &data, 1) != 1) {
+ return -1;
+ } else {
+ LOG2(("keyboard_tty::getchar <---- %02x", data))
+ m_connected = 1;
+ return data;
+ }
+#else
+ return -1;
+#endif
+}
+
+void apollo_kbd_device::keyboard_tty::putchar(UINT8 data)
+{
+#if defined(KBD_TTY_NAME)
+ if (isConnected() && m_tty_fd >= 0 ) {
+ while (write(m_tty_fd, &data, 1) != 1) {
+ LOG(("keyboard_tty::putchar data=%02x errno=%d", data, errno ));
+ }
+ LOG2(("keyboard_tty::putchar -> %02x", data));
+ }
+#endif
+}
+
+/*-------------------------------------------------
+ keyboard_is_german - check for german keyboard
+ -------------------------------------------------*/
+
+int apollo_kbd_device::keyboard_is_german()
+{
+ return apollo_kbd_is_german ?
+ (*apollo_kbd_is_german)(this, 0) : 0;
+}
+
+/*-------------------------------------------------
+ putchar - put keyboard char to sio
+ -------------------------------------------------*/
+
+void apollo_kbd_device::set_mode(UINT16 mode)
+{
+ putchar(0xff);
+ putchar(mode);
+ m_mode = mode;
+}
+
+/*-------------------------------------------------
+ putchar - put keyboard char to sio
+ -------------------------------------------------*/
+
+void apollo_kbd_device::putchar(const UINT8 data)
+{
+ LOG1(("putchar(%d) -> %02x", m_mode, data));
+ m_tx_fifo.putchar(data);
+}
+
+/*-------------------------------------------------
+ putdata - put keyboard data to sio
+ -------------------------------------------------*/
+
+void apollo_kbd_device::putdata(const UINT8 *data, int data_length)
+{
+ // send data only if no real Apollo keyboard has been connected
+ if (!m_keyboard_tty.isConnected())
+ {
+ if (m_mode > KBD_MODE_1_KEYSTATE)
+ {
+ set_mode(KBD_MODE_1_KEYSTATE);
+ }
+ m_tx_fifo.putdata(data, data_length);
+ }
+}
+
+/*-------------------------------------------------
+ putstring - put keyboard string to sio
+ -------------------------------------------------*/
+
+void apollo_kbd_device::putstring(const char *data)
+{
+ putdata((UINT8 *) data, strlen(data));
+}
+
+/*-------------------------------------------------
+ apollo_kbd_getchar - get char from sio line
+ -------------------------------------------------*/
+
+void apollo_kbd_getchar(device_t *device, UINT8 data)
+{
+ downcast<apollo_kbd_device *> (device)->getchar(data);
+}
+
+void apollo_kbd_device::getchar(UINT8 data)
+{
+ static const UINT8 ff1116_data[] = { 0x00, 0xff, 0x00 };
+
+ LOG1(("getchar <- %02x", data));
+
+ if (m_keyboard_tty.isConnected())
+ {
+ m_keyboard_tty.putchar(data);
+ }
+
+ if (data == 0xff)
+ {
+ m_rx_message = data;
+ putdata(&data, 1);
+ m_loopback_mode = 1;
+ }
+ else if (data == 0x00)
+ {
+ if (m_loopback_mode)
+ {
+ set_mode(KBD_MODE_0_COMPATIBILITY);
+ m_loopback_mode = 0;
+ }
+ }
+ else
+ {
+ m_rx_message = m_rx_message << 8 | data;
+
+ switch (m_rx_message)
+ {
+ case 0xff00:
+ putdata(&data, 1);
+ m_mode = KBD_MODE_0_COMPATIBILITY;
+ m_loopback_mode = 0;
+ m_rx_message = 0;
+ case 0xff01:
+ putdata(&data, 1);
+ m_mode = KBD_MODE_1_KEYSTATE;
+ m_rx_message = 0;
+ break;
+ case 0xff11:
+ putdata(&data, 1);
+ break;
+ case 0xff1116:
+ putdata(ff1116_data, sizeof(ff1116_data));
+ m_loopback_mode = 0;
+ m_rx_message = 0;
+ break;
+ case 0xff1117:
+ m_rx_message = 0;
+ break;
+ case 0xff12:
+ putdata(&data, 1);
+ break;
+ case 0xff1221: // receive ID message
+ m_loopback_mode = 0;
+ putdata(&data, 1);
+ if (keyboard_is_german())
+ {
+ putstring("3-A\r2-0\rSD-03863-MS\r");
+ }
+ else
+ {
+ putstring("3-@\r2-0\rSD-03863-MS\r");
+ }
+
+ if (m_mode == KBD_MODE_0_COMPATIBILITY)
+ {
+ set_mode(KBD_MODE_0_COMPATIBILITY);
+ }
+ else
+ {
+ set_mode(KBD_MODE_1_KEYSTATE);
+ }
+ m_rx_message = 0;
+ break;
+ case 0xff2181: // beeper on (for 300 ms)
+ putdata(&data, 1);
+ m_rx_message = 0;
+ m_beeper.on();
+ break;
+ case 0xff2182: // beeper off
+ putdata(&data, 1);
+ m_rx_message = 0;
+ m_beeper.off();
+ break;
+ default:
+ if (m_loopback_mode && data != 0)
+ {
+ putdata(&data, 1);
+ }
+ break;
+ }
+ }
+}
+
+int apollo_kbd_device::push_scancode(UINT8 code, UINT8 repeat)
+{
+ int n_chars = 0;
+ UINT16 key_code = 0;
+ UINT8 caps = BIT(machine().root_device().ioport("keyboard4")->read(),0);
+ UINT8 shift = BIT(machine().root_device().ioport("keyboard4")->read(),1) | BIT(machine().root_device().ioport("keyboard4")->read(),5);
+ UINT8 ctrl = BIT(machine().root_device().ioport("keyboard4")->read(),2);
+ UINT8 numlock = BIT(machine().root_device().ioport("keyboard4")->read(),6);
+ UINT16 index;
+
+ if (keyboard_is_german())
+ {
+ // map special keys for German keyboard
+ switch (code)
+ {
+ case 0x00: code = 0x68; break; // _
+ case 0x0e: code = 0x6b; break; // #
+ case 0x29: code = 0x69; break; // <>
+ case 0x42: code = 0x6f; break; // NP-
+ case 0x46: code = 0x6e; break; // NP+
+ case 0x4e: code = 0x73; break; // NP ENTER
+ }
+ }
+
+#if MAP_APOLLO_KEYS
+ if (numlock)
+ {
+ // don't map function keys to Apollo left keypad
+ switch (code)
+ {
+ case 0x52: code = 0x75; break; // F1
+ case 0x53: code = 0x76; break; // F2
+ case 0x54: code = 0x77; break; // F3
+ case 0x55: code = 0x78; break; // F4
+ case 0x56: code = 0x79; break; // F5
+ case 0x57: code = 0x7a; break; // F6
+ case 0x58: code = 0x7b; break; // F7
+ case 0x59: code = 0x7c; break; // F8
+ case 0x5a: code = 0x7d; break; // F9
+ case 0x5b: code = 0x74; break; // F0 = F10
+ }
+ }
+#endif
+
+ index = (code & 0x7f) * CODE_TABLE_ENTRY_SIZE;
+ if (m_mode == KBD_MODE_0_COMPATIBILITY)
+ {
+ if (code & 0x80)
+ {
+ // skip up code in ASCII mode
+ }
+ else if (repeat > 0
+ && m_code_table[index + CODE_TABLE_AUTO_REPEAT_CODE] != Yes)
+ {
+ // skip repeat in ASCII mode
+ }
+ else if (ctrl)
+ {
+ key_code = m_code_table[index + CODE_TABLE_CONTROL_CODE];
+ }
+ else if (shift)
+ {
+ key_code = m_code_table[index + CODE_TABLE_SHIFTED_CODE];
+ }
+ else if (caps)
+ {
+ key_code = m_code_table[index + CODE_TABLE_CAPS_LOCK_CODE];
+ }
+ else
+ {
+ key_code = m_code_table[index + CODE_TABLE_UNSHIFTED_CODE];
+ }
+ }
+ else
+ {
+ if (repeat > 0)
+ {
+ if (repeat == 1)
+ {
+ // auto repeat (but only for first scanned key)
+ key_code = 0x7f;
+ }
+ }
+ else if (code & 0x80)
+ {
+ key_code = m_code_table[index + CODE_TABLE_UP_CODE];
+ }
+ else
+ {
+ key_code = m_code_table[index + CODE_TABLE_DOWN_CODE];
+ }
+ }
+
+ if (key_code != 0)
+ {
+ LOG2(("scan_code = 0x%02x key_code = 0x%04x",code, key_code));
+ if (m_mode > KBD_MODE_1_KEYSTATE)
+ {
+ set_mode(KBD_MODE_1_KEYSTATE);
+ }
+
+ if (key_code & 0xff00)
+ {
+ putchar(key_code >> 8);
+ n_chars++;
+ }
+ putchar(key_code & 0xff);
+ n_chars++;
+ }
+ return n_chars;
+}
+
+void apollo_kbd_device::scan_keyboard()
+{
+ int x;
+ int repeat = 0;
+
+ static const char * const keynames[] = { "keyboard1", "keyboard2", "keyboard3", "keyboard4" };
+
+ for (x = 0; x < 0x80; x++)
+ {
+ if (!(machine().root_device().ioport(keynames[x / 32])->read() & (1 << (x % 32))))
+ {
+ // no key pressed
+ if (m_keyon[x] != 0)
+ {
+ // a key has been released
+ push_scancode(0x80 + x, 0);
+ m_keytime[x] = 0;
+ m_keyon[x] = 0;
+ m_last_pressed = 0;
+ LOG2(("released key 0x%02x at time %d",x, m_keytime[x]));
+ }
+ }
+ else if (m_keyon[x] == 0)
+ {
+ // a key has been pressed
+ if (push_scancode(x, 0) > 0)
+ {
+ m_keytime[x] = m_mode == KBD_MODE_0_COMPATIBILITY ? m_delay : m_repeat;
+ m_keyon[x] = 1;
+ m_last_pressed = x;
+ LOG2(("pushed key 0x%02x at time %d",x, m_keytime[x]));
+ }
+ }
+ else if (m_last_pressed == x)
+ {
+ // a key is being held; adjust delay/repeat timers
+ m_keytime[x] -= 5;
+ if (m_keytime[x] <= 0)
+ {
+ push_scancode(x, ++repeat);
+ m_keytime[x] = m_repeat;
+ }
+ LOG2(("holding key 0x%02x at time %d",x, m_keytime[x]));
+ }
+ }
+}
+
+void apollo_kbd_device::poll_callback()
+{
+ int data;
+ while ((data = m_keyboard_tty.getchar()) >= 0)
+ {
+ putchar(data);
+ }
+ scan_keyboard();
+
+ // Note: we omit extra traffic while keyboard is in Compatibitlit mode
+ if (m_device->m_mode != KBD_MODE_0_COMPATIBILITY)
+ {
+ m_mouse.read_mouse();
+ }
+}
+
+TIMER_CALLBACK( apollo_kbd_device::static_poll_callback )
+{
+ reinterpret_cast<apollo_kbd_device *> (ptr)->poll_callback();
+}
+
+UINT16 apollo_kbd_device::m_code_table[] = {
+
+ /* Key | Keycap | Down | Up |Unshifted|Shifted|Control|Caps Lock|Up Trans|Auto */
+ /* Number| Legend | Code | Code|Code | Code | Code |Code | Code |Repeat*/
+
+ /* B14 ~ ' / ESC */ 0x24, 0xA4, 0x60, 0x7E, 0x1E, 0x60, NOP, No,
+ /* B1 ESC */ 0x17, 0x97, 0x1B, 0x1B, NOP, 0x1B, NOP, No,
+ /* B2 ! 1 */ 0x18, 0x98, 0x31, 0x21, NOP, 0x31, NOP, No,
+ /* B3 @ 2 */ 0x19, 0x99, 0x32, 0x40, NOP, 0x32, NOP, No,
+ /* B4 # 3 */ 0x1A, 0x9A, 0x33, 0x23, NOP, 0x33, NOP, No,
+ /* B5 $ 4 */ 0x1B, 0x9B, 0x34, 0x24, NOP, 0x34, NOP, No,
+ /* B6 % 5 */ 0x1C, 0x9C, 0x35, 0x25, NOP, 0x35, NOP, No,
+ /* B7 ^ 6 */ 0x1D, 0x9D, 0x36, 0x5E, NOP, 0x36, NOP, No,
+ /* B8 & 7 */ 0x1E, 0x9E, 0x37, 0x26, NOP, 0x37, NOP, No,
+ /* B9 * 8 */ 0x1F, 0x9F, 0x38, 0x2A, NOP, 0x38, NOP, No,
+ /* B10 ( 9 */ 0x20, 0xA0, 0x39, 0x28, NOP, 0x39, NOP, No,
+ /* B11 ) 0 */ 0x21, 0xA1, 0x30, 0x29, NOP, 0x30, NOP, No,
+ /* B12 _ - */ 0x22, 0xA2, 0x2D, 0x5F, NOP, 0x2D, NOP, Yes,
+ /* B13 + = */ 0x23, 0xA3, 0x3D, 0x2B, NOP, 0x3D, NOP, Yes,
+ /* B14 ~ ' / BS */ 0x24, 0xA4, 0x60, 0x7E, 0x1E, 0x60, NOP, No,
+ /* B15 BACKSPACE */ 0x25, 0xA5, 0xDE, 0xDE, NOP, 0xDE, NOP, Yes,
+
+ /* C1 TAB */ 0x2C, 0xAC, 0xCA, 0xDA, 0xFA, 0xCA, NOP, No,
+ /* C2 Q */ 0x2D, 0xAD, 0x71, 0x51, 0x11, 0x51, NOP, No,
+ /* C3 W */ 0x2E, 0xAE, 0x77, 0x57, 0x17, 0x57, NOP, No,
+ /* C4 E */ 0x2F, 0xAF, 0x65, 0x45, 0x05, 0x45, NOP, No,
+ /* C5 R */ 0x30, 0xB0, 0x72, 0x52, 0x12, 0x52, NOP, No,
+ /* C6 T */ 0x31, 0xB1, 0x74, 0x54, 0x14, 0x54, NOP, No,
+ /* C7 V */ 0x32, 0xB2, 0x79, 0x59, 0x19, 0x59, NOP, No,
+ /* C8 U */ 0x33, 0xB3, 0x75, 0x55, 0x15, 0x55, NOP, No,
+ /* C9 I */ 0x34, 0xB4, 0x69, 0x49, 0x09, 0x49, NOP, No,
+ /* C10 O */ 0x35, 0xB5, 0x6F, 0x4F, 0x0F, 0x4F, NOP, No,
+ /* C11 P */ 0x36, 0xB6, 0x70, 0x50, 0x10, 0x50, NOP, No,
+ /* C12 { [ / Ue */ 0x37, 0xB7, 0x7B, 0x5B, 0x1B, 0x7B, NOP, No,
+ /* C13 } ] / Oe */ 0x38, 0xB8, 0x7D, 0x5D, 0x1D, 0x7D, NOP, No,
+ /* D13 RETURN */ 0x52, 0xD2, 0xCB, 0xDB, NOP, 0xCB, NOP, No,
+
+ /* D2 A */ 0x46, 0xC6, 0x61, 0x41, 0x01, 0x41, NOP, No,
+ /* D3 S */ 0x47, 0xC7, 0x73, 0x53, 0x13, 0x53, NOP, No,
+ /* D4 D */ 0x48, 0xC8, 0x64, 0x44, 0x04, 0x44, NOP, No,
+ /* D5 F */ 0x49, 0xC9, 0x66, 0x46, 0x06, 0x46, NOP, No,
+ /* D6 G */ 0x4A, 0xCA, 0x67, 0x47, 0x07, 0x47, NOP, No,
+ /* D7 H */ 0x4B, 0xCB, 0x68, 0x48, 0x08, 0x48, NOP, No,
+ /* D8 J */ 0x4C, 0xCC, 0x6A, 0x4A, 0x0A, 0x4A, NOP, No,
+ /* D9 K */ 0x4D, 0xCD, 0x6B, 0x4B, 0x0B, 0x4B, NOP, No,
+ /* D10 L */ 0x4E, 0xCE, 0x6C, 0x4C, 0x0C, 0x4C, NOP, No,
+ /* D11 : ; */ 0x4F, 0xCF, 0x3B, 0x3A, 0xFB, 0x3B, NOP, No,
+ /* D12 " ' / Ae */ 0x50, 0xD0, 0x27, 0x22, 0xF8, 0x27, NOP, No,
+ /* D14 ! \ */ 0x53, 0xD3, 0xC8, 0xC9, NOP, 0xC8, NOP, No,
+
+ /* E2 Z */ 0x60, 0xE0, 0x7A, 0x5A, 0x1A, 0x5A, NOP, No,
+ /* E3 X */ 0x61, 0xE1, 0x78, 0x58, 0x18, 0x58, NOP, No,
+ /* E4 C */ 0x62, 0xE2, 0x63, 0x43, 0x03, 0x43, NOP, No,
+ /* E5 V */ 0x63, 0xE3, 0x76, 0x56, 0x16, 0x56, NOP, No,
+ /* E6 8 */ 0x64, 0xE4, 0x62, 0x42, 0x02, 0x42, NOP, No,
+ /* E7 N */ 0x65, 0xE5, 0x6E, 0x4E, 0x0E, 0x4E, NOP, No,
+ /* E8 M */ 0x66, 0xE6, 0x6D, 0x4D, 0x0D, 0x4D, NOP, No,
+ /* E9 < , */ 0x67, 0xE7, 0x2C, 0x3C, NOP, 0x2C, NOP, No,
+ /* E10 > . */ 0x68, 0xE8, 0x2E, 0x3E, NOP, 0x2E, NOP, Yes,
+ /* E11 ? / */ 0x69, 0xE9, 0xCC, 0xDC, 0xFC, 0xCC, NOP, No,
+
+// /* B14 ~ ' */ 0x24, 0xA4, 0x60, 0x7E, 0x1E, 0x60, NOP, No,
+ /* _ */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP,
+ /* F1 (space bar) */ 0x76, 0xF6, 0x20, 0x20, 0x20, 0x20, NOP, Yes,
+ /* LC0 Home */ 0x27, 0xA7, 0x84, 0x94, 0x84, 0x84, 0xA4, No,
+#if !MAP_APOLLO_KEYS
+ /* C14 DELETE */ 0x3A, 0xBA, 0x7F, 0x7F, NOP, 0x7F, NOP, Yes,
+#else
+ /* E13 POP */ 0x6C, 0xEC, 0x80, 0x90, 0x80, 0x80, 0xA0, No,
+#endif
+ /* LF0 Roll Up */ 0x72, 0xF2, 0x8D, 0x9D, 0x8D, 0x8D, 0xAD, No,
+ /* LF2 Roll Down */ 0x74, 0xF4, 0x8F, 0x9F, 0x8F, 0x8F, 0xAF, No,
+ /* LC2 End */ 0x29, 0xA9, 0x86, 0x96, 0x86, 0x86, 0xA6, No,
+ /* LE0 Cursor left */ 0x59, 0xD9, 0x8A, 0x9A, 0x9A, 0x9A, 0xAA, Yes,
+ /* LD1 Cursor Up */ 0x41, 0xC1, 0x88, 0x98, 0x88, 0x88, 0xA8, Yes,
+ /* LE2 Cursor right*/ 0x5B, 0xDB, 0x8C, 0x9C, 0x8C, 0xBE, 0xAC, Yes,
+ /* LF1 Cursor down */ 0x73, 0xF3, 0x8E, 0x9E, 0x8E, 0x8E, 0xAE, Yes,
+
+#if !MAP_APOLLO_KEYS
+ /* Numpad CLR */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP,
+ /* Numpad / */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP,
+ /* Numpad * */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP,
+ /* RD4 - */ 0x58, 0xD8, 0xFE2D, 0xFE5F, NOP, 0xFE2D, NOP, No,
+ /* RC1 7 */ 0x3C, 0xBC, 0xFE37, 0xFE26, NOP, 0xFE37, NOP, No,
+ /* RC2 8 */ 0x3D, 0xBD, 0xFE38, 0xFE2A, NOP, 0xFE38, NOP, No,
+ /* RC3 9 */ 0x3E, 0xBE, 0xFE39, 0xFE28, NOP, 0xFE39, NOP, No,
+ /* RC4 + */ 0x3F, 0xBF, 0xFE2B, 0xFE3D, NOP, 0xFE2B, NOP, No,
+ /* RD1 4 */ 0x55, 0xD5, 0xFE34, 0xFE24, NOP, 0xFE34, NOP, No,
+ /* RD2 5 */ 0x56, 0xD6, 0xFE35, 0xFE25, NOP, 0xFE35, NOP, No,
+ /* RD3 6 */ 0x57, 0xD7, 0xFE36, 0xFE5E, NOP, 0xFE36, NOP, No,
+ /* Numpad = */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP,
+ /* RE1 1 */ 0x6E, 0xEE, 0xFE31, 0xFE21, NOP, 0xFE31, NOP, No,
+ /* RE2 2 */ 0x6F, 0xEF, 0xFE32, 0xFE40, NOP, 0xFE32, NOP, No,
+ /* RE3 3 */ 0x70, 0xF0, 0xFE33, 0xFE23, NOP, 0xFE33, NOP, No,
+ /* RF3 ENTER */ 0x7C, 0xFC, 0xFECB, 0xFEDB, NOP, 0xFECB, NOP, No,
+ /* RF1 0 */ 0x79, 0xF9, 0xFE30, 0xFE29, NOP, 0xFE30, NOP, No,
+ /* Numpad , */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP,
+ /* RF2 . */ 0x7B, 0xFB, 0xFE2E, 0xFE2E, NOP, 0xFE2E, NOP, No,
+ /* A0 F0 */ 0x04, 0x84, 0x1C, 0x5C, 0x7C, 0x1C, 0xBC, No,
+ /* A1 F1 */ 0x05, 0x85, 0xC0, 0xD0, 0xF0, 0xC0, 0xE0, No,
+ /* A2 F2 */ 0x06, 0x86, 0xC1, 0x01, 0xF1, 0xC1, 0xE1, No,
+ /* A3 F3 */ 0x07, 0x87, 0xC2, 0x02, 0xF2, 0xC2, 0xE2, No,
+ /* A4 F4 */ 0x08, 0x88, 0xC3, 0x03, 0xF3, 0xC3, 0xE3, No,
+ /* A5 F5 */ 0x09, 0x89, 0xC4, 0x04, 0xF4, 0xC4, 0xE4, No,
+ /* A6 F6 */ 0x0A, 0x8A, 0xC5, 0x05, 0xF5, 0xC5, 0xE5, No,
+ /* A7 F7 */ 0x0B, 0x8B, 0xC6, 0x06, 0xF6, 0xC6, 0xE6, No,
+ /* A8 F8 */ 0x0C, 0x8C, 0xC7, 0x07, 0xF7, 0xC7, 0xE7, No,
+ /* A9 F9 */ 0x0D, 0x8D, 0x1F, 0x2F, 0x3F, 0x1F, 0xBD, No,
+#else
+ /* E13 POP */ 0x6C, 0xEC, 0x80, 0x90, 0x80, 0x80, 0xA0, No,
+ /* LDO [<-] */ 0x40, 0xC0, 0x87, 0x97, 0x87, 0x87, 0xA7, No,
+ /* LD2 [->] */ 0x42, 0xC2, 0x89, 0x99, 0x89, 0x89, 0xA9, No,
+ /* RD4 Numpad - */ 0x58, 0xD8, 0xFE2D, 0xFE5F, NOP, 0xFE2D, NOP, No,
+ /* LC0 7 Home */ 0x27, 0xA7, 0x84, 0x94, 0x84, 0x84, 0xA4, No,
+ /* LD1 8 Cursor Up */ 0x41, 0xC1, 0x88, 0x98, 0x88, 0x88, 0xA8, Yes,
+ /* LF0 9 Roll Up */ 0x72, 0xF2, 0x8D, 0x9D, 0x8D, 0x8D, 0xAD, No,
+ /* RC4 Numpad + */ 0x3F, 0xBF, 0xFE2B, 0xFE3D, NOP, 0xFE2B, NOP, No,
+ /* LE0 4 Cursor left */ 0x59, 0xD9, 0x8A, 0x9A, 0x9A, 0x9A, 0xAA, Yes,
+ /* LE1 NEXT WINDOW */ 0x5A, 0xDA, 0x8B, 0x9B, 0x8B, 0x8B, 0xAB, No,
+ /* LE2 6 Cursor right*/ 0x5B, 0xDB, 0x8C, 0x9C, 0x8C, 0xBE, 0xAC, Yes,
+ /* Numpad = */ 0x7C, 0xFC, 0xFEC8, 0xFED8, NOP, 0xFECB, NOP, No,
+ /* LC2 1 End */ 0x29, 0xA9, 0x86, 0x96, 0x86, 0x86, 0xA6, No,
+ /* LF1 2 Cursor down */ 0x73, 0xF3, 0x8E, 0x9E, 0x8E, 0x8E, 0xAE, Yes,
+ /* LF2 3 Roll Down */ 0x74, 0xF4, 0x8F, 0x9F, 0x8F, 0x8F, 0xAF, No,
+ /* RF3 ENTER */ 0x7C, 0xFC, 0xFECB, 0xFEDB, NOP, 0xFECB, NOP, No,
+ /* LE1 NEXT WINDOW */ 0x5A, 0xDA, 0x8B, 0x9B, 0x8B, 0x8B, 0xAB, No,
+ /* Numpad , */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP,
+ /* E13 POP */ 0x6C, 0xEC, 0x80, 0x90, 0x80, 0x80, 0xA0, No,
+
+ /* LC1 F1/SHELL/CMD */ 0x28, 0xA8, 0x85, 0x95, 0x85, 0x85, 0xA5, No,
+ /* LB0 F2/CUT/COPY */ 0x13, 0x93, 0xB0, 0xB4, 0xB0, 0xB0, 0xB8, No,
+ /* LB1 F3/UNDO/PASTE */ 0x14, 0x94, 0xB1, 0xB5, 0xB1, 0xB1, 0xB9, No,
+ /* LB2 F4/MOVE/GROW */ 0x15, 0x95, 0xB2, 0xB6, 0xB2, 0xB2, 0xBA, No,
+
+ /* LAO F5/INS/MARK */ 0x01, 0x81, 0x81, 0x91, 0x81, 0x81, 0xA1, No,
+ /* LA1 F6/LINE DEL */ 0x02, 0x82, 0x82, 0x92, 0x82, 0x82, 0xA2, No,
+ /* LA2 F7/CHAR DEL */ 0x03, 0x83, 0x83, 0x93, 0x83, 0x83, 0xA3, Yes,
+ /* RA0 F8/AGAIN */ 0x0E, 0x8E, 0xCD, 0xE9, 0xCD, 0xCD, 0xED, No,
+
+ /* RA1 F9/READ */ 0x0F, 0x8F, 0xCE, 0xEA, 0xCE, 0xCE, 0xEE, No,
+ /* RA2 F10/SAVE/EDIT */ 0x10, 0x90, 0xCF, 0xEB, 0xCF, 0xCF, 0xEF, No,
+#endif
+ /* RA3 F11/ABORT/EXIT */ 0x11, 0x91, 0xDD, 0xEC, 0xD0, 0xD0, 0xFD, No,
+ /* RA4 F12/HELP/HOLD */ 0x12, 0x92, 0xB3, 0xB7, 0xB3, 0xB3, 0xBB, No,
+
+ /* LE1 NEXT WINDOW */ 0x5A, 0xDA, 0x8B, 0x9B, 0x8B, 0x8B, 0xAB, No,
+ /* LE1 NEXT WINDOW */ 0x5A, 0xDA, 0x8B, 0x9B, 0x8B, 0x8B, 0xAB, No,
+
+ /* D1 CAPS LOCK */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP,
+ /* E1 SHIFT */ 0x5E, 0xDE, NOP, NOP, NOP, NOP, NOP, NOP,
+ /* DO CTRL */ 0x43, 0xC3, NOP, NOP, NOP, NOP, NOP, NOP,
+// FIXME: ALT swapped!
+ /* ?? ALT_R */ 0x77, 0xF7, 0xfe00, NOP, NOP, NOP, 0xfe01, No,
+ /* ?? ALT_L */ 0x75, 0xF5, 0xfe02, NOP, NOP, NOP, 0xfe03, No,
+ /* E12 SHIFT */ 0x6A, 0xEA, NOP, NOP, NOP, NOP, NOP, NOP,
+// not yet used:
+ /* E0 REPEAT */ 0x5D, 0xDD, NOP, NOP, NOP, NOP, NOP, NOP,
+ /* CAPS LOCK LED*/ 0x7E, 0xFE, NOP, NOP, NOP, NOP, NOP, NOP,
+// german kbd:
+ /* 0x68 B1_DE _ */ 0x17, 0x97, 0x60, 0x7E, 0x1E, 0x60, NOP, No,
+ /* 0x69 E1a_DE <> */ 0x5F, 0xDF, 0xBE, 0xBE, NOP, 0xBE, NOP, No,
+ /* 0x6a B14_DE ESC */ 0x16, 0x96, 0x1B, 0x1B, NOP, 0x1B, NOP, No,
+ /* 0x6b D14_DE # \ */ 0x51, 0xD1, 0xC8, 0xC9, NOP, 0xC8, NOP, No,
+
+ /* 0x6c NPG NP ( */ 0x3F, 0xBF, 0xFE28, 0xFE0E, NOP, 0xFE28, NOP, No,
+ /* 0x6d NPF NP ) */ 0x58, 0xD8, 0xFE29, 0xFE0F, NOP, 0xFE29, NOP, No,
+ /* 0x6e NPD NP + */ 0x3B, 0xBB, 0xFE2B, 0xFE26, NOP, 0xFE2B, NOP, No,
+ /* 0x6f NPC NP - */ 0x54, 0xD4, 0xFE2D, 0xFE7E, NOP, 0xFE2D, NOP, No,
+ /* 0x70 NPB NP * */ 0x6D, 0xED, 0xFE2A, 0xFE21, NOP, 0xFE2A, NOP, No,
+ /* 0x71 NPA NP / */ 0x78, 0xF8, 0xFECC, 0xFEC8, NOP, 0xFECC, NOP, No,
+ /* 0x72 NPP NP . */ 0x7B, 0xFB, 0xFE2E, 0xFE2C, NOP, 0xFE2E, NOP, No,
+ /* 0x73 NPE ENTER */ 0x7C, 0xFC, 0xFECB, 0xFE3D, NOP, 0xFECB, NOP, No,
+
+ /* 0x74 A0 F0 */ 0x04, 0x84, 0x1C, 0x5C, 0x7C, 0x1C, 0xBC, No,
+ /* 0x75 A1 F1 */ 0x05, 0x85, 0xC0, 0xD0, 0xF0, 0xC0, 0xE0, No,
+ /* 0x76 A2 F2 */ 0x06, 0x86, 0xC1, 0x01, 0xF1, 0xC1, 0xE1, No,
+ /* 0x77 A3 F3 */ 0x07, 0x87, 0xC2, 0x02, 0xF2, 0xC2, 0xE2, No,
+ /* 0x78 A4 F4 */ 0x08, 0x88, 0xC3, 0x03, 0xF3, 0xC3, 0xE3, No,
+ /* 0x79 A5 F5 */ 0x09, 0x89, 0xC4, 0x04, 0xF4, 0xC4, 0xE4, No,
+ /* 0x7a A6 F6 */ 0x0A, 0x8A, 0xC5, 0x05, 0xF5, 0xC5, 0xE5, No,
+ /* 0x7b A7 F7 */ 0x0B, 0x8B, 0xC6, 0x06, 0xF6, 0xC6, 0xE6, No,
+ /* 0x7c A8 F8 */ 0x0C, 0x8C, 0xC7, 0x07, 0xF7, 0xC7, 0xE7, No,
+ /* 0x7d A9 F9 */ 0x0D, 0x8D, 0x1F, 0x2F, 0x3F, 0x1F, 0xBD, No,
+
+ /* Key | Keycap | Down | Up |Unshifted|Shifted|Control|Caps Lock|Up Trans|Auto */
+ /* Number| Legend | Code | Code|Code | Code | Code |Code | Code |Repeat*/
+};
+
+INPUT_PORTS_START( apollo_kbd )
+
+ PORT_START( "keyboard1" )
+ PORT_BIT( 0x00000001, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("~ '") PORT_CODE(KEYCODE_TILDE) /* ESC */
+ PORT_BIT( 0x00000002, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("ESC") PORT_CODE(KEYCODE_ESC) /* ESC */
+ PORT_BIT( 0x00000004, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("1 !") PORT_CODE(KEYCODE_1) /* 1 ! */
+ PORT_BIT( 0x00000008, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("2 \"") PORT_CODE(KEYCODE_2) /* 2 " */
+ PORT_BIT( 0x00000010, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("3 #") PORT_CODE(KEYCODE_3) /* 3 # */
+ PORT_BIT( 0x00000020, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("4 $") PORT_CODE(KEYCODE_4) /* 4 $ */
+ PORT_BIT( 0x00000040, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("5 %") PORT_CODE(KEYCODE_5) /* 5 % */
+ PORT_BIT( 0x00000080, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("6 &") PORT_CODE(KEYCODE_6) /* 6 & */
+ PORT_BIT( 0x00000100, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("7 \'") PORT_CODE(KEYCODE_7) /* 7 ' */
+ PORT_BIT( 0x00000200, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("8 (") PORT_CODE(KEYCODE_8) /* 8 ( */
+ PORT_BIT( 0x00000400, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("9 )") PORT_CODE(KEYCODE_9) /* 9 ) */
+ PORT_BIT( 0x00000800, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("0") PORT_CODE(KEYCODE_0) /* 0 */
+ PORT_BIT( 0x00001000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("- _") PORT_CODE(KEYCODE_MINUS) /* - _ */
+ PORT_BIT( 0x00002000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("= +") PORT_CODE(KEYCODE_EQUALS) /* = + */
+ PORT_BIT( 0x00004000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("@ ^") PORT_CODE(KEYCODE_BACKSLASH2) /* ~ ` */
+ PORT_BIT( 0x00008000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSPACE) /* Backspace */
+ PORT_BIT( 0x00010000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TAB) /* Tab */
+ PORT_BIT( 0x00020000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Q") PORT_CODE(KEYCODE_Q) /* Q */
+ PORT_BIT( 0x00040000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("W") PORT_CODE(KEYCODE_W) /* W */
+ PORT_BIT( 0x00080000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("E") PORT_CODE(KEYCODE_E) /* E */
+ PORT_BIT( 0x00100000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("R") PORT_CODE(KEYCODE_R) /* R */
+ PORT_BIT( 0x00200000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("T") PORT_CODE(KEYCODE_T) /* T */
+ PORT_BIT( 0x00400000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Y") PORT_CODE(KEYCODE_Y) /* Y */
+ PORT_BIT( 0x00800000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("U") PORT_CODE(KEYCODE_U) /* U */
+ PORT_BIT( 0x01000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("I") PORT_CODE(KEYCODE_I) /* I */
+ PORT_BIT( 0x02000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("O") PORT_CODE(KEYCODE_O) /* O */
+ PORT_BIT( 0x04000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("P") PORT_CODE(KEYCODE_P) /* P */
+ PORT_BIT( 0x08000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("[ {") PORT_CODE(KEYCODE_OPENBRACE) /* [ { */
+ PORT_BIT( 0x10000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("] }") PORT_CODE(KEYCODE_CLOSEBRACE) /* ] } */
+ PORT_BIT( 0x20000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ENTER) /* Return */
+ PORT_BIT( 0x40000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("A") PORT_CODE(KEYCODE_A) /* A */
+ PORT_BIT( 0x80000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("S") PORT_CODE(KEYCODE_S) /* S */
+
+ PORT_START( "keyboard2" )
+ PORT_BIT( 0x00000001, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("D") PORT_CODE(KEYCODE_D) /* D */
+ PORT_BIT( 0x00000002, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F") PORT_CODE(KEYCODE_F) /* F */
+ PORT_BIT( 0x00000004, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("G") PORT_CODE(KEYCODE_G) /* G */
+ PORT_BIT( 0x00000008, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("H") PORT_CODE(KEYCODE_H) /* H */
+ PORT_BIT( 0x00000010, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("J") PORT_CODE(KEYCODE_J) /* J */
+ PORT_BIT( 0x00000020, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("K") PORT_CODE(KEYCODE_K) /* K */
+ PORT_BIT( 0x00000040, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("L") PORT_CODE(KEYCODE_L) /* L */
+ PORT_BIT( 0x00000080, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("; +") PORT_CODE(KEYCODE_COLON) /* ; + */
+ PORT_BIT( 0x00000100, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(": *") PORT_CODE(KEYCODE_QUOTE) /* : * */
+ PORT_BIT( 0x00000200, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("\\ |") PORT_CODE(KEYCODE_BACKSLASH) /* \\ | */
+ PORT_BIT( 0x00000400, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Z") PORT_CODE(KEYCODE_Z) /* Z */
+ PORT_BIT( 0x00000800, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("X") PORT_CODE(KEYCODE_X) /* X */
+ PORT_BIT( 0x00001000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("C") PORT_CODE(KEYCODE_C) /* C */
+ PORT_BIT( 0x00002000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("V") PORT_CODE(KEYCODE_V) /* V */
+ PORT_BIT( 0x00004000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("B") PORT_CODE(KEYCODE_B) /* B */
+ PORT_BIT( 0x00008000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("N") PORT_CODE(KEYCODE_N) /* N */
+ PORT_BIT( 0x00010000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("M") PORT_CODE(KEYCODE_M) /* M */
+ PORT_BIT( 0x00020000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(", <") PORT_CODE(KEYCODE_COMMA) /* , < */
+ PORT_BIT( 0x00040000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(". >") PORT_CODE(KEYCODE_STOP) /* . > */
+ PORT_BIT( 0x00080000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("/ ?") PORT_CODE(KEYCODE_SLASH) /* / ? */
+//??
+ PORT_BIT( 0x00100000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("~ '") PORT_CODE(KEYCODE_TILDE) /* Underscore (shifted only?) */
+ PORT_BIT( 0x00200000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Space") PORT_CODE(KEYCODE_SPACE) /* Space */
+ PORT_BIT( 0x00400000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Home") PORT_CODE(KEYCODE_HOME) /* Home */
+ PORT_BIT( 0x00800000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Delete") PORT_CODE(KEYCODE_DEL) /* Del */
+ PORT_BIT( 0x01000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Roll Up") PORT_CODE(KEYCODE_PGUP) /* Roll Up */
+ PORT_BIT( 0x02000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Roll Down") PORT_CODE(KEYCODE_PGDN) /* Roll Down */
+ PORT_BIT( 0x04000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("End") PORT_CODE(KEYCODE_END) /* End */
+ PORT_BIT( 0x08000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Cursor Left") PORT_CODE(KEYCODE_LEFT) /* Left */
+ PORT_BIT( 0x10000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Cursor Up") PORT_CODE(KEYCODE_UP) /* Up */
+ PORT_BIT( 0x20000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Cursor Right") PORT_CODE(KEYCODE_RIGHT) /* Right */
+ PORT_BIT( 0x40000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Cursor Down") PORT_CODE(KEYCODE_DOWN) /* Down */
+// PORT_BIT( 0x80000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad CLR") PORT_CODE(KEYCODE_NUMLOCK) /* CLR */
+ PORT_BIT( 0x80000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("MENU") PORT_CODE(KEYCODE_MENU) /* Menu = POP */
+
+ PORT_START( "keyboard3" )
+ PORT_BIT( 0x00000001, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad /") PORT_CODE(KEYCODE_SLASH_PAD) /* / (numpad) */
+ PORT_BIT( 0x00000002, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad *") PORT_CODE(KEYCODE_ASTERISK) /* * (numpad) */
+ PORT_BIT( 0x00000004, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad -") PORT_CODE(KEYCODE_MINUS_PAD) /* - (numpad) */
+ PORT_BIT( 0x00000008, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad 7") PORT_CODE(KEYCODE_7_PAD) /* 7 (numpad) */
+ PORT_BIT( 0x00000010, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad 8") PORT_CODE(KEYCODE_8_PAD) /* 8 (numpad) */
+ PORT_BIT( 0x00000020, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad 9") PORT_CODE(KEYCODE_9_PAD) /* 9 (numpad) */
+ PORT_BIT( 0x00000040, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad +") PORT_CODE(KEYCODE_PLUS_PAD) /* + (numpad) */
+ PORT_BIT( 0x00000080, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad 4") PORT_CODE(KEYCODE_4_PAD) /* 4 (numpad) */
+ PORT_BIT( 0x00000100, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad 5") PORT_CODE(KEYCODE_5_PAD) /* 5 (numpad) */
+ PORT_BIT( 0x00000200, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad 6") PORT_CODE(KEYCODE_6_PAD) /* 6 (numpad) */
+ PORT_BIT( 0x00000400, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad =") /* = (numpad) */
+ PORT_BIT( 0x00000800, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad 1") PORT_CODE(KEYCODE_1_PAD) /* 1 (numpad) */
+ PORT_BIT( 0x00001000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad 2") PORT_CODE(KEYCODE_2_PAD) /* 2 (numpad) */
+ PORT_BIT( 0x00002000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad 3") PORT_CODE(KEYCODE_3_PAD) /* 3 (numpad) */
+ PORT_BIT( 0x00004000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad Enter") PORT_CODE(KEYCODE_ENTER_PAD) /* Enter (numpad) */
+ PORT_BIT( 0x00008000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad 0") PORT_CODE(KEYCODE_0_PAD) /* 0 (numpad) */
+ PORT_BIT( 0x00010000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad ,") /* , (numpad) */
+ PORT_BIT( 0x00020000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad .") PORT_CODE(KEYCODE_DEL_PAD) /* 2 (numpad) */
+
+ PORT_BIT( 0x00040000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F1") PORT_CODE(KEYCODE_F1) /* F1 */
+ PORT_BIT( 0x00080000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F2") PORT_CODE(KEYCODE_F2) /* F2 */
+ PORT_BIT( 0x00100000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F3") PORT_CODE(KEYCODE_F3) /* F3 */
+ PORT_BIT( 0x00200000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F4") PORT_CODE(KEYCODE_F4) /* F4 */
+ PORT_BIT( 0x00400000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F5") PORT_CODE(KEYCODE_F5) /* F5 */
+ PORT_BIT( 0x00800000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F6") PORT_CODE(KEYCODE_F6) /* F6 */
+ PORT_BIT( 0x01000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F7") PORT_CODE(KEYCODE_F7) /* F7 */
+ PORT_BIT( 0x02000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F8") PORT_CODE(KEYCODE_F8) /* F8 */
+ PORT_BIT( 0x04000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F9") PORT_CODE(KEYCODE_F9) /* F9 */
+ PORT_BIT( 0x08000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F10") PORT_CODE(KEYCODE_F10) /* F10 */
+ PORT_BIT( 0x10000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F11") PORT_CODE(KEYCODE_F11) /* F11 */
+ PORT_BIT( 0x20000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F12") PORT_CODE(KEYCODE_F12) /* F12 */
+ PORT_BIT( 0x40000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Insert") PORT_CODE(KEYCODE_INSERT) /* Insert */
+// PORT_BIT( 0x80000000, 0x0000, IPT_UNUSED )
+ PORT_BIT( 0x80000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("WIN_R") PORT_CODE(KEYCODE_RWIN) /* Windows Right = Next Window */
+
+ PORT_START( "keyboard4" )
+
+ PORT_BIT( 0x00000001, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Caps") PORT_CODE(KEYCODE_CAPSLOCK) /* Caps lock */
+ PORT_BIT( 0x00000002, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Shift") PORT_CODE(KEYCODE_LSHIFT) /* Shift */
+ PORT_BIT( 0x00000004, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Ctrl") PORT_CODE(KEYCODE_LCONTROL) PORT_CODE(KEYCODE_RCONTROL) /* Ctrl */
+ PORT_BIT( 0x00000008, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("ALT_L") PORT_CODE(KEYCODE_LALT) /* ALT */
+ PORT_BIT( 0x00000010, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("ALT_R") PORT_CODE(KEYCODE_RALT) /* ALT GR */
+ PORT_BIT( 0x00000020, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Shift") PORT_CODE(KEYCODE_RSHIFT) /* Shift */
+ PORT_BIT( 0x00000040, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Num Lock") PORT_CODE(KEYCODE_NUMLOCK) /* Num Lock */
+
+ PORT_START("mouse1") // mouse buttons
+ PORT_BIT( 0x00000010, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Left mouse button") PORT_CODE(MOUSECODE_BUTTON1)
+ PORT_BIT( 0x00000020, IP_ACTIVE_HIGH, IPT_BUTTON3) PORT_NAME("Right mouse button") PORT_CODE(MOUSECODE_BUTTON3)
+ PORT_BIT( 0x00000040, IP_ACTIVE_HIGH, IPT_BUTTON2) PORT_NAME("Center mouse button") PORT_CODE(MOUSECODE_BUTTON2)
+
+ PORT_START("mouse2") // X-axis
+ PORT_BIT( 0xfff, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1)
+
+ PORT_START("mouse3") // Y-axis
+ PORT_BIT( 0xfff, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1)
+
+INPUT_PORTS_END
diff --git a/src/mess/machine/apollo_kbd.h b/src/mess/machine/apollo_kbd.h
new file mode 100644
index 00000000000..eb8fff90752
--- /dev/null
+++ b/src/mess/machine/apollo_kbd.h
@@ -0,0 +1,201 @@
+/*
+ * apollo_kbd.h
+ *
+ * Created on: Dec 27, 2010
+ * Author: Hans Ostermeyer
+ *
+ * Released for general non-commercial use under the MAME license
+ * Visit http://mamedev.org for licensing and usage restrictions.
+ *
+ */
+
+#pragma once
+
+#ifndef __APOLLO_KBD_H__
+#define __APOLLO_KBD_H__
+
+#include "emu.h"
+
+// BSD-derived systems get very sad when you party with system reserved names.
+#ifdef getchar
+#undef getchar
+#endif
+
+#ifdef putchar
+#undef putchar
+#endif
+
+#define TX_FIFO_SIZE 128
+
+//**************************************************************************
+// DEVICE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_APOLLO_KBD_ADD(_tag, _interface) \
+ MCFG_DEVICE_ADD(_tag, APOLLO_KBD, 0) \
+ apollo_kbd_device::static_set_interface(*device, _interface);
+
+INPUT_PORTS_EXTERN(apollo_kbd);
+
+//**************************************************************************
+// Keyboard READ/WRITE
+//**************************************************************************
+
+void apollo_kbd_getchar(device_t *device, UINT8 data);
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> apollo_kbd_interface
+
+struct apollo_kbd_interface
+{
+ write8_device_func apollo_kbd_putchar;
+ read8_device_func apollo_kbd_has_beeper;
+ read8_device_func apollo_kbd_is_german;
+};
+
+#define APOLLO_KBD_INTERFACE(name) const struct apollo_kbd_interface (name)
+
+// ======================> apollo_kbd_device
+
+class apollo_kbd_device : public device_t, public apollo_kbd_interface
+{
+public:
+ // construction/destruction
+ apollo_kbd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // static configuration helpers
+ static void static_set_interface(device_t &device, const apollo_kbd_interface &interface);
+
+ void getchar(UINT8 data);
+
+private:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ const char *cpu_context() ;
+
+ int keyboard_is_german();
+
+ void set_mode(UINT16 mode);
+ void putchar(const UINT8 data);
+ void putdata(const UINT8 *data, int data_length);
+ void putstring(const char *data);
+
+ int push_scancode( UINT8 code, UINT8 repeat);
+ void scan_keyboard();
+ void poll_callback();
+ static TIMER_CALLBACK( static_poll_callback );
+
+ // the keyboard beeper
+ class beeper
+ {
+ public:
+ beeper();
+ void start(apollo_kbd_device *device);
+ void reset();
+ void off();
+ void on();
+ private:
+ int keyboard_has_beeper();
+ void beeper_callback();
+ static TIMER_CALLBACK( static_beeper_callback );
+
+ apollo_kbd_device *m_device; // pointer back to our device
+ device_t *m_beeper; // the keyboard beeper device
+ emu_timer * m_timer; // timer to clock data in
+ };
+
+ // the keyboard mouse
+ class mouse
+ {
+ public:
+ mouse();
+ void start(apollo_kbd_device *device);
+ void reset();
+ void read_mouse();
+ private:
+ apollo_kbd_device *m_device; // pointer back to our device
+
+ int m_last_b; // previous mouse button values
+ int m_last_x; // previous mouse x-axis value
+ int m_last_y; // previous mouse y-axis value
+ int m_tx_pending; // mouse data packet is pending
+ };
+
+ /* Transmitter fifo */
+ class tx_fifo
+ {
+ public:
+ tx_fifo();
+ void start(apollo_kbd_device *device);
+ void reset();
+ UINT8 getchar();
+ void putchar(UINT8 data);
+ int putdata(const UINT8 *data, int data_length);
+ void flush();
+
+ private:
+ void timer_callback();
+ static TIMER_CALLBACK( static_timer_callback );
+
+ apollo_kbd_device *m_device; // pointer back to our device
+
+ UINT16 m_baud_rate;
+
+ UINT16 fifo[TX_FIFO_SIZE];
+ UINT16 m_read_ptr;
+ UINT16 m_write_ptr;
+ UINT16 m_char_count;
+ UINT16 m_tx_pending;
+ emu_timer *m_timer;
+ };
+
+ // the keyboard tty
+ class keyboard_tty
+ {
+ public:
+ keyboard_tty();
+ void start(apollo_kbd_device *device);
+ void reset();
+ int isConnected();
+ int getchar();
+ void putchar(UINT8 data);
+ private:
+ apollo_kbd_device *m_device; // pointer back to our device
+ const char *m_tty_name;
+ int m_tty_fd; /* File descriptor of keyboard tty */
+ int m_connected;
+ };
+
+// const apollo_kbd_interface &m_config;
+
+ beeper m_beeper;
+ mouse m_mouse;
+ tx_fifo m_tx_fifo;
+ keyboard_tty m_keyboard_tty;
+
+ apollo_kbd_device *m_device; // pointer to myself (nasty: used for cpu_context)
+
+ /* Receiver */
+ UINT32 m_rx_message;
+ UINT16 m_loopback_mode;
+
+ emu_timer* m_timer;
+ UINT16 m_mode;
+ UINT16 m_delay; // key press delay after initial press
+ UINT16 m_repeat; // key press repeat rate
+ UINT16 m_last_pressed; // last key pressed, for repeat key handling
+ int m_keytime[0x80]; // time until next key press (1 ms)
+ UINT8 m_keyon[0x80]; // is 1 if key is pressed
+
+ static UINT16 m_code_table[];
+};
+
+// device type definition
+extern const device_type APOLLO_KBD;
+
+#endif
diff --git a/src/mess/machine/apollo_net.c b/src/mess/machine/apollo_net.c
new file mode 100644
index 00000000000..ad3d068c2df
--- /dev/null
+++ b/src/mess/machine/apollo_net.c
@@ -0,0 +1,890 @@
+/*
+ * apollo_net.c - simple APOLLO netserver emulation (netman, ARP, IP echo, ...)
+ *
+ * Created on: May 12, 2010
+ * Author: Hans Ostermeyer
+ *
+ * Released for general non-commercial use under the MAME license
+ * Visit http://mamedev.org for licensing and usage restrictions.
+ *
+ * see also:
+ * - http://www.bitsavers.org/pdf/apollo/AEGIS_Internals_and_Data_Structures_Jan86.pdf
+ */
+
+#define VERBOSE 0
+
+// FIXME: these three should not be hardcoded
+#define NETSERVER_NODE_ID 0x012340
+#define NETSERVER_IP_ADDRESS {192,168,2,3} /* 192.168.2.3 */
+#define NETSERVER_ROOT_PATH "apollo"
+
+#include "includes/apollo.h"
+#include "machine/3c505.h"
+
+typedef struct {
+ UINT8 dest[6];
+ UINT8 source[6];
+ UINT16 proto;
+} ethernet_header;
+
+typedef struct
+{
+ UINT8 version;
+ UINT8 tos;
+ UINT16 tot_len;
+ UINT16 id;
+ UINT16 frag_off;
+ UINT8 ttl;
+ UINT8 protocol;
+ UINT16 check;
+ UINT32 saddr;
+ UINT32 daddr;
+} ip_header;
+
+#define ETHERNET_HEADER_SIZE sizeof(ethernet_header)
+
+/* Ethernet protocol ID's */
+#define ETHERNET_PACKET_TYPE_IP 0x0800 /* IP */
+#define ETHERNET_PACKET_TYPE_ARP 0x0806 /* Address resolution */
+#define ETHERNET_PACKET_TYPE_APOLLO 0x8019
+
+#define ETHERNET_APOLLO_PREFIX 0x08001e
+#define ETHERNET_APOLLO_DOMAIN_PREFIX 0x09001e
+
+#define ICMP_ECHOREPLY 0 /* Echo Reply */
+#define ICMP_ECHO 8 /* Echo Request */
+
+#define PACKET_HEADER_SIZE 64
+
+// #define ETH_BUFFER_SIZE 2000
+
+// Note: these three pathnames are hardcoded in Apollo DomainOS; don't change them
+#define APOLLO_NETBOOT_PATH "/sys/net/netboot"
+#define APOLLO_SAU7_PATH "/sau7"
+#define APOLLO_SAU8_PATH "/sau8"
+#define APOLLO_SAU14_PATH "/sau14"
+
+static emu_file *current_file = NULL;
+
+static UINT16 current_sector = 0;
+static UINT16 current_last_sector = 0;
+static char current_pathname[256];
+
+static UINT8 current_rx_data_buffer[ETH_BUFFER_SIZE];
+static int current_rx_data_length;
+
+static apollo_netserver_transmit tx_callback = NULL;
+
+static UINT32 my_node_id;
+static UINT8 my_ip_address[4] = NETSERVER_IP_ADDRESS; /* 192.168.2.3 */
+static UINT8 my_mac_address[6];
+
+static astring root_path;
+
+// boot_$volun (find partner node)
+static UINT8 response_0006[] = {
+ 0x00,0x01, // 0x40:
+ 0x00,0x01,
+ 0x00,0x07, // 0x44: packet type (07 = 06+1)
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00
+};
+
+static UINT8 list_directory_header[] = {
+ 0x00,0x01, // 0x40:
+ 0x00,0x01,
+ 0x00,0x0d, // 0x44: packet type (0d = 0c+1)
+ 0x00,0x00,0x00,0x00, // 0x46:
+ 0x00,0x01,0x00,0x01,
+ 0x73,0x61,0x6d,0x62,0x61,0x2f,0x73,0x61,0x75,0x37, // "samba/sau7"
+ 0x00,0x00,0x28,0xd8,0x00,0x00,0x00,0x00,
+ 0x75,0x37,0xd8,0xa0,0x76,0x08,0xb5,0x52,
+ 0x75,0x37,0xe6,0xc6,0x75,0x37,0xd8,0xac
+};
+
+static UINT8 receive_data_header[] = {
+ 0x00,0x01, // 0x40:
+ 0x00,0x01, // 0x42:
+ 0x00,0x09, // 0x44: packet type (09 = 08+1)
+ 0x00,0x00,0x00,0x00, // 0x46:
+ 0x00,0x13,0xfc,0xaf, // 0x4A: high
+ 0x00,0x13,0xd8,0x00, // 0x4E: low
+ 0x00,0x13,0xd8,0x2a, // 0x52: start
+ 0x00,0x13,0xd8,0x00, // 0x56: current load address
+ 0x00,0x00 // 0x5a:
+};
+
+static UINT8 not_found_data_header[] = {
+ 0x00,0x01, // 0x40:
+ 0x00,0x01, // 0x42: ?
+ 0x00,0x13, // 0x44: packet type (13 = 12+1)
+ 0x00,0x0e,0x00,0x07,
+ 0x00,0x12, // 0x4a = string length
+ 0x2f,0x2f,0x73,0x61,0x6d,0x62,0x61,0x2f, 0x73,0x61,0x75,0x37,0x2f,0x78,0x78,0x78, /*//samba/sau7/xxxxx */
+ 0x78,0x78,
+
+ 0x07,0x48,0x00,0x08,0x07,0x6a,0x00,0x08, 0x07,0x6c,0x00,0x04,0x0c,0x94
+};
+
+// boot_$get_uids
+static UINT8 response_070a[] = {
+ 0x00,0x01, // 0x40:
+ 0x00,0x01,
+ 0x00,0x0b, // 0x44: packet type (0b = 0a+1)
+ 0x00,0x00,0x00,0x00,
+ // d993195c (2010-04-28 07:27:15)
+ 0xd9,0x93,0x19,0x5c,0x60,0x04,0x20,0xe8, // FIXME: UID of OS paging file (?)
+ // 7742b564 (1996-08-14 19:12:59)
+ 0x77,0x42,0xb5,0x64,0xf0,0x04,0x20,0xe8, // 7742B564.F00420E8 is UID of //
+ 0x77,0x42,0xb5,0x64,0xe0,0x04,0x20,0xe8 // 7742B564.E00420E8 is UID of / (resp. //samba)
+};
+
+// get (dex) file parameters
+static UINT8 response_0718[] = {
+ 0x00,0x01, // 0x40:
+ 0x00,0x01, // 0x42:
+ 0x00,0x19, // 0x44: packet type (19 = 18+1)
+ 0x00,0x00,0x00,0x00, // 0x46:
+ 0x01,
+ 0x01, // 0x4b: systyp (1=dir, 0=file) i.e. is directory
+ 0x90,0x00,
+ 0x77,0x43,0x02,0x58,0xe0,0x04,0x20,0xe8, // 0x4e: source UID
+ 0x00,0x00, // 0x56
+ 0x00,0x00, // 0x58: file type (0x0321 = UASC file)
+ 0x00,0x00,0x00,0x00, // 0x5A:
+ 0x77,0x43,0x02,0x58,0xe8,0x04,0x20,0xe8, // 0x5E: source UID
+ 0x00,0x00,0x10,0x00, // 0x66: file size
+ 0x00,0x00,0x00,0x04, // 0x6A: n sectors (?)
+ 0xd9,0x8f,0xb5,0xef, // 0x6E:
+ 0x80,0x27,0x94,0x1e, // 0x72:
+ 0x77,0x42,0xb5,0x64,0xe0,0x04,0x20,0xe8, // source UID
+ 0x8d,0x15,0x00,0x02,
+ 0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00
+};
+
+static UINT8 get_byte(const UINT8 *data) {
+ return data[0];
+}
+
+static void set_byte(UINT8 *data, const UINT8 value) {
+ data[0] = value;
+}
+
+static UINT16 get_word(const UINT8 *data) {
+ return (data[0] << 8) | data[1];
+}
+
+static void set_word(UINT8 *data, const UINT16 value) {
+ data[0] = value >> 8;
+ data[1] = value & 0xff;
+}
+
+static UINT32 get_3byte(const UINT8 *data) {
+ return (((data[0] << 8) | data[1]) << 8) | data[2];
+}
+
+static void set_3byte(UINT8 *data, const UINT32 value) {
+ data[0] = (value >> 16) & 0xff;
+ data[1] = (value >> 8) & 0xff;
+ data[2] = value & 0xff;
+}
+
+static UINT32 get_long(const UINT8 *data) {
+ return (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3];
+}
+
+static void set_long(UINT8 *data, const UINT32 value) {
+ data[0] = (value >> 24) & 0xff;
+ data[1] = (value >> 16) & 0xff;
+ data[2] = (value >> 8) & 0xff;
+ data[3] = value & 0xff;
+}
+
+static char *get_string(const UINT8 *data) {
+ static char sb[256];
+ int i;
+ int stringLength = get_word(data);
+ for (i = 0; i < stringLength && i < sizeof(sb) - 1; i++) {
+ sb[i] = data[i + 2];
+ }
+ sb[stringLength] = 0;
+ return sb;
+}
+
+static char *get_file_name(const UINT8 *data) {
+ char * s = get_string(data);
+ int i = strlen(s);
+ while (--i >= 0) {
+ s[i] = tolower(s[i]);
+ }
+ return s;
+}
+
+static int get_file_size(const char *path) {
+ int file_size = 0;
+ emu_file file(OPEN_FLAG_READ | OPEN_FLAG_NO_PRELOAD);
+ file_error filerr = file.open(path);
+ if (filerr == FILERR_NONE)
+ {
+ file_size = file.size();
+ file.close();
+ }
+ LOG1(("##### %s - file_size=%d",path, file_size));
+ return file_size;
+}
+
+static int is_directory(const char *path) {
+ int is_directory = 0;
+ osd_directory *curdir;
+ if ((curdir = osd_opendir(path)) != NULL)
+ {
+ osd_closedir(curdir);
+ is_directory = 1;
+ }
+ LOG1(("##### %s - is_directory=%d",path, is_directory));
+ return is_directory;
+}
+
+static int get_file_type(const char *path) {
+ if (!is_directory(path)) {
+ const char *suffix = path + strlen(path);
+ while (suffix != path && *--suffix != '.') {
+ }
+
+ if (strcmp(suffix, ".cmd") == 0 || strcmp(suffix, ".hlp") == 0) {
+ return 0x0321; // UASC file
+ }
+ }
+ return 0;
+}
+
+static int set_ethernet_header(UINT8 *data, UINT8 client_ethernet_address[6]) {
+ memcpy(data + 0, client_ethernet_address, 6);
+ set_3byte(data + 6, ETHERNET_APOLLO_PREFIX);
+ set_3byte(data + 9, my_node_id);
+ set_word(data + 12, ETHERNET_PACKET_TYPE_APOLLO);
+ return ETHERNET_HEADER_SIZE;
+}
+
+static int set_packet_header(UINT8 *packet_buffer, UINT32 dest_node_id,
+ UINT32 source_node_id) {
+ // --------- apollo header --------------
+ set_word(packet_buffer, 0xffff);
+ // set_word(packet_buffer + 2, data_size + PACKET_HEADER_SIZE);
+ set_word(packet_buffer + 4, 0x00be);
+ set_word(packet_buffer + 6, 0x0000);
+ set_word(packet_buffer + 8, 0x0000); // Apollo network number
+ set_3byte(packet_buffer + 10, ETHERNET_APOLLO_PREFIX);
+ set_3byte(packet_buffer + 13, dest_node_id);
+ set_word(packet_buffer + 16, 0x0000);
+ set_word(packet_buffer + 18, 0x0000);
+ set_word(packet_buffer + 20, 0x0000);
+ set_3byte(packet_buffer + 22, ETHERNET_APOLLO_PREFIX);
+ set_3byte(packet_buffer + 25, source_node_id);
+ set_word(packet_buffer + 28, 0x0003);
+ // --------- data header --------------
+ set_long(packet_buffer + 30, dest_node_id);
+ set_long(packet_buffer + 34, 0x24000000L);
+ set_long(packet_buffer + 38, source_node_id);
+ set_long(packet_buffer + 42, 0x01002400L);
+ // set_word(packet_buffer + 46, data_size + 0x22);
+ // set_word(packet_buffer + 48, data_size);
+ set_word(packet_buffer + 50, 0x0000);
+ set_word(packet_buffer + 52, 0x0000);
+ // --------- data --------------
+ set_word(packet_buffer + 54, 0x0401);
+ set_word(packet_buffer + 56, 0x0003);
+ set_word(packet_buffer + 58, 0x20e8);
+ set_word(packet_buffer + 60, 0x616d);
+ set_word(packet_buffer + 62, 0x0000);
+ return PACKET_HEADER_SIZE;
+}
+
+static int set_packet(UINT8 *packet_buffer, UINT8 *packet_data,
+ int packet_data_size) {
+ set_word(packet_buffer + 2, packet_data_size + PACKET_HEADER_SIZE);
+ set_word(packet_buffer + 46, packet_data_size + 0x22);
+ set_word(packet_buffer + 48, packet_data_size);
+
+ memcpy(packet_buffer + PACKET_HEADER_SIZE, packet_data, packet_data_size);
+
+ return packet_data_size;
+}
+
+static int get_packet_size(UINT8 *packet_buffer) {
+ return get_word(packet_buffer + 2);
+}
+
+static int get_dir_data(const char *pathname, UINT8 *packet_buffer) {
+ int nBytes, lineLength;
+ char *data_buffer;
+ osd_directory *curdir;
+ const osd_directory_entry *dir;
+
+ char dir_path[1024];
+ strcpy(dir_path, root_path);
+ strcat (dir_path, pathname);
+
+ set_packet(packet_buffer, list_directory_header,
+ sizeof(list_directory_header));
+ data_buffer = (char *) (packet_buffer + get_packet_size(packet_buffer));
+
+ strcpy(data_buffer, "\n\r");
+ strcat(data_buffer, pathname);
+ strcat(data_buffer, "\n\r");
+
+ if ((curdir = osd_opendir(dir_path)) == NULL)
+ {
+ strcat(data_buffer, "Error: failed to open directory ");
+ strcat(data_buffer, dir_path);
+ strcat(data_buffer, "\r\n");
+ }
+ else
+ {
+ osd_closedir(curdir);
+
+ // open a path to the netserver directory
+ file_enumerator path(dir_path);
+
+ lineLength = 99;
+ while ((dir = path.next()) != NULL)
+ {
+ LOG1(("##### %d %s", (int)strlen(dir->name), dir->name));
+
+ if (strcmp(dir->name, ".") != 0 && strcmp(dir->name, "..") != 0)
+ {
+ lineLength += 3 + strlen(dir->name);
+ if (lineLength > 72) {
+ strcat(data_buffer, "\n\r");
+ lineLength = 3 + strlen(dir->name);
+ }
+ strcat(data_buffer, " ");
+ strcat(data_buffer, dir->name);
+ }
+ }
+ strcat(data_buffer, "\n\r");
+ }
+
+ nBytes = strlen(data_buffer);
+ nBytes = (nBytes + 1) & 0xfffffffe;
+
+ set_word(packet_buffer + 2, get_word(packet_buffer + 2) + nBytes);
+ set_word(packet_buffer + 50, nBytes);
+
+ return nBytes + sizeof(list_directory_header);
+}
+
+static int get_file_data(const char *pathname, UINT8 *packet_buffer,
+ UINT16 first_sector, UINT16 last_sector) {
+ UINT8 *packet_data = packet_buffer + PACKET_HEADER_SIZE;
+ UINT8 *data_buffer;
+ int nBytes;
+ UINT32 fileSize = 0;
+ file_error filerr;
+
+ if(current_file == NULL)
+ {
+ current_file = global_alloc(emu_file(root_path, OPEN_FLAG_READ));
+ // skip leading '/'
+ filerr = current_file->open( pathname+1);
+
+ if (filerr != FILERR_NONE)
+ {
+ global_free(current_file);
+ current_file = NULL;
+ }
+
+ fileSize = current_file == NULL ? 0 : current_file->size();
+ current_sector = 0;
+
+ LOG1(("##### %s - %s filerr=%d fileSize=%d", root_path.cstr(), pathname, filerr, fileSize));
+ } else {
+ current_sector++;
+ }
+ current_last_sector = last_sector;
+
+ if (current_file == NULL)
+ {
+ set_packet(packet_buffer, not_found_data_header,
+ sizeof(not_found_data_header));
+
+ set_word(packet_data + 0x0A, strlen(pathname));
+ strncpy((char *) packet_data + 0x0C, pathname, 0x24);
+ return sizeof(not_found_data_header);
+ } else {
+ set_packet(packet_buffer, receive_data_header,
+ sizeof(receive_data_header));
+
+ data_buffer = (packet_buffer + get_packet_size(packet_buffer));
+
+ nBytes = current_file->read(data_buffer, 1024);
+
+ if (nBytes < 0) {
+ nBytes = 0;
+ }
+
+ // help in dex will fail, if size is odd (5.5.2010 - ost)
+ nBytes = (nBytes + 1) & 0xfffffffe;
+
+ if (nBytes < 1024)
+ {
+ current_file->close();
+ global_free(current_file);
+ current_file = NULL;
+ }
+ else if (current_sector == 0) {
+ // set header addresses from first sector read
+ UINT32 low = get_long(data_buffer + 0);
+ UINT32 start = get_long(data_buffer + 4);
+ UINT32 high = low + fileSize - 1;
+
+ set_long(receive_data_header + 0x0A, high);
+ set_long(receive_data_header + 0x0E, low);
+ set_long(receive_data_header + 0x12, start);
+ set_long(receive_data_header + 0x16, low);
+
+ set_packet(packet_buffer, receive_data_header,
+ sizeof(receive_data_header));
+ }
+
+ if (VERBOSE > 1) {
+ LOG1(("##### %s: 3C505 current address = %0x first/last/current sector = %0x / %0x / %0x",
+ pathname, get_long(receive_data_header + 0x16), first_sector, last_sector, current_sector));
+ }
+
+ set_long(receive_data_header + 0x16, get_long(receive_data_header + 0x16) + nBytes);
+ set_word(packet_data + 0x1A, nBytes < 1024 ? 0xffff : current_sector == last_sector ? 0x00ff : 0);
+
+ set_word(packet_buffer + 2, get_word(packet_buffer + 2) + nBytes);
+ set_word(packet_buffer + 50, nBytes);
+
+ return nBytes + sizeof(receive_data_header);
+ }
+}
+
+static void log_data(const device_t *device, const char *type,
+ const UINT8 *data, int data_length) {
+ if (VERBOSE > 1) {
+ int i;
+ logerror("%s - %s: Net Server %s Data (length=%2x)", apollo_cpu_context(
+ device->machine().firstcpu), device->tag(), type, data_length);
+ for (i = 0; i < data_length; i++) {
+ logerror(" %02x", data[i]);
+ }
+ logerror("\n");
+ }
+}
+
+static UINT16 get_socket(const UINT8 rx_data_buffer[], int rx_data_length) {
+
+ const UINT8 * packet_buffer = rx_data_buffer + ETHERNET_HEADER_SIZE;
+ int packet_length = rx_data_length - ETHERNET_HEADER_SIZE;
+
+ UINT16 socket = packet_length < 0x11 ? 0xffff : get_word(packet_buffer + 0x10); // 0x10: dest socket
+
+ return socket;
+}
+
+/***************************************************************************
+ netman server
+ ***************************************************************************/
+
+static int netman_server(const device_t *device,
+ const UINT8 rx_data_buffer[], int rx_data_length, UINT8 tx_data_buffer[]) {
+ UINT16 service;
+ UINT16 node_type; // SAU7, SAU8 or SAU14
+ char pathname[256];
+
+ int tx_data_length;
+
+ UINT8 *packet_buffer = tx_data_buffer + ETHERNET_HEADER_SIZE;
+
+ UINT32 client_node_id;
+ UINT8 client_ethernet_address[6];
+
+ UINT16 last_sector;
+ UINT16 first_sector;
+
+ client_node_id = get_3byte(rx_data_buffer + 9);
+ memcpy(client_ethernet_address, rx_data_buffer + 6, 6);
+
+ log_data(device, "Rx", rx_data_buffer, rx_data_length);
+
+ // strip off the ethernet header;
+ rx_data_buffer += ETHERNET_HEADER_SIZE;
+ rx_data_length -= ETHERNET_HEADER_SIZE;
+
+ service = (rx_data_length > 0x45) ? get_word(rx_data_buffer + 0x44) : 0xffff;
+ first_sector = (rx_data_length > 0x6b) ? get_word(rx_data_buffer + 0x6a) : 0;
+ // FIXME: hack
+// last_sector = (rx_data_length > 0x6d) ? get_word(rx_data_buffer + 0x6c) : 0;
+ last_sector = (rx_data_length > 0x6d) ? get_word(rx_data_buffer + 0x6c) : 0x0f;
+
+ set_ethernet_header(tx_data_buffer, client_ethernet_address);
+ set_packet_header(packet_buffer, client_node_id, my_node_id);
+
+ node_type = service >> 8;
+
+ switch (service & 0xff) {
+ case 6: // boot_$volun (find partner node)
+ DLOG1(("Net Server service=%04x (boot_$volun)", service));
+ set_packet(packet_buffer, response_0006, sizeof(response_0006));
+ break;
+
+ case 8: // boot_$sysboot (get netboot)
+ get_file_data(APOLLO_NETBOOT_PATH, packet_buffer, first_sector, last_sector);
+ DLOG1(("Net Server service=%04x (boot_$sysboot - sector %x of %x-%x)", service, current_sector, first_sector, last_sector));
+ break;
+ case 0x0a: // boot_$get_uids (get UIDs for OS paging file, network root and the node entry directory)
+ set_packet(packet_buffer, response_070a, sizeof(response_070a));
+ DLOG1(("Net Server service=%04x (boot_$get_uids)", service));
+ break;
+ case 0x0c: // boot_$mult_ld (list directory for sau7, SAU8, SAU14)
+ get_dir_data( node_type == 7 ? APOLLO_SAU7_PATH : node_type == 8 ? APOLLO_SAU8_PATH : APOLLO_SAU14_PATH, packet_buffer);
+ DLOG1(("Net Server service=%04x (boot_$mult_ld)", service));
+ break;
+ case 0x12: // boot_$load (ex /sau7/self_test, domain_os, ...)
+ strcpy(pathname, node_type == 7 ? APOLLO_SAU7_PATH : node_type == 8 ? APOLLO_SAU8_PATH : APOLLO_SAU14_PATH);
+ strcat(pathname, "/");
+ strcat(pathname, get_file_name(rx_data_buffer + 0x48));
+ get_file_data(pathname, packet_buffer, first_sector, last_sector);
+ DLOG1(("Net Server service=%04x (boot_$load %s - sector %x of %x-%x)", service, pathname, current_sector, first_sector, last_sector));
+ break;
+ case 0x18: // boot_$set_path (set current path and get attributes of current path)
+ set_packet(packet_buffer, response_0718, sizeof(response_0718));
+
+ if (get_long(rx_data_buffer + 0x6e) == 0L && get_long(rx_data_buffer + 0x72) == 0L) {
+ // reset path name to root dir
+ strcpy(current_pathname, root_path);
+ }
+
+ // FIXME: why is this necessary???
+ if (is_directory(current_pathname)) {
+ strcat(current_pathname, "/");
+ strcat(current_pathname, get_file_name(rx_data_buffer + 0x48));
+ }
+
+ // 0x4b: systyp (1=dir, 0=file)
+ set_byte(packet_buffer + 0x4b, is_directory(current_pathname));
+ set_word(packet_buffer + 0x58, get_file_type(current_pathname));
+ set_long(packet_buffer + 0x66, get_file_size(current_pathname));
+
+ DLOG1(("Net Server service=%04x (boot_$set_path %s)", service, current_pathname + strlen(root_path)));
+ break;
+ case 0x1a: // boot_$load_file (?): load /sau7/cmd/startup.cmd, /sau7/cpu.dex, ...
+ get_file_data(current_pathname + strlen(root_path), packet_buffer, first_sector, last_sector);
+ DLOG1(("Net Server service=%04x (boot_$load_file %s - sector %x of %x-%x)", service, current_pathname + strlen(root_path), current_sector, first_sector, last_sector));
+ break;
+ default:
+ DLOG(("Net Server - unexpected service %04x", service&0xff));
+ return 0;
+ }
+
+ set_word(packet_buffer + 0x44, (service & 0xff) + 1); // 0x44: response packet type
+
+ tx_data_length = ETHERNET_HEADER_SIZE + get_packet_size(packet_buffer);
+
+ log_data(device, "Tx", tx_data_buffer, tx_data_length);
+ return tx_data_length;
+}
+
+static int is_ethernet_broadcast_address(const UINT8 ethernet_header[]) {
+ return get_3byte(ethernet_header + 0) == 0xffffff && //
+ get_3byte(ethernet_header + 3) == 0xffffff;
+}
+
+static int is_apollo_multicast_address(const UINT8 ethernet_header[]) {
+ return get_3byte(ethernet_header + 0) == ETHERNET_APOLLO_DOMAIN_PREFIX && //
+ (get_3byte(ethernet_header + 3) == 0L || get_3byte(ethernet_header + 3) == 1L);
+}
+
+static int is_my_ethernet_address(const UINT8 mac_address[]) {
+ return memcmp(mac_address, my_mac_address, 6) == 0;
+}
+
+static int is_my_ip_address(const UINT8 ip_address[]) {
+ return memcmp (ip_address, my_ip_address, 4) == 0;
+}
+
+static int is_my_node_id(const UINT8 node_id[]) {
+ return get_long(node_id) == my_node_id;
+}
+
+static int ethernet_packet_is_for_me(const UINT8 ethernet_packet_header[],
+ const int data_length) {
+ return data_length >= ETHERNET_HEADER_SIZE && (
+ is_ethernet_broadcast_address(ethernet_packet_header) ||
+ is_apollo_multicast_address(ethernet_packet_header) ||
+ is_my_ethernet_address(ethernet_packet_header));
+}
+
+static int is_apollo_request(const UINT8 ethernet_header[],
+ const int data_length) {
+
+ return data_length >= 0x30 && //
+ get_word(ethernet_header + 0x0c) == ETHERNET_PACKET_TYPE_APOLLO;
+}
+
+static int is_apollo_arp_request(const UINT8 ethernet_header[], const int data_length) {
+ return data_length >= 0x30 && //
+ get_word(ethernet_header + 0x0c) == ETHERNET_PACKET_TYPE_ARP && //
+ get_word(ethernet_header + 0x10) == ETHERNET_PACKET_TYPE_APOLLO && //
+ is_apollo_multicast_address(ethernet_header) && //
+ is_my_node_id(ethernet_header + 0x26);
+}
+
+static int is_ip_arp_request(const UINT8 ethernet_header[], const int data_length) {
+ return data_length >= 0x30 && //
+ get_word(ethernet_header + 0x0c) == ETHERNET_PACKET_TYPE_ARP && //
+ get_word(ethernet_header + 0x10) == ETHERNET_PACKET_TYPE_IP && //
+ is_ethernet_broadcast_address(ethernet_header) && //
+ is_my_ip_address (ethernet_header + 0x26);
+}
+
+static int is_ip_echo_request(const UINT8 ethernet_header[], const int data_length) {
+ return data_length >= 0x30 && //
+ get_word(ethernet_header + 0x0c) == ETHERNET_PACKET_TYPE_IP && //
+ get_byte(ethernet_header + 0x22) == ICMP_ECHO && //
+ is_my_ethernet_address(ethernet_header);
+}
+
+static UINT16 in_checksum(UINT8 *ptr, UINT32 nbytes)
+{
+ UINT32 sum = 0;
+ while (nbytes > 1)
+ {
+ // MSB first
+ sum += (*ptr++) << 8;
+ sum += *ptr++;
+ nbytes -=2;
+ }
+ if (nbytes == 1)
+ {
+ sum += (*ptr++) << 8;
+ }
+ sum = (sum >> 16) + (sum & 0xffff);
+ sum += (sum >> 16);
+
+ return (~sum) & 0xffff;
+}
+
+/***************************************************************************
+ simple ARP Server emulation
+ ***************************************************************************/
+
+static int arp_server(const device_t *device,
+ const UINT8 rx_data[], int rx_data_length,
+ UINT8 tx_data[]) {
+
+// static UINT8 arp_response[] = {
+// 0x08,0x00,0x1e,0x02,0x61,0x6d, // 0x00: Ethernet address of destination
+// 0x08,0x00,0x1e,0x04,0x20,0xe8, // 0x06: Ethernet address of sender
+// 0x08,0x06, // 0x0c: Protocol type
+// 0x00,0x01, // 0x0e: Hardware address space
+// 0x80,0x19, // 0x10: Protocol address space
+// 0x06, // 0x12: byte length of each hardware address
+// 0x04, // 0x13: byte length of each protocol address
+// 0x00,0x02, // 0x14: opcode (ares_op$REQUEST | ares_op$REPLY)
+// 0x08,0x00,0x1e,0x04,0x20,0xe8, // 0x16: Hardware address of sender of this packet
+// 0x00,0x04,0x20,0xe8, // 0x1c: Protocol address of sender of this packet
+// 0x08,0x00,0x1e,0x02,0x61,0x6d, // 0x20: Hardware address of target of this packet (if known)
+// 0x00,0x02,0x61,0x6d, // 0x26: Protocol address of target
+// ...
+// };
+
+ UINT16 tx_data_length = rx_data_length;
+ memcpy(tx_data, rx_data, tx_data_length);
+
+ // 0x00: Ethernet address of destination
+ memcpy(tx_data + 0x00, rx_data + 0x06, 6);
+ // 0x06: Ethernet address of sender
+ memcpy(tx_data + 0x06, my_mac_address, 6);
+ // 0x14: opcode (ares_op$REQUEST | ares_op$REPLY)
+ set_word(tx_data + 0x14, 2);
+ // 0x16: Hardware address of sender
+ memcpy(tx_data + 0x16, my_mac_address, 6);
+ // 0x1c: Protocol address of sender
+ memcpy(tx_data + 0x1c, rx_data + 0x26, 4);
+ // 0x20: Hardware address of target (if known)
+ memcpy(tx_data + 0x20, rx_data + 0x16, 6);
+ // 0x26: Protocol address of target
+ memcpy(tx_data + 0x26, rx_data + 0x1c, 4);
+
+ log_data(device, "ARP Rx", rx_data, rx_data_length);
+ log_data(device, "ARP Tx", tx_data, tx_data_length);
+ return tx_data_length;
+}
+
+/***************************************************************************
+ simple Echo (ping) Server emulation
+ ***************************************************************************/
+
+static int echo_server(const device_t *device,
+ const UINT8 rx_data[], int rx_data_length,
+ UINT8 tx_data[]) {
+
+ static const UINT32 ip_offset = sizeof(ethernet_header);
+ static const UINT32 icmp_offset = ip_offset + sizeof(ip_header);
+
+ UINT16 tx_data_length = rx_data_length;
+ memcpy(tx_data, rx_data, tx_data_length);
+
+ // 0x00: Ethernet address of destination
+ memcpy(tx_data + 0x00, rx_data + 0x06, 6);
+ // 0x06: Ethernet address of sender
+ memcpy(tx_data + 0x06, rx_data + 0x00, 6);
+ // 0x12: ip.id
+ set_word(tx_data + 0x12, 0x0573);
+ // 0x18: ip.checksum
+ set_word(tx_data + 0x18, 0);
+ set_word(tx_data + 0x18, in_checksum(tx_data + ip_offset, sizeof(ip_header)));
+
+ // 0x1a: Protocol address of sender
+ memcpy(tx_data + 0x1a, rx_data + 0x1e, 4);
+ // 0x1e: Protocol address of target
+ memcpy(tx_data + 0x1e, rx_data + 0x1a, 4);
+ // 0x22: icmp.type
+ set_byte(tx_data + 0x22, ICMP_ECHOREPLY);
+ // 0x24: icmp.cksump
+ set_word(tx_data + 0x24, 0);
+ set_word(tx_data + 0x24, in_checksum(tx_data + icmp_offset, tx_data_length-icmp_offset));
+
+ log_data(device, "Echo Rx", rx_data, rx_data_length);
+ log_data(device, "Echo Tx", tx_data, tx_data_length);
+ return tx_data_length;
+}
+
+/***************************************************************************
+ netserver
+ ***************************************************************************/
+
+static int netserver(const device_t *device,
+ const UINT8 rx_data[], int rx_data_length,
+ UINT8 tx_data[]) {
+
+ if (!ethernet_packet_is_for_me(rx_data, rx_data_length))
+ return 0; // skip
+ else if (is_apollo_request(rx_data, rx_data_length))
+ {
+ UINT16 socket = get_socket(rx_data, rx_data_length);
+
+ switch (socket) {
+ case 1: // Paging socket
+ break;
+ case 2: // File socket
+// return file_server(device, rx_data, rx_data_length, tx_data);
+ break;
+ case 3: // NETMAN socket
+ return netman_server(device, rx_data, rx_data_length, tx_data);
+ case 4: // Information socket
+ break;
+ case 5: // Receives internet asknode "who" replies
+ break;
+ case 6: // File server overflow socket
+ break;
+ case 7: // Software diagnostic socket
+ break;
+ case 8: // routing information protocol (RIP) socket
+ break;
+ case 9: // Mailbox socket
+ break;
+ case 10: // NS Helper socket
+ break;
+ case 11: // TCP/IP
+ break;
+ case 12: // ?
+ break;
+ default:
+ break;
+ }
+
+ DLOG1(("Net Server - socket %d not yet supported", socket));
+ return 0;
+ } else if (is_apollo_arp_request(rx_data, rx_data_length)) {
+ return arp_server(device, rx_data, rx_data_length, tx_data);
+ } else if (is_ip_arp_request(rx_data, rx_data_length)) {
+ return arp_server(device, rx_data, rx_data_length, tx_data);
+ } else if (is_ip_echo_request(rx_data, rx_data_length)) {
+ return echo_server(device, rx_data, rx_data_length, tx_data);
+ } else {
+ log_data(device, "unexpected Rx", rx_data, rx_data_length);
+ return 0;
+ }
+}
+
+/***************************************************************************
+ receive_interrupt
+ ***************************************************************************/
+
+static TIMER_CALLBACK(receive_interrupt) {
+ device_t *device = (device_t *)ptr;
+
+ UINT8 tx_data_buffer[ETH_BUFFER_SIZE];
+
+ int tx_data_length = netserver(device, current_rx_data_buffer, current_rx_data_length, tx_data_buffer);
+
+ DLOG2(("Net Server rx/tx_data_length = %x/%x current_sector=%x current_last_sector=%x",
+ current_rx_data_length, tx_data_length, current_sector, current_last_sector ));
+
+ if (tx_data_length > 0 && tx_callback != NULL) {
+ // threecom3c505_receive(device, tx_data_buffer, tx_data_length);
+ (*tx_callback)(device, tx_data_buffer, tx_data_length);
+ }
+
+ if (current_file != NULL && current_sector < current_last_sector)
+ {
+ // more packets pending
+ machine.scheduler().timer_set(attotime::from_msec(1), FUNC(receive_interrupt), 0, device);
+ } else {
+ current_rx_data_length = 0;
+ }
+}
+
+/***************************************************************************
+ apollo_netserver_receive - receive and process an ethernet packet
+ ***************************************************************************/
+
+int apollo_netserver_receive(device_t *device, const UINT8 rx_data_buffer[],
+ int rx_data_length)
+{
+ if (!ethernet_packet_is_for_me(rx_data_buffer, rx_data_length))
+ {
+ return 1; // skip packet
+ }
+ else if (current_rx_data_length > 0)
+ {
+ LOG(("!!!! apollo_netserver_receive: busy - skipped data with length %02x",rx_data_length));
+ return 0;
+ }
+ else
+ {
+ memcpy(current_rx_data_buffer, rx_data_buffer, rx_data_length);
+ current_rx_data_length = rx_data_length;
+
+ // delay response to multicast requests
+ int ms = is_apollo_multicast_address(rx_data_buffer) ? 100 : 1;
+ device->machine().scheduler().timer_set(attotime::from_msec(ms), FUNC(receive_interrupt), 0, device);
+ return 1;
+ }
+}
+
+/***************************************************************************
+ apollo_netserver_init - specify the transmitter call back function
+ ***************************************************************************/
+
+void apollo_netserver_init(const char *root_path, apollo_netserver_transmit tx_data)
+{
+ ::root_path.cat(root_path);
+ ::root_path.cat(PATH_SEPARATOR);
+ ::root_path.cat(NETSERVER_ROOT_PATH);
+
+ ::tx_callback = tx_data;
+
+ my_node_id = NETSERVER_NODE_ID;
+ set_3byte(my_mac_address, ETHERNET_APOLLO_PREFIX);
+ set_3byte(my_mac_address + 3, my_node_id);
+
+ current_rx_data_length = 0;
+}
diff --git a/src/mess/machine/apple1.c b/src/mess/machine/apple1.c
new file mode 100644
index 00000000000..83126915169
--- /dev/null
+++ b/src/mess/machine/apple1.c
@@ -0,0 +1,554 @@
+/***************************************************************************
+
+ machine.c
+
+ Functions to emulate general aspects of the machine (RAM, ROM, interrupts,
+ I/O ports)
+
+ The Apple I used a Motorola 6820 PIA for its keyboard and display
+ I/O. The keyboard was mapped to PIA port A, and the display to port
+ B.
+
+ Port A, the keyboard, was an input port connected to a standard
+ ASCII-encoded keyboard. The high bit of the port was tied to +5V.
+ The keyboard strobe signal was connected to the PIA's CA1 control
+ input so that the keyboard could signal each keypress to the PIA.
+ The processor could check for a keypress by testing the IRQA1 flag
+ in the Port A Control Register and then reading the character value
+ from Port A.
+
+ The keyboard connector also had two special lines, RESET and CLEAR
+ SCREEN, which were meant to be connected to pushbutton switches on
+ the keyboard. RESET was tied to the reset inputs for the CPU and
+ PIA; it allowed the user to stop a program and return control to the
+ Monitor. CLEAR SCREEN was directly tied to the video hardware and
+ would clear the display.
+
+ Port B, the display, was an output port which accepted 7-bit ASCII
+ characters from the PIA and wrote them on the display. The details
+ of this are described in video/apple1.c. Control line CB2 served
+ as an output signal to inform the display of a new character. (CB2
+ was also connected to line 7 of port B, which was configured as an
+ input, so that the CPU could more easily check the status of the
+ write.) The CB1 control input signaled the PIA when the display had
+ finished writing the character and could accept a new one.
+
+ MAME models the 6821 instead of the earlier 6820 used in the Apple
+ I, but there is no difference in functionality between the two
+ chips; the 6821 simply has a better ability to drive electrical
+ loads.
+
+ The Apple I had an optional cassette interface which plugged into
+ the expansion connector. This is described below in the "Cassette
+ interface I/O" section.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/apple1.h"
+#include "machine/6821pia.h"
+#include "cpu/m6502/m6502.h"
+#include "imagedev/cassette.h"
+#include "machine/ram.h"
+
+static TIMER_CALLBACK(apple1_kbd_poll);
+static TIMER_CALLBACK(apple1_kbd_strobe_end);
+
+static READ8_DEVICE_HANDLER( apple1_pia0_kbdin );
+static WRITE8_DEVICE_HANDLER( apple1_pia0_dspout );
+static WRITE8_DEVICE_HANDLER( apple1_pia0_dsp_write_signal );
+
+static TIMER_CALLBACK(apple1_dsp_ready_start);
+static TIMER_CALLBACK(apple1_dsp_ready_end);
+
+/*****************************************************************************
+** Structures
+*****************************************************************************/
+
+/* Handlers for the PIA. The inputs for Port B, CA1, and CB1 are
+ handled by writing to them at the moment when their values change,
+ rather than updating them when they are read; thus they don't need
+ handler functions. */
+
+const pia6821_interface apple1_pia0 =
+{
+ DEVCB_DEVICE_HANDLER("pia", apple1_pia0_kbdin), /* Port A input (keyboard) */
+ DEVCB_NULL, /* Port B input (display status) */
+ DEVCB_NULL, /* CA1 input (key pressed) */
+ DEVCB_NULL, /* CB1 input (display ready) */
+ DEVCB_NULL, /* CA2 not used as input */
+ DEVCB_NULL, /* CB2 not used as input */
+ DEVCB_NULL, /* Port A not used as output */
+ DEVCB_DEVICE_HANDLER("pia", apple1_pia0_dspout), /* Port B output (display) */
+ DEVCB_NULL, /* CA2 not used as output */
+ DEVCB_DEVICE_HANDLER("pia", apple1_pia0_dsp_write_signal), /* CB2 output (display write) */
+ DEVCB_NULL, /* IRQA not connected */
+ DEVCB_NULL /* IRQB not connected */
+};
+
+/* Use the same keyboard mapping as on a modern keyboard. This is not
+ the same as the keyboard mapping of the actual teletype-style
+ keyboards used with the Apple I, but it's less likely to cause
+ confusion for people who haven't memorized that layout.
+
+ The Backspace key is mapped to the '_' (underscore) character
+ because the Apple I ROM Monitor used "back-arrow" to erase
+ characters, rather than backspace, and back-arrow is an earlier
+ form of the underscore. */
+
+#define ESCAPE '\x1b'
+
+static const UINT8 apple1_unshifted_keymap[] =
+{
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', '-', '=', '[', ']', ';', '\'',
+ ',', '.', '/', '\\', 'A', 'B', 'C', 'D',
+ 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
+ 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
+ 'U', 'V', 'W', 'X', 'Y', 'Z', '\r', '_',
+ ' ', ESCAPE
+};
+
+static const UINT8 apple1_shifted_keymap[] =
+{
+ ')', '!', '@', '#', '$', '%', '^', '&',
+ '*', '(', '_', '+', '[', ']', ':', '"',
+ '<', '>', '?', '\\', 'A', 'B', 'C', 'D',
+ 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
+ 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
+ 'U', 'V', 'W', 'X', 'Y', 'Z', '\r', '_',
+ ' ', ESCAPE
+};
+
+/* Control key mappings, like the other mappings, conform to a modern
+ keyboard where possible. Note that the Apple I ROM Monitor ignores
+ most control characters. */
+
+static const UINT8 apple1_control_keymap[] =
+{
+ '0', '1', '\x00', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
+ '8', '9', '\x1f', '=', '\x1b', '\x1d', ';', '\'',
+ ',', '.', '/', '\x1c', '\x01', '\x02', '\x03', '\x04',
+ '\x05', '\x06', '\x07', '\x08', '\x09', '\x0a', '\x0b', '\x0c',
+ '\x0d', '\x0e', '\x0f', '\x10', '\x11', '\x12', '\x13', '\x14',
+ '\x15', '\x16', '\x17', '\x18', '\x19', '\x1a', '\r', '_',
+ '\x00', ESCAPE
+};
+
+
+
+/*****************************************************************************
+** DRIVER_INIT: driver-specific setup, executed once at MESS startup.
+*****************************************************************************/
+
+DRIVER_INIT_MEMBER(apple1_state,apple1)
+{
+ address_space* space = machine().device("maincpu")->memory().space(AS_PROGRAM);
+ /* Set up the handlers for MESS's dynamically-sized RAM. */
+ space->install_readwrite_bank(0x0000, machine().device<ram_device>(RAM_TAG)->size() - 1, "bank1");
+ membank("bank1")->set_base(machine().device<ram_device>(RAM_TAG)->pointer());
+
+ /* Poll the keyboard input ports periodically. These include both
+ ordinary keys and the RESET and CLEAR SCREEN pushbutton
+ switches. We can't handle these switches in a VBLANK_INT or
+ PERIODIC_INT because both switches need to be monitored even
+ while the CPU is suspended during RESET; VBLANK_INT and
+ PERIODIC_INT callbacks aren't run while the CPU is in this
+ state.
+
+ A 120-Hz poll rate seems to be fast enough to ensure no
+ keystrokes are missed. */
+ machine().scheduler().timer_pulse(attotime::from_hz(120), FUNC(apple1_kbd_poll));
+}
+
+
+/*****************************************************************************
+** MACHINE_RESET: actions to perform on each cold boot.
+*****************************************************************************/
+
+MACHINE_RESET( apple1 )
+{
+ /* Reset the display hardware. */
+ apple1_vh_dsp_clr(machine);
+}
+
+
+/*****************************************************************************
+** apple1_verify_header
+*****************************************************************************/
+static int apple1_verify_header (UINT8 *data)
+{
+ /* Verify the format for the snapshot */
+ if ((data[0] == 'L') &&
+ (data[1] == 'O') &&
+ (data[2] == 'A') &&
+ (data[3] == 'D') &&
+ (data[4] == ':') &&
+ (data[7] == 'D') &&
+ (data[8] == 'A') &&
+ (data[9] == 'T') &&
+ (data[10]== 'A') &&
+ (data[11]== ':'))
+ {
+ return(IMAGE_VERIFY_PASS);
+ }
+ else
+ {
+ return(IMAGE_VERIFY_FAIL);
+ }
+}
+
+#define SNAP_HEADER_LEN 12
+
+/*****************************************************************************
+** snapshot_load_apple1
+**
+** Format of the binary snapshot image is:
+**
+** [ LOAD:xxyyDATA:zzzzzz...]
+**
+** where xxyy is the binary starting address (in big-endian byte
+** order) to load the binary data zzzzzz to.
+**
+** The image can be of arbitrary length, but it must fit in available
+** memory.
+*****************************************************************************/
+SNAPSHOT_LOAD(apple1)
+{
+ UINT64 filesize, datasize;
+ UINT8 *snapbuf, *snapptr;
+ UINT16 start_addr, end_addr, addr;
+
+ filesize = image.length();
+
+ /* Read the snapshot data into a temporary array */
+ if (filesize < SNAP_HEADER_LEN)
+ return IMAGE_INIT_FAIL;
+ snapbuf = (UINT8*)image.ptr();
+ if (!snapbuf)
+ return IMAGE_INIT_FAIL;
+
+ /* Verify the snapshot header */
+ if (apple1_verify_header(snapbuf) == IMAGE_VERIFY_FAIL)
+ {
+ logerror("apple1 - Snapshot Header is in incorrect format - needs to be LOAD:xxyyDATA:\n");
+ return IMAGE_INIT_FAIL;
+ }
+
+ datasize = filesize - SNAP_HEADER_LEN;
+
+ /* Extract the starting address to load the snapshot to. */
+ start_addr = (snapbuf[5] << 8) | (snapbuf[6]);
+ logerror("apple1 - LoadAddress is 0x%04x\n", start_addr);
+
+ end_addr = start_addr + datasize - 1;
+
+ if ((start_addr < 0xE000 && end_addr > image.device().machine().device<ram_device>(RAM_TAG)->size() - 1)
+ || end_addr > 0xEFFF)
+ {
+ logerror("apple1 - Snapshot won't fit in this memory configuration;\n"
+ "needs memory from $%04X to $%04X.\n", start_addr, end_addr);
+ return IMAGE_INIT_FAIL;
+ }
+
+ /* Copy the data into memory space. */
+ for (addr = start_addr, snapptr = snapbuf + SNAP_HEADER_LEN;
+ addr <= end_addr;
+ addr++, snapptr++)
+ image.device().machine().device("maincpu")->memory().space(AS_PROGRAM)->write_byte(addr, *snapptr);
+
+
+ return IMAGE_INIT_PASS;
+}
+
+
+/*****************************************************************************
+** apple1_kbd_poll
+**
+** Keyboard polling handles both ordinary keys and the special RESET
+** and CLEAR SCREEN switches.
+**
+** For ordinary keys, this implements 2-key rollover to reduce the
+** chance of missed keypresses. If we press a key and then press a
+** second key while the first hasn't been completely released, as
+** might happen during rapid typing, only the second key is
+** registered; the first key is ignored.
+**
+** If multiple newly-pressed keys are found, the one closest to the
+** end of the input ports list is counted; the others are ignored.
+*****************************************************************************/
+static TIMER_CALLBACK(apple1_kbd_poll)
+{
+ apple1_state *state = machine.driver_data<apple1_state>();
+ int port, bit;
+ int key_pressed;
+ UINT32 shiftkeys, ctrlkeys;
+ pia6821_device *pia = machine.device<pia6821_device>("pia");
+ static const char *const keynames[] = { "KEY0", "KEY1", "KEY2", "KEY3" };
+
+ /* This holds the values of all the input ports for ordinary keys
+ seen during the last scan. */
+
+ /* First we check the RESET and CLEAR SCREEN pushbutton switches. */
+
+ /* The RESET switch resets the CPU and the 6820 PIA. */
+ if (machine.root_device().ioport("KEY5")->read() & 0x0001)
+ {
+ if (!state->m_reset_flag) {
+ state->m_reset_flag = 1;
+ /* using PULSE_LINE does not allow us to press and hold key */
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_RESET, ASSERT_LINE);
+ pia->reset();
+ }
+ }
+ else if (state->m_reset_flag) {
+ /* RESET released--allow the processor to continue. */
+ state->m_reset_flag = 0;
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_RESET, CLEAR_LINE);
+ }
+
+ /* The CLEAR SCREEN switch clears the video hardware. */
+ if (machine.root_device().ioport("KEY5")->read() & 0x0002)
+ {
+ if (!state->m_vh_clrscrn_pressed)
+ {
+ /* Ignore further video writes, and clear the screen. */
+ state->m_vh_clrscrn_pressed = 1;
+ apple1_vh_dsp_clr(machine);
+ }
+ }
+ else if (state->m_vh_clrscrn_pressed)
+ {
+ /* CLEAR SCREEN released--pay attention to video writes again. */
+ state->m_vh_clrscrn_pressed = 0;
+ }
+
+ /* Now we scan all the input ports for ordinary keys, recording
+ new keypresses while ignoring keys that were already pressed in
+ the last scan. */
+
+ state->m_kbd_data = 0;
+ key_pressed = 0;
+
+ /* The keyboard strobe line should always be low when a scan starts. */
+ pia->ca1_w(0);
+
+ shiftkeys = machine.root_device().ioport("KEY4")->read() & 0x0003;
+ ctrlkeys = machine.root_device().ioport("KEY4")->read() & 0x000c;
+
+ for (port = 0; port < 4; port++)
+ {
+ UINT32 portval, newkeys;
+
+ portval = machine.root_device().ioport(keynames[port])->read();
+ newkeys = portval & ~(state->m_kbd_last_scan[port]);
+
+ if (newkeys)
+ {
+ key_pressed = 1;
+ for (bit = 0; bit < 16; bit++) {
+ if (newkeys & 1)
+ {
+ state->m_kbd_data = (ctrlkeys)
+ ? apple1_control_keymap[port*16 + bit]
+ : (shiftkeys)
+ ? apple1_shifted_keymap[port*16 + bit]
+ : apple1_unshifted_keymap[port*16 + bit];
+ }
+ newkeys >>= 1;
+ }
+ }
+ state->m_kbd_last_scan[port] = portval;
+ }
+
+ if (key_pressed)
+ {
+ /* The keyboard will pulse its strobe line when a key is
+ pressed. A 10-usec pulse is typical. */
+ pia->ca1_w(1);
+ machine.scheduler().timer_set(attotime::from_usec(10), FUNC(apple1_kbd_strobe_end));
+ }
+}
+
+static TIMER_CALLBACK(apple1_kbd_strobe_end)
+{
+ pia6821_device *pia = machine.device<pia6821_device>("pia");
+
+ /* End of the keyboard strobe pulse. */
+ pia->ca1_w(0);
+}
+
+
+/*****************************************************************************
+** READ/WRITE HANDLERS
+*****************************************************************************/
+static READ8_DEVICE_HANDLER( apple1_pia0_kbdin )
+{
+ apple1_state *state = device->machine().driver_data<apple1_state>();
+ /* Bit 7 of the keyboard input is permanently wired high. This is
+ what the ROM Monitor software expects. */
+ return state->m_kbd_data | 0x80;
+}
+
+static WRITE8_DEVICE_HANDLER( apple1_pia0_dspout )
+{
+ /* Send an ASCII character to the video hardware. */
+ apple1_vh_dsp_w(device->machine(), data);
+}
+
+static WRITE8_DEVICE_HANDLER( apple1_pia0_dsp_write_signal )
+{
+ /* PIA output CB2 is inverted to become the DA signal, used to
+ signal a display write to the video hardware. */
+
+ /* DA is directly connected to PIA input PB7, so the processor can
+ read bit 7 of port B to test whether the display has completed
+ a write. */
+ pia6821_device *pia = downcast<pia6821_device *>(device);
+ pia->portb_w((!data) << 7);
+
+ /* Once DA is asserted, the display will wait until it can perform
+ the write, when the cursor position is about to be refreshed.
+ Only then will it assert \RDA to signal readiness for another
+ write. Thus the write delay depends on the cursor position and
+ where the display is in the refresh cycle. */
+ if (!data)
+ device->machine().scheduler().timer_set(apple1_vh_dsp_time_to_ready(device->machine()), FUNC(apple1_dsp_ready_start));
+}
+
+static TIMER_CALLBACK(apple1_dsp_ready_start)
+{
+ pia6821_device *pia = machine.device<pia6821_device>("pia");
+
+ /* When the display asserts \RDA to signal it is ready, it
+ triggers a 74123 one-shot to send a 3.5-usec low pulse to PIA
+ input CB1. The end of this pulse will tell the PIA that the
+ display is ready for another write. */
+ pia->cb1_w(0);
+ machine.scheduler().timer_set(attotime::from_nsec(3500), FUNC(apple1_dsp_ready_end));
+}
+
+static TIMER_CALLBACK(apple1_dsp_ready_end)
+{
+ pia6821_device *pia = machine.device<pia6821_device>("pia");
+
+ /* The one-shot pulse has ended; return CB1 to high, so we can do
+ another display write. */
+ pia->cb1_w(1);
+}
+
+
+/*****************************************************************************
+** 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.
+*****************************************************************************/
+
+static cassette_image_device *cassette_device_image(running_machine &machine)
+{
+ return machine.device<cassette_image_device>(CASSETTE_TAG);
+}
+
+/* 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. */
+static void cassette_toggle_output(running_machine &machine)
+{
+ apple1_state *state = machine.driver_data<apple1_state>();
+ state->m_cassette_output_flipflop = !state->m_cassette_output_flipflop;
+ cassette_device_image(machine)->output(state->m_cassette_output_flipflop ? 1.0 : -1.0);
+}
+
+READ8_MEMBER(apple1_state::apple1_cassette_r)
+{
+ cassette_toggle_output(machine());
+
+ 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 space.read_byte(0xc100 + 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 (cassette_device_image(machine())->input() > 0.0)
+ return space.read_byte(0xc100 + (offset & ~1));
+ else
+ return space.read_byte(0xc100 + offset);
+ }
+}
+
+WRITE8_MEMBER(apple1_state::apple1_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(machine());
+}
diff --git a/src/mess/machine/apple2.c b/src/mess/machine/apple2.c
new file mode 100644
index 00000000000..39537256074
--- /dev/null
+++ b/src/mess/machine/apple2.c
@@ -0,0 +1,1952 @@
+/***************************************************************************
+
+ apple2.c
+
+ Machine file to handle emulation of the Apple II series.
+
+ TODO: Verify correctness of C08X switches.
+ - need to do double-read before write-enable RAM
+
+***************************************************************************/
+
+#include "emu.h"
+#include "cpu/m6502/m6502.h"
+#include "includes/apple2.h"
+#include "machine/a2bus.h"
+#include "machine/ay3600.h"
+#include "machine/applefdc.h"
+#include "devices/sonydriv.h"
+#include "devices/appldriv.h"
+#include "imagedev/flopdrv.h"
+#include "imagedev/cassette.h"
+#include "sound/speaker.h"
+#include "debugger.h"
+
+#ifdef MAME_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif /* MAME_DEBUG */
+
+#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
+
+#define PROFILER_C00X PROFILER_USER2
+#define PROFILER_C01X PROFILER_USER2
+#define PROFILER_C08X PROFILER_USER2
+#define PROFILER_A2INT PROFILER_USER2
+
+/* -----------------------------------------------------------------------
+ * New Apple II memory manager
+ * ----------------------------------------------------------------------- */
+
+READ8_MEMBER(apple2_state::read_floatingbus)
+{
+ return apple2_getfloatingbusvalue(space.machine());
+}
+
+
+
+void apple2_setup_memory(running_machine &machine, const apple2_memmap_config *config)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+ state->m_mem_config = *config;
+ state->m_current_meminfo = NULL;
+ apple2_update_memory(machine);
+}
+
+
+
+void apple2_update_memory(running_machine &machine)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+ address_space* space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ int i, bank;
+ char rbank[10], wbank[10];
+ int full_update = 0;
+ apple2_meminfo meminfo;
+ read8_delegate *rh;
+ write8_delegate *wh;
+ offs_t begin, end_r, end_w;
+ UINT8 *rbase, *wbase, *rom;
+ UINT32 rom_length, offset;
+ bank_disposition_t bank_disposition;
+ int wh_nop = 0;
+
+ /* need to build list of current info? */
+ if (!state->m_current_meminfo)
+ {
+ for (i = 0; state->m_mem_config.memmap[i].end; i++)
+ ;
+ state->m_current_meminfo = auto_alloc_array(machine, apple2_meminfo, i);
+ full_update = 1;
+ }
+
+ /* get critical info */
+ rom = machine.root_device().memregion("maincpu")->base();
+ rom_length = machine.root_device().memregion("maincpu")->bytes() & ~0xFFF;
+
+ /* loop through the entire memory map */
+ bank = state->m_mem_config.first_bank;
+ for (i = 0; state->m_mem_config.memmap[i].get_meminfo; i++)
+ {
+ /* retrieve information on this entry */
+ memset(&meminfo, 0, sizeof(meminfo));
+ state->m_mem_config.memmap[i].get_meminfo(machine, state->m_mem_config.memmap[i].begin, state->m_mem_config.memmap[i].end, &meminfo);
+
+ bank_disposition = state->m_mem_config.memmap[i].bank_disposition;
+
+ /* do we need to memory reading? */
+ if (full_update
+ || (meminfo.read_mem != state->m_current_meminfo[i].read_mem)
+ || (meminfo.read_handler != state->m_current_meminfo[i].read_handler))
+ {
+ rbase = NULL;
+ sprintf(rbank,"bank%d",bank);
+ begin = state->m_mem_config.memmap[i].begin;
+ end_r = state->m_mem_config.memmap[i].end;
+ rh = NULL;
+
+ LOG(("apple2_update_memory(): Updating RD {%06X..%06X} [#%02d] --> %08X\n",
+ begin, end_r, bank, meminfo.read_mem));
+
+ /* read handling */
+ if (meminfo.read_handler)
+ {
+ /* handler */
+ rh = meminfo.read_handler;
+ }
+ else if (meminfo.read_mem == APPLE2_MEM_FLOATING)
+ {
+ /* floating RAM */
+ rh = &state->read_delegates_master[0];
+ }
+ else if ((meminfo.read_mem & 0xC0000000) == APPLE2_MEM_AUX)
+ {
+ /* auxillary memory */
+ assert(state->m_mem_config.auxmem);
+ offset = meminfo.read_mem & APPLE2_MEM_MASK;
+ rbase = &state->m_mem_config.auxmem[offset];
+ }
+ else if ((meminfo.read_mem & 0xC0000000) == APPLE2_MEM_SLOT)
+ {
+ // slots 1-2
+ if ((meminfo.write_mem & APPLE2_MEM_MASK) == 0)
+ {
+ rh = &state->read_delegates_master[1];
+ }
+ else if ((meminfo.write_mem & APPLE2_MEM_MASK) == 0x200)
+ { // slot 3
+ rh = &state->read_delegates_master[2];
+ }
+ else if ((meminfo.write_mem & APPLE2_MEM_MASK) == 0x300)
+ { // slots 4-7
+ rh = &state->read_delegates_master[3];
+ }
+ else
+ {
+ printf("ERROR: Unhandled case for APPLE2_MEM_SLOT write_mem = %x!\n", (meminfo.write_mem & APPLE2_MEM_MASK));
+ }
+ }
+ else if ((meminfo.read_mem & 0xC0000000) == APPLE2_MEM_ROM)
+ {
+ /* ROM */
+ offset = meminfo.read_mem & APPLE2_MEM_MASK;
+ rbase = &rom[offset % rom_length];
+ }
+ else
+ {
+ /* RAM */
+ if (end_r >= state->m_ram->size())
+ end_r = state->m_ram->size() - 1;
+ offset = meminfo.read_mem & APPLE2_MEM_MASK;
+ if (end_r >= begin)
+ rbase = &state->m_ram->pointer()[offset];
+ }
+
+ /* install the actual handlers */
+ if (begin <= end_r) {
+ if (rh) {
+ space->install_read_handler(begin, end_r, *rh);
+ } else {
+ space->install_read_bank(begin, end_r, rbank);
+ }
+ }
+
+ /* did we 'go past the end?' */
+ if (end_r < state->m_mem_config.memmap[i].end)
+ space->nop_read(end_r + 1, state->m_mem_config.memmap[i].end);
+
+ /* set the memory bank */
+ if (rbase)
+ {
+ state->membank(rbank)->set_base(rbase);
+ }
+
+ /* record the current settings */
+ state->m_current_meminfo[i].read_mem = meminfo.read_mem;
+ state->m_current_meminfo[i].read_handler = meminfo.read_handler;
+ }
+
+ /* do we need to memory writing? */
+ if (full_update
+ || (meminfo.write_mem != state->m_current_meminfo[i].write_mem)
+ || (meminfo.write_handler != state->m_current_meminfo[i].write_handler))
+ {
+ wbase = NULL;
+ if (bank_disposition == A2MEM_MONO)
+ sprintf(wbank,"bank%d",bank);
+ else if (bank_disposition == A2MEM_DUAL)
+ sprintf(wbank,"bank%d",bank+1);
+ begin = state->m_mem_config.memmap[i].begin;
+ end_w = state->m_mem_config.memmap[i].end;
+ wh = NULL;
+
+ LOG(("apple2_update_memory(): Updating WR {%06X..%06X} [#%02d] --> %08X\n",
+ begin, end_w, bank, meminfo.write_mem));
+
+ /* write handling */
+ if (meminfo.write_handler)
+ {
+ /* handler */
+ wh = meminfo.write_handler;
+ }
+ else if ((meminfo.write_mem & 0xC0000000) == APPLE2_MEM_AUX)
+ {
+ /* auxillary memory */
+ assert(state->m_mem_config.auxmem);
+ offset = meminfo.write_mem & APPLE2_MEM_MASK;
+ wbase = &state->m_mem_config.auxmem[offset];
+ }
+ else if ((meminfo.write_mem & 0xC0000000) == APPLE2_MEM_SLOT)
+ {
+ /* slot RAM/ROM */
+
+ // slots 1-2
+ if ((meminfo.write_mem & APPLE2_MEM_MASK) == 0)
+ {
+ wh = &state->write_delegates_master[0];
+ }
+ else if ((meminfo.write_mem & APPLE2_MEM_MASK) == 0x200)
+ { // slot 3
+ wh = &state->write_delegates_master[1];
+ }
+ else if ((meminfo.write_mem & APPLE2_MEM_MASK) == 0x300)
+ { // slots 4-7
+ wh = &state->write_delegates_master[2];
+ }
+ }
+ else if ((meminfo.write_mem & 0xC0000000) == APPLE2_MEM_ROM)
+ {
+ /* ROM */
+ wh_nop = 1;
+ }
+ else
+ {
+ /* RAM */
+ if (end_w >= state->m_ram->size())
+ end_w = state->m_ram->size() - 1;
+ offset = meminfo.write_mem & APPLE2_MEM_MASK;
+ if (end_w >= begin)
+ wbase = &state->m_ram->pointer()[offset];
+ }
+
+
+ /* install the actual handlers */
+ if (begin <= end_w) {
+ if (wh) {
+ space->install_write_handler(begin, end_w, *wh);
+ } else {
+ if (wh_nop) {
+ space->nop_write(begin, end_w);
+ } else {
+ space->install_write_bank(begin, end_w, wbank);
+ }
+ }
+ }
+
+ /* did we 'go past the end?' */
+ if (end_w < state->m_mem_config.memmap[i].end)
+ space->nop_write(end_w + 1, state->m_mem_config.memmap[i].end);
+
+ /* set the memory bank */
+ if (wbase)
+ {
+ state->membank(wbank)->set_base(wbase);
+ }
+
+ /* record the current settings */
+ state->m_current_meminfo[i].write_mem = meminfo.write_mem;
+ state->m_current_meminfo[i].write_handler = meminfo.write_handler;
+ }
+ bank += bank_disposition;
+ }
+}
+
+
+
+static void apple2_update_memory_postload(apple2_state *state)
+{
+ apple2_update_memory(state->machine());
+}
+
+
+
+/* -----------------------------------------------------------------------
+ * Apple II memory map
+ * ----------------------------------------------------------------------- */
+
+READ8_MEMBER(apple2_state::apple2_c0xx_r)
+{
+ if(!space.debugger_access())
+ {
+ static read8_delegate handlers[] =
+ {
+ read8_delegate(FUNC(apple2_state::apple2_c00x_r), this),
+ read8_delegate(FUNC(apple2_state::apple2_c01x_r), this),
+ read8_delegate(FUNC(apple2_state::apple2_c02x_r), this),
+ read8_delegate(FUNC(apple2_state::apple2_c03x_r), this),
+ read8_delegate(FUNC(apple2_state::apple2_c03x_r), this), // not called here, handled elsewhere
+ read8_delegate(FUNC(apple2_state::apple2_c05x_r), this),
+ read8_delegate(FUNC(apple2_state::apple2_c06x_r), this),
+ read8_delegate(FUNC(apple2_state::apple2_c07x_r), this)
+ };
+
+ offset &= 0x7F;
+
+ /* normal handler */
+ if (offset / 0x10 != 4)
+ {
+ return handlers[offset / 0x10](space, offset % 0x10, 0);
+ }
+ }
+
+ return 0;
+}
+
+
+
+WRITE8_MEMBER(apple2_state::apple2_c0xx_w)
+{
+ static write8_delegate handlers[] =
+ {
+ write8_delegate(FUNC(apple2_state::apple2_c00x_w), this),
+ write8_delegate(FUNC(apple2_state::apple2_c01x_w), this),
+ write8_delegate(FUNC(apple2_state::apple2_c02x_w), this),
+ write8_delegate(FUNC(apple2_state::apple2_c03x_w), this),
+ write8_delegate(FUNC(apple2_state::apple2_c03x_w), this), // unused
+ write8_delegate(FUNC(apple2_state::apple2_c05x_w), this),
+ write8_delegate(FUNC(apple2_state::apple2_c05x_w), this), // unused
+ write8_delegate(FUNC(apple2_state::apple2_c07x_w), this)
+ };
+
+ offset &= 0x7F;
+
+ /* normal handler */
+ if (((offset / 0x10) != 4) && (offset / 0x10) != 6)
+ {
+ handlers[offset / 0x10](space, offset % 0x10, data, 0);
+ }
+}
+
+READ8_MEMBER(apple2_state::apple2_c080_r)
+{
+ if(!space.debugger_access())
+ {
+ device_a2bus_card_interface *slotdevice;
+
+ offset &= 0x7F;
+
+ /* now identify the device */
+ slotdevice = m_a2bus->get_a2bus_card(offset / 0x10);
+
+ /* and if we can, read from the slot */
+ if (slotdevice != NULL)
+ {
+ return slotdevice->read_c0nx(space, offset % 0x10);
+ }
+ }
+
+ return 0;
+}
+
+
+WRITE8_MEMBER(apple2_state::apple2_c080_w)
+{
+ device_a2bus_card_interface *slotdevice;
+
+ offset &= 0x7F;
+
+ /* now identify the device */
+ slotdevice = m_a2bus->get_a2bus_card(offset / 0x10);
+
+ /* and if we can, write to the slot */
+ if (slotdevice != NULL)
+ {
+ slotdevice->write_c0nx(space, offset % 0x10, data);
+ }
+}
+
+/* returns default CnXX slotram for a slot space */
+INT8 apple2_slotram_r(address_space &space, int slotnum, int offset)
+{
+ apple2_state *state = space.machine().driver_data<apple2_state>();
+ UINT8 *rom, *slot_ram;
+ UINT32 rom_length, slot_length;
+
+ // find slot_ram if any
+ rom = space.machine().root_device().memregion("maincpu")->base();
+ rom_length = space.machine().root_device().memregion("maincpu")->bytes() & ~0xFFF;
+ slot_length = state->memregion("maincpu")->bytes() - rom_length;
+ slot_ram = (slot_length > 0) ? &rom[rom_length] : NULL;
+
+ if (slot_ram)
+ {
+ if (!space.debugger_access())
+ {
+// printf("slotram_r: taking cnxx_slot to -1\n");
+ state->m_a2_cnxx_slot = -1;
+ apple2_update_memory(space.machine());
+ }
+
+ return slot_ram[offset];
+ }
+
+ // else fall through to floating bus
+ return apple2_getfloatingbusvalue(space.machine());
+}
+
+READ8_MEMBER(apple2_state::apple2_c1xx_r )
+{
+ int slotnum;
+ device_a2bus_card_interface *slotdevice;
+
+ slotnum = ((offset>>8) & 0xf) + 1;
+ slotdevice = m_a2bus->get_a2bus_card(slotnum);
+
+ if (slotdevice != NULL)
+ {
+ if (slotdevice->take_c800())
+ {
+// printf("c1xx_r: taking cnxx_slot to %d\n", slotnum);
+ m_a2_cnxx_slot = slotnum;
+ apple2_update_memory(space.machine());
+ }
+
+ return slotdevice->read_cnxx(space, offset&0xff);
+ }
+ else
+ {
+ return apple2_slotram_r(space, slotnum, offset);
+ }
+
+ // else fall through to floating bus
+ return apple2_getfloatingbusvalue(space.machine());
+}
+
+WRITE8_MEMBER(apple2_state::apple2_c1xx_w )
+{
+ int slotnum;
+ device_a2bus_card_interface *slotdevice;
+ UINT8 *rom, *slot_ram;
+ UINT32 rom_length, slot_length;
+
+ // find slot_ram if any
+ rom = space.machine().root_device().memregion("maincpu")->base();
+ rom_length = space.machine().root_device().memregion("maincpu")->bytes() & ~0xFFF;
+ slot_length = memregion("maincpu")->bytes() - rom_length;
+ slot_ram = (slot_length > 0) ? &rom[rom_length] : NULL;
+
+ slotnum = ((offset>>8) & 0xf) + 1;
+
+ slotdevice = m_a2bus->get_a2bus_card(slotnum);
+
+ if (slotdevice != NULL)
+ {
+ slotdevice->write_cnxx(space, offset&0xff, data);
+ }
+ else
+ {
+ if (slot_ram)
+ slot_ram[offset] = data;
+ }
+}
+
+READ8_MEMBER(apple2_state::apple2_c3xx_r )
+{
+ int slotnum;
+ device_a2bus_card_interface *slotdevice;
+
+ slotnum = 3;
+ slotdevice = m_a2bus->get_a2bus_card(slotnum);
+
+ // is a card installed in this slot?
+ if (slotdevice != NULL)
+ {
+ if (slotdevice->take_c800())
+ {
+// printf("c3xx_r: taking cnxx_slot to %d\n", slotnum);
+ m_a2_cnxx_slot = slotnum;
+ apple2_update_memory(space.machine());
+ }
+ return slotdevice->read_cnxx(space, offset&0xff);
+ }
+ else
+ {
+ return apple2_slotram_r(space, slotnum, offset);
+ }
+
+ // else fall through to floating bus
+ return apple2_getfloatingbusvalue(space.machine());
+}
+
+WRITE8_MEMBER(apple2_state::apple2_c3xx_w )
+{
+ int slotnum;
+ device_a2bus_card_interface *slotdevice;
+ UINT8 *rom, *slot_ram;
+ UINT32 rom_length, slot_length;
+
+ // find slot_ram if any
+ rom = space.machine().root_device().memregion("maincpu")->base();
+ rom_length = space.machine().root_device().memregion("maincpu")->bytes() & ~0xFFF;
+ slot_length = memregion("maincpu")->bytes() - rom_length;
+ slot_ram = (slot_length > 0) ? &rom[rom_length] : NULL;
+
+ slotnum = 3;
+ slotdevice = m_a2bus->get_a2bus_card(slotnum);
+
+ if (slotdevice != NULL)
+ {
+ if (slotdevice->take_c800())
+ {
+// printf("c3xx_w: taking cnxx_slot to %d\n", slotnum);
+ m_a2_cnxx_slot = slotnum;
+ apple2_update_memory(space.machine());
+ }
+ slotdevice->write_cnxx(space, offset&0xff, data);
+ }
+ else
+ {
+ if (slot_ram)
+ slot_ram[offset] = data;
+ }
+}
+
+READ8_MEMBER(apple2_state::apple2_c4xx_r )
+{
+ int slotnum;
+ device_a2bus_card_interface *slotdevice;
+
+ slotnum = ((offset>>8) & 0xf) + 4;
+ slotdevice = m_a2bus->get_a2bus_card(slotnum);
+
+ // is a card installed in this slot?
+ if (slotdevice != NULL)
+ {
+ if (slotdevice->take_c800())
+ {
+// printf("c4xx_r: taking cnxx_slot to %d\n", slotnum);
+ m_a2_cnxx_slot = slotnum;
+ apple2_update_memory(space.machine());
+ }
+ return slotdevice->read_cnxx(space, offset&0xff);
+ }
+ else
+ {
+ return apple2_slotram_r(space, slotnum, offset);
+ }
+
+ // else fall through to floating bus
+ return apple2_getfloatingbusvalue(space.machine());
+}
+
+WRITE8_MEMBER ( apple2_state::apple2_c4xx_w )
+{
+ int slotnum;
+ device_a2bus_card_interface *slotdevice;
+ UINT8 *rom, *slot_ram;
+ UINT32 rom_length, slot_length;
+
+ // find slot_ram if any
+ rom = space.machine().root_device().memregion("maincpu")->base();
+ rom_length = space.machine().root_device().memregion("maincpu")->bytes() & ~0xFFF;
+ slot_length = memregion("maincpu")->bytes() - rom_length;
+ slot_ram = (slot_length > 0) ? &rom[rom_length] : NULL;
+
+ slotnum = ((offset>>8) & 0xf) + 4;
+ slotdevice = m_a2bus->get_a2bus_card(slotnum);
+
+ if (slotdevice != NULL)
+ {
+ if (slotdevice->take_c800())
+ {
+// printf("c4xx_w: taking cnxx_slot to %d\n", slotnum);
+ m_a2_cnxx_slot = slotnum;
+ apple2_update_memory(space.machine());
+ }
+ slotdevice->write_cnxx(space, offset&0xff, data);
+ }
+ else
+ {
+ if (slot_ram)
+ slot_ram[offset] = data;
+ }
+}
+
+READ8_MEMBER(apple2_state::apple2_cfff_r)
+{
+ // debugger guard
+ if (!space.debugger_access())
+ {
+// printf("cfff_r: taking cnxx_slot to -1\n");
+ m_a2_cnxx_slot = -1;
+ apple2_update_memory(space.machine());
+ }
+
+ return apple2_getfloatingbusvalue(space.machine());
+}
+
+WRITE8_MEMBER(apple2_state::apple2_cfff_w)
+{
+ if (!space.debugger_access())
+ {
+// printf("cfff_w: taking cnxx_slot to -1\n");
+ m_a2_cnxx_slot = -1;
+ apple2_update_memory(space.machine());
+ }
+}
+
+READ8_MEMBER(apple2_state::apple2_c800_r )
+{
+ device_a2bus_card_interface *slotdevice;
+
+ slotdevice = m_a2bus->get_a2bus_card(m_a2_cnxx_slot);
+
+ if (slotdevice != NULL)
+ {
+ return slotdevice->read_c800(space, offset&0xfff);
+ }
+
+ return apple2_getfloatingbusvalue(space.machine());
+}
+
+WRITE8_MEMBER(apple2_state::apple2_c800_w )
+{
+ device_a2bus_card_interface *slotdevice;
+
+ slotdevice = m_a2bus->get_a2bus_card(m_a2_cnxx_slot);
+
+ if (slotdevice != NULL)
+ {
+ slotdevice->write_c800(space, offset&0xfff, data);
+ }
+}
+
+READ8_MEMBER(apple2_state::apple2_ce00_r )
+{
+ device_a2bus_card_interface *slotdevice;
+
+ slotdevice = m_a2bus->get_a2bus_card(m_a2_cnxx_slot);
+
+ if (slotdevice != NULL)
+ {
+ return slotdevice->read_c800(space, (offset&0xfff) + 0x600);
+ }
+
+ return apple2_getfloatingbusvalue(space.machine());
+}
+
+WRITE8_MEMBER(apple2_state::apple2_ce00_w )
+{
+ device_a2bus_card_interface *slotdevice;
+
+ slotdevice = m_a2bus->get_a2bus_card(m_a2_cnxx_slot);
+
+ if (slotdevice != NULL)
+ {
+ slotdevice->write_c800(space, (offset&0xfff)+0x600, data);
+ }
+}
+
+READ8_MEMBER(apple2_state::apple2_inh_d000_r )
+{
+ device_a2bus_card_interface *slotdevice;
+
+ slotdevice = m_a2bus->get_a2bus_card(m_inh_slot);
+
+ if (slotdevice != NULL)
+ {
+ return slotdevice->read_inh_rom(space, offset & 0xfff);
+ }
+
+ return apple2_getfloatingbusvalue(space.machine());
+}
+
+WRITE8_MEMBER(apple2_state::apple2_inh_d000_w )
+{
+ device_a2bus_card_interface *slotdevice;
+
+ slotdevice = m_a2bus->get_a2bus_card(m_inh_slot);
+
+ if (slotdevice != NULL)
+ {
+ return slotdevice->write_inh_rom(space, offset & 0xfff, data);
+ }
+}
+
+READ8_MEMBER(apple2_state::apple2_inh_e000_r )
+{
+ device_a2bus_card_interface *slotdevice;
+
+ slotdevice = m_a2bus->get_a2bus_card(m_inh_slot);
+
+ if (slotdevice != NULL)
+ {
+ return slotdevice->read_inh_rom(space, (offset & 0x1fff) + 0x1000);
+ }
+
+ return apple2_getfloatingbusvalue(space.machine());
+}
+
+WRITE8_MEMBER(apple2_state::apple2_inh_e000_w )
+{
+ device_a2bus_card_interface *slotdevice;
+
+ slotdevice = m_a2bus->get_a2bus_card(m_inh_slot);
+
+ if (slotdevice != NULL)
+ {
+ slotdevice->write_inh_rom(space, (offset & 0x1fff) + 0x1000, data);
+ }
+}
+
+static void apple2_mem_0000(running_machine &machine, offs_t begin, offs_t end, apple2_meminfo *meminfo)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+ meminfo->read_mem = (state->m_flags & VAR_ALTZP) ? 0x010000 : 0x000000;
+ meminfo->write_mem = (state->m_flags & VAR_ALTZP) ? 0x010000 : 0x000000;
+}
+
+static void apple2_mem_0200(running_machine &machine, offs_t begin, offs_t end, apple2_meminfo *meminfo)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+ meminfo->read_mem = (state->m_flags & VAR_RAMRD) ? 0x010200 : 0x000200;
+ meminfo->write_mem = (state->m_flags & VAR_RAMWRT) ? 0x010200 : 0x000200;
+}
+
+static void apple2_mem_0400(running_machine &machine, offs_t begin, offs_t end, apple2_meminfo *meminfo)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+
+ if (state->m_flags & VAR_80STORE)
+ {
+ meminfo->read_mem = (state->m_flags & VAR_PAGE2) ? 0x010400 : 0x000400;
+ meminfo->write_mem = (state->m_flags & VAR_PAGE2) ? 0x010400 : 0x000400;
+ meminfo->write_handler = (state->m_flags & VAR_PAGE2) ? &state->write_delegates_0400[0] : &state->write_delegates_0400[1];
+ }
+ else
+ {
+ meminfo->read_mem = (state->m_flags & VAR_RAMRD) ? 0x010400 : 0x000400;
+ meminfo->write_mem = (state->m_flags & VAR_RAMWRT) ? 0x010400 : 0x000400;
+ meminfo->write_handler = (state->m_flags & VAR_RAMWRT) ? &state->write_delegates_0400[0] : &state->write_delegates_0400[1];
+ }
+}
+
+static void apple2_mem_0800(running_machine &machine, offs_t begin, offs_t end, apple2_meminfo *meminfo)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+ meminfo->read_mem = (state->m_flags & VAR_RAMRD) ? 0x010800 : 0x000800;
+ meminfo->write_mem = (state->m_flags & VAR_RAMWRT) ? 0x010800 : 0x000800;
+}
+
+static void apple2_mem_2000(running_machine &machine, offs_t begin, offs_t end, apple2_meminfo *meminfo)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+ if ((state->m_flags & (VAR_80STORE|VAR_HIRES)) == (VAR_80STORE|VAR_HIRES))
+ {
+ meminfo->read_mem = (state->m_flags & VAR_PAGE2) ? 0x012000 : 0x002000;
+ meminfo->write_mem = (state->m_flags & VAR_PAGE2) ? 0x012000 : 0x002000;
+ meminfo->write_handler = (state->m_flags & VAR_PAGE2) ? &state->write_delegates_2000[0] : &state->write_delegates_2000[1];
+ }
+ else
+ {
+ meminfo->read_mem = (state->m_flags & VAR_RAMRD) ? 0x012000 : 0x002000;
+ meminfo->write_mem = (state->m_flags & VAR_RAMWRT) ? 0x012000 : 0x002000;
+ meminfo->write_handler = (state->m_flags & VAR_RAMWRT) ? &state->write_delegates_2000[0] : &state->write_delegates_2000[1];
+ }
+}
+
+static void apple2_mem_4000(running_machine &machine, offs_t begin, offs_t end, apple2_meminfo *meminfo)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+ meminfo->read_mem = (state->m_flags & VAR_RAMRD) ? 0x014000 : 0x004000;
+ meminfo->write_mem = (state->m_flags & VAR_RAMWRT) ? 0x014000 : 0x004000;
+}
+
+static void apple2_mem_C000(running_machine &machine, offs_t begin, offs_t end, apple2_meminfo *meminfo)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+ meminfo->read_handler = &state->rd_c000;
+ meminfo->write_handler = &state->wd_c000;
+}
+
+static void apple2_mem_C080(running_machine &machine, offs_t begin, offs_t end, apple2_meminfo *meminfo)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+
+ meminfo->read_handler = &state->rd_c080;
+ meminfo->write_handler = &state->wd_c080;
+}
+
+static void tk2000_mem_C100(running_machine &machine, offs_t begin, offs_t end, apple2_meminfo *meminfo)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+
+ if (state->m_flags & VAR_TK2000RAM)
+ {
+ meminfo->read_mem = 0x00C100;
+ meminfo->write_mem = 0x00C100;
+ }
+ else
+ {
+ meminfo->read_mem = (begin & 0x3fff) | APPLE2_MEM_ROM;
+ meminfo->write_mem = 0x00C100;
+ }
+}
+
+static void apple2_mem_CFFF(running_machine &machine, offs_t begin, offs_t end, apple2_meminfo *meminfo)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+
+ meminfo->read_handler = &state->rd_cfff;
+ meminfo->write_handler = &state->wd_cfff;
+}
+
+static void apple2_mem_Cx00(running_machine &machine, offs_t begin, offs_t end, apple2_meminfo *meminfo)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+ if (state->m_flags & VAR_INTCXROM)
+ {
+ meminfo->read_mem = (begin & 0x0FFF) | (state->m_flags & VAR_ROMSWITCH ? 0x4000 : 0x0000) | APPLE2_MEM_ROM;
+ meminfo->write_mem = APPLE2_MEM_FLOATING;
+ }
+ else
+ {
+ meminfo->read_mem = ((begin & 0x0FFF) - 0x100) | APPLE2_MEM_SLOT;
+ meminfo->write_mem = ((begin & 0x0FFF) - 0x100) | APPLE2_MEM_SLOT;
+ }
+}
+
+static void apple2_mem_C300(running_machine &machine, offs_t begin, offs_t end, apple2_meminfo *meminfo)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+ if (((state->m_flags & (VAR_INTCXROM|VAR_SLOTC3ROM)) != VAR_SLOTC3ROM) && !(state->m_flags_mask & VAR_SLOTC3ROM))
+ {
+ meminfo->read_mem = (begin & 0x0FFF) | (state->m_flags & VAR_ROMSWITCH ? 0x4000 : 0x0000) | APPLE2_MEM_ROM;
+ meminfo->write_mem = APPLE2_MEM_FLOATING;
+ }
+ else
+ {
+ meminfo->read_mem = ((begin & 0x0FFF) - 0x100) | APPLE2_MEM_SLOT;
+ meminfo->write_mem = ((begin & 0x0FFF) - 0x100) | APPLE2_MEM_SLOT;
+ }
+}
+
+static void apple2_mem_C800(running_machine &machine, offs_t begin, offs_t end, apple2_meminfo *meminfo)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+ if ((state->m_flags & VAR_INTCXROM) || (state->m_a2_cnxx_slot == -1))
+ {
+ meminfo->read_mem = (begin & 0x0FFF) | (state->m_flags & VAR_ROMSWITCH ? 0x4000 : 0x0000) | APPLE2_MEM_ROM;
+ meminfo->write_mem = APPLE2_MEM_FLOATING;
+ }
+ else
+ {
+ meminfo->read_handler = &state->rd_c800;
+ meminfo->write_handler = &state->wd_c800;
+ }
+}
+
+static void apple2_mem_CE00(running_machine &machine, offs_t begin, offs_t end, apple2_meminfo *meminfo)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+ if ((state->m_flags & VAR_ROMSWITCH) && !strcmp(machine.system().name, "apple2cp"))
+ {
+ meminfo->read_mem = APPLE2_MEM_AUX;
+ meminfo->write_mem = APPLE2_MEM_AUX;
+ }
+ else
+ {
+ if ((state->m_flags & VAR_INTCXROM) || (state->m_a2_cnxx_slot == -1))
+ {
+ meminfo->read_mem = (begin & 0x0FFF) | (state->m_flags & VAR_ROMSWITCH ? 0x4000 : 0x0000) | APPLE2_MEM_ROM;
+ meminfo->write_mem = APPLE2_MEM_FLOATING;
+ }
+ else
+ {
+ meminfo->read_handler = &state->rd_c800;
+ meminfo->write_handler = &state->wd_c800;
+ }
+ }
+}
+
+static void apple2_mem_D000(running_machine &machine, offs_t begin, offs_t end, apple2_meminfo *meminfo)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+
+ if (state->m_inh_slot == INH_SLOT_INVALID)
+ {
+ if (state->m_flags & VAR_LCRAM)
+ {
+ if (state->m_flags & VAR_LCRAM2)
+ meminfo->read_mem = (state->m_flags & VAR_ALTZP) ? 0x01C000 : 0x00C000;
+ else
+ meminfo->read_mem = (state->m_flags & VAR_ALTZP) ? 0x01D000 : 0x00D000;
+ }
+ else
+ {
+ meminfo->read_mem = (state->m_flags & VAR_ROMSWITCH) ? 0x005000 : 0x001000;
+ meminfo->read_mem |= APPLE2_MEM_ROM;
+ }
+
+ if (state->m_flags & VAR_LCWRITE)
+ {
+ if (state->m_flags & VAR_LCRAM2)
+ meminfo->write_mem = (state->m_flags & VAR_ALTZP) ? 0x01C000 : 0x00C000;
+ else
+ meminfo->write_mem = (state->m_flags & VAR_ALTZP) ? 0x01D000 : 0x00D000;
+ }
+ else
+ {
+ meminfo->write_mem = APPLE2_MEM_FLOATING;
+ }
+ }
+ else
+ {
+ meminfo->read_handler = &state->rd_inh_d000;
+ meminfo->write_handler = &state->wd_inh_d000;
+ }
+}
+
+static void apple2_mem_E000(running_machine &machine, offs_t begin, offs_t end, apple2_meminfo *meminfo)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+
+ if (state->m_inh_slot == INH_SLOT_INVALID)
+ {
+ if (state->m_flags & VAR_LCRAM)
+ {
+ meminfo->read_mem = (state->m_flags & VAR_ALTZP) ? 0x01E000 : 0x00E000;
+ }
+ else
+ {
+ meminfo->read_mem = (state->m_flags & VAR_ROMSWITCH) ? 0x006000 : 0x002000;
+ meminfo->read_mem |= APPLE2_MEM_ROM;
+ }
+
+ if (state->m_flags & VAR_LCWRITE)
+ {
+ meminfo->write_mem = (state->m_flags & VAR_ALTZP) ? 0x01E000 : 0x00E000;
+ }
+ else
+ {
+ meminfo->write_mem = APPLE2_MEM_FLOATING;
+ }
+ }
+ else
+ {
+ meminfo->read_handler = &state->rd_inh_e000;
+ meminfo->write_handler = &state->wd_inh_e000;
+ }
+}
+
+
+
+static const apple2_memmap_entry apple2_memmap_entries[] =
+{
+ { 0x0000, 0x01FF, apple2_mem_0000, A2MEM_MONO },
+ { 0x0200, 0x03FF, apple2_mem_0200, A2MEM_DUAL },
+ { 0x0400, 0x07FF, apple2_mem_0400, A2MEM_DUAL },
+ { 0x0800, 0x1FFF, apple2_mem_0800, A2MEM_DUAL },
+ { 0x2000, 0x3FFF, apple2_mem_2000, A2MEM_DUAL },
+ { 0x4000, 0xBFFF, apple2_mem_4000, A2MEM_DUAL },
+ { 0xC000, 0xC07F, apple2_mem_C000, A2MEM_IO },
+ { 0xC080, 0xC0FF, apple2_mem_C080, A2MEM_IO },
+ { 0xC100, 0xC2FF, apple2_mem_Cx00, A2MEM_MONO },
+ { 0xC300, 0xC3FF, apple2_mem_C300, A2MEM_MONO },
+ { 0xC400, 0xC7FF, apple2_mem_Cx00, A2MEM_MONO },
+ { 0xC800, 0xCDFF, apple2_mem_C800, A2MEM_MONO },
+ { 0xCE00, 0xCFFE, apple2_mem_CE00, A2MEM_MONO },
+ { 0xCFFF, 0xCFFF, apple2_mem_CFFF, A2MEM_IO },
+ { 0xD000, 0xDFFF, apple2_mem_D000, A2MEM_DUAL },
+ { 0xE000, 0xFFFF, apple2_mem_E000, A2MEM_DUAL },
+ { 0 }
+};
+
+
+static const apple2_memmap_entry tk2000_memmap_entries[] =
+{
+ { 0x0000, 0x01FF, apple2_mem_0000, A2MEM_MONO },
+ { 0x0200, 0x03FF, apple2_mem_0200, A2MEM_DUAL },
+ { 0x0400, 0x07FF, apple2_mem_0400, A2MEM_DUAL },
+ { 0x0800, 0x1FFF, apple2_mem_0800, A2MEM_DUAL },
+ { 0x2000, 0x3FFF, apple2_mem_2000, A2MEM_DUAL },
+ { 0x4000, 0xBFFF, apple2_mem_4000, A2MEM_DUAL },
+ { 0xC000, 0xC07F, apple2_mem_C000, A2MEM_IO },
+ { 0xC080, 0xC0FF, apple2_mem_C080, A2MEM_IO },
+ { 0xC100, 0xFFFF, tk2000_mem_C100, A2MEM_DUAL },
+ { 0 }
+};
+
+void apple2_setvar(running_machine &machine, UINT32 val, UINT32 mask)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+ LOG(("apple2_setvar(): val=0x%06x mask=0x%06x pc=0x%04x\n", val, mask,
+ (unsigned int) cpu_get_reg(machine.device("maincpu"), STATE_GENPC)));
+
+ assert((val & mask) == val);
+
+ /* apply mask and set */
+ val &= state->m_a2_mask;
+ val |= state->m_a2_set;
+
+ /* change the softswitch */
+ state->m_flags &= ~mask;
+ state->m_flags |= val;
+
+ // disable flags that don't apply (INTCXROM/SLOTC3ROM on II/II+ for instance)
+ state->m_flags &= ~state->m_flags_mask;
+
+ apple2_update_memory(machine);
+}
+
+
+
+/* -----------------------------------------------------------------------
+ * Floating bus code
+ *
+ * preliminary floating bus video scanner code - look for comments
+ * with FIX:
+ * ----------------------------------------------------------------------- */
+
+UINT8 apple2_getfloatingbusvalue(running_machine &machine)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+ enum
+ {
+ // scanner types
+ kScannerNone = 0, kScannerApple2, kScannerApple2e,
+
+ // scanner constants
+ kHBurstClock = 53, // clock when Color Burst starts
+ kHBurstClocks = 4, // clocks per Color Burst duration
+ kHClock0State = 0x18, // H[543210] = 011000
+ kHClocks = 65, // clocks per horizontal scan (including HBL)
+ kHPEClock = 40, // clock when HPE (horizontal preset enable) goes low
+ kHPresetClock = 41, // clock when H state presets
+ kHSyncClock = 49, // clock when HSync starts
+ kHSyncClocks = 4, // clocks per HSync duration
+ kNTSCScanLines = 262, // total scan lines including VBL (NTSC)
+ kNTSCVSyncLine = 224, // line when VSync starts (NTSC)
+ kPALScanLines = 312, // total scan lines including VBL (PAL)
+ kPALVSyncLine = 264, // line when VSync starts (PAL)
+ kVLine0State = 0x100, // V[543210CBA] = 100000000
+ kVPresetLine = 256, // line when V state presets
+ kVSyncLines = 4, // lines per VSync duration
+ kClocksPerVSync = kHClocks * kNTSCScanLines // FIX: NTSC only?
+ };
+
+ // vars
+ //
+ int i, Hires, Mixed, Page2, _80Store, ScanLines, /* VSyncLine, ScanCycles,*/
+ h_clock, h_state, h_0, h_1, h_2, h_3, h_4, h_5,
+ v_line, v_state, v_A, v_B, v_C, v_0, v_1, v_2, v_3, v_4, /* v_5, */
+ _hires, addend0, addend1, addend2, sum, address;
+
+ // video scanner data
+ //
+ i = (machine.device<cpu_device>("maincpu"))->total_cycles() % kClocksPerVSync; // cycles into this VSync
+
+ // machine state switches
+ //
+ Hires = (state->m_flags & VAR_HIRES) ? 1 : 0;
+ Mixed = (state->m_flags & VAR_MIXED) ? 1 : 0;
+ Page2 = (state->m_flags & VAR_PAGE2) ? 1 : 0;
+ _80Store = (state->m_flags & VAR_80STORE) ? 1 : 0;
+
+ // calculate video parameters according to display standard
+ //
+ ScanLines = 1 ? kNTSCScanLines : kPALScanLines; // FIX: NTSC only?
+ // VSyncLine = 1 ? kNTSCVSyncLine : kPALVSyncLine; // FIX: NTSC only?
+ // ScanCycles = ScanLines * kHClocks;
+
+ // calculate horizontal scanning state
+ //
+ h_clock = (i + kHPEClock) % kHClocks; // which horizontal scanning clock
+ h_state = kHClock0State + h_clock; // H state bits
+ if (h_clock >= kHPresetClock) // check for horizontal preset
+ {
+ h_state -= 1; // correct for state preset (two 0 states)
+ }
+ h_0 = (h_state >> 0) & 1; // get horizontal state bits
+ h_1 = (h_state >> 1) & 1;
+ h_2 = (h_state >> 2) & 1;
+ h_3 = (h_state >> 3) & 1;
+ h_4 = (h_state >> 4) & 1;
+ h_5 = (h_state >> 5) & 1;
+
+ // calculate vertical scanning state
+ //
+ v_line = i / kHClocks; // which vertical scanning line
+ v_state = kVLine0State + v_line; // V state bits
+ if ((v_line >= kVPresetLine)) // check for previous vertical state preset
+ {
+ v_state -= ScanLines; // compensate for preset
+ }
+ v_A = (v_state >> 0) & 1; // get vertical state bits
+ v_B = (v_state >> 1) & 1;
+ v_C = (v_state >> 2) & 1;
+ v_0 = (v_state >> 3) & 1;
+ v_1 = (v_state >> 4) & 1;
+ v_2 = (v_state >> 5) & 1;
+ v_3 = (v_state >> 6) & 1;
+ v_4 = (v_state >> 7) & 1;
+ //v_5 = (v_state >> 8) & 1;
+
+ // calculate scanning memory address
+ //
+ _hires = Hires;
+ if (Hires && Mixed && (v_4 & v_2))
+ {
+ _hires = 0; // (address is in text memory)
+ }
+
+ addend0 = 0x68; // 1 1 0 1
+ addend1 = (h_5 << 5) | (h_4 << 4) | (h_3 << 3);
+ addend2 = (v_4 << 6) | (v_3 << 5) | (v_4 << 4) | (v_3 << 3);
+ sum = (addend0 + addend1 + addend2) & (0x0F << 3);
+
+ address = 0;
+ address |= h_0 << 0; // a0
+ address |= h_1 << 1; // a1
+ address |= h_2 << 2; // a2
+ address |= sum; // a3 - aa6
+ address |= v_0 << 7; // a7
+ address |= v_1 << 8; // a8
+ address |= v_2 << 9; // a9
+ address |= ((_hires) ? v_A : (1 ^ (Page2 & (1 ^ _80Store)))) << 10; // a10
+ address |= ((_hires) ? v_B : (Page2 & (1 ^ _80Store))) << 11; // a11
+ if (_hires) // hires?
+ {
+ // Y: insert hires only address bits
+ //
+ address |= v_C << 12; // a12
+ address |= (1 ^ (Page2 & (1 ^ _80Store))) << 13; // a13
+ address |= (Page2 & (1 ^ _80Store)) << 14; // a14
+ }
+ else
+ {
+ // N: text, so no higher address bits unless Apple ][, not Apple //e
+ //
+ if ((1) && // Apple ][? // FIX: check for Apple ][? (FB is most useful in old games)
+ (kHPEClock <= h_clock) && // Y: HBL?
+ (h_clock <= (kHClocks - 1)))
+ {
+ address |= 1 << 12; // Y: a12 (add $1000 to address!)
+ }
+ }
+
+ // update VBL' state
+ //
+ if (v_4 & v_3) // VBL?
+ {
+ //CMemory::mState &= ~CMemory::kVBLBar; // Y: VBL' is false // FIX: MESS?
+ }
+ else
+ {
+ //CMemory::mState |= CMemory::kVBLBar; // N: VBL' is true // FIX: MESS?
+ }
+
+ return state->m_ram->pointer()[address % machine.device<ram_device>(RAM_TAG)->size()]; // FIX: this seems to work, but is it right!?
+}
+
+
+
+/* -----------------------------------------------------------------------
+ * Machine reset
+ * ----------------------------------------------------------------------- */
+
+static void apple2_reset(running_machine &machine)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+ int need_intcxrom;
+
+ state->m_rambase = state->m_ram->pointer();
+ state->apple2_refresh_delegates();
+
+ need_intcxrom = !strcmp(machine.system().name, "apple2c")
+ || !strcmp(machine.system().name, "apple2c0")
+ || !strcmp(machine.system().name, "apple2c3")
+ || !strcmp(machine.system().name, "apple2c4")
+ || !strcmp(machine.system().name, "prav8c")
+ || !strcmp(machine.system().name, "apple2cp")
+ || !strncmp(machine.system().name, "apple2g", 7);
+ apple2_setvar(machine, need_intcxrom ? VAR_INTCXROM : 0, ~0);
+
+ // ROM 0 cannot boot unless language card bank 2 is write-enabled (but read ROM) on startup
+ if (!strncmp(machine.system().name, "apple2g", 7))
+ {
+ apple2_setvar(machine, VAR_LCWRITE|VAR_LCRAM2, VAR_LCWRITE | VAR_LCRAM | VAR_LCRAM2);
+ }
+
+ state->m_a2_speaker_state = 0;
+
+ state->m_a2_cnxx_slot = -1; // bank in ROM at C800 on reset
+
+ state->m_joystick_x1_time = state->m_joystick_y1_time = 0;
+ state->m_joystick_x2_time = state->m_joystick_y2_time = 0;
+}
+
+
+
+/* -----------------------------------------------------------------------
+ * Apple II interrupt; used to force partial updates
+ * ----------------------------------------------------------------------- */
+
+TIMER_DEVICE_CALLBACK( apple2_interrupt )
+{
+ int scanline = param;
+
+ if((scanline % 8) == 0)
+ timer.machine().primary_screen->update_partial(timer.machine().primary_screen->vpos());
+}
+
+
+
+/***************************************************************************
+ apple2_mainram0400_w
+ apple2_mainram2000_w
+ apple2_auxram0400_w
+ apple2_auxram2000_w
+***************************************************************************/
+
+WRITE8_MEMBER ( apple2_state::apple2_mainram0400_w )
+{
+ offset += 0x400;
+ m_rambase[offset] = data;
+}
+
+WRITE8_MEMBER ( apple2_state::apple2_mainram2000_w )
+{
+ offset += 0x2000;
+ m_rambase[offset] = data;
+}
+
+WRITE8_MEMBER ( apple2_state::apple2_auxram0400_w )
+{
+ offset += 0x10400;
+ m_rambase[offset] = data;
+}
+
+WRITE8_MEMBER ( apple2_state::apple2_auxram2000_w )
+{
+ offset += 0x12000;
+ m_rambase[offset] = data;
+}
+
+
+
+/***************************************************************************
+ apple2_c00x_r
+***************************************************************************/
+
+READ8_MEMBER ( apple2_state::apple2_c00x_r )
+{
+ UINT8 result = 0;
+
+ if(!space.debugger_access())
+ {
+ /* Read the keyboard data and strobe */
+ g_profiler.start(PROFILER_C00X);
+ result = AY3600_keydata_strobe_r(space.machine());
+ g_profiler.stop();
+ }
+
+
+
+ return result;
+}
+
+
+
+/***************************************************************************
+ apple2_c00x_w
+
+ C000 80STOREOFF
+ C001 80STOREON - use 80-column memory mapping
+ C002 RAMRDOFF
+ C003 RAMRDON - read from aux 48k
+ C004 RAMWRTOFF
+ C005 RAMWRTON - write to aux 48k
+ C006 INTCXROMOFF
+ C007 INTCXROMON
+ C008 ALTZPOFF
+ C009 ALTZPON - use aux ZP, stack and language card area
+ C00A SLOTC3ROMOFF
+ C00B SLOTC3ROMON - use external slot 3 ROM
+ C00C 80COLOFF
+ C00D 80COLON - use 80-column display mode
+ C00E ALTCHARSETOFF
+ C00F ALTCHARSETON - use alt character set
+***************************************************************************/
+
+WRITE8_MEMBER ( apple2_state::apple2_c00x_w )
+{
+ UINT32 mask;
+
+ mask = 1 << (offset / 2);
+ apple2_setvar(space.machine(), (offset & 1) ? mask : 0, mask);
+}
+
+
+
+/***************************************************************************
+ apple2_c01x_r
+***************************************************************************/
+
+READ8_MEMBER( apple2_state::apple2_c01x_r )
+{
+ UINT8 result = apple2_getfloatingbusvalue(space.machine()) & 0x7F;
+
+ if(!space.debugger_access())
+ {
+ g_profiler.start(PROFILER_C01X);
+
+ LOG(("a2 softswitch_r: %04x\n", offset + 0xc010));
+ switch (offset)
+ {
+ case 0x00: result |= AY3600_anykey_clearstrobe_r(space.machine()); break;
+ case 0x01: result |= (m_flags & VAR_LCRAM2) ? 0x80 : 0x00; break;
+ case 0x02: result |= (m_flags & VAR_LCRAM) ? 0x80 : 0x00; break;
+ case 0x03: result |= (m_flags & VAR_RAMRD) ? 0x80 : 0x00; break;
+ case 0x04: result |= (m_flags & VAR_RAMWRT) ? 0x80 : 0x00; break;
+ case 0x05: result |= (m_flags & VAR_INTCXROM) ? 0x80 : 0x00; break;
+ case 0x06: result |= (m_flags & VAR_ALTZP) ? 0x80 : 0x00; break;
+ case 0x07: result |= (m_flags & VAR_SLOTC3ROM) ? 0x80 : 0x00; break;
+ case 0x08: result |= (m_flags & VAR_80STORE) ? 0x80 : 0x00; break;
+ case 0x09: result |= !space.machine().primary_screen->vblank() ? 0x80 : 0x00; break;
+ case 0x0A: result |= (m_flags & VAR_TEXT) ? 0x80 : 0x00; break;
+ case 0x0B: result |= (m_flags & VAR_MIXED) ? 0x80 : 0x00; break;
+ case 0x0C: result |= (m_flags & VAR_PAGE2) ? 0x80 : 0x00; break;
+ case 0x0D: result |= (m_flags & VAR_HIRES) ? 0x80 : 0x00; break;
+ case 0x0E: result |= (m_flags & VAR_ALTCHARSET) ? 0x80 : 0x00; break;
+ case 0x0F: result |= (m_flags & VAR_80COL) ? 0x80 : 0x00; break;
+ }
+
+ g_profiler.stop();
+ }
+
+ return result;
+}
+
+
+
+/***************************************************************************
+ apple2_c01x_w
+***************************************************************************/
+
+WRITE8_MEMBER( apple2_state::apple2_c01x_w )
+{
+ /* Clear the keyboard strobe - ignore the returned results */
+ g_profiler.start(PROFILER_C01X);
+ AY3600_anykey_clearstrobe_r(space.machine());
+ g_profiler.stop();
+}
+
+
+
+/***************************************************************************
+ apple2_c02x_r
+***************************************************************************/
+
+READ8_MEMBER( apple2_state::apple2_c02x_r )
+{
+ if(!space.debugger_access())
+ {
+ apple2_c02x_w(space, offset, 0, 0);
+ }
+ return apple2_getfloatingbusvalue(space.machine());
+}
+
+
+
+/***************************************************************************
+ apple2_c02x_w
+***************************************************************************/
+
+WRITE8_MEMBER( apple2_state::apple2_c02x_w )
+{
+ switch(offset)
+ {
+ case 0x08:
+ apple2_setvar(space.machine(), (m_flags & VAR_ROMSWITCH) ^ VAR_ROMSWITCH, VAR_ROMSWITCH);
+ break;
+ }
+}
+
+
+
+/***************************************************************************
+ apple2_c03x_r
+***************************************************************************/
+
+READ8_MEMBER ( apple2_state::apple2_c03x_r )
+{
+ if(!space.debugger_access())
+ {
+ if (!offset)
+ {
+ device_t *speaker_device = space.machine().device("a2speaker");
+
+ if (m_a2_speaker_state == 1)
+ {
+ m_a2_speaker_state = 0;
+ }
+ else
+ {
+ m_a2_speaker_state = 1;
+ }
+ speaker_level_w(speaker_device, m_a2_speaker_state);
+ }
+ }
+ return apple2_getfloatingbusvalue(space.machine());
+}
+
+
+
+/***************************************************************************
+ apple2_c03x_w
+***************************************************************************/
+
+WRITE8_MEMBER ( apple2_state::apple2_c03x_w )
+{
+ apple2_c03x_r(space, offset, 0);
+}
+
+
+
+/***************************************************************************
+ apple2_c05x_r
+***************************************************************************/
+
+READ8_MEMBER ( apple2_state::apple2_c05x_r )
+{
+ if(!space.debugger_access())
+ {
+ UINT32 mask;
+
+ if (m_machinetype == TK2000)
+ {
+ if (offset == 0xa) // RAM
+ {
+ apple2_setvar(space.machine(), VAR_TK2000RAM, ~0);
+ printf("TK2000: RAM (PC %x)\n", cpu_get_pc(m_maincpu));
+ }
+ else if (offset == 0xb) // ROM
+ {
+ apple2_setvar(space.machine(), 0, ~VAR_TK2000RAM);
+ printf("TK2000: ROM (PC %x)\n", cpu_get_pc(m_maincpu));
+ }
+ }
+
+ /* ANx has reverse SET logic */
+ if (offset >= 8)
+ {
+ offset ^= 1;
+ }
+
+ mask = 0x100 << (offset / 2);
+ apple2_setvar(space.machine(), (offset & 1) ? mask : 0, mask);
+ }
+ return apple2_getfloatingbusvalue(space.machine());
+}
+
+
+
+/***************************************************************************
+ apple2_c05x_w
+***************************************************************************/
+
+WRITE8_MEMBER ( apple2_state::apple2_c05x_w )
+{
+ apple2_c05x_r(space, offset, 0);
+}
+
+
+
+/***************************************************************************
+ apple2_c06x_r
+***************************************************************************/
+
+static cassette_image_device *cassette_device_image(running_machine &machine)
+{
+ return machine.device<cassette_image_device>(CASSETTE_TAG);
+}
+
+READ8_MEMBER ( apple2_state::apple2_c06x_r )
+{
+ int result = 0;
+ if(!space.debugger_access())
+ {
+ switch (offset & 0x0F)
+ {
+ case 0x00:
+ /* Cassette input */
+ {
+ cassette_image_device *dev = cassette_device_image(space.machine());
+
+ if (dev)
+ {
+ result = dev->input() > 0.0 ? 0x80 : 0;
+ }
+ else
+ {
+ result = 0;
+ }
+ }
+ break;
+ case 0x01:
+ /* Open-Apple/Joystick button 0 */
+ result = apple2_pressed_specialkey(space.machine(), SPECIALKEY_BUTTON0);
+ break;
+ case 0x02:
+ /* Closed-Apple/Joystick button 1 */
+ result = apple2_pressed_specialkey(space.machine(), SPECIALKEY_BUTTON1);
+ break;
+ case 0x03:
+ /* Joystick button 2. Later revision motherboards connected this to SHIFT also */
+ result = apple2_pressed_specialkey(space.machine(), SPECIALKEY_BUTTON2);
+ break;
+ case 0x04:
+ /* X Joystick 1 axis */
+ result = space.machine().time().as_double() < m_joystick_x1_time;
+ break;
+ case 0x05:
+ /* Y Joystick 1 axis */
+ result = space.machine().time().as_double() < m_joystick_y1_time;
+ break;
+ case 0x06:
+ /* X Joystick 2 axis */
+ result = space.machine().time().as_double() < m_joystick_x2_time;
+ break;
+ case 0x07:
+ /* Y Joystick 2 axis */
+ result = space.machine().time().as_double() < m_joystick_y2_time;
+ break;
+ default:
+ /* c060 Empty Cassette head read
+ * and any other non joystick c06 port returns this according to applewin
+ */
+ return apple2_getfloatingbusvalue(space.machine());
+ }
+ }
+ return result ? 0x80 : 0x00;
+}
+
+
+
+/***************************************************************************
+ apple2_c07x_r
+***************************************************************************/
+
+READ8_MEMBER ( apple2_state::apple2_c07x_r )
+{
+ if(!space.debugger_access())
+ {
+ double x_calibration = attotime::from_usec(12).as_double();
+ double y_calibration = attotime::from_usec(13).as_double();
+
+ if (offset == 0)
+ {
+ m_joystick_x1_time = space.machine().time().as_double() + x_calibration * space.machine().root_device().ioport("joystick_1_x")->read();
+ m_joystick_y1_time = space.machine().time().as_double() + y_calibration * space.machine().root_device().ioport("joystick_1_y")->read();
+ m_joystick_x2_time = space.machine().time().as_double() + x_calibration * space.machine().root_device().ioport("joystick_2_x")->read();
+ m_joystick_y2_time = space.machine().time().as_double() + y_calibration * space.machine().root_device().ioport("joystick_2_y")->read();
+ }
+ }
+ return 0;
+}
+
+
+
+/***************************************************************************
+ apple2_c07x_w
+***************************************************************************/
+
+WRITE8_MEMBER ( apple2_state::apple2_c07x_w )
+{
+ apple2_c07x_r(space, offset, 0);
+}
+
+
+
+/* -----------------------------------------------------------------------
+ * Floppy disk controller
+ * ----------------------------------------------------------------------- */
+
+
+static int apple2_fdc_has_35(running_machine &machine)
+{
+ return (floppy_get_count(machine)); // - apple525_get_count(machine)) > 0;
+}
+
+static int apple2_fdc_has_525(running_machine &machine)
+{
+ return 1; //apple525_get_count(machine) > 0;
+}
+
+static void apple2_fdc_set_lines(device_t *device, UINT8 lines)
+{
+ apple2_state *state = device->machine().driver_data<apple2_state>();
+ if (state->m_fdc_diskreg & 0x40)
+ {
+ if (apple2_fdc_has_35(device->machine()))
+ {
+ /* slot 5: 3.5" disks */
+ sony_set_lines(device,lines);
+ }
+ }
+ else
+ {
+ if (apple2_fdc_has_525(device->machine()))
+ {
+ /* slot 6: 5.25" disks */
+ apple525_set_lines(device,lines);
+ }
+ }
+}
+
+
+
+static void apple2_fdc_set_enable_lines(device_t *device,int enable_mask)
+{
+ apple2_state *state = device->machine().driver_data<apple2_state>();
+ int slot5_enable_mask = 0;
+ int slot6_enable_mask = 0;
+
+ if (state->m_fdc_diskreg & 0x40)
+ slot5_enable_mask = enable_mask;
+ else
+ slot6_enable_mask = enable_mask;
+
+ if (apple2_fdc_has_35(device->machine()))
+ {
+ /* set the 3.5" enable lines */
+ sony_set_enable_lines(device,slot5_enable_mask);
+ }
+
+ if (apple2_fdc_has_525(device->machine()))
+ {
+ /* set the 5.25" enable lines */
+ apple525_set_enable_lines(device,slot6_enable_mask);
+ }
+}
+
+
+
+static UINT8 apple2_fdc_read_data(device_t *device)
+{
+ apple2_state *state = device->machine().driver_data<apple2_state>();
+ UINT8 result = 0x00;
+
+ if (state->m_fdc_diskreg & 0x40)
+ {
+ if (apple2_fdc_has_35(device->machine()))
+ {
+ /* slot 5: 3.5" disks */
+ result = sony_read_data(device);
+ }
+ }
+ else
+ {
+ if (apple2_fdc_has_525(device->machine()))
+ {
+ /* slot 6: 5.25" disks */
+ result = apple525_read_data(device);
+ }
+ }
+ return result;
+}
+
+
+
+static void apple2_fdc_write_data(device_t *device, UINT8 data)
+{
+ apple2_state *state = device->machine().driver_data<apple2_state>();
+ if (state->m_fdc_diskreg & 0x40)
+ {
+ if (apple2_fdc_has_35(device->machine()))
+ {
+ /* slot 5: 3.5" disks */
+ sony_write_data(device,data);
+ }
+ }
+ else
+ {
+ if (apple2_fdc_has_525(device->machine()))
+ {
+ /* slot 6: 5.25" disks */
+ apple525_write_data(device,data);
+ }
+ }
+}
+
+
+
+static int apple2_fdc_read_status(device_t *device)
+{
+ apple2_state *state = device->machine().driver_data<apple2_state>();
+ int result = 0;
+
+ if (state->m_fdc_diskreg & 0x40)
+ {
+ if (apple2_fdc_has_35(device->machine()))
+ {
+ /* slot 5: 3.5" disks */
+ result = sony_read_status(device);
+ }
+ }
+ else
+ {
+ if (apple2_fdc_has_525(device->machine()))
+ {
+ /* slot 6: 5.25" disks */
+ result = apple525_read_status(device);
+ }
+ }
+ return result;
+}
+
+
+void apple2_iwm_setdiskreg(running_machine &machine, UINT8 data)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+ state->m_fdc_diskreg = data & 0xC0;
+ if (apple2_fdc_has_35(machine))
+ sony_set_sel_line( machine.device("fdc"),state->m_fdc_diskreg & 0x80);
+}
+
+
+const applefdc_interface apple2_fdc_interface =
+{
+ apple2_fdc_set_lines, /* set_lines */
+ apple2_fdc_set_enable_lines, /* set_enable_lines */
+
+ apple2_fdc_read_data, /* read_data */
+ apple2_fdc_write_data, /* write_data */
+ apple2_fdc_read_status /* read_status */
+};
+
+
+
+/* -----------------------------------------------------------------------
+ * Driver init
+ * ----------------------------------------------------------------------- */
+
+void apple2_init_common(running_machine &machine)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+ state->m_inh_slot = INH_SLOT_INVALID;
+ state->m_flags = 0;
+ state->m_fdc_diskreg = 0;
+
+ AY3600_init(machine);
+ machine.add_notifier(MACHINE_NOTIFY_RESET, machine_notify_delegate(FUNC(apple2_reset),&machine));
+
+ /* state save registers */
+ state->save_item(NAME(state->m_flags));
+ machine.save().register_postload(save_prepost_delegate(FUNC(apple2_update_memory_postload), state));
+
+ /* --------------------------------------------- *
+ * set up the softswitch mask/set *
+ * --------------------------------------------- */
+ state->m_a2_mask = ~0;
+ state->m_a2_set = 0;
+
+ /* disable VAR_ROMSWITCH if the ROM is only 16k */
+ if (state->memregion("maincpu")->bytes() < 0x8000)
+ state->m_a2_mask &= ~VAR_ROMSWITCH;
+
+ if (machine.device<ram_device>(RAM_TAG)->size() <= 64*1024)
+ state->m_a2_mask &= ~(VAR_RAMRD | VAR_RAMWRT | VAR_80STORE | VAR_ALTZP | VAR_80COL);
+
+ state->apple2_refresh_delegates();
+}
+
+
+
+MACHINE_START( apple2 )
+{
+ apple2_memmap_config mem_cfg;
+ void *apple2cp_ce00_ram = NULL;
+ apple2_state *state = machine.driver_data<apple2_state>();
+
+ state->m_flags_mask = 0;
+
+ /* there appears to be some hidden RAM that is swapped in on the Apple
+ * IIc plus; I have not found any official documentation but the BIOS
+ * clearly uses this area as writeable memory */
+ if (!strcmp(machine.system().name, "apple2cp"))
+ apple2cp_ce00_ram = auto_alloc_array(machine, UINT8, 0x200);
+
+ state->m_machinetype = APPLE_IIEPLUS;
+
+ apple2_init_common(machine);
+
+ /* setup memory */
+ memset(&mem_cfg, 0, sizeof(mem_cfg));
+ mem_cfg.first_bank = 1;
+ mem_cfg.memmap = apple2_memmap_entries;
+ mem_cfg.auxmem = (UINT8*)apple2cp_ce00_ram;
+ apple2_setup_memory(machine, &mem_cfg);
+
+ /* perform initial reset */
+ apple2_reset(machine);
+}
+
+MACHINE_START( laser128 )
+{
+ apple2_memmap_config mem_cfg;
+ apple2_state *state = machine.driver_data<apple2_state>();
+
+ state->m_flags_mask = 0;
+ state->m_machinetype = LASER128;
+
+ apple2_init_common(machine);
+
+ /* setup memory */
+ memset(&mem_cfg, 0, sizeof(mem_cfg));
+ mem_cfg.first_bank = 1;
+ mem_cfg.memmap = apple2_memmap_entries;
+ mem_cfg.auxmem = (UINT8*)NULL;
+ apple2_setup_memory(machine, &mem_cfg);
+
+ /* perform initial reset */
+ apple2_reset(machine);
+}
+
+MACHINE_START( apple2orig )
+{
+ apple2_memmap_config mem_cfg;
+ void *apple2cp_ce00_ram = NULL;
+ apple2_state *state = machine.driver_data<apple2_state>();
+
+ // II and II+ have no internal ROM or internal slot 3 h/w, so don't allow these states
+ state->m_flags_mask = VAR_INTCXROM|VAR_SLOTC3ROM;
+
+ state->m_machinetype = APPLE_II;
+
+ apple2_init_common(machine);
+
+ /* setup memory */
+ memset(&mem_cfg, 0, sizeof(mem_cfg));
+ mem_cfg.first_bank = 1;
+ mem_cfg.memmap = apple2_memmap_entries;
+ mem_cfg.auxmem = (UINT8*)apple2cp_ce00_ram;
+ apple2_setup_memory(machine, &mem_cfg);
+
+ /* perform initial reset */
+ apple2_reset(machine);
+}
+
+MACHINE_START( space84 )
+{
+ apple2_memmap_config mem_cfg;
+ void *apple2cp_ce00_ram = NULL;
+ apple2_state *state = machine.driver_data<apple2_state>();
+
+ // II and II+ have no internal ROM or internal slot 3 h/w, so don't allow these states
+ state->m_flags_mask = VAR_INTCXROM|VAR_SLOTC3ROM;
+
+ state->m_machinetype = SPACE84;
+
+ apple2_init_common(machine);
+
+ /* setup memory */
+ memset(&mem_cfg, 0, sizeof(mem_cfg));
+ mem_cfg.first_bank = 1;
+ mem_cfg.memmap = apple2_memmap_entries;
+ mem_cfg.auxmem = (UINT8*)apple2cp_ce00_ram;
+ apple2_setup_memory(machine, &mem_cfg);
+
+ /* perform initial reset */
+ apple2_reset(machine);
+}
+
+MACHINE_START( tk2000 )
+{
+ apple2_memmap_config mem_cfg;
+ apple2_state *state = machine.driver_data<apple2_state>();
+
+ // II and II+ have no internal ROM or internal slot 3 h/w, so don't allow these states
+ state->m_flags_mask = VAR_INTCXROM|VAR_SLOTC3ROM;
+
+ state->m_machinetype = TK2000;
+
+ apple2_init_common(machine);
+
+ /* setup memory */
+ memset(&mem_cfg, 0, sizeof(mem_cfg));
+ mem_cfg.first_bank = 1;
+ mem_cfg.memmap = tk2000_memmap_entries;
+ mem_cfg.auxmem = (UINT8*)NULL;
+ apple2_setup_memory(machine, &mem_cfg);
+
+ /* perform initial reset */
+ apple2_reset(machine);
+}
+
+int apple2_pressed_specialkey(running_machine &machine, UINT8 key)
+{
+ return (machine.root_device().ioport("keyb_special")->read() & key)
+ || (machine.root_device().ioport("joystick_buttons")->read_safe(0x00) & key);
+}
+
+void apple2_state::apple2_refresh_delegates()
+{
+ read_delegates_master[0] = read8_delegate(FUNC(apple2_state::read_floatingbus), this);
+ read_delegates_master[1] = read8_delegate(FUNC(apple2_state::apple2_c1xx_r), this);
+ read_delegates_master[2] = read8_delegate(FUNC(apple2_state::apple2_c3xx_r), this);
+ read_delegates_master[3] = read8_delegate(FUNC(apple2_state::apple2_c4xx_r), this);
+ write_delegates_master[0] = write8_delegate(FUNC(apple2_state::apple2_c1xx_w), this);
+ write_delegates_master[1] = write8_delegate(FUNC(apple2_state::apple2_c3xx_w), this);
+ write_delegates_master[2] = write8_delegate(FUNC(apple2_state::apple2_c4xx_w), this);
+
+ write_delegates_2000[0] = write8_delegate(FUNC(apple2_state::apple2_auxram2000_w), this);
+ write_delegates_2000[1] = write8_delegate(FUNC(apple2_state::apple2_mainram2000_w), this);
+
+ rd_c000 = read8_delegate(FUNC(apple2_state::apple2_c0xx_r), this);
+ wd_c000 = write8_delegate(FUNC(apple2_state::apple2_c0xx_w), this);
+
+ rd_c080 = read8_delegate(FUNC(apple2_state::apple2_c080_r), this);
+ wd_c080 = write8_delegate(FUNC(apple2_state::apple2_c080_w), this);
+
+ rd_cfff = read8_delegate(FUNC(apple2_state::apple2_cfff_r), this);
+ wd_cfff = write8_delegate(FUNC(apple2_state::apple2_cfff_w), this);
+
+ rd_c800 = read8_delegate(FUNC(apple2_state::apple2_c800_r), this);
+ wd_c800 = write8_delegate(FUNC(apple2_state::apple2_c800_w), this);
+
+ rd_ce00 = read8_delegate(FUNC(apple2_state::apple2_ce00_r), this);
+ wd_ce00 = write8_delegate(FUNC(apple2_state::apple2_ce00_w), this);
+
+ rd_inh_d000 = read8_delegate(FUNC(apple2_state::apple2_inh_d000_r), this);
+ wd_inh_d000 = write8_delegate(FUNC(apple2_state::apple2_inh_d000_w), this);
+
+ rd_inh_e000 = read8_delegate(FUNC(apple2_state::apple2_inh_e000_r), this);
+ wd_inh_e000 = write8_delegate(FUNC(apple2_state::apple2_inh_e000_w), this);
+
+ write_delegates_0400[0] = write8_delegate(FUNC(apple2_state::apple2_auxram0400_w), this);
+ write_delegates_0400[1] = write8_delegate(FUNC(apple2_state::apple2_mainram0400_w), this);
+
+}
diff --git a/src/mess/machine/apple2gs.c b/src/mess/machine/apple2gs.c
new file mode 100644
index 00000000000..098b0f13f0a
--- /dev/null
+++ b/src/mess/machine/apple2gs.c
@@ -0,0 +1,2033 @@
+/*********************************************************************
+
+ apple2gs.c
+
+ Apple IIgs code
+
+
+ Apple IIgs specific softswitches:
+
+ C019 - RDVBLBAR
+ bits 7 - set during vblank (when at scanline 192 or higher)
+
+ C022 - TBCOLOR
+ bits 7-4 - text foreground color
+ bits 3-0 - text background color
+
+ C023 - VGCINT
+ bit 7 - set for interrupt generated by VGC
+
+ bit 6 - set during one second interrupt
+ bit 5 - set during scanline interrupt
+
+ bit 4 - set during external interrupt
+ bit 3 - ???
+ bit 2 - set for interrupt every second
+
+ bit 1 - set for scanline interrupt
+ bit 0 - set for external interrupt
+
+ C025 - KEYMODREG
+ bit 7 - option key pressed
+ bit 6 - command key presssed
+ bit 5 - modified latch
+ bit 4 - keypad key pressed
+ bit 3 - repeating
+ bit 2 - caps lock latched
+ bit 1 - control key pressed
+ bit 0 - shift key pressed
+
+ C027 - KMSTATUS
+ bit 7 - set if mouse register full
+ bit 6 - mouse interupt enable flag
+ bit 5 - set if data register full
+ bit 4 - data interrupt enabled
+ bit 3 - set if key data full
+ bit 2 - key data interurpt enabled
+ bit 1 - clear if horizontal mouse data, set if vertical
+ bit 0 - command register full
+
+ C029 - NEWVIDEO
+ bit 7 - 1 for Super Hi-Res mode, 0 for old Apple II video modes
+ bit 6 - 1 to enable memory linearization (2000-9D00 in banks 01/E1), 0 for physical layout
+ bit 5 - 1 to display double hi-res mode in monochrome, 0 for color
+ bit 4 - ???
+ bit 3 - ???
+ bit 2 - ???
+ bit 1 - ???
+ bit 0 - ???
+
+ C02D - SLTROMSEL
+
+ C031 - DISKREG
+ bit 7 - set to select head on 3.5" drive
+ bit 6 - set to enable 3.5" drive, clear to enable 5.25" drive
+
+ C035 - SHADOW
+ bit 7 - ???
+ bit 6 - set to inhibit I/O and LC operations ($C000-$FFFF)
+ bit 5 - ???
+ bit 4 - set to inhibit shadowing aux hires page
+ bit 3 - set to inhibit shadowing super hires video
+ bit 2 - set to inhibit shadowing hires page 2
+ bit 1 - set to inhibit shadowing hires page 2
+ bit 0 - set to inhibit shadowing text pages
+
+ C036 - CYAREG
+ bit 7 - clear for slow speed, set for hi speed
+ bit 6 - ???
+ bit 5 - ???
+ bit 4 - shadow in all RAM banks
+ bit 3 - slot 7 motor on
+ bit 2 - slot 6 motor on
+ bit 1 - slot 5 motor on
+ bit 0 - slot 4 motor on
+
+ C041 - INTEN
+ bit 4 - set to enable quarter second interrupts
+ bit 3 - set to enable VBL interrupts
+ bit 2 - set to enable Mega II mouse switch interrupts
+ bit 1 - set to enable Mega II mouse movement interrupts
+ bit 0 - set to enable Mega II mouse mouse operation
+
+ C046 - DIAGTYPE/INTFLAG
+ bit 7 - set if mouse button currently down
+ bit 6 - set if mouse button down on last read
+ bit 5 - set for AN3
+ bit 4 - set if currently in quarter second interrupt
+ bit 3 - set if currently in VBL interrupt
+ bit 2 - set if currently in Mega II mouse switch interrupt
+ bit 1 - set if currently in Mega II mouse movement interrupt
+ bit 0 - set if system IRQ line asserted
+
+ C047 - CLRVBLINT
+
+ C068 - STATEREG
+ bit 7 - ALTZP status
+ bit 6 - PAGE2 status
+ bit 5 - RAMRD status
+ bit 4 - RAMWRT status
+ bit 3 - !LCRAM status (inverted)
+ bit 2 - LCRAM2 status
+ bit 1 - ROMBANK status (unimplemented)
+ bit 0 - INTCXROM status
+
+*********************************************************************/
+
+#include <assert.h>
+#include "emu.h"
+
+#include "includes/apple2gs.h"
+#include "includes/apple2.h"
+#include "machine/ay3600.h"
+#include "machine/applefdc.h"
+#include "devices/sonydriv.h"
+#include "machine/8530scc.h"
+#include "imagedev/flopdrv.h"
+#include "cpu/g65816/g65816.h"
+#include "sound/es5503.h"
+#include "machine/ram.h"
+#include "debugger.h"
+#include "machine/a2bus.h"
+
+#define LOG_C0XX 0
+#define LOG_ADB 0
+#define LOG_IRQ 0
+
+/* -----------------------------------------------------------------------
+ * Apple IIgs clock
+ * ----------------------------------------------------------------------- */
+
+static void process_clock(running_machine &machine)
+{
+ apple2gs_state *state = machine.driver_data<apple2gs_state>();
+ UINT8 operation;
+ seconds_t current_interval;
+
+ /* update clock_curtime */
+ current_interval = machine.time().seconds;
+ state->m_clock_curtime += current_interval - state->m_clock_curtime_interval;
+ state->m_clock_curtime_interval = current_interval;
+
+ switch(state->m_clock_mode)
+ {
+ case CLOCKMODE_IDLE:
+ state->m_clock_read = (state->m_clock_data >> 7);
+ state->m_clock_reg1 = (state->m_clock_data >> 2) & 0x03;
+ operation = (state->m_clock_data >> 4) & 0x07;
+
+ if ((state->m_clock_data & 0x40) == 0x00)
+ {
+ switch(operation)
+ {
+ case 0x00:
+ /* read/write seconds register */
+ state->m_clock_mode = CLOCKMODE_TIME;
+ break;
+
+ case 0x03:
+ /* internal registers */
+ if (state->m_clock_reg1 & 0x02)
+ {
+ state->m_clock_mode = CLOCKMODE_BRAM2;
+ state->m_clock_reg1 = (state->m_clock_data & 0x07) << 5;
+ }
+ else
+ {
+ state->m_clock_mode = CLOCKMODE_INTERNALREGS;
+ }
+ break;
+
+ default:
+ //fatalerror("NYI");
+ break;
+ }
+ }
+ break;
+
+ case CLOCKMODE_BRAM1:
+ if (state->m_clock_read)
+ state->m_clock_data = state->m_clock_bram[state->m_clock_reg1];
+ else
+ state->m_clock_bram[state->m_clock_reg1] = state->m_clock_data;
+ state->m_clock_mode = CLOCKMODE_IDLE;
+ break;
+
+ case CLOCKMODE_BRAM2:
+ state->m_clock_reg1 |= (state->m_clock_data >> 2) & 0x1F;
+ state->m_clock_mode = CLOCKMODE_BRAM1;
+ break;
+
+ case CLOCKMODE_INTERNALREGS:
+ switch (state->m_clock_reg1)
+ {
+ case 0x00:
+ /* test register */
+ break;
+
+ case 0x01:
+ /* write protect register */
+ break;
+ }
+ state->m_clock_mode = CLOCKMODE_IDLE;
+ break;
+
+ case CLOCKMODE_TIME:
+ if (state->m_clock_data & 0x40)
+ {
+ state->m_clock_data = state->m_clock_curtime >> (state->m_clock_reg1 * 8);
+ }
+ else
+ {
+ state->m_clock_curtime &= ~(0xFF << (state->m_clock_reg1 * 8));
+ state->m_clock_curtime |= state->m_clock_data << (state->m_clock_reg1 * 8);
+ }
+ state->m_clock_mode = CLOCKMODE_IDLE;
+ break;
+
+ default:
+ //fatalerror("NYI");
+ break;
+ }
+}
+
+/* -----------------------------------------------------------------------
+ * Interrupts
+ * ----------------------------------------------------------------------- */
+
+static const char *apple2gs_irq_name(UINT16 irq_mask)
+{
+ switch(irq_mask)
+ {
+ case IRQ_KBD_SRQ: return "IRQ_KBD_SRQ";
+ case IRQ_ADB_DATA: return "IRQ_ADB_DATA";
+ case IRQ_ADB_MOUSE: return "IRQ_ADB_MOUSE";
+ case IRQ_VGC_SCANLINE: return "IRQ_VGC_SCANLINE";
+ case IRQ_VGC_SECOND: return "IRQ_VGC_SECOND";
+ case IRQ_INTEN_QSECOND: return "IRQ_INTEN_QSECOND";
+ case IRQ_INTEN_VBL: return "IRQ_INTEN_VBL";
+ case IRQ_DOC: return "IRQ_DOC";
+ case IRQ_SLOT: return "IRQ_SLOT";
+ }
+ return NULL;
+}
+
+void apple2gs_add_irq(running_machine &machine, UINT16 irq_mask)
+{
+ apple2gs_state *state = machine.driver_data<apple2gs_state>();
+ if ((state->m_pending_irqs & irq_mask) == 0x00)
+ {
+ if (LOG_IRQ)
+ logerror("apple2gs_add_irq(): adding %s\n", apple2gs_irq_name(irq_mask));
+
+ state->m_pending_irqs |= irq_mask;
+ cputag_set_input_line(machine, "maincpu", G65816_LINE_IRQ, state->m_pending_irqs ? ASSERT_LINE : CLEAR_LINE);
+ }
+}
+
+
+
+void apple2gs_remove_irq(running_machine &machine, UINT16 irq_mask)
+{
+ apple2gs_state *state = machine.driver_data<apple2gs_state>();
+ if (state->m_pending_irqs & irq_mask)
+ {
+ if (LOG_IRQ)
+ logerror("apple2gs_remove_irq(): removing %s\n", apple2gs_irq_name(irq_mask));
+
+ state->m_pending_irqs &= ~irq_mask;
+ cputag_set_input_line(machine, "maincpu", G65816_LINE_IRQ, state->m_pending_irqs ? ASSERT_LINE : CLEAR_LINE);
+ }
+}
+
+void apple2gs_doc_irq(device_t *device, int state)
+{
+ if (state)
+ {
+ apple2gs_add_irq(device->machine(), IRQ_DOC);
+ }
+ else
+ {
+ apple2gs_remove_irq(device->machine(), IRQ_DOC);
+ }
+}
+
+
+/* Clock interrupt */
+static TIMER_CALLBACK( apple2gs_clock_tick )
+{
+ apple2gs_state *state = machine.driver_data<apple2gs_state>();
+ if ((state->m_vgcint & 0x04) && !(state->m_vgcint & 0x40))
+ {
+ state->m_vgcint |= 0xc0;
+ apple2gs_add_irq(machine, IRQ_VGC_SECOND);
+ }
+}
+
+
+/* Quarter-second interrupt */
+static TIMER_CALLBACK( apple2gs_qsecond_tick )
+{
+ apple2gs_state *state = machine.driver_data<apple2gs_state>();
+ if ((state->m_inten & 0x10) && !(state->m_intflag & 0x10))
+ {
+ state->m_intflag |= 0x10;
+ apple2gs_add_irq(machine, IRQ_INTEN_QSECOND);
+ }
+}
+
+
+/* -----------------------------------------------------------------------
+ * ADB
+ * ----------------------------------------------------------------------- */
+
+
+
+static UINT8 adb_read_memory(apple2gs_state *state, UINT32 address)
+{
+ if (address < ARRAY_LENGTH(state->m_adb_memory))
+ return state->m_adb_memory[address];
+ else
+ return 0x00;
+}
+
+
+
+static void adb_write_memory(apple2gs_state *state, UINT32 address, UINT8 data)
+{
+ if (address < ARRAY_LENGTH(state->m_adb_memory))
+ state->m_adb_memory[address] = data;
+}
+
+
+
+static void adb_set_mode(apple2gs_state *state, UINT8 mode)
+{
+ state->m_adb_mode = mode;
+}
+
+
+
+static void adb_set_config(UINT8 b1, UINT8 b2, UINT8 b3)
+{
+ /* ignore for now */
+}
+
+
+
+static void adb_post_response(apple2gs_state *state, const UINT8 *bytes, size_t length)
+{
+ assert(length < ARRAY_LENGTH(state->m_adb_response_bytes));
+ memcpy(state->m_adb_response_bytes, bytes, length);
+
+ state->m_adb_state = ADBSTATE_INRESPONSE;
+ state->m_adb_response_length = length;
+ state->m_adb_response_pos = 0;
+}
+
+
+
+static void adb_post_response_1(apple2gs_state *state, UINT8 b)
+{
+ adb_post_response(state, &b, 1);
+}
+
+
+
+static void adb_post_response_2(apple2gs_state *state, UINT8 b1, UINT8 b2)
+{
+ UINT8 b[2];
+ b[0] = b1;
+ b[1] = b2;
+ adb_post_response(state, b, 2);
+}
+
+
+
+static void adb_do_command(apple2gs_state *state)
+{
+ int device;
+ UINT32 address;
+ UINT8 val;
+
+ state->m_adb_state = ADBSTATE_IDLE;
+ if (LOG_ADB)
+ logerror("adb_do_command(): adb_command=0x%02x\n", state->m_adb_command);
+
+ switch(state->m_adb_command)
+ {
+ case 0x00: /* ??? */
+ break;
+
+ case 0x03: /* flush keyboard buffer */
+ break;
+
+ case 0x04: /* set modes */
+ adb_set_mode(state, state->m_adb_mode | state->m_adb_command_bytes[0]);
+ break;
+
+ case 0x05: /* clear modes */
+ adb_set_mode(state, state->m_adb_mode & ~state->m_adb_command_bytes[0]);
+ break;
+
+ case 0x06: /* set config */
+ adb_set_config(state->m_adb_command_bytes[0], state->m_adb_command_bytes[1], state->m_adb_command_bytes[2]);
+ break;
+
+ case 0x07: /* synchronize */
+ adb_set_mode(state, state->m_adb_command_bytes[0]);
+ adb_set_config(state->m_adb_command_bytes[1], state->m_adb_command_bytes[2], state->m_adb_command_bytes[3]);
+ break;
+
+ case 0x08: /* write memory */
+ address = state->m_adb_command_bytes[0];
+ val = state->m_adb_command_bytes[1];
+ adb_write_memory(state, address, val);
+ break;
+
+ case 0x09: /* read memory */
+ address = (state->m_adb_command_bytes[1] << 8) | state->m_adb_command_bytes[0];
+ adb_post_response_1(state, adb_read_memory(state, address));
+ break;
+
+ case 0x0a: /* ??? */
+ case 0x0b: /* ??? */
+ break;
+
+ case 0x0d: /* get version */
+ adb_post_response_1(state, 0x06);
+ break;
+
+ case 0x0e: /* read available charsets */
+ adb_post_response_2(state, 0x01, 0x00);
+ break;
+
+ case 0x0f: /* read available layouts */
+ adb_post_response_2(state, 0x01, 0x00);
+ break;
+
+ case 0x12: /* mystery command 0x12 */
+ case 0x13: /* mystery command 0x13 */
+ 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:
+ /* send data to device */
+ device = state->m_adb_command & 0x0f;
+ if (device == state->m_adb_address_keyboard)
+ {
+ }
+ else if (device == state->m_adb_address_mouse)
+ {
+ }
+ break;
+
+ case 0xf2:
+ break;
+
+ default:
+ fatalerror("ADB command 0x%02x unimplemented", state->m_adb_command);
+ break;
+ }
+ state->m_adb_kmstatus |= 0x20;
+}
+
+
+
+UINT8 apple2gs_state::adb_read_datareg()
+{
+ UINT8 result;
+
+ switch(m_adb_state)
+ {
+ case ADBSTATE_INRESPONSE:
+ result = m_adb_response_bytes[m_adb_response_pos++];
+ if (m_adb_response_pos >= m_adb_response_length)
+ {
+ m_adb_state = ADBSTATE_IDLE;
+ m_adb_latent_result = result;
+ m_adb_kmstatus &= ~0x20;
+ }
+ break;
+
+ default:
+ result = 0; //state->m_adb_latent_result & 0x7f;
+ break;
+ }
+
+ if (LOG_ADB)
+ logerror("adb_read_datareg(): result=0x%02x\n", result);
+
+ return result;
+}
+
+
+
+static void adb_write_datareg(running_machine &machine, UINT8 data)
+{
+ apple2gs_state *state = machine.driver_data<apple2gs_state>();
+ if (LOG_ADB)
+ logerror("adb_write_datareg(): data=0x%02x\n", data);
+
+ switch(state->m_adb_state)
+ {
+ case ADBSTATE_IDLE:
+ state->m_adb_command = data;
+ state->m_adb_command_length = 0;
+ state->m_adb_command_pos = 0;
+
+ switch(data)
+ {
+ case 0x00: /* ??? */
+ case 0x01: /* abort */
+ /* do nothing for now */
+ break;
+
+ case 0x03: /* flush keyboard buffer */
+ state->m_adb_command_length = 0;
+ break;
+
+ case 0x04: /* set modes */
+ case 0x05: /* clear modes */
+ state->m_adb_command_length = 1;
+ break;
+
+ case 0x06: /* set config */
+ state->m_adb_command_length = 3;
+ break;
+
+ case 0x07: /* synchronize */
+ if (state->memregion("maincpu")->bytes() == 0x40000) /* HACK */
+ state->m_adb_command_length = 8;
+ else
+ state->m_adb_command_length = 4;
+ break;
+
+ case 0x08: /* write memory */
+ case 0x09: /* read memory */
+ state->m_adb_command_length = 2;
+ break;
+
+ case 0x0a: /* ??? */
+ case 0x0b: /* ??? */
+ state->m_adb_command_length = 0;
+ break;
+
+ case 0x0d: /* get version */
+ state->m_adb_command_length = 0;
+ break;
+
+ case 0x0e: /* read available charsets */
+ state->m_adb_command_length = 0;
+ state->m_adb_state = ADBSTATE_INCOMMAND; /* HACK */
+ break;
+
+ case 0x0f: /* read available layouts */
+ state->m_adb_command_length = 0;
+ state->m_adb_state = ADBSTATE_INCOMMAND; /* HACK */
+ break;
+
+ case 0x12: /* mystery command 0x12 */
+ case 0x13: /* mystery command 0x13 */
+ state->m_adb_command_length = 2;
+ break;
+
+ case 0x70: /* disable SRQ device 0 */
+ case 0x71: /* disable SRQ device 1 */
+ case 0x72: /* disable SRQ device 2 */
+ case 0x73: /* disable SRQ device 3 */
+ /* ignore for now */
+ 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:
+ /* send data to device */
+ state->m_adb_command_length = 2;
+ break;
+
+ case 0xf2:
+ break;
+
+ default:
+ fatalerror("ADB command 0x%02x unimplemented", data);
+ break;
+
+ }
+
+ if (state->m_adb_command_length > 0)
+ {
+ state->m_adb_state = ADBSTATE_INCOMMAND;
+ if (LOG_ADB)
+ logerror("adb_write_datareg(): in command length %u\n", (unsigned) state->m_adb_command_length);
+ }
+ break;
+
+ case ADBSTATE_INCOMMAND:
+ assert(state->m_adb_command_pos < ARRAY_LENGTH(state->m_adb_command_bytes));
+ state->m_adb_command_bytes[state->m_adb_command_pos++] = data;
+ break;
+
+ case ADBSTATE_INRESPONSE:
+ state->m_adb_state = ADBSTATE_IDLE;
+ break;
+ }
+
+ /* do command if necessary */
+ if ((state->m_adb_state == ADBSTATE_INCOMMAND) && (state->m_adb_command_pos >= state->m_adb_command_length))
+ adb_do_command(state);
+}
+
+
+// real rom 3 h/w reads 0x90 when idle, 0x98 when key pressed
+// current MESS reads back 0xb0 when idle
+UINT8 apple2gs_state::adb_read_kmstatus()
+{
+ return m_adb_kmstatus;
+}
+
+
+
+static void adb_write_kmstatus(apple2gs_state *state, UINT8 data)
+{
+ state->m_adb_kmstatus &= ~0x54;
+ state->m_adb_kmstatus |= data & 0x54;
+}
+
+
+
+static UINT8 adb_read_mousedata(running_machine &machine)
+{
+ apple2gs_state *state = machine.driver_data<apple2gs_state>();
+ UINT8 result = 0x00;
+ UINT8 absolute;
+ INT8 delta;
+
+ if (state->m_adb_kmstatus & 0x80) // mouse register full
+ {
+ if (state->m_adb_kmstatus & 0x02) // H/V mouse data select
+ {
+ absolute = state->m_mouse_y;
+ delta = state->m_mouse_dy;
+ state->m_adb_kmstatus &= ~0x82;
+ apple2gs_remove_irq(machine, IRQ_ADB_MOUSE);
+ }
+ else
+ {
+ absolute = state->m_mouse_x;
+ delta = state->m_mouse_dx;
+ state->m_adb_kmstatus |= 0x02;
+ }
+
+ if (delta > 63)
+ delta = 63;
+ else if (delta < -64)
+ delta = -64;
+
+ result = (absolute & 0x80) | (delta & 0x7F);
+ }
+ return result;
+}
+
+
+
+static INT8 seven_bit_diff(UINT8 v1, UINT8 v2)
+{
+ v1 -= v2;
+ if (v1 & 0x40)
+ v1 |= 0x80;
+ else
+ v1 &= ~0x80;
+ return v1;
+}
+
+
+
+static void adb_check_mouse(running_machine &machine)
+{
+ apple2gs_state *state = machine.driver_data<apple2gs_state>();
+ UINT8 new_mouse_x, new_mouse_y;
+
+ /* read mouse values */
+ if ((state->m_adb_kmstatus & 0x80) == 0x00)
+ {
+ new_mouse_x = machine.root_device().ioport("adb_mouse_x")->read();
+ new_mouse_y = machine.root_device().ioport("adb_mouse_y")->read();
+
+ if ((state->m_mouse_x != new_mouse_x) || (state->m_mouse_y != new_mouse_y))
+ {
+ state->m_mouse_dx = seven_bit_diff(new_mouse_x, state->m_mouse_x);
+ state->m_mouse_dy = seven_bit_diff(new_mouse_y, state->m_mouse_y);
+ state->m_mouse_x = new_mouse_x;
+ state->m_mouse_y = new_mouse_y;
+
+ state->m_adb_kmstatus |= 0x80;
+ state->m_adb_kmstatus &= ~0x02;
+ if (state->m_adb_kmstatus & 0x40)
+ apple2gs_add_irq(machine, IRQ_ADB_MOUSE);
+ }
+ }
+}
+
+
+
+static void apple2gs_set_scanint(running_machine &machine, UINT8 data)
+{
+ apple2gs_state *state = machine.driver_data<apple2gs_state>();
+ /* second interrupt */
+ if ((state->m_vgcint & 0x40) && !(data & 0x40))
+ {
+ apple2gs_remove_irq(machine, IRQ_VGC_SECOND);
+ state->m_vgcint &= ~0xC0;
+ }
+
+ /* scanline interrupt */
+ if ((state->m_vgcint & 0x20) && !(data & 0x20))
+ {
+ apple2gs_remove_irq(machine, IRQ_VGC_SCANLINE);
+ state->m_vgcint &= ~0xA0;
+ }
+
+ if (state->m_pending_irqs & (IRQ_VGC_SECOND | IRQ_VGC_SCANLINE))
+ state->m_vgcint |= 0x80;
+}
+
+
+static TIMER_CALLBACK(apple2gs_scanline_tick)
+{
+ apple2gs_state *state = machine.driver_data<apple2gs_state>();
+ int scanline;
+
+ scanline = machine.primary_screen->vpos();
+ machine.primary_screen->update_partial(scanline);
+
+ /* check scanline interrupt bits if we're in super hi-res and the current scanline is within the active display area */
+ if ((state->m_newvideo & 0x80) && (scanline >= (BORDER_TOP-1)) && (scanline < (200+BORDER_TOP-1)))
+ {
+ UINT8 scb;
+
+ scb = state->m_slowmem[0x19D00 + scanline - BORDER_TOP + 1];
+
+ if (scb & 0x40)
+ {
+ // scanline int flag is set even when the actual interrupt is disabled
+ state->m_vgcint |= 0x20;
+
+ // see if the interrupt is also enabled and trigger it if so
+ if (state->m_vgcint & 0x02)
+ {
+ state->m_vgcint |= 0x80;
+ apple2gs_add_irq(machine, IRQ_VGC_SCANLINE);
+ }
+ }
+ }
+
+ if (scanline == (192+BORDER_TOP))
+ {
+ /* VBL interrupt */
+ if ((state->m_inten & 0x08) && !(state->m_intflag & 0x08))
+ {
+ state->m_intflag |= 0x08;
+ apple2gs_add_irq(machine, IRQ_INTEN_VBL);
+ }
+ }
+
+ /* check the mouse status */
+ if ((scanline % 8) == 0)
+ {
+ adb_check_mouse(machine);
+
+ /* call Apple II interrupt handler */
+ if ((machine.primary_screen->vpos() % 8) == 7)
+ {
+ //apple2_interrupt(machine.device("maincpu"));
+ /* TODO: check me! */
+ machine.primary_screen->update_partial(machine.primary_screen->vpos());
+ }
+ }
+
+ state->m_scanline_timer->adjust(machine.primary_screen->time_until_pos((scanline+1)%262, 0));
+}
+
+
+
+/* -----------------------------------------------------------------------
+ * Sound handlers
+ * ----------------------------------------------------------------------- */
+
+
+static READ8_HANDLER( gssnd_r )
+{
+ apple2gs_state *state = space->machine().driver_data<apple2gs_state>();
+ UINT8 ret = 0;
+
+ switch (offset)
+ {
+ case 0: // control
+ ret = state->m_sndglu_ctrl;
+ break;
+ case 1: // data read
+ ret = state->m_sndglu_dummy_read;
+
+ if (state->m_sndglu_ctrl & 0x40) // docram access
+ {
+ UINT8 *docram = state->memregion("es5503")->base();
+ state->m_sndglu_dummy_read = docram[state->m_sndglu_addr];
+ }
+ else
+ {
+ state->m_sndglu_dummy_read = state->m_es5503->read(*space, state->m_sndglu_addr);
+ }
+
+ if (state->m_sndglu_ctrl & 0x20) // auto-increment
+ {
+ state->m_sndglu_addr++;
+ }
+ break;
+ case 2: // addr l
+ ret = state->m_sndglu_addr & 0xff;
+ break;
+ case 3: // addr h
+ ret = (state->m_sndglu_addr >> 8) & 0xff;
+ break;
+ }
+
+ return ret;
+}
+
+
+
+static WRITE8_HANDLER( gssnd_w )
+{
+ apple2gs_state *state = space->machine().driver_data<apple2gs_state>();
+ switch (offset)
+ {
+ case 0: // control
+ state->m_sndglu_ctrl = data & 0x7f; // make sure DOC is never busy
+ if (!(state->m_sndglu_ctrl & 0x40)) // clear hi byte of address pointer on DOC access
+ {
+ state->m_sndglu_addr &= 0xff;
+ }
+ break;
+ case 1: // data write
+ if (state->m_sndglu_ctrl & 0x40) // docram access
+ {
+ UINT8 *docram = space->machine().root_device().memregion("es5503")->base();
+ docram[state->m_sndglu_addr] = data;
+ }
+ else
+ {
+ state->m_es5503->write(*space, state->m_sndglu_addr, data);
+ }
+
+ if (state->m_sndglu_ctrl & 0x20) // auto-increment
+ {
+ state->m_sndglu_addr++;
+ }
+ break;
+ case 2: // addr l
+ state->m_sndglu_addr &= 0xff00;
+ state->m_sndglu_addr |= data;
+ break;
+ case 3: // addr h
+ state->m_sndglu_addr &= 0x00ff;
+ state->m_sndglu_addr |= data<<8;
+ break;
+ }
+}
+
+/* -----------------------------------------------------------------------
+ * IO handlers
+ * ----------------------------------------------------------------------- */
+
+// apple2gs_get_vpos - return the correct vertical counter value for the current scanline,
+// keeping borders in mind.
+
+static int apple2gs_get_vpos(running_machine &machine)
+{
+ int result, scan;
+ static const UINT8 top_border_vert[BORDER_TOP] =
+ {
+ 0xfa, 0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb,
+ 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfe, 0xfe, 0xff,
+
+ };
+
+ scan = machine.primary_screen->vpos();
+
+ if (scan < BORDER_TOP)
+ {
+ result = top_border_vert[scan];
+ }
+ else
+ {
+ result = scan - BORDER_TOP + 0x100 + 1;
+ }
+
+ return result;
+}
+
+READ8_MEMBER( apple2gs_state::apple2gs_c0xx_r )
+{
+ UINT8 result;
+ scc8530_t *scc;
+
+ if(space.debugger_access())
+ {
+ return 0;
+ }
+
+ offset &= 0xFF;
+
+ switch(offset)
+ {
+ case 0x19: /* C019 - RDVBLBAR */
+ result = (space.machine().primary_screen->vpos() >= (192+BORDER_TOP)) ? 0x80 : 0x00;
+ break;
+
+ case 0x22: /* C022 - TBCOLOR */
+ result = (m_fgcolor << 4) | m_bgcolor;
+ break;
+
+ case 0x23: /* C023 - VGCINT */
+ result = m_vgcint;
+ break;
+
+ case 0x24: /* C024 - MOUSEDATA */
+ result = adb_read_mousedata(space.machine());
+ break;
+
+ case 0x25: /* C025 - KEYMODREG */
+ result = AY3600_keymod_r(space.machine());
+ break;
+
+ case 0x26: /* C026 - DATAREG */
+ result = adb_read_datareg();
+ break;
+
+ case 0x27: /* C027 - KMSTATUS */
+ result = adb_read_kmstatus();
+ break;
+
+ case 0x29: /* C029 - NEWVIDEO */
+ result = m_newvideo;
+ break;
+
+ case 0x2B: /* C02B - LANGSEL */
+ result = m_langsel;
+ break;
+
+ case 0x2D: /* C02D - SLTROMSEL */
+ result = m_sltromsel;
+ break;
+
+ case 0x2E: /* C02E - VERTCNT */
+ result = apple2gs_get_vpos(space.machine()) >> 1;
+ break;
+
+ case 0x2F: /* C02F - HORIZCNT */
+ result = space.machine().primary_screen->hpos() / 11;
+ if (result > 0)
+ {
+ result += 0x40;
+ }
+
+ if (apple2gs_get_vpos(space.machine()) & 1)
+ {
+ result |= 0x80;
+ }
+ break;
+
+ case 0x31: /* C031 - DISKREG */
+ result = m_fdc_diskreg;
+ break;
+
+ case 0x33: /* C033 - CLOCKDATA */
+ result = m_clock_data;
+ break;
+
+ case 0x34: /* C034 - CLOCKCTL */
+ result = m_clock_control;
+ break;
+
+ case 0x35: /* C035 - SHADOW */
+ result = m_shadow;
+ break;
+
+ case 0x36: /* C036 - CYAREG */
+ result = m_cyareg;
+ break;
+
+ case 0x38: /* C038 - SCCBREG */
+ case 0x39: /* C039 - SCCAREG */
+ case 0x3A: /* C03A - SCCBDATA */
+ case 0x3B: /* C03B - SCCADATA */
+ scc = space.machine().device<scc8530_t>("scc");
+ result = scc->reg_r(space, offset & 0x03);
+ break;
+
+ case 0x3C: /* C03C - SOUNDCTL */
+ case 0x3D: /* C03D - SOUNDDATA */
+ case 0x3E: /* C03E - SOUNDADRL */
+ case 0x3F: /* C03F - SOUNDADRH */
+ result = gssnd_r(&space, offset & 0x03);
+ break;
+
+ case 0x41: /* C041 - INTEN */
+ result = m_inten;
+ break;
+
+ case 0x46: /* C046 - INTFLAG */
+ result = m_intflag;
+ break;
+
+ case 0x68: /* C068 - STATEREG */
+ result = ((m_flags & VAR_ALTZP) ? 0x80 : 0x00)
+ | ((m_flags & VAR_PAGE2) ? 0x40 : 0x00)
+ | ((m_flags & VAR_RAMRD) ? 0x20 : 0x00)
+ | ((m_flags & VAR_RAMWRT) ? 0x10 : 0x00)
+ | ((m_flags & VAR_LCRAM) ? 0x00 : 0x08)
+ | ((m_flags & VAR_LCRAM2) ? 0x04 : 0x00)
+ | ((m_flags & VAR_INTCXROM)? 0x01 : 0x00);
+ 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:
+ offset |= (space.machine().root_device().memregion("maincpu")->bytes() - 1) & ~0x3FFF;
+ result = space.machine().root_device().memregion("maincpu")->base()[offset];
+ break;
+
+ case 0x21: /* C021 - MONOCOLOR */
+ case 0x2C: /* C02C - CHARROM */
+ result = 0x00;
+ break;
+
+ // slot 6 registers should go to applefdc if slot 6 not "Your Card"
+ 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:
+ if ((m_sltromsel & (1 << 6)) == 0)
+ {
+ result = applefdc_r(m_fdc, offset);
+ }
+ else
+ {
+ result = apple2_c0xx_r(space, offset, 0);
+ }
+ break;
+
+ default:
+ if (offset < 0x80)
+ {
+ result = apple2_c0xx_r(space, offset, 0);
+ }
+ else
+ {
+ result = apple2_c080_r(space, offset, 0);
+ }
+ break;
+ }
+
+ if (LOG_C0XX)
+ logerror("apple2gs_c0xx_r(): offset=0x%02x result=0x%02x\n", offset, result);
+ return result;
+}
+
+
+
+WRITE8_MEMBER( apple2gs_state::apple2gs_c0xx_w )
+{
+ scc8530_t *scc;
+
+ offset &= 0xFF;
+
+ if (LOG_C0XX)
+ logerror("apple2gs_c0xx_w(): offset=0x%02x data=0x%02x\n", offset, data);
+
+ switch(offset)
+ {
+ case 0x22: /* C022 - TBCOLOR */
+ m_fgcolor = (data >> 4) & 0x0F;
+ m_bgcolor = (data >> 0) & 0x0F;
+ break;
+
+ case 0x23: /* C023 - VGCINT */
+ m_vgcint &= ~0x0F;
+ m_vgcint |= data & 0x0F;
+ break;
+
+ case 0x24: /* C024 - MOUSEDATA */
+ case 0x25: /* C025 - KEYMODREG */
+ case 0x28: /* C028 - ROMBANK */
+ case 0x2C: /* C02C - CHARROM */
+ case 0x2E: /* C02E - VERTCNT */
+ case 0x2F: /* C02F - HORIZCNT */
+ /* ignore these writes */
+ break;
+
+ case 0x26: /* C026 - DATAREG */
+ adb_write_datareg(space.machine(), data);
+ break;
+
+ case 0x27: /* C027 - KMSTATUS */
+ adb_write_kmstatus(this, data);
+ break;
+
+ case 0x29: /* C029 - NEWVIDEO */
+ m_newvideo = data;
+ break;
+
+ case 0x2B: /* C02B - LANGSEL */
+ m_langsel = data;
+ break;
+
+ case 0x2D: /* C02D - SLTROMSEL */
+ m_sltromsel = data;
+ apple2_update_memory(space.machine());
+ break;
+
+ case 0x31: /* C031 - DISKREG */
+ apple2_iwm_setdiskreg(space.machine(), data);
+ break;
+
+ case 0x32: /* C032 - SCANINT */
+ apple2gs_set_scanint(space.machine(), data);
+ break;
+
+ case 0x33: /* C033 - CLOCKDATA */
+ m_clock_data = data;
+ break;
+
+ case 0x34: /* C034 - CLOCKCTL */
+ m_clock_control = data & 0x7F;
+ m_bordercolor = data & 0x0F;
+ if (data & 0x80)
+ process_clock(space.machine());
+ break;
+
+ case 0x35: /* C035 - SHADOW */
+ if (m_shadow != data)
+ {
+ m_shadow = data;
+ apple2_update_memory(space.machine());
+ }
+ break;
+
+ case 0x36: /* C036 - CYAREG */
+ m_cyareg = data & ~0x20;
+ space.machine().device("maincpu")->set_unscaled_clock((data & 0x80) ? APPLE2GS_14M/5 : APPLE2GS_7M/7);
+ break;
+
+ case 0x38: /* C038 - SCCBREG */
+ case 0x39: /* C039 - SCCAREG */
+ case 0x3A: /* C03A - SCCBDATA */
+ case 0x3B: /* C03B - SCCADATA */
+ scc = space.machine().device<scc8530_t>("scc");
+ scc->reg_w(space, offset & 0x03, data);
+ break;
+
+ case 0x3C: /* C03C - SOUNDCTL */
+ case 0x3D: /* C03D - SOUNDDATA */
+ case 0x3E: /* C03E - SOUNDADRL */
+ case 0x3F: /* C03F - SOUNDADRH */
+ gssnd_w(&space, offset & 0x03, data);
+ break;
+
+ case 0x41: /* C041 - INTEN */
+ m_inten = data & 0x1F;
+ if ((m_inten & 0x10) == 0x00)
+ apple2gs_remove_irq(space.machine(), IRQ_INTEN_QSECOND);
+ if ((m_inten & 0x08) == 0x00)
+ apple2gs_remove_irq(space.machine(), IRQ_INTEN_VBL);
+ break;
+
+ case 0x47: /* C047 - CLRVBLINT */
+ m_intflag &= ~0x18;
+ apple2gs_remove_irq(space.machine(), IRQ_INTEN_QSECOND);
+ apple2gs_remove_irq(space.machine(), IRQ_INTEN_VBL);
+ break;
+
+ case 0x68: /* C068 - STATEREG */
+ apple2_setvar(space.machine(),
+ ((data & 0x80) ? VAR_ALTZP : 0) |
+ ((data & 0x40) ? VAR_PAGE2 : 0) |
+ ((data & 0x20) ? VAR_RAMRD : 0) |
+ ((data & 0x10) ? VAR_RAMWRT : 0) |
+ ((data & 0x08) ? 0 : VAR_LCRAM) |
+ ((data & 0x04) ? VAR_LCRAM2 : 0) |
+ ((data & 0x01) ? VAR_INTCXROM : 0),
+ VAR_ALTZP | VAR_PAGE2 | VAR_RAMRD | VAR_RAMWRT | VAR_LCRAM | VAR_LCRAM2 | VAR_INTCXROM);
+ break;
+
+ // slot 6 registers should go to applefdc if slot 6 not "Your Card"
+ 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:
+ if ((m_sltromsel & (1 << 6)) == 0)
+ {
+ applefdc_w(m_fdc, offset, data);
+ }
+ else
+ {
+ apple2_c0xx_w(space, offset, data, 0);
+ }
+ break;
+
+ default:
+ if (offset < 0x80)
+ {
+ apple2_c0xx_w(space, offset, data, 0);
+ }
+ else
+ {
+ apple2_c080_w(space, offset, data, 0);
+ }
+ break;
+ }
+}
+
+
+
+/* -----------------------------------------------------------------------
+ * Memory management
+ * ----------------------------------------------------------------------- */
+
+WRITE8_MEMBER( apple2gs_state::apple2gs_main0400_w )
+{
+ offset += 0x000400;
+ m_rambase[offset] = data;
+
+ if (!(m_shadow & 0x01))
+ {
+ m_slowmem[offset] = data;
+ }
+}
+
+WRITE8_MEMBER( apple2gs_state::apple2gs_aux0400_w )
+{
+ offset += 0x010400;
+ m_rambase[offset] = data;
+
+ if (!(m_shadow & 0x01))
+ {
+ m_slowmem[offset] = data;
+ }
+}
+
+WRITE8_MEMBER( apple2gs_state::apple2gs_main2000_w )
+{
+ offset += 0x002000;
+ m_rambase[offset] = data;
+
+ if (!(m_shadow & 0x02))
+ {
+ m_slowmem[offset] = data;
+ }
+}
+
+WRITE8_MEMBER( apple2gs_state::apple2gs_aux2000_w )
+{
+ offset += 0x012000;
+ m_rambase[offset] = data;
+
+ if (!(m_shadow & 0x12) || !(m_shadow & 0x08))
+ {
+ m_slowmem[offset] = data;
+ }
+}
+
+WRITE8_MEMBER( apple2gs_state::apple2gs_main4000_w )
+{
+ offset += 0x004000;
+ m_rambase[offset] = data;
+
+ if ((offset >= 0x004000) && (offset <= 0x005FFF))
+ {
+ if (!(m_shadow & 0x04))
+ m_slowmem[offset] = data;
+ }
+}
+
+WRITE8_MEMBER( apple2gs_state::apple2gs_aux4000_w )
+{
+ offset += 0x014000;
+ m_rambase[offset] = data;
+
+ if ((offset >= 0x014000) && (offset <= 0x015FFF))
+ {
+ if (!(m_shadow & 0x14) || !(m_shadow & 0x08))
+ m_slowmem[offset] = data;
+ }
+ else if ((offset >= 0x016000) && (offset <= 0x019FFF))
+ {
+ if (!(m_shadow & 0x08))
+ {
+ m_slowmem[offset] = data;
+
+ if (offset >= 0x19e00)
+ {
+ int color = (offset - 0x19e00) >> 1;
+
+ palette_set_color_rgb(space.machine(), color + 16,
+ ((m_slowmem[0x19E00 + (color * 2) + 1] >> 0) & 0x0F) * 17,
+ ((m_slowmem[0x19E00 + (color * 2) + 0] >> 4) & 0x0F) * 17,
+ ((m_slowmem[0x19E00 + (color * 2) + 0] >> 0) & 0x0F) * 17);
+ }
+ }
+ }
+}
+
+
+
+static void apple2gs_mem_000000(running_machine &machine,offs_t begin, offs_t end, apple2_meminfo *meminfo)
+{
+ apple2gs_state *state = machine.driver_data<apple2gs_state>();
+ meminfo->read_mem = (state->m_flags & VAR_ALTZP) ? 0x010000 : 0x000000;
+ meminfo->write_mem = (state->m_flags & VAR_ALTZP) ? 0x010000 : 0x000000;
+}
+
+static void apple2gs_mem_000200(running_machine &machine,offs_t begin, offs_t end, apple2_meminfo *meminfo)
+{
+ apple2gs_state *state = machine.driver_data<apple2gs_state>();
+ meminfo->read_mem = (state->m_flags & VAR_RAMRD) ? 0x010200 : 0x000200;
+ meminfo->write_mem = (state->m_flags & VAR_RAMWRT) ? 0x010200 : 0x000200;
+}
+
+static void apple2gs_mem_000400(running_machine &machine,offs_t begin, offs_t end, apple2_meminfo *meminfo)
+{
+ apple2gs_state *state = machine.driver_data<apple2gs_state>();
+ if (state->m_flags & VAR_80STORE)
+ {
+ meminfo->read_mem = (state->m_flags & VAR_PAGE2) ? 0x010400 : 0x000400;
+ meminfo->write_mem = (state->m_flags & VAR_PAGE2) ? 0x010400 : 0x000400;
+ meminfo->write_handler = (state->m_flags & VAR_PAGE2) ? &state->write_delegates_2gs0400[0] : &state->write_delegates_2gs0400[1];
+ }
+ else
+ {
+ meminfo->read_mem = (state->m_flags & VAR_RAMRD) ? 0x010400 : 0x000400;
+ meminfo->write_mem = (state->m_flags & VAR_RAMWRT) ? 0x010400 : 0x000400;
+ meminfo->write_handler = (state->m_flags & VAR_RAMWRT) ? &state->write_delegates_2gs0400[0] : &state->write_delegates_2gs0400[1];
+ }
+}
+
+static void apple2gs_mem_000800(running_machine &machine,offs_t begin, offs_t end, apple2_meminfo *meminfo)
+{
+ apple2gs_state *state = machine.driver_data<apple2gs_state>();
+ meminfo->read_mem = (state->m_flags & VAR_RAMRD) ? 0x010800 : 0x000800;
+ meminfo->write_mem = (state->m_flags & VAR_RAMWRT) ? 0x010800 : 0x000800;
+}
+
+static void apple2gs_mem_002000(running_machine &machine,offs_t begin, offs_t end, apple2_meminfo *meminfo)
+{
+ apple2gs_state *state = machine.driver_data<apple2gs_state>();
+ if ((state->m_flags & (VAR_80STORE|VAR_HIRES)) == (VAR_80STORE|VAR_HIRES))
+ {
+ meminfo->read_mem = (state->m_flags & VAR_PAGE2) ? 0x012000 : 0x002000;
+ meminfo->write_mem = (state->m_flags & VAR_PAGE2) ? 0x012000 : 0x002000;
+ meminfo->write_handler = (state->m_flags & VAR_PAGE2) ? &state->write_delegates_2gs2000[0] : &state->write_delegates_2gs2000[1];
+ }
+ else
+ {
+ meminfo->read_mem = (state->m_flags & VAR_RAMRD) ? 0x012000 : 0x002000;
+ meminfo->write_mem = (state->m_flags & VAR_RAMWRT) ? 0x012000 : 0x002000;
+ meminfo->write_handler = (state->m_flags & VAR_RAMWRT) ? &state->write_delegates_2gs2000[0] : &state->write_delegates_2gs2000[1];
+ }
+}
+
+static void apple2gs_mem_004000(running_machine &machine,offs_t begin, offs_t end, apple2_meminfo *meminfo)
+{
+ apple2gs_state *state = machine.driver_data<apple2gs_state>();
+ meminfo->read_mem = (state->m_flags & VAR_RAMRD) ? 0x014000 : 0x004000;
+ meminfo->write_handler = (state->m_flags & VAR_RAMWRT) ? &state->write_delegates_2gs4000[0] : &state->write_delegates_2gs4000[1];
+}
+
+static void apple2gs_mem_xxD000(running_machine &machine,apple2_meminfo *meminfo, UINT32 lcmem)
+{
+ apple2gs_state *state = machine.driver_data<apple2gs_state>();
+ if (state->m_flags & VAR_LCRAM)
+ {
+ if (state->m_flags & VAR_LCRAM2)
+ meminfo->read_mem = lcmem | 0x00C000;
+ else
+ meminfo->read_mem = lcmem | 0x00D000;
+ }
+ else
+ {
+ meminfo->read_mem = 0x03D000 | APPLE2_MEM_ROM;
+ }
+
+ if (state->m_flags & VAR_LCWRITE)
+ {
+ if (state->m_flags & VAR_LCRAM2)
+ meminfo->write_mem = lcmem | 0x00C000;
+ else
+ meminfo->write_mem = lcmem | 0x00D000;
+ }
+ else
+ {
+ meminfo->write_mem = APPLE2_MEM_FLOATING;
+ }
+}
+
+static void apple2gs_mem_xxE000(running_machine &machine,apple2_meminfo *meminfo, UINT32 lcmem)
+{
+ apple2gs_state *state = machine.driver_data<apple2gs_state>();
+ if (state->m_flags & VAR_LCRAM)
+ meminfo->read_mem = lcmem | 0x00E000;
+ else
+ meminfo->read_mem = 0x03E000 | APPLE2_MEM_ROM;
+
+ if (state->m_flags & VAR_LCWRITE)
+ meminfo->write_mem = lcmem | 0x00E000;
+ else
+ meminfo->write_mem = APPLE2_MEM_FLOATING;
+}
+
+static void apple2gs_mem_00D000(running_machine &machine,offs_t begin, offs_t end, apple2_meminfo *meminfo)
+{
+ apple2gs_state *state = machine.driver_data<apple2gs_state>();
+ if (state->m_shadow & 0x40)
+ {
+ meminfo->read_mem = (state->m_flags & VAR_RAMRD) ? 0x01D000 : 0x00D000;
+ meminfo->write_mem = (state->m_flags & VAR_RAMWRT) ? 0x01D000 : 0x00D000;
+ }
+ else
+ {
+ apple2gs_mem_xxD000(machine,meminfo, (state->m_flags & VAR_ALTZP) ? 0x010000 : 0x000000);
+ }
+}
+
+static void apple2gs_mem_00E000(running_machine &machine,offs_t begin, offs_t end, apple2_meminfo *meminfo)
+{
+ apple2gs_state *state = machine.driver_data<apple2gs_state>();
+ if (state->m_shadow & 0x40)
+ {
+ meminfo->read_mem = (state->m_flags & VAR_RAMRD) ? 0x01E000 : 0x00E000;
+ meminfo->write_mem = (state->m_flags & VAR_RAMWRT) ? 0x01E000 : 0x00E000;
+ }
+ else
+ {
+ apple2gs_mem_xxE000(machine,meminfo, (state->m_flags & VAR_ALTZP) ? 0x010000 : 0x000000);
+ }
+}
+
+static void apple2gs_mem_01D000(running_machine &machine,offs_t begin, offs_t end, apple2_meminfo *meminfo)
+{
+ apple2gs_state *state = machine.driver_data<apple2gs_state>();
+ if (state->m_shadow & 0x40)
+ {
+ meminfo->read_mem = 0x01D000;
+ meminfo->write_mem = 0x01D000;
+ }
+ else
+ {
+ apple2gs_mem_xxD000(machine,meminfo, 0x010000);
+ }
+}
+
+static void apple2gs_mem_01E000(running_machine &machine,offs_t begin, offs_t end, apple2_meminfo *meminfo)
+{
+ apple2gs_state *state = machine.driver_data<apple2gs_state>();
+ if (state->m_shadow & 0x40)
+ {
+ meminfo->read_mem = 0x01E000;
+ meminfo->write_mem = 0x01E000;
+ }
+ else
+ {
+ apple2gs_mem_xxE000(machine,meminfo, 0x010000);
+ }
+}
+
+static void apple2gs_mem_E0D000(running_machine &machine,offs_t begin, offs_t end, apple2_meminfo *meminfo)
+{
+ apple2gs_mem_xxD000(machine,meminfo, 0x000000 | APPLE2_MEM_AUX);
+}
+
+static void apple2gs_mem_E0E000(running_machine &machine,offs_t begin, offs_t end, apple2_meminfo *meminfo)
+{
+ apple2gs_mem_xxE000(machine,meminfo, 0x000000 | APPLE2_MEM_AUX);
+}
+
+static void apple2gs_mem_E1D000(running_machine &machine,offs_t begin, offs_t end, apple2_meminfo *meminfo)
+{
+ apple2gs_mem_xxD000(machine,meminfo, 0x010000 | APPLE2_MEM_AUX);
+}
+
+static void apple2gs_mem_E1E000(running_machine &machine,offs_t begin, offs_t end, apple2_meminfo *meminfo)
+{
+ apple2gs_mem_xxE000(machine,meminfo, 0x010000 | APPLE2_MEM_AUX);
+}
+
+
+
+static const apple2_memmap_entry apple2gs_memmap_entries[] =
+{
+ { 0x000000, 0x0001FF, apple2gs_mem_000000, A2MEM_MONO },
+ { 0x000200, 0x0003FF, apple2gs_mem_000200, A2MEM_DUAL },
+ { 0x000400, 0x0007FF, apple2gs_mem_000400, A2MEM_DUAL },
+ { 0x000800, 0x001FFF, apple2gs_mem_000800, A2MEM_DUAL },
+ { 0x002000, 0x003FFF, apple2gs_mem_002000, A2MEM_DUAL },
+ { 0x004000, 0x00BFFF, apple2gs_mem_004000, A2MEM_DUAL },
+ { 0x00D000, 0x00DFFF, apple2gs_mem_00D000, A2MEM_DUAL },
+ { 0x00E000, 0x00FFFF, apple2gs_mem_00E000, A2MEM_DUAL },
+
+ { 0x01D000, 0x01DFFF, apple2gs_mem_01D000, A2MEM_DUAL },
+ { 0x01E000, 0x01FFFF, apple2gs_mem_01E000, A2MEM_DUAL },
+ { 0xE0D000, 0xE0DFFF, apple2gs_mem_E0D000, A2MEM_DUAL },
+ { 0xE0E000, 0xE0FFFF, apple2gs_mem_E0E000, A2MEM_DUAL },
+ { 0xE1D000, 0xE1DFFF, apple2gs_mem_E1D000, A2MEM_DUAL },
+ { 0xE1E000, 0xE1FFFF, apple2gs_mem_E1E000, A2MEM_DUAL },
+
+ { 0 }
+};
+
+
+
+static UINT8 *apple2gs_getslotmem(running_machine &machine, offs_t address)
+{
+ UINT8 *rom;
+
+ address %= 0x00FFFF;
+ assert(address >= 0xC000);
+ assert(address <= 0xCFFF);
+
+ rom = machine.root_device().memregion("maincpu")->base();
+ rom += 0x030000 % machine.root_device().memregion("maincpu")->bytes();
+ return &rom[address];
+}
+
+
+
+static UINT8 apple2gs_xxCxxx_r(address_space &space, running_machine &machine, offs_t address)
+{
+ apple2gs_state *state = machine.driver_data<apple2gs_state>();
+ UINT8 result;
+ int slot;
+
+ if ((state->m_shadow & 0x40) && ((address & 0xF00000) == 0x000000)) // shadow all banks and C0xx?
+ {
+ result = machine.device<ram_device>(RAM_TAG)->pointer()[address];
+ }
+ else if ((address & 0x000F00) == 0x000000) // accessing C0xx?
+ {
+ result = state->apple2gs_c0xx_r(*machine.device("maincpu")->memory().space(AS_PROGRAM), address, 0);
+ }
+ else
+ {
+ device_a2bus_card_interface *slotdevice;
+
+ slot = (address & 0x000F00) / 0x100;
+ if (slot <= 7) // slots 1-7, it's the slot
+ {
+ slotdevice = state->m_a2bus->get_a2bus_card(slot);
+
+ // is this slot internal or "Your Card"?
+ if ((state->m_sltromsel & (1 << slot)) == 0)
+ {
+ // accessing a slot mapped to internal, let's put back the internal ROM
+ state->m_a2_cnxx_slot = -1;
+ apple2_update_memory(space.machine());
+ result = *apple2gs_getslotmem(machine, address);
+ }
+ else
+ {
+ // accessing a slot mapped to "Your Card", C800 should belong to that card
+ if (slotdevice != NULL)
+ {
+ if (slotdevice->take_c800())
+ {
+ state->m_a2_cnxx_slot = slot;
+ apple2_update_memory(space.machine());
+ }
+ result = slotdevice->read_cnxx(space, address&0xff);
+ }
+ else
+ {
+ result = apple2_getfloatingbusvalue(machine);
+ }
+ }
+ }
+ else // C800-CFFF, not cards
+ {
+ slotdevice = NULL;
+
+ // if CFFF accessed, reset C800 area to internal ROM
+ if(!space.debugger_access())
+ {
+ if ((address & 0xfff) == 0xfff)
+ {
+ state->m_a2_cnxx_slot = -1;
+ apple2_update_memory(space.machine());
+ }
+ }
+
+ if ( state->m_a2_cnxx_slot >= 0 && state->m_a2_cnxx_slot <= 7 )
+ {
+ slotdevice = state->m_a2bus->get_a2bus_card(state->m_a2_cnxx_slot);
+ }
+
+ if (slotdevice)
+ {
+ result = slotdevice->read_c800(space, address&0x7ff);
+ }
+ else
+ {
+ result = *apple2gs_getslotmem(machine, address);
+ }
+ }
+ }
+ return result;
+}
+
+
+
+static void apple2gs_xxCxxx_w(address_space &space, running_machine &machine, offs_t address, UINT8 data)
+{
+ apple2gs_state *state = machine.driver_data<apple2gs_state>();
+ int slot;
+
+ // if CFFF accessed, reset C800 area to internal ROM
+ if(!space.debugger_access())
+ {
+ if ((address & 0xfff) == 0xfff)
+ {
+ state->m_a2_cnxx_slot = -1;
+ apple2_update_memory(space.machine());
+ }
+ }
+
+ if ((state->m_shadow & 0x40) && ((address & 0xF00000) == 0x000000))
+ {
+ machine.device<ram_device>(RAM_TAG)->pointer()[address] = data;
+ }
+ else if ((address & 0x000F00) == 0x000000)
+ {
+ state->apple2gs_c0xx_w(*machine.device("maincpu")->memory().space(AS_PROGRAM), address, data, 0);
+ }
+ else
+ {
+ device_a2bus_card_interface *slotdevice;
+
+ slot = (address & 0x000F00) / 0x100;
+
+ if (slot <= 7) // slots 1-7, it's the slot
+ {
+ slotdevice = state->m_a2bus->get_a2bus_card(slot);
+
+ // is this slot internal or "Your Card"?
+ if ((state->m_sltromsel & (1 << slot)) == 0)
+ {
+ // accessing a slot mapped to internal, let's put back the internal ROM
+ state->m_a2_cnxx_slot = -1;
+ apple2_update_memory(space.machine());
+ *apple2gs_getslotmem(machine, address) = data;
+ }
+ else
+ {
+ // accessing a slot mapped to "Your Card", C800 should belong to that card if it can take it
+ if (slotdevice != NULL)
+ {
+ if (slotdevice->take_c800())
+ {
+ state->m_a2_cnxx_slot = slot;
+ apple2_update_memory(space.machine());
+ }
+ slotdevice->write_cnxx(space, address&0xff, data);
+ }
+ // (else slot is your card but there's no card inserted so the write goes nowhere)
+ }
+ }
+ else // C800-CFFF, not cards
+ {
+ slotdevice = NULL;
+
+ // if CFFF accessed, reset C800 area to internal ROM
+ if ((address & 0xfff) == 0xfff)
+ {
+ state->m_a2_cnxx_slot = -1;
+ apple2_update_memory(space.machine());
+ }
+
+ if ( state->m_a2_cnxx_slot >= 0 && state->m_a2_cnxx_slot <= 7 )
+ {
+ slotdevice = state->m_a2bus->get_a2bus_card(state->m_a2_cnxx_slot);
+ }
+
+ if (slotdevice)
+ {
+ slotdevice->write_c800(space, address&0x7ff, data);
+ }
+ else
+ {
+ *apple2gs_getslotmem(machine, address) = data;
+ }
+ }
+ }
+}
+
+
+
+DIRECT_UPDATE_MEMBER(apple2gs_state::apple2gs_opbase)
+{
+ UINT8 *opptr = NULL;
+ int slot;
+
+ if (((address & 0xFEF000) == 0x00C000) || ((address & 0xFEF000) == 0xE0C000))
+ {
+ if ((m_shadow & 0x40) && ((address & 0xF00000) == 0x000000))
+ {
+ opptr = &machine().device<ram_device>(RAM_TAG)->pointer()[address];
+ }
+ else if ((address & 0x000F00) == 0x000000)
+ {
+ if (((address & 0xFF) >= 0x71) && ((address & 0xFF) <= 0x7F))
+ opptr = apple2gs_getslotmem(machine(), address);
+ }
+ else
+ {
+ slot = (address & 0x000F00) / 0x100;
+
+ if ((slot > 7) || ((m_sltromsel & (1 << slot)) == 0))
+ opptr = apple2gs_getslotmem(machine(), address);
+ }
+
+ if (opptr != NULL)
+ {
+ direct.explicit_configure(address, address, ~0, opptr - address);
+
+ address = ~0;
+ }
+ }
+ return address;
+}
+
+
+
+static READ8_HANDLER( apple2gs_00Cxxx_r ) { return apple2gs_xxCxxx_r(*space, space->machine(), offset | 0x00C000); }
+static READ8_HANDLER( apple2gs_01Cxxx_r ) { return apple2gs_xxCxxx_r(*space, space->machine(), offset | 0x01C000); }
+static READ8_HANDLER( apple2gs_E0Cxxx_r ) { return apple2gs_xxCxxx_r(*space, space->machine(), offset | 0xE0C000); }
+static READ8_HANDLER( apple2gs_E1Cxxx_r ) { return apple2gs_xxCxxx_r(*space, space->machine(), offset | 0xE1C000); }
+
+static WRITE8_HANDLER( apple2gs_00Cxxx_w ) { apple2gs_xxCxxx_w(*space, space->machine(), offset | 0x00C000, data); }
+static WRITE8_HANDLER( apple2gs_01Cxxx_w ) { apple2gs_xxCxxx_w(*space, space->machine(), offset | 0x01C000, data); }
+static WRITE8_HANDLER( apple2gs_E0Cxxx_w ) { apple2gs_xxCxxx_w(*space, space->machine(), offset | 0xE0C000, data); }
+static WRITE8_HANDLER( apple2gs_E1Cxxx_w ) { apple2gs_xxCxxx_w(*space, space->machine(), offset | 0xE1C000, data); }
+
+static WRITE8_HANDLER( apple2gs_Exxxxx_w )
+{
+ apple2gs_state *state = space->machine().driver_data<apple2gs_state>();
+ state->m_slowmem[offset] = data;
+}
+
+static WRITE8_HANDLER( apple2gs_E004xx_w ) { apple2gs_Exxxxx_w(space, offset + 0x00400, data); }
+static WRITE8_HANDLER( apple2gs_E02xxx_w ) { apple2gs_Exxxxx_w(space, offset + 0x02000, data); }
+static WRITE8_HANDLER( apple2gs_E104xx_w ) { apple2gs_Exxxxx_w(space, offset + 0x10400, data); }
+static WRITE8_HANDLER( apple2gs_E12xxx_w ) { apple2gs_Exxxxx_w(space, offset + 0x12000, data); }
+
+static WRITE8_HANDLER( apple2gs_slowmem_w )
+{
+ apple2gs_state *state = space->machine().driver_data<apple2gs_state>();
+ state->m_slowmem[offset] = data;
+
+ if ((offset >= 0x19e00) && (offset < 0x19fff))
+ {
+ int color = (offset - 0x19e00) >> 1;
+
+ palette_set_color_rgb(space->machine(), color + 16,
+ ((state->m_slowmem[0x19E00 + (color * 2) + 1] >> 0) & 0x0F) * 17,
+ ((state->m_slowmem[0x19E00 + (color * 2) + 0] >> 4) & 0x0F) * 17,
+ ((state->m_slowmem[0x19E00 + (color * 2) + 0] >> 0) & 0x0F) * 17);
+ }
+}
+
+// Because the bank address multiplexes on the 65816 data bus, reading a memory area
+// which doesn't drive the bus results in reading back the bank number.
+static READ8_HANDLER(apple2gs_bank_echo_r)
+{
+ apple2gs_state *state = space->machine().driver_data<apple2gs_state>();
+
+ return state->m_echo_bank + (offset>>16);
+}
+
+static void apple2gs_setup_memory(running_machine &machine)
+{
+ apple2gs_state *state = machine.driver_data<apple2gs_state>();
+ address_space* space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ offs_t begin, end;
+ apple2_memmap_config cfg;
+
+ /* allocate memory for E00000-E1FFFF */
+ state->m_slowmem = auto_alloc_array_clear(machine, UINT8, 128*1024);
+ state_save_register_item_pointer(machine, "APPLE2GS_SLOWMEM", NULL, 0, state->m_slowmem, 128*1024);
+
+ // install expanded memory
+ // fair warning: other code assumes banks 0 and 1 are the first 128k of the RAM device, so you must install bank 1 at 0x10000
+ // otherwise nothing works :)
+ if (state->m_is_rom3)
+ {
+ int ramsize = machine.device<ram_device>(RAM_TAG)->size();
+
+ // ROM 03 hardware: the quoted "1 MB" for a base machine doesn't include banks e0/e1, so map accordingly
+ space->install_readwrite_bank(0x010000, ramsize - 1, "bank1");
+ state->membank("bank1")->set_base(machine.device<ram_device>(RAM_TAG)->pointer() + 0x010000);
+
+ space->install_legacy_read_handler( ramsize, 0xdfffff, FUNC(apple2gs_bank_echo_r));
+ state->m_echo_bank = (ramsize >> 16);
+ }
+ else
+ {
+ int ramsize = machine.device<ram_device>(RAM_TAG)->size()-0x30000;
+
+ // ROM 00/01 hardware: the quoted "256K" for a base machine *does* include banks e0/e1.
+ space->install_readwrite_bank(0x010000, ramsize - 1 + 0x10000, "bank1");
+ state->membank("bank1")->set_base(machine.device<ram_device>(RAM_TAG)->pointer() + 0x010000);
+
+ space->install_legacy_read_handler( ramsize + 0x10000, 0xdfffff, FUNC(apple2gs_bank_echo_r));
+ state->m_echo_bank = (ramsize+0x10000) >> 16;
+ }
+
+ /* install hi memory */
+ space->install_read_bank(0xe00000, 0xe1ffff, "bank2");
+ space->install_legacy_write_handler(0xe00000, 0xe1ffff, FUNC(apple2gs_slowmem_w));
+ space->install_legacy_write_handler(0xe00400, 0xe007ff, FUNC(apple2gs_E004xx_w));
+ space->install_legacy_write_handler(0xe02000, 0xe03fff, FUNC(apple2gs_E02xxx_w));
+ space->install_legacy_write_handler(0xe10400, 0xe107ff, FUNC(apple2gs_E104xx_w));
+ space->install_legacy_write_handler(0xe12000, 0xe13fff, FUNC(apple2gs_E12xxx_w));
+ state->membank("bank2")->set_base(state->m_slowmem);
+
+ /* install alternate ROM bank */
+ begin = 0x1000000 - machine.root_device().memregion("maincpu")->bytes();
+ end = 0xffffff;
+ space->install_read_bank(begin, end, "bank3");
+ state->membank("bank3")->set_base(machine.root_device().memregion("maincpu")->base());
+
+ /* install new xxC000-xxCFFF handlers */
+ space->install_legacy_read_handler(0x00c000, 0x00cfff, FUNC(apple2gs_00Cxxx_r));
+ space->install_legacy_write_handler(0x00c000, 0x00cfff, FUNC(apple2gs_00Cxxx_w));
+ space->install_legacy_read_handler(0x01c000, 0x01cfff, FUNC(apple2gs_01Cxxx_r));
+ space->install_legacy_write_handler(0x01c000, 0x01cfff, FUNC(apple2gs_01Cxxx_w));
+ space->install_legacy_read_handler(0xe0c000, 0xe0cfff, FUNC(apple2gs_E0Cxxx_r));
+ space->install_legacy_write_handler(0xe0c000, 0xe0cfff, FUNC(apple2gs_E0Cxxx_w));
+ space->install_legacy_read_handler(0xe1c000, 0xe1cfff, FUNC(apple2gs_E1Cxxx_r));
+ space->install_legacy_write_handler(0xe1c000, 0xe1cfff, FUNC(apple2gs_E1Cxxx_w));
+ space->set_direct_update_handler(direct_update_delegate(FUNC(apple2gs_state::apple2gs_opbase), state));
+
+
+ /* install aux memory writes (for shadowing) */
+ space->install_write_handler(0x010400, 0x0107FF, write8_delegate(FUNC(apple2gs_state::apple2gs_aux0400_w), state));
+ space->install_write_handler(0x012000, 0x013FFF, write8_delegate(FUNC(apple2gs_state::apple2gs_aux2000_w), state));
+ space->install_write_handler(0x014000, 0x019FFF, write8_delegate(FUNC(apple2gs_state::apple2gs_aux4000_w), state));
+
+ /* setup the Apple II memory system */
+ memset(&cfg, 0, sizeof(cfg));
+ cfg.first_bank = 4;
+ cfg.memmap = apple2gs_memmap_entries;
+ cfg.auxmem = state->m_slowmem;
+ cfg.auxmem_length = 0x20000;
+ apple2_setup_memory(machine, &cfg);
+}
+
+
+
+/* -----------------------------------------------------------------------
+ * Driver Init
+ * ----------------------------------------------------------------------- */
+
+static READ8_HANDLER( apple2gs_read_vector )
+{
+ return space->read_byte(offset | 0xFF0000);
+}
+
+MACHINE_RESET( apple2gs )
+{
+ apple2gs_state *state = machine.driver_data<apple2gs_state>();
+
+ state->apple2gs_refresh_delegates();
+
+ state->m_cur_slot6_image = NULL;
+ state->m_newvideo = 0x00;
+ state->m_vgcint = 0x00;
+ state->m_langsel = 0x00;
+ state->m_sltromsel = 0x00;
+ state->m_cyareg = 0x80;
+ state->m_inten = 0x00;
+ state->m_intflag = 0x00;
+ state->m_shadow = 0x00;
+ state->m_pending_irqs = 0x00;
+ state->m_mouse_x = 0x00;
+ state->m_mouse_y = 0x00;
+ state->m_mouse_dx = 0x00;
+ state->m_mouse_dy = 0x00;
+ state->m_adb_state = ADBSTATE_IDLE;
+ state->m_adb_kmstatus = 0x00;
+ state->m_adb_command = 0;
+ state->m_adb_mode = 0;
+ state->m_adb_latent_result = 0;
+ state->m_adb_command_length = 0;
+ state->m_adb_command_pos = 0;
+ memset(state->m_adb_command_bytes, 0, sizeof(state->m_adb_command_bytes));
+ memset(state->m_adb_response_bytes, 0, sizeof(state->m_adb_response_bytes));
+ state->m_adb_response_length = 0;
+ state->m_adb_response_pos = 0;
+ memset(state->m_adb_memory, 0, sizeof(state->m_adb_memory));
+ state->m_adb_address_keyboard = 2;
+ state->m_adb_address_mouse = 3;
+
+ /* init time */
+ state->m_clock_data = 0;
+ state->m_clock_control =0;
+ state->m_clock_read = 0;
+ state->m_clock_reg1 = 0;
+ state->m_clock_mode = CLOCKMODE_IDLE;
+ state->m_clock_curtime = 0;
+ state->m_clock_curtime_interval = 0;
+
+ state->m_sndglu_ctrl = 0x00;
+ state->m_sndglu_addr = 0;
+ state->m_sndglu_dummy_read = 0;
+}
+
+MACHINE_START( apple2gscommon )
+{
+ apple2gs_state *state = machine.driver_data<apple2gs_state>();
+
+ state->apple2gs_refresh_delegates();
+ apple2_init_common(machine);
+
+ /* set up Apple IIgs vectoring */
+ g65816_set_read_vector_callback(machine.device("maincpu"), apple2gs_read_vector);
+
+ /* setup globals */
+ state->m_is_rom3 = true;
+
+ machine.device<nvram_device>("nvram")->set_base(state->m_clock_bram, sizeof(state->m_clock_bram));
+
+ /* save state stuff. note that the driver takes care of docram. */
+ UINT8* ram = machine.device<ram_device>(RAM_TAG)->pointer();
+ state_save_register_item_pointer(machine, "APPLE2GS_RAM", NULL, 0, ram, machine.device<ram_device>(RAM_TAG)->size());
+
+ state_save_register_item(machine, "NEWVIDEO", NULL, 0, state->m_newvideo);
+
+ state_save_register_item(machine, "VGCINT", NULL,0, state->m_vgcint);
+ state_save_register_item(machine, "LANGSEL", NULL,0, state->m_langsel);
+ state_save_register_item(machine, "SLTROMSEL", NULL,0, state->m_sltromsel);
+ state_save_register_item(machine, "CYAREG", NULL,0, state->m_cyareg);
+ state_save_register_item(machine, "INTEN", NULL,0, state->m_inten);
+ state_save_register_item(machine, "INTFLAG", NULL,0, state->m_intflag);
+ state_save_register_item(machine, "SHADOW", NULL,0, state->m_shadow);
+ state_save_register_item(machine, "PENDIRQ", NULL,0, state->m_pending_irqs);
+ state_save_register_item(machine, "MX", NULL,0, state->m_mouse_x);
+ state_save_register_item(machine, "MY", NULL,0, state->m_mouse_y);
+ state_save_register_item(machine, "MDX", NULL,0, state->m_mouse_dx);
+ state_save_register_item(machine, "MDY", NULL,0, state->m_mouse_dy);
+
+ state_save_register_item(machine, "CLKDATA", NULL,0, state->m_clock_data);
+ state_save_register_item(machine, "CLKCTRL", NULL,0, state->m_clock_control);
+ state_save_register_item(machine, "CLKRD", NULL,0, state->m_clock_read);
+ state_save_register_item(machine, "CLKREG1", NULL,0, state->m_clock_reg1);
+ state_save_register_item(machine, "CLKCURTIME", NULL,0, state->m_clock_curtime);
+ state_save_register_item(machine, "CLKCURTIMEINT", NULL,0, state->m_clock_curtime_interval);
+// state_save_register_item(machine, "CLKMODE", NULL,0, state->m_clock_mode);
+ state->save_item(NAME(state->m_clock_bram));
+
+ state->save_item(NAME(state->m_adb_memory));
+ state->save_item(NAME(state->m_adb_command_bytes));
+ state->save_item(NAME(state->m_adb_response_bytes));
+// state_save_register_item(machine, "ADB", NULL,0, state->m_adb_state);
+ state_save_register_item(machine, "ADB", NULL,0, state->m_adb_command);
+ state_save_register_item(machine, "ADB", NULL,0, state->m_adb_mode);
+ state_save_register_item(machine, "ADB", NULL,0, state->m_adb_kmstatus);
+ state_save_register_item(machine, "ADB", NULL,0, state->m_adb_latent_result);
+ state_save_register_item(machine, "ADB", NULL,0, state->m_adb_command_length);
+ state_save_register_item(machine, "ADB", NULL,0, state->m_adb_command_pos);
+ state_save_register_item(machine, "ADB", NULL,0, state->m_adb_response_length);
+ state_save_register_item(machine, "ADB", NULL,0, state->m_adb_response_pos);
+ state_save_register_item(machine, "ADB", NULL,0, state->m_adb_address_keyboard);
+ state_save_register_item(machine, "ADB", NULL,0, state->m_adb_address_mouse);
+
+ state_save_register_item(machine, "SNDGLUCTRL", NULL,0, state->m_sndglu_ctrl);
+ state_save_register_item(machine, "SNDGLUADDR", NULL,0, state->m_sndglu_addr);
+ state_save_register_item(machine, "SNDGLUDUMMYRD", NULL,0, state->m_sndglu_dummy_read);
+
+ state->m_clock_timer = machine.scheduler().timer_alloc(FUNC(apple2gs_clock_tick));
+ state->m_clock_timer->adjust(attotime::from_seconds(1), 0, attotime::from_seconds(1));
+
+ state->m_qsecond_timer = machine.scheduler().timer_alloc(FUNC(apple2gs_qsecond_tick));
+ state->m_qsecond_timer->adjust(attotime::from_usec(266700), 0, attotime::from_usec(266700));
+
+ state->m_scanline_timer = machine.scheduler().timer_alloc(FUNC(apple2gs_scanline_tick));
+ state->m_scanline_timer->adjust(attotime::never);
+
+ // fire on scanline zero
+ state->m_scanline_timer->adjust(machine.primary_screen->time_until_pos(0, 0));
+}
+
+MACHINE_START( apple2gs )
+{
+ MACHINE_START_NAME(apple2gscommon)(machine);
+ apple2gs_setup_memory(machine);
+}
+
+MACHINE_START( apple2gsr1 )
+{
+ MACHINE_START_NAME(apple2gscommon)(machine);
+
+ apple2gs_state *state = machine.driver_data<apple2gs_state>();
+ state->m_is_rom3 = false;
+ apple2gs_setup_memory(machine);
+}
+
+void apple2gs_state::apple2gs_refresh_delegates()
+{
+ write_delegates_2gs0400[0] = write8_delegate(FUNC(apple2gs_state::apple2gs_aux0400_w), this);
+ write_delegates_2gs0400[1] = write8_delegate(FUNC(apple2gs_state::apple2gs_main0400_w), this);
+ write_delegates_2gs2000[0] = write8_delegate(FUNC(apple2gs_state::apple2gs_aux2000_w), this);
+ write_delegates_2gs2000[1] = write8_delegate(FUNC(apple2gs_state::apple2gs_main2000_w), this);
+ write_delegates_2gs4000[0] = write8_delegate(FUNC(apple2gs_state::apple2gs_aux4000_w), this);
+ write_delegates_2gs4000[1] = write8_delegate(FUNC(apple2gs_state::apple2gs_main4000_w), this);
+}
+
diff --git a/src/mess/machine/apple3.c b/src/mess/machine/apple3.c
new file mode 100644
index 00000000000..e8059f65aa4
--- /dev/null
+++ b/src/mess/machine/apple3.c
@@ -0,0 +1,738 @@
+/***************************************************************************
+
+ machine/apple3.c
+
+ Apple ///
+
+
+ VIA #0 (D VIA)
+ CA1: 1 if a cartridge is inserted, 0 otherwise
+
+ VIA #1 (E VIA)
+ CA2: 1 if key pressed, 0 otherwise
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/apple3.h"
+#include "includes/apple2.h"
+#include "cpu/m6502/m6502.h"
+#include "machine/6522via.h"
+#include "machine/ay3600.h"
+#include "machine/applefdc.h"
+#include "devices/appldriv.h"
+#include "machine/6551acia.h"
+#include "machine/ram.h"
+
+
+static void apple3_update_drives(device_t *device);
+
+
+#define LOG_MEMORY 1
+#define LOG_INDXADDR 1
+
+
+
+/* ----------------------------------------------------------------------- */
+
+
+static void apple3_profile_init(void)
+{
+}
+
+
+
+static void apple3_profile_statemachine(void)
+{
+}
+
+
+
+UINT8 apple3_state::apple3_profile_r(offs_t offset)
+{
+ UINT8 result = 0;
+
+ offset %= 4;
+ apple3_profile_statemachine();
+
+ m_profile_lastaddr = offset;
+
+ switch(offset)
+ {
+ case 1:
+ m_profile_gotstrobe = 1;
+ apple3_profile_statemachine();
+ result = m_profile_readdata;
+ break;
+
+ case 2:
+ if (m_profile_busycount > 0)
+ {
+ m_profile_busycount--;
+ result = 0xFF;
+ }
+ else
+ {
+ result = m_profile_busy | m_profile_online;
+ }
+ break;
+ }
+ return result;
+}
+
+
+
+void apple3_state::apple3_profile_w(offs_t offset, UINT8 data)
+{
+ offset %= 4;
+ m_profile_lastaddr = -1;
+
+ switch(offset)
+ {
+ case 0:
+ m_profile_writedata = data;
+ m_profile_gotstrobe = 1;
+ break;
+ }
+ apple3_profile_statemachine();
+}
+
+
+
+/* ----------------------------------------------------------------------- */
+
+READ8_MEMBER(apple3_state::apple3_c0xx_r)
+{
+ acia6551_device *acia = machine().device<acia6551_device>("acia");
+ device_t *fdc = machine().device("fdc");
+ UINT8 result = 0xFF;
+
+ switch(offset)
+ {
+ case 0x00: case 0x01: case 0x02: case 0x03:
+ case 0x04: case 0x05: case 0x06: case 0x07:
+ result = AY3600_keydata_strobe_r(machine());
+ break;
+
+ case 0x08: case 0x09: case 0x0A: case 0x0B:
+ case 0x0C: case 0x0D: case 0x0E: case 0x0F:
+ /* modifier keys */
+ result = 0x7d;
+ 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:
+ AY3600_anykey_clearstrobe_r(machine());
+ break;
+
+ case 0x50: case 0x51: case 0x52: case 0x53:
+ case 0x54: case 0x55: case 0x56: case 0x57:
+ /* graphics softswitches */
+ if (offset & 1)
+ m_flags |= 1 << ((offset - 0x50) / 2);
+ else
+ m_flags &= ~(1 << ((offset - 0x50) / 2));
+ 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:
+ /* unsure what these are */
+ result = 0x00;
+ 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:
+ /* profile */
+ result = apple3_profile_r(offset);
+ break;
+
+ case 0xD0: case 0xD1: case 0xD2: case 0xD3:
+ case 0xD4: case 0xD5: case 0xD6: case 0xD7:
+ /* external drive stuff */
+ if (offset & 1)
+ m_flags |= VAR_EXTA0 << ((offset - 0xD0) / 2);
+ else
+ m_flags &= ~(VAR_EXTA0 << ((offset - 0xD0) / 2));
+ apple3_update_drives(machine().device("fdc"));
+ result = 0x00;
+ break;
+
+ case 0xDB:
+ apple3_write_charmem(machine());
+ 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:
+ result = applefdc_r(fdc, offset);
+ break;
+
+ case 0xF0:
+ case 0xF1:
+ case 0xF2:
+ case 0xF3:
+ result = acia->read(space, offset & 0x03);
+ break;
+ }
+ return result;
+}
+
+
+
+WRITE8_MEMBER(apple3_state::apple3_c0xx_w)
+{
+ acia6551_device *acia = machine().device<acia6551_device>("acia");
+ device_t *fdc = machine().device("fdc");
+ switch(offset)
+ {
+ 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:
+ AY3600_anykey_clearstrobe_r(machine());
+ break;
+
+ case 0x50: case 0x51: case 0x52: case 0x53:
+ case 0x54: case 0x55: case 0x56: case 0x57:
+ /* graphics softswitches */
+ if (offset & 1)
+ m_flags |= 1 << ((offset - 0x50) / 2);
+ else
+ m_flags &= ~(1 << ((offset - 0x50) / 2));
+ 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:
+ /* profile */
+ apple3_profile_w(offset, data);
+ break;
+
+ case 0xD0: case 0xD1: case 0xD2: case 0xD3:
+ case 0xD4: case 0xD5: case 0xD6: case 0xD7:
+ /* external drive stuff */
+ if (offset & 1)
+ m_flags |= VAR_EXTA0 << ((offset - 0xD0) / 2);
+ else
+ m_flags &= ~(VAR_EXTA0 << ((offset - 0xD0) / 2));
+ apple3_update_drives(machine().device("fdc"));
+ break;
+
+ case 0xDB:
+ apple3_write_charmem(machine());
+ 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:
+ applefdc_w(fdc, offset, data);
+ break;
+
+ case 0xF0:
+ case 0xF1:
+ case 0xF2:
+ case 0xF3:
+ acia->write(space, offset & 0x03, data);
+ break;
+ }
+}
+
+INTERRUPT_GEN( apple3_interrupt )
+{
+ via6522_device *via_1 = device->machine().device<via6522_device>("via6522_1");
+
+ via_1->write_ca2((AY3600_keydata_strobe_r(device->machine()) & 0x80) ? 1 : 0);
+ via_1->write_cb1(device->machine().primary_screen->vblank());
+ via_1->write_cb2(device->machine().primary_screen->vblank());
+}
+
+
+
+static UINT8 *apple3_bankaddr(running_machine &machine,UINT16 bank, offs_t offset)
+{
+ if (bank != (UINT16) ~0)
+ {
+ bank %= machine.device<ram_device>(RAM_TAG)->size() / 0x8000;
+ if ((bank + 1) == (machine.device<ram_device>(RAM_TAG)->size() / 0x8000))
+ bank = 0x02;
+ }
+ offset += ((offs_t) bank) * 0x8000;
+ offset %= machine.device<ram_device>(RAM_TAG)->size();
+ return &machine.device<ram_device>(RAM_TAG)->pointer()[offset];
+}
+
+
+
+static void apple3_setbank(running_machine &machine,const char *mame_bank, UINT16 bank, offs_t offset)
+{
+ UINT8 *ptr;
+ apple3_state *state = machine.driver_data<apple3_state>();
+ ptr = apple3_bankaddr(machine,bank, offset);
+ state->membank(mame_bank)->set_base(ptr);
+
+ #if 0
+ if (LOG_MEMORY)
+ {
+ #ifdef PTR64
+ //logerror("\tbank %s --> %02x/%04x [0x%08lx]\n", mame_bank, (unsigned) bank, (unsigned)offset, ptr - machine.device<ram_device>(RAM_TAG)->pointer());
+ #else
+ logerror("\tbank %s --> %02x/%04x [0x%08lx]\n", mame_bank, (unsigned) bank, (unsigned)offset, ptr - machine.device<ram_device>(RAM_TAG)->pointer());
+ #endif
+ }
+ #endif
+}
+
+
+
+static UINT8 *apple3_get_zpa_addr(running_machine &machine,offs_t offset)
+{
+ apple3_state *state = machine.driver_data<apple3_state>();
+ state->m_zpa = (((offs_t) state->m_via_0_b) * 0x100) + offset;
+
+ if (state->m_via_0_b < 0x20)
+ return apple3_bankaddr(machine,~0, state->m_zpa);
+ else if (state->m_via_0_b > 0x9F)
+ return apple3_bankaddr(machine,~0, state->m_zpa - 0x8000);
+ else
+ return apple3_bankaddr(machine,state->m_via_1_a, state->m_zpa - 0x2000);
+}
+
+
+
+READ8_MEMBER(apple3_state::apple3_00xx_r)
+{
+ return *apple3_get_zpa_addr(machine(),offset);
+}
+
+
+
+WRITE8_MEMBER(apple3_state::apple3_00xx_w)
+{
+ *apple3_get_zpa_addr(machine(),offset) = data;
+}
+
+
+
+static void apple3_update_memory(running_machine &machine)
+{
+ apple3_state *state = machine.driver_data<apple3_state>();
+ UINT16 bank;
+ UINT8 page;
+ address_space* space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ if (LOG_MEMORY)
+ {
+ logerror("apple3_update_memory(): via_0_b=0x%02x via_1_a=0x0x%02x\n", state->m_via_0_b, state->m_via_1_a);
+ }
+
+ machine.device("maincpu")->set_unscaled_clock((state->m_via_0_a & 0x80) ? 1000000 : 2000000);
+
+ /* bank 2 (0100-01FF) */
+ if (!(state->m_via_0_a & 0x04))
+ {
+ if (state->m_via_0_b < 0x20)
+ {
+ bank = ~0; /* system bank */
+ page = state->m_via_0_b ^ 0x01;
+ }
+ else if (state->m_via_0_b >= 0xA0)
+ {
+ bank = ~0; /* system bank */
+ page = (state->m_via_0_b ^ 0x01) - 0x80;
+ }
+ else
+ {
+ bank = state->m_via_1_a;
+ page = (state->m_via_0_b ^ 0x01) - 0x20;
+ }
+ }
+ else
+ {
+ bank = ~0;
+ page = 0x01;
+ }
+ apple3_setbank(machine,"bank2", bank, ((offs_t) page) * 0x100);
+
+ /* bank 3 (0200-1FFF) */
+ apple3_setbank(machine,"bank3", ~0, 0x0200);
+
+ /* bank 4 (2000-9FFF) */
+ apple3_setbank(machine,"bank4", state->m_via_1_a, 0x0000);
+
+ /* bank 5 (A000-BFFF) */
+ apple3_setbank(machine,"bank5", ~0, 0x2000);
+
+ /* install bank 8 (C000-CFFF) */
+ if (state->m_via_0_a & 0x40)
+ {
+ space->install_read_handler(0xC000, 0xC0FF, read8_delegate(FUNC(apple3_state::apple3_c0xx_r),state));
+ space->install_write_handler(0xC000, 0xC0FF, write8_delegate(FUNC(apple3_state::apple3_c0xx_w),state));
+ }
+ else
+ {
+ space->install_read_bank(0xC000, 0xC0FF, "bank8");
+ if (state->m_via_0_a & 0x08)
+ space->unmap_write(0xC000, 0xC0FF);
+ else
+ space->install_write_bank(0xC000, 0xC0FF, "bank8");
+ apple3_setbank(machine,"bank8", ~0, 0x4000);
+ }
+
+ /* install bank 9 (C100-C4FF) */
+ if (state->m_via_0_a & 0x40)
+ {
+ space->nop_readwrite(0xC100, 0xC4FF);
+ }
+ else
+ {
+ space->install_read_bank(0xC100, 0xC4FF, "bank9");
+ if (state->m_via_0_a & 0x08)
+ space->unmap_write(0xC100, 0xC4FF);
+ else
+ space->install_write_bank(0xC100, 0xC4FF, "bank9");
+ apple3_setbank(machine,"bank9", ~0, 0x4100);
+ }
+
+ /* install bank 10 (C500-C7FF) */
+ space->install_read_bank(0xC500, 0xC7FF, "bank10");
+ if (state->m_via_0_a & 0x08)
+ space->unmap_write(0xC500, 0xC7FF);
+ else
+ space->install_write_bank(0xC500, 0xC7FF, "bank10");
+ apple3_setbank(machine,"bank10", ~0, 0x4500);
+
+ /* install bank 11 (C800-CFFF) */
+ if (state->m_via_0_a & 0x40)
+ {
+ space->nop_readwrite(0xC800, 0xCFFF);
+ }
+ else
+ {
+ space->install_read_bank(0xC800, 0xCFFF, "bank11");
+ if (state->m_via_0_a & 0x08)
+ space->unmap_write(0xC800, 0xCFFF);
+ else
+ space->install_write_bank(0xC800, 0xCFFF, "bank11");
+ apple3_setbank(machine,"bank11", ~0, 0x4800);
+ }
+
+ /* install bank 6 (D000-EFFF) */
+ space->install_read_bank(0xD000, 0xEFFF, "bank6");
+ if (state->m_via_0_a & 0x08)
+ space->unmap_write(0xD000, 0xEFFF);
+ else
+ space->install_write_bank(0xD000, 0xEFFF, "bank6");
+ apple3_setbank(machine,"bank6", ~0, 0x5000);
+
+ /* install bank 7 (F000-FFFF) */
+ space->install_read_bank(0xF000, 0xFFFF, "bank7");
+ if (state->m_via_0_a & 0x09)
+ space->unmap_write(0xF000, 0xFFFF);
+ else
+ space->install_write_bank(0xF000, 0xFFFF, "bank7");
+ if (state->m_via_0_a & 0x01)
+ state->membank("bank7")->set_base(machine.root_device().memregion("maincpu")->base());
+ else
+ apple3_setbank(machine,"bank7", ~0, 0x7000);
+
+ /* reinstall VIA handlers */
+ {
+ via6522_device *via_0 = space->machine().device<via6522_device>("via6522_0");
+ via6522_device *via_1 = space->machine().device<via6522_device>("via6522_1");
+
+ space->install_readwrite_handler(0xFFD0, 0xFFDF, 0, 0, read8_delegate(FUNC(via6522_device::read),via_0), write8_delegate(FUNC(via6522_device::write),via_0));
+ space->install_readwrite_handler(0xFFE0, 0xFFEF, 0, 0, read8_delegate(FUNC(via6522_device::read),via_1), write8_delegate(FUNC(via6522_device::write),via_1));
+ }
+}
+
+
+
+static void apple3_via_out(running_machine &machine, UINT8 *var, UINT8 data)
+{
+ if (*var != data)
+ {
+ *var = data;
+ apple3_update_memory(machine);
+ }
+}
+
+
+/* these are here to appease the Apple /// confidence tests */
+static READ8_DEVICE_HANDLER(apple3_via_1_in_a) { return ~0; }
+static READ8_DEVICE_HANDLER(apple3_via_1_in_b) { return ~0; }
+
+static WRITE8_DEVICE_HANDLER(apple3_via_0_out_a)
+{
+ apple3_state *state = device->machine().driver_data<apple3_state>();
+ apple3_via_out(device->machine(), &state->m_via_0_a, data);
+}
+
+static WRITE8_DEVICE_HANDLER(apple3_via_0_out_b)
+{
+ apple3_state *state = device->machine().driver_data<apple3_state>();
+ apple3_via_out(device->machine(), &state->m_via_0_b, data);
+}
+
+static WRITE8_DEVICE_HANDLER(apple3_via_1_out_a)
+{
+ apple3_state *state = device->machine().driver_data<apple3_state>();
+ apple3_via_out(device->machine(), &state->m_via_1_a, data);
+}
+
+static WRITE8_DEVICE_HANDLER(apple3_via_1_out_b)
+{
+ apple3_state *state = device->machine().driver_data<apple3_state>();
+ apple3_via_out(device->machine(), &state->m_via_1_b, data);
+}
+
+static void apple2_via_1_irq_func(device_t *device, int state)
+{
+ apple3_state *drvstate = device->machine().driver_data<apple3_state>();
+ if (!drvstate->m_via_1_irq && state)
+ {
+ cputag_set_input_line(device->machine(), "maincpu", M6502_IRQ_LINE, ASSERT_LINE);
+ cputag_set_input_line(device->machine(), "maincpu", M6502_IRQ_LINE, CLEAR_LINE);
+ }
+ drvstate->m_via_1_irq = state;
+}
+
+const via6522_interface apple3_via_0_intf =
+{
+ DEVCB_NULL, /* in_a_func */
+ DEVCB_NULL, /* in_b_func */
+ DEVCB_NULL, /* in_ca1_func */
+ DEVCB_NULL, /* in_cb1_func */
+ DEVCB_NULL, /* in_ca2_func */
+ DEVCB_NULL, /* in_cb2_func */
+ DEVCB_HANDLER(apple3_via_0_out_a), /* out_a_func */
+ DEVCB_HANDLER(apple3_via_0_out_b), /* out_b_func */
+ DEVCB_NULL, /* out_ca1_func */
+ DEVCB_NULL, /* out_cb1_func */
+ DEVCB_NULL, /* out_ca2_func */
+ DEVCB_NULL, /* out_cb2_func */
+ DEVCB_NULL /* irq_func */
+};
+
+const via6522_interface apple3_via_1_intf =
+{
+ DEVCB_HANDLER(apple3_via_1_in_a), /* in_a_func */
+ DEVCB_HANDLER(apple3_via_1_in_b), /* in_b_func */
+ DEVCB_NULL, /* in_ca1_func */
+ DEVCB_NULL, /* in_cb1_func */
+ DEVCB_NULL, /* in_ca2_func */
+ DEVCB_NULL, /* in_cb2_func */
+ DEVCB_HANDLER(apple3_via_1_out_a), /* out_a_func */
+ DEVCB_HANDLER(apple3_via_1_out_b), /* out_b_func */
+ DEVCB_NULL, /* out_ca1_func */
+ DEVCB_NULL, /* out_cb1_func */
+ DEVCB_NULL, /* out_ca2_func */
+ DEVCB_NULL, /* out_cb2_func */
+ DEVCB_LINE(apple2_via_1_irq_func) /* irq_func */
+};
+
+
+
+MACHINE_RESET( apple3 )
+{
+}
+
+
+
+static UINT8 *apple3_get_indexed_addr(running_machine &machine,offs_t offset)
+{
+ apple3_state *state = machine.driver_data<apple3_state>();
+ UINT8 n;
+ UINT8 *result = NULL;
+
+ if ((state->m_via_0_b >= 0x18) && (state->m_via_0_b <= 0x1F))
+ {
+ n = *apple3_bankaddr(machine,~0, state->m_zpa ^ 0x0C00);
+
+ if (LOG_INDXADDR)
+ {
+ if (state->m_last_n != n)
+ {
+ logerror("indxaddr: zpa=0x%04x n=0x%02x\n", state->m_zpa, n);
+ state->m_last_n = n;
+ }
+ }
+
+ if (n == 0x8F)
+ {
+ /* get at that special ram under the VIAs */
+ if ((offset >= 0xFFD0) && (offset <= 0xFFEF))
+ result = apple3_bankaddr(machine,~0, offset & 0x7FFF);
+ else if (offset < 0x2000)
+ result = apple3_bankaddr(machine,~0, offset - 0x2000);
+ else if (offset > 0x9FFF)
+ result = apple3_bankaddr(machine,~0, offset - 0x8000);
+ else
+ result = &machine.device<ram_device>(RAM_TAG)->pointer()[offset - 0x2000];
+ }
+ else if ((n >= 0x80) && (n <= 0x8E))
+ {
+ if (offset < 0x0100)
+ result = apple3_bankaddr(machine,~0, ((offs_t) state->m_via_0_b) * 0x100 + offset);
+ else
+ result = apple3_bankaddr(machine,n, offset);
+ }
+ else if (n == 0xFF)
+ {
+ if (offset < 0x2000)
+ result = apple3_bankaddr(machine,~0, offset - 0x2000);
+ else if (offset < 0xA000)
+ result = apple3_bankaddr(machine,state->m_via_1_a, offset - 0x2000);
+ else if (offset < 0xC000)
+ result = apple3_bankaddr(machine,~0, offset - 0x8000);
+ else if (offset < 0xD000)
+ result = NULL;
+ else if (offset < 0xF000)
+ result = apple3_bankaddr(machine,~0, offset - 0x8000);
+ else
+ result = (UINT8 *) ~0;
+ }
+ else if (offset < 0x0100)
+ {
+ result = apple3_bankaddr(machine,~0, ((offs_t) state->m_via_0_b) * 0x100 + offset);
+ }
+ }
+ else if ((offset >= 0xF000) && (state->m_via_0_a & 0x01))
+ {
+#if 0
+ /* The Apple /// Diagnostics seems to expect that indexed writes
+ * always write to RAM. That image jumps to an address that is
+ * undefined unless this code is enabled. However, the Sara
+ * emulator does not have corresponding code here, though Chris
+ * Smolinski does not rule out the possibility
+ */
+ result = apple3_bankaddr(machine,~0, offset - 0x8000);
+#endif
+ }
+
+ return result;
+}
+
+
+
+READ8_MEMBER(apple3_state::apple3_indexed_read)
+{
+ UINT8 result;
+ UINT8 *addr;
+
+ addr = apple3_get_indexed_addr(machine(),offset);
+ if (!addr)
+ result = space.read_byte(offset);
+ else if (addr != (UINT8 *) ~0)
+ result = *addr;
+ else
+ result = memregion("maincpu")->base()[offset % memregion("maincpu")->bytes()];
+ return result;
+}
+
+
+
+WRITE8_MEMBER(apple3_state::apple3_indexed_write)
+{
+ UINT8 *addr;
+
+ addr = apple3_get_indexed_addr(machine(),offset);
+ if (!addr)
+ space.write_byte(offset, data);
+ else if (addr != (UINT8 *) ~0)
+ *addr = data;
+}
+
+
+
+DIRECT_UPDATE_MEMBER(apple3_state::apple3_opbase)
+{
+ UINT8 *opptr;
+
+ if ((address & 0xFF00) == 0x0000)
+ {
+ opptr = apple3_get_zpa_addr(machine(),address);
+ direct.explicit_configure(address, address, ~0, opptr - address);
+ address = ~0;
+ }
+ return address;
+}
+
+
+
+static void apple3_update_drives(device_t *device)
+{
+ apple3_state *state = device->machine().driver_data<apple3_state>();
+ int enable_mask = 0x00;
+
+ if (state->m_enable_mask & 0x01)
+ enable_mask |= 0x01;
+
+ if (state->m_enable_mask & 0x02)
+ {
+ switch(state->m_flags & (VAR_EXTA0 | VAR_EXTA1))
+ {
+ case VAR_EXTA0:
+ enable_mask |= 0x02;
+ break;
+ case VAR_EXTA1:
+ enable_mask |= 0x04;
+ break;
+ case VAR_EXTA1|VAR_EXTA0:
+ enable_mask |= 0x08;
+ break;
+ }
+ }
+
+ apple525_set_enable_lines(device,enable_mask);
+}
+
+
+
+static void apple3_set_enable_lines(device_t *device,int enable_mask)
+{
+ apple3_state *state = device->machine().driver_data<apple3_state>();
+ state->m_enable_mask = enable_mask;
+ apple3_update_drives(device);
+}
+
+
+
+const applefdc_interface apple3_fdc_interface =
+{
+ apple525_set_lines,
+ apple3_set_enable_lines,
+ apple525_read_data,
+ apple525_write_data
+};
+
+
+
+DRIVER_INIT_MEMBER(apple3_state,apple3)
+{
+ /* hack to get around VIA problem */
+ memregion("maincpu")->base()[0x0685] = 0x00;
+
+ m_enable_mask = 0;
+ apple3_update_drives(machine().device("fdc"));
+
+ AY3600_init(machine());
+
+ apple3_profile_init();
+
+ m_flags = 0;
+ m_via_0_a = ~0;
+ m_via_1_a = ~0;
+ m_via_1_irq = 0;
+ apple3_update_memory(machine());
+
+ machine().device("maincpu")->memory().space(AS_PROGRAM)->set_direct_update_handler(direct_update_delegate(FUNC(apple3_state::apple3_opbase), this));
+}
diff --git a/src/mess/machine/applefdc.c b/src/mess/machine/applefdc.c
new file mode 100644
index 00000000000..01719f1abac
--- /dev/null
+++ b/src/mess/machine/applefdc.c
@@ -0,0 +1,863 @@
+/*********************************************************************
+
+ applefdc.c
+
+ Implementation of various Apple Floppy Disk Controllers, including
+ the classic Apple controller and the IWM (Integrated Woz Machine)
+ chip
+
+ The IWM chip was used as the floppy disk controller for early Macs and the
+ Apple IIgs, and was eventually superseded by the SWIM chp.
+
+ Nate Woods
+ Raphael Nabet
+
+ Writing this code would not be possible if it weren't for the work of the
+ XGS and KEGS emulators which also contain IWM emulations.
+
+ TODO
+ - Implement the unimplemented IWM modes
+ - IWM_MODE_CLOCKSPEED
+ - IWM_MODE_BITCELLTIME
+ - IWM_MODE_HANDSHAKEPROTOCOL
+ - IWM_MODE_LATCHMODE
+ - Investigate the differences between the IWM and the classic Apple II
+ controller more fully. It is currently unclear what are genuine
+ differences and what are effectively hacks that "just seem" to work.
+ - Figure out iwm_readenable2handshake() and iwm_enable2(); they are
+ hackish at best
+ - Support the SWIM chip
+ - Proper timing
+ - This code was originally IWM specific; we need to clean up IWMisms in
+ the code
+ - Make it faster?
+ - Add sound?
+
+*********************************************************************/
+
+#include "applefdc.h"
+
+
+/***************************************************************************
+ PARAMETERS
+***************************************************************************/
+
+/* logging */
+#define LOG_APPLEFDC 0
+#define LOG_APPLEFDC_EXTRA 0
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* mask for FDC lines */
+#define IWM_MOTOR 0x10
+#define IWM_DRIVE 0x20
+#define IWM_Q6 0x40
+#define IWM_Q7 0x80
+
+typedef enum
+{
+ APPLEFDC_APPLE2, /* classic Apple II disk controller (pre-IWM) */
+ APPLEFDC_IWM, /* Integrated Woz Machine */
+ APPLEFDC_SWIM /* Sander/Woz Integrated Machine */
+} applefdc_t;
+
+
+static UINT8 swim_default_parms[16] =
+{
+ 0x38, 0x18, 0x41, 0x2e, 0x2e, 0x18, 0x18, 0x1b,
+ 0x1b, 0x2f, 0x2f, 0x19, 0x19, 0x97, 0x1b, 0x57
+};
+
+/***************************************************************************
+ IWM MODE
+
+ The IWM mode has the following values:
+
+ Bit 7 Reserved
+ Bit 6 Reserved
+ Bit 5 Reserved
+ Bit 4 ! Clock speed
+ 0=7MHz; used by Apple IIgs
+ 1=8MHz; used by Mac (I believe)
+ Bit 3 ! Bit cell time
+ 0=4usec/bit (used for 5.25" drives)
+ 1=2usec/bit (used for 3.5" drives)
+ Bit 2 Motor-off delay
+ 0=leave on for 1 sec after system turns it off
+ 1=turn off immediately
+ Bit 1 ! Handshake protocol
+ 0=synchronous (software supplies timing for writing data; used for 5.25" drives)
+ 1=asynchronous (IWM supplies timing; used for 3.5" drives)
+ Bit 0 ! Latch mode
+ 0=read data stays valid for 7usec (used for 5.25" drives)
+ 1=read data stays valid for full byte time (used for 3.5" drives)
+
+ ***************************************************************************/
+
+enum
+{
+ IWM_MODE_CLOCKSPEED = 0x10,
+ IWM_MODE_BITCELLTIME = 0x08,
+ IWM_MODE_MOTOROFFDELAY = 0x04,
+ IWM_MODE_HANDSHAKEPROTOCOL = 0x02,
+ IWM_MODE_LATCHMODE = 0x01
+};
+
+enum
+{
+ SWIM_MODE_IWM,
+ SWIM_MODE_SWIM,
+ SWIM_MODE_SWIM2,
+ SWIM_MODE_SWIM3
+};
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _applefdc_token applefdc_token;
+struct _applefdc_token
+{
+ /* data that is constant for the lifetime of the emulation */
+ emu_timer *motor_timer;
+ applefdc_t type;
+
+ /* data that changes at emulation time */
+ UINT8 write_byte;
+ UINT8 lines; /* flags from IWM_MOTOR - IWM_Q7 */
+ UINT8 mode; /* 0-31; see above */
+ UINT8 handshake_hack; /* not sure what this is for */
+
+ /* SWIM extentions */
+ UINT8 swim_mode;
+ UINT8 swim_magic_state;
+ UINT8 ism_regs[8];
+ UINT8 parm_offset;
+ UINT8 parms[16];
+};
+
+
+
+/***************************************************************************
+ PROTOTYPES
+***************************************************************************/
+
+static TIMER_CALLBACK(iwm_turnmotor_onoff);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+INLINE void assert_is_applefdc(device_t *device)
+{
+ assert(device != NULL);
+ assert((device->type() == APPLEFDC) || (device->type() == IWM) || (device->type() == SWIM));
+}
+
+
+
+INLINE applefdc_token *get_token(device_t *device)
+{
+ assert_is_applefdc(device);
+ return (applefdc_token *) downcast<legacy_device_base *>(device)->token();
+}
+
+
+
+INLINE const applefdc_interface *get_interface(device_t *device)
+{
+ static const applefdc_interface dummy_interface = {0, };
+
+ assert_is_applefdc(device);
+ return (device->static_config() != NULL)
+ ? (const applefdc_interface *) device->static_config()
+ : &dummy_interface;
+}
+
+
+
+/***************************************************************************
+ CORE IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ applefdc_start - starts up an FDC
+-------------------------------------------------*/
+
+static void applefdc_start(device_t *device, applefdc_t type)
+{
+ applefdc_token *fdc = get_token(device);
+
+ memset(fdc, 0, sizeof(*fdc));
+ fdc->type = type;
+ fdc->motor_timer = device->machine().scheduler().timer_alloc(FUNC(iwm_turnmotor_onoff), (void *) device);
+ fdc->lines = 0x00;
+ fdc->mode = 0x1F; /* default value needed by Lisa 2 - no, I don't know if it is true */
+ fdc->swim_mode = SWIM_MODE_IWM;
+
+ /* register save states */
+ state_save_register_item(device->machine(), "applefdc", NULL, 0, fdc->write_byte);
+ state_save_register_item(device->machine(), "applefdc", NULL, 0, fdc->lines);
+ state_save_register_item(device->machine(), "applefdc", NULL, 0, fdc->mode);
+ state_save_register_item(device->machine(), "applefdc", NULL, 0, fdc->handshake_hack);
+}
+
+
+
+/*-------------------------------------------------
+ DEVICE_RESET(applefdc) - resets an FDC
+-------------------------------------------------*/
+
+static DEVICE_RESET(applefdc)
+{
+ applefdc_token *fdc = get_token(device);
+
+ fdc->handshake_hack = 0x00;
+ fdc->write_byte = 0x00;
+ fdc->lines = 0x00;
+ fdc->mode = 0x1F; /* default value needed by Lisa 2 - no, I don't know if it is true */
+ fdc->swim_magic_state = 0;
+ fdc->swim_mode = SWIM_MODE_IWM;
+ fdc->parm_offset = 0;
+
+ // setup SWIM default parms if it's a SWIM
+ if (fdc->type == APPLEFDC_SWIM)
+ {
+ for (int i = 0; i < 16; i++)
+ {
+ fdc->parms[i] = swim_default_parms[i];
+ }
+ }
+
+ fdc->motor_timer->reset();
+}
+
+
+
+/*-------------------------------------------------
+ iwm_enable2 - hackish function
+-------------------------------------------------*/
+
+static int iwm_enable2(device_t *device)
+{
+ applefdc_token *fdc = get_token(device);
+
+ /* R. Nabet : This function looks more like a hack than a real feature of the IWM; */
+ /* it is not called from the Mac Plus driver */
+ return (fdc->lines & APPLEFDC_PH1) && (fdc->lines & APPLEFDC_PH3);
+}
+
+
+
+/*-------------------------------------------------
+ iwm_readenable2handshake - hackish function
+-------------------------------------------------*/
+
+static UINT8 iwm_readenable2handshake(device_t *device)
+{
+ applefdc_token *fdc = get_token(device);
+
+ /* R. Nabet : This function looks more like a hack than a real feature of the IWM; */
+ /* it is not called from the Mac Plus driver */
+ fdc->handshake_hack++;
+ fdc->handshake_hack %= 4;
+ return (fdc->handshake_hack != 0) ? 0xc0 : 0x80;
+}
+
+
+
+/*-------------------------------------------------
+ applefdc_statusreg_r - reads the status register
+-------------------------------------------------*/
+
+static UINT8 applefdc_statusreg_r(device_t *device)
+{
+ UINT8 result;
+ int status;
+ applefdc_token *fdc = get_token(device);
+ const applefdc_interface *intf = get_interface(device);
+
+ /* IWM status:
+ *
+ * Bit 7 Sense input (write protect for 5.25" drive and general status line for 3.5")
+ * Bit 6 Reserved
+ * Bit 5 Drive enable (is 1 if drive is on)
+ * Bits 4-0 Same as IWM mode bits 4-0
+ */
+
+ status = iwm_enable2(device) ? 1 : (intf->read_status ? intf->read_status(device) : 0);
+
+ result = (status ? 0x80 : 0x00);
+
+ if (fdc->type != APPLEFDC_APPLE2)
+ result |= (((fdc->lines & IWM_MOTOR) ? 1 : 0) << 5) | fdc->mode;
+ return result;
+}
+
+
+
+/*-------------------------------------------------
+ iwm_modereg_w - changes the mode register
+-------------------------------------------------*/
+
+static void iwm_modereg_w(device_t *device, UINT8 data)
+{
+ applefdc_token *fdc = get_token(device);
+
+ fdc->mode = data & 0x1f; /* write mode register */
+
+ // SWIM mode is unlocked by writing 1/0/1/1 in a row to bit 6 (which is unused on IWM)
+ // when SWIM mode engages, the IWM is disconnected from both the 68k and the drives,
+ // and the ISM is substituted.
+ if (fdc->type == APPLEFDC_SWIM)
+ {
+ switch (fdc->swim_magic_state)
+ {
+ case 0:
+ case 2:
+ case 3:
+ if (data & 0x40)
+ {
+ fdc->swim_magic_state++;
+ }
+ else
+ {
+ fdc->swim_magic_state = 0;
+ }
+ break;
+ case 1:
+ if (!(data & 0x40))
+ {
+ fdc->swim_magic_state++;
+ }
+ else
+ {
+ fdc->swim_magic_state = 0;
+ }
+ break;
+ }
+
+ if (fdc->swim_magic_state == 4)
+ {
+ fdc->swim_magic_state = 0;
+// printf("IWM: switching to SWIM mode\n");
+ fdc->swim_mode = SWIM_MODE_SWIM;
+ }
+ }
+
+ if (LOG_APPLEFDC_EXTRA)
+ logerror("iwm_modereg_w: iwm_mode=0x%02x\n", (unsigned) fdc->mode);
+}
+
+
+
+/*-------------------------------------------------
+ applefdc_read_reg - reads a register
+-------------------------------------------------*/
+
+static UINT8 applefdc_read_reg(device_t *device, int lines)
+{
+ applefdc_token *fdc = get_token(device);
+ const applefdc_interface *intf = get_interface(device);
+ UINT8 result = 0;
+
+ switch(lines)
+ {
+ case 0:
+ /* Read data register */
+ if ((fdc->type != APPLEFDC_APPLE2) && (iwm_enable2(device) || !(fdc->lines & IWM_MOTOR)))
+ {
+ result = 0xFF;
+ }
+ else
+ {
+ /*
+ * Right now, this function assumes latch mode; which is always used for
+ * 3.5 inch drives. Eventually we should check to see if latch mode is
+ * off
+ */
+ if (LOG_APPLEFDC)
+ {
+ if ((fdc->mode & IWM_MODE_LATCHMODE) == 0x00)
+ logerror("applefdc_read_reg(): latch mode off not implemented\n");
+ }
+
+ result = (intf->read_data ? intf->read_data(device) : 0x00);
+ }
+ break;
+
+ case IWM_Q6:
+ /* Read status register */
+ result = applefdc_statusreg_r(device);
+ break;
+
+ case IWM_Q7:
+ /* Classic Apple II: Read status register
+ * IWM: Read handshake register
+ */
+ if (fdc->type == APPLEFDC_APPLE2)
+ result = applefdc_statusreg_r(device);
+ else
+ result = iwm_enable2(device) ? iwm_readenable2handshake(device) : 0x80;
+ break;
+ }
+ return result;
+}
+
+
+
+/*-------------------------------------------------
+ applefdc_write_reg - writes a register
+-------------------------------------------------*/
+
+static void applefdc_write_reg(device_t *device, UINT8 data)
+{
+ applefdc_token *fdc = get_token(device);
+ const applefdc_interface *intf = get_interface(device);
+
+ switch(fdc->lines & (IWM_Q6 | IWM_Q7))
+ {
+ case IWM_Q6 | IWM_Q7:
+ if (!(fdc->lines & IWM_MOTOR))
+ {
+ iwm_modereg_w(device, data);
+ }
+ else if (!iwm_enable2(device))
+ {
+ /*
+ * Right now, this function assumes latch mode; which is always used for
+ * 3.5 inch drives. Eventually we should check to see if latch mode is
+ * off
+ */
+ if (LOG_APPLEFDC)
+ {
+ if ((fdc->mode & IWM_MODE_LATCHMODE) == 0)
+ logerror("applefdc_write_reg(): latch mode off not implemented\n");
+ }
+
+ if (intf->write_data != NULL)
+ intf->write_data(device,data);
+ }
+ break;
+ }
+}
+
+
+
+/*-------------------------------------------------
+ TIMER_CALLBACK(iwm_turnmotor_onoff) - timer
+ callback for turning motor on or off
+-------------------------------------------------*/
+
+static TIMER_CALLBACK(iwm_turnmotor_onoff)
+{
+ device_t *device = (device_t *) ptr;
+ applefdc_token *fdc = get_token(device);
+ const applefdc_interface *intf = get_interface(device);
+ int status = param;
+ int enable_lines;
+
+ if (status != 0)
+ {
+ fdc->lines |= IWM_MOTOR;
+ enable_lines = (fdc->lines & IWM_DRIVE) ? 2 : 1;
+ }
+ else
+ {
+ fdc->lines &= ~IWM_MOTOR;
+
+ if (fdc->type == APPLEFDC_APPLE2)
+ enable_lines = (fdc->lines & IWM_DRIVE) ? 2 : 1;
+ else
+ enable_lines = 0;
+ }
+
+ /* invoke callback, if present */
+ if (intf->set_enable_lines != NULL)
+ intf->set_enable_lines(device,enable_lines);
+
+ if (LOG_APPLEFDC_EXTRA)
+ logerror("iwm_turnmotor_onoff(): Turning motor %s\n", status ? "on" : "off");
+}
+
+
+
+/*-------------------------------------------------
+ iwm_access
+-------------------------------------------------*/
+
+static void iwm_access(device_t *device, int offset)
+{
+ static const char *const lines[] =
+ {
+ "PH0",
+ "PH1",
+ "PH2",
+ "PH3",
+ "MOTOR",
+ "DRIVE",
+ "Q6",
+ "Q7"
+ };
+
+ applefdc_token *fdc = get_token(device);
+ const applefdc_interface *intf = get_interface(device);
+
+ if (offset & 1)
+ fdc->lines |= (1 << (offset >> 1));
+ else
+ fdc->lines &= ~(1 << (offset >> 1));
+
+ if (LOG_APPLEFDC_EXTRA)
+ {
+ logerror("iwm_access(): %s line %s => %02x\n",
+ (offset & 1) ? "setting" : "clearing", lines[offset >> 1], fdc->lines);
+ }
+
+ if ((offset < 0x08) && (intf->set_lines != NULL))
+ intf->set_lines(device,fdc->lines & 0x0f);
+
+ switch(offset)
+ {
+ case 0x08:
+ /* turn off motor */
+ fdc->motor_timer->adjust(
+ (fdc->mode & IWM_MODE_MOTOROFFDELAY) ? attotime::zero : attotime::from_seconds(1), 0);
+ break;
+
+ case 0x09:
+ /* turn on motor */
+ fdc->motor_timer->adjust(attotime::zero, 1);
+ break;
+
+ case 0x0A:
+ /* turn off IWM_DRIVE */
+ if ((fdc->lines & IWM_MOTOR) && (intf->set_enable_lines != NULL))
+ intf->set_enable_lines(device,1);
+ break;
+
+ case 0x0B:
+ /* turn on IWM_DRIVE */
+ if ((fdc->lines & IWM_MOTOR) && (intf->set_enable_lines != NULL))
+ intf->set_enable_lines(device,2);
+ break;
+ }
+}
+
+
+
+/*-------------------------------------------------
+ applefdc_r - reads a byte from the FDC
+-------------------------------------------------*/
+
+READ8_DEVICE_HANDLER( applefdc_r )
+{
+ applefdc_token *fdc = get_token(device);
+ const applefdc_interface *intf = get_interface(device);
+ UINT8 result = 0;
+
+ /* normalize offset */
+ offset &= 0xf;
+
+ if (LOG_APPLEFDC_EXTRA)
+ logerror("applefdc_r: offset=%i\n", offset);
+
+ if ((fdc->type < APPLEFDC_SWIM) || (fdc->swim_mode == SWIM_MODE_IWM))
+ {
+ iwm_access(device, offset);
+
+ switch(fdc->type)
+ {
+ case APPLEFDC_APPLE2:
+ switch(offset)
+ {
+ case 0x0C:
+ if (fdc->lines & IWM_Q7)
+ {
+ if (intf->write_data != NULL)
+ intf->write_data(device,fdc->write_byte);
+ result = 0;
+ }
+ else
+ result = applefdc_read_reg(device, 0);
+
+ break;
+ case 0x0D:
+ result = applefdc_read_reg(device, IWM_Q6);
+ break;
+ case 0x0E:
+ result = applefdc_read_reg(device, IWM_Q7);
+ break;
+ case 0x0F:
+ result = applefdc_read_reg(device, IWM_Q7 | IWM_Q6);
+ break;
+ }
+ break;
+
+ case APPLEFDC_IWM:
+ if ((offset & 1) == 0)
+ result = applefdc_read_reg(device, fdc->lines & (IWM_Q6 | IWM_Q7));
+ break;
+
+ case APPLEFDC_SWIM:
+ if ((offset & 1) == 0)
+ result = applefdc_read_reg(device, fdc->lines & (IWM_Q6 | IWM_Q7));
+ break;
+ }
+ }
+ else if (fdc->swim_mode >= SWIM_MODE_SWIM)
+ {
+ // reading parameter RAM?
+ if ((offset & 7) == 3)
+ {
+ result = fdc->parms[fdc->parm_offset++];
+ fdc->parm_offset &= 0xf;
+ }
+ else
+ {
+ result = fdc->ism_regs[offset&7];
+ }
+ printf("SWIM: read %02x from offset %x\n", result, offset & 7);
+ }
+
+ return result;
+}
+
+
+
+/*-------------------------------------------------
+ applefdc_w - writes a byte to the FDC
+-------------------------------------------------*/
+
+WRITE8_DEVICE_HANDLER( applefdc_w )
+{
+ applefdc_token *fdc = get_token(device);
+ const applefdc_interface *intf = get_interface(device);
+
+ /* normalize offset */
+ offset &= 15;
+
+ if (LOG_APPLEFDC_EXTRA)
+ logerror("applefdc_w: offset=%i data=0x%02x\n", offset, data);
+
+ if ((fdc->type < APPLEFDC_SWIM) || (fdc->swim_mode == SWIM_MODE_IWM))
+ {
+ iwm_access(device, offset);
+
+ switch(fdc->type)
+ {
+ case APPLEFDC_APPLE2:
+ switch(offset)
+ {
+ case 0x0C:
+ if (fdc->lines & IWM_Q7)
+ {
+ if (intf->write_data != NULL)
+ intf->write_data(device,fdc->write_byte);
+ }
+ break;
+
+ case 0x0D:
+ fdc->write_byte = data;
+ break;
+ }
+ break;
+
+ case APPLEFDC_IWM:
+ if (offset & 1)
+ applefdc_write_reg(device, data);
+ break;
+
+ case APPLEFDC_SWIM:
+ if (offset & 1)
+ applefdc_write_reg(device, data);
+ break;
+ }
+ }
+ else if (fdc->swim_mode >= SWIM_MODE_SWIM)
+ {
+ printf("SWIM: write %02x to offset %x\n", data, offset & 7);
+ switch (offset & 7)
+ {
+ case 2: // write CRC
+ break;
+
+ case 3: // write parameter
+ fdc->parms[fdc->parm_offset++] = data;
+ fdc->parm_offset &= 0xf;
+ break;
+
+ case 6: // write zeros to status (also zeroes parameter RAM pointer)
+ fdc->ism_regs[6] &= ~data;
+ fdc->parm_offset = 0;
+
+ if (data == 0xf8) // magic "revert to IWM" value
+ {
+ printf("SWIM: reverting to IWM\n");
+ fdc->swim_mode = SWIM_MODE_IWM;
+ }
+ break;
+
+ case 7: // write ones to status
+ fdc->ism_regs[6] |= data;
+ break;
+
+ default:
+ fdc->ism_regs[offset & 7] = data;
+ break;
+
+ }
+ }
+}
+
+
+
+/*-------------------------------------------------
+ applefdc_w - writes a byte to the FDC
+-------------------------------------------------*/
+
+UINT8 applefdc_get_lines(device_t *device)
+{
+ applefdc_token *fdc = get_token(device);
+ return fdc->lines & 0x0f;
+}
+
+
+
+/***************************************************************************
+ INTERFACE
+***************************************************************************/
+
+/*-------------------------------------------------
+ DEVICE_GET_INFO(applefdc_base) - device get info
+ callback
+-------------------------------------------------*/
+
+static DEVICE_GET_INFO(applefdc_base)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(applefdc_token); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: /* Nothing */ break;
+ case DEVINFO_FCT_STOP: /* Nothing */ break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(applefdc); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "Apple FDC"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ }
+}
+
+
+
+/*-------------------------------------------------
+ DEVICE_START(oldfdc) - device start
+ callback
+-------------------------------------------------*/
+
+static DEVICE_START(oldfdc)
+{
+ applefdc_start(device, APPLEFDC_APPLE2);
+}
+
+
+
+/*-------------------------------------------------
+ DEVICE_GET_INFO(applefdc) - device get info
+ callback
+-------------------------------------------------*/
+
+DEVICE_GET_INFO(applefdc)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "Apple FDC"); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(oldfdc); break;
+
+ default: DEVICE_GET_INFO_CALL(applefdc_base); break;
+ }
+}
+
+
+
+/*-------------------------------------------------
+ DEVICE_START(iwm) - device start
+ callback
+-------------------------------------------------*/
+
+static DEVICE_START(iwm)
+{
+ applefdc_start(device, APPLEFDC_IWM);
+}
+
+
+
+/*-------------------------------------------------
+ DEVICE_GET_INFO(iwm) - device get info
+ callback
+-------------------------------------------------*/
+
+DEVICE_GET_INFO(iwm)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "Apple IWM (Integrated Woz Machine)"); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(iwm); break;
+
+ default: DEVICE_GET_INFO_CALL(applefdc_base); break;
+ }
+}
+
+
+
+/*-------------------------------------------------
+ DEVICE_START(iwm) - device start
+ callback
+-------------------------------------------------*/
+
+static DEVICE_START(swim)
+{
+ applefdc_start(device, APPLEFDC_SWIM);
+}
+
+
+
+/*-------------------------------------------------
+ DEVICE_GET_INFO(swim) - device get info
+ callback
+-------------------------------------------------*/
+
+DEVICE_GET_INFO(swim)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "Apple SWIM (Steve Woz Integrated Machine)"); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(swim); break;
+
+ default: DEVICE_GET_INFO_CALL(applefdc_base); break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(APPLEFDC, applefdc);
+DEFINE_LEGACY_DEVICE(IWM, iwm);
+DEFINE_LEGACY_DEVICE(SWIM, swim);
diff --git a/src/mess/machine/applefdc.h b/src/mess/machine/applefdc.h
new file mode 100644
index 00000000000..04f8f1da776
--- /dev/null
+++ b/src/mess/machine/applefdc.h
@@ -0,0 +1,93 @@
+/*********************************************************************
+
+ applefdc.h
+
+ Implementation of various Apple Floppy Disk Controllers, including
+ the classic Apple controller and the IWM (Integrated Woz Machine)
+ chip
+
+ Nate Woods
+ Raphael Nabet
+ R. Belmont
+
+*********************************************************************/
+
+#ifndef __APPLEFDC_H__
+#define __APPLEFDC_H__
+
+#include "emu.h"
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define APPLEFDC_PH0 0x01
+#define APPLEFDC_PH1 0x02
+#define APPLEFDC_PH2 0x04
+#define APPLEFDC_PH3 0x08
+
+DECLARE_LEGACY_DEVICE(APPLEFDC, applefdc);
+DECLARE_LEGACY_DEVICE(IWM, iwm);
+DECLARE_LEGACY_DEVICE(SWIM, swim);
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _applefdc_interface applefdc_interface;
+struct _applefdc_interface
+{
+ void (*set_lines)(device_t *device, UINT8 lines);
+ void (*set_enable_lines)(device_t *device, int enable_mask);
+
+ UINT8 (*read_data)(device_t *device);
+ void (*write_data)(device_t *device, UINT8 data);
+ int (*read_status)(device_t *device);
+};
+
+
+
+/***************************************************************************
+ PROTOTYPES
+***************************************************************************/
+/* read/write handlers */
+READ8_DEVICE_HANDLER(applefdc_r);
+WRITE8_DEVICE_HANDLER(applefdc_w);
+
+/* accessor */
+UINT8 applefdc_get_lines(device_t *device);
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+#define MCFG_APPLEFDC_ADD(_tag, _intrf) \
+ MCFG_DEVICE_ADD(_tag, APPLEFDC, 0) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#define MCFG_APPLEFDC_MODIFY(_tag, _intrf) \
+ MCFG_DEVICE_MODIFY(_tag) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#define MCFG_IWM_ADD(_tag, _intrf) \
+ MCFG_DEVICE_ADD(_tag, IWM, 0) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#define MCFG_IWM_MODIFY(_tag, _intrf) \
+ MCFG_DEVICE_MODIFY(_tag) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#define MCFG_SWIM_ADD(_tag, _intrf) \
+ MCFG_DEVICE_ADD(_tag, SWIM, 0) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#define MCFG_SWIM_MODIFY(_tag, _intrf) \
+ MCFG_DEVICE_MODIFY(_tag) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+
+#endif /* __APPLEFDC_H__ */
diff --git a/src/mess/machine/apricotkb.c b/src/mess/machine/apricotkb.c
new file mode 100644
index 00000000000..38b937c44ea
--- /dev/null
+++ b/src/mess/machine/apricotkb.c
@@ -0,0 +1,412 @@
+/**********************************************************************
+
+ Apricot keyboard emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#include "apricotkb.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define UPD7507C_TAG "ic2"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type APRICOT_KEYBOARD = &device_creator<apricot_keyboard_device>;
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void apricot_keyboard_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const apricot_keyboard_interface *intf = reinterpret_cast<const apricot_keyboard_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<apricot_keyboard_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_txd_cb, 0, sizeof(m_out_txd_cb));
+ }
+
+ m_shortname = "aprikb";
+}
+
+
+//-------------------------------------------------
+// ROM( apricot_keyboard )
+//-------------------------------------------------
+
+ROM_START( apricot_keyboard )
+ ROM_REGION( 0x800, UPD7507C_TAG, 0 )
+ ROM_LOAD( "keyboard controller upd7507c.ic2", 0x000, 0x800, NO_DUMP )
+ROM_END
+
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *apricot_keyboard_device::device_rom_region() const
+{
+ return ROM_NAME( apricot_keyboard );
+}
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( kb_io )
+//-------------------------------------------------
+/*
+static ADDRESS_MAP_START( apricot_keyboard_io, AS_IO, 8, apricot_keyboard_device )
+ AM_RANGE(0x00, 0x00) AM_READ(kb_lo_r)
+ AM_RANGE(0x01, 0x01) AM_READ(kb_hi_r)
+ AM_RANGE(0x03, 0x03) AM_WRITE(kb_p3_w)
+ AM_RANGE(0x04, 0x04) AM_WRITE(kb_y0_w)
+ AM_RANGE(0x05, 0x05) AM_WRITE(kb_y4_w)
+ AM_RANGE(0x06, 0x06) AM_READWRITE(kb_p6_r, kb_yc_w)
+ AM_RANGE(0x07, 0x07) AM_WRITE(kb_y8_w)
+ADDRESS_MAP_END
+*/
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( apricot_keyboard )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( apricot_keyboard )
+/*
+ MCFG_CPU_ADD(UPD7507C_TAG, UPD7507, XTAL_32_768kHz)
+ MCFG_CPU_IO_MAP(apricot_keyboard_io)
+*/
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor apricot_keyboard_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( apricot_keyboard );
+}
+
+
+//-------------------------------------------------
+// INPUT_PORTS( apricot_keyboard )
+//-------------------------------------------------
+
+INPUT_PORTS_START( apricot_keyboard )
+ PORT_START("Y0")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("Y1")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("Y2")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("Y3")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("Y4")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("Y5")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("Y6")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("Y7")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("Y8")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("Y9")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("YA")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("YB")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("YC")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("MODIFIERS")
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("CTRL") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL))
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("SHIFT") PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
+INPUT_PORTS_END
+
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+ioport_constructor apricot_keyboard_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( apricot_keyboard );
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// apricot_keyboard_device - constructor
+//-------------------------------------------------
+
+apricot_keyboard_device::apricot_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, APRICOT_KEYBOARD, "Apricot Keyboard", tag, owner, clock)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void apricot_keyboard_device::device_start()
+{
+ // resolve callbacks
+ m_out_txd_func.resolve(m_out_txd_cb, *this);
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void apricot_keyboard_device::device_reset()
+{
+}
+
+
+//-------------------------------------------------
+// read_keyboard -
+//-------------------------------------------------
+
+UINT8 apricot_keyboard_device::read_keyboard()
+{
+ UINT8 data = 0xff;
+
+ if (!BIT(m_kb_y, 0)) data &= ioport("Y0")->read();
+ if (!BIT(m_kb_y, 1)) data &= ioport("Y1")->read();
+ if (!BIT(m_kb_y, 2)) data &= ioport("Y2")->read();
+ if (!BIT(m_kb_y, 3)) data &= ioport("Y3")->read();
+ if (!BIT(m_kb_y, 4)) data &= ioport("Y4")->read();
+ if (!BIT(m_kb_y, 5)) data &= ioport("Y5")->read();
+ if (!BIT(m_kb_y, 6)) data &= ioport("Y6")->read();
+ if (!BIT(m_kb_y, 7)) data &= ioport("Y7")->read();
+ if (!BIT(m_kb_y, 8)) data &= ioport("Y8")->read();
+ if (!BIT(m_kb_y, 9)) data &= ioport("Y9")->read();
+ if (!BIT(m_kb_y, 10)) data &= ioport("YA")->read();
+ if (!BIT(m_kb_y, 11)) data &= ioport("YB")->read();
+ if (!BIT(m_kb_y, 12)) data &= ioport("YC")->read();
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// kb_lo_r -
+//-------------------------------------------------
+
+READ8_MEMBER( apricot_keyboard_device::kb_lo_r )
+{
+ return read_keyboard() & 0x0f;
+}
+
+
+//-------------------------------------------------
+// kb_hi_r -
+//-------------------------------------------------
+
+READ8_MEMBER( apricot_keyboard_device::kb_hi_r )
+{
+ return read_keyboard() >> 4;
+}
+
+
+//-------------------------------------------------
+// kb_p6_r -
+//-------------------------------------------------
+
+READ8_MEMBER( apricot_keyboard_device::kb_p6_r )
+{
+ /*
+
+ bit description
+
+ P60
+ P61 SHIFT
+ P62 CONTROL
+
+ */
+
+ UINT8 modifiers = ioport("MODIFIERS")->read();
+
+ return modifiers << 1;
+}
+
+
+//-------------------------------------------------
+// kb_p3_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( apricot_keyboard_device::kb_p3_w )
+{
+ // bit 1 controls the IR LEDs
+}
+
+
+//-------------------------------------------------
+// kb_y0_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( apricot_keyboard_device::kb_y0_w )
+{
+ m_kb_y = (m_kb_y & 0xfff0) | (data & 0x0f);
+}
+
+
+//-------------------------------------------------
+// kb_y4_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( apricot_keyboard_device::kb_y4_w )
+{
+ m_kb_y = (m_kb_y & 0xff0f) | ((data & 0x0f) << 4);
+}
+
+
+//-------------------------------------------------
+// kb_y8_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( apricot_keyboard_device::kb_y8_w )
+{
+ m_kb_y = (m_kb_y & 0xf0ff) | ((data & 0x0f) << 8);
+}
+
+
+//-------------------------------------------------
+// kb_yc_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( apricot_keyboard_device::kb_yc_w )
+{
+ m_kb_y = (m_kb_y & 0xf0ff) | ((data & 0x0f) << 12);
+}
diff --git a/src/mess/machine/apricotkb.h b/src/mess/machine/apricotkb.h
new file mode 100644
index 00000000000..853597ea0d4
--- /dev/null
+++ b/src/mess/machine/apricotkb.h
@@ -0,0 +1,97 @@
+/**********************************************************************
+
+ Apricot keyboard emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#pragma once
+
+#ifndef __APRICOT_KEYBOARD__
+#define __APRICOT_KEYBOARD__
+
+
+#include "emu.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define APRICOT_KEYBOARD_TAG "aprikb"
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_APRICOT_KEYBOARD_ADD(_config) \
+ MCFG_DEVICE_ADD(APRICOT_KEYBOARD_TAG, APRICOT_KEYBOARD, 0) \
+ MCFG_DEVICE_CONFIG(_config)
+
+
+#define APRICOT_KEYBOARD_INTERFACE(_name) \
+ const apricot_keyboard_interface (_name) =
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> apricot_keyboard_interface
+
+struct apricot_keyboard_interface
+{
+ devcb_write_line m_out_txd_cb;
+};
+
+
+// ======================> apricot_keyboard_device
+
+class apricot_keyboard_device : public device_t,
+ public apricot_keyboard_interface
+{
+public:
+ // construction/destruction
+ apricot_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;
+
+ UINT8 read_keyboard();
+
+ DECLARE_READ8_MEMBER( kb_lo_r );
+ DECLARE_READ8_MEMBER( kb_hi_r );
+ DECLARE_READ8_MEMBER( kb_p6_r );
+ DECLARE_WRITE8_MEMBER( kb_p3_w );
+ DECLARE_WRITE8_MEMBER( kb_y0_w );
+ DECLARE_WRITE8_MEMBER( kb_y4_w );
+ DECLARE_WRITE8_MEMBER( kb_y8_w );
+ DECLARE_WRITE8_MEMBER( kb_yc_w );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete();
+
+private:
+ devcb_resolved_write_line m_out_txd_func;
+
+ UINT16 m_kb_y;
+};
+
+
+// device type definition
+extern const device_type APRICOT_KEYBOARD;
+
+
+
+#endif
diff --git a/src/mess/machine/at.c b/src/mess/machine/at.c
new file mode 100644
index 00000000000..1bccf1394ce
--- /dev/null
+++ b/src/mess/machine/at.c
@@ -0,0 +1,347 @@
+/***************************************************************************
+
+ IBM AT Compatibles
+
+***************************************************************************/
+
+#include "includes/at.h"
+
+#define LOG_PORT80 0
+
+/*************************************************************
+ *
+ * pic8259 configuration
+ *
+ *************************************************************/
+READ8_MEMBER( at_state::get_slave_ack )
+{
+ if (offset==2) // IRQ = 2
+ return pic8259_acknowledge(m_pic8259_slave);
+
+ return 0x00;
+}
+
+const struct pic8259_interface at_pic8259_master_config =
+{
+ DEVCB_CPU_INPUT_LINE("maincpu", 0),
+ DEVCB_LINE_VCC,
+ DEVCB_DRIVER_MEMBER(at_state, get_slave_ack)
+};
+
+const struct pic8259_interface at_pic8259_slave_config =
+{
+ DEVCB_DEVICE_LINE("pic8259_master", pic8259_ir2_w),
+ DEVCB_LINE_GND,
+ DEVCB_NULL
+};
+
+
+
+/*************************************************************************
+ *
+ * PC Speaker related
+ *
+ *************************************************************************/
+
+void at_state::at_speaker_set_spkrdata(UINT8 data)
+{
+ m_at_spkrdata = data ? 1 : 0;
+ speaker_level_w( m_speaker, m_at_spkrdata & m_at_speaker_input);
+}
+
+void at_state::at_speaker_set_input(UINT8 data)
+{
+ m_at_speaker_input = data ? 1 : 0;
+ speaker_level_w( m_speaker, m_at_spkrdata & m_at_speaker_input);
+}
+
+
+
+/*************************************************************
+ *
+ * pit8254 configuration
+ *
+ *************************************************************/
+
+WRITE_LINE_MEMBER( at_state::at_pit8254_out0_changed )
+{
+ if (m_pic8259_master)
+ pic8259_ir0_w(m_pic8259_master, state);
+}
+
+
+WRITE_LINE_MEMBER( at_state::at_pit8254_out2_changed )
+{
+ at_speaker_set_input( state );
+}
+
+
+const struct pit8253_config at_pit8254_config =
+{
+ {
+ {
+ 4772720/4, /* heartbeat IRQ */
+ DEVCB_NULL,
+ DEVCB_DRIVER_LINE_MEMBER(at_state, at_pit8254_out0_changed)
+ }, {
+ 4772720/4, /* dram refresh */
+ DEVCB_NULL,
+ DEVCB_NULL
+ }, {
+ 4772720/4, /* pio port c pin 4, and speaker polling enough */
+ DEVCB_NULL,
+ DEVCB_DRIVER_LINE_MEMBER(at_state, at_pit8254_out2_changed)
+ }
+ }
+};
+
+
+/*************************************************************************
+ *
+ * PC DMA stuff
+ *
+ *************************************************************************/
+
+READ8_MEMBER( at_state::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( at_state::at_page8_w )
+{
+ m_at_pages[offset % 0x10] = data;
+
+ if (LOG_PORT80 && (offset == 0))
+ {
+ logerror(" at_page8_w(): Port 80h <== 0x%02x (PC=0x%08x)\n", data,
+ (unsigned) cpu_get_reg(m_maincpu, STATE_GENPC));
+ }
+
+ 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( at_state::pc_dma_hrq_changed )
+{
+ device_set_input_line(m_maincpu, INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE);
+
+ /* Assert HLDA */
+ m_dma8237_2->hack_w(state);
+}
+
+READ8_MEMBER(at_state::pc_dma_read_byte)
+{
+ UINT8 result;
+ offs_t page_offset = (((offs_t) m_dma_offset[0][m_dma_channel]) << 16) & 0xFF0000;
+
+ result = space.read_byte(page_offset + offset);
+ return result;
+}
+
+
+WRITE8_MEMBER(at_state::pc_dma_write_byte)
+{
+ offs_t page_offset = (((offs_t) m_dma_offset[0][m_dma_channel]) << 16) & 0xFF0000;
+
+ space.write_byte(page_offset + offset, data);
+}
+
+
+READ8_MEMBER(at_state::pc_dma_read_word)
+{
+ UINT16 result;
+ offs_t page_offset = (((offs_t) m_dma_offset[1][m_dma_channel & 3]) << 16) & 0xFF0000;
+
+ result = space.read_word(page_offset + ( offset << 1 ) );
+ m_dma_high_byte = result & 0xFF00;
+
+ return result & 0xFF;
+}
+
+
+WRITE8_MEMBER(at_state::pc_dma_write_word)
+{
+ offs_t page_offset = (((offs_t) m_dma_offset[1][m_dma_channel & 3]) << 16) & 0xFF0000;
+
+ space.write_word(page_offset + ( offset << 1 ), m_dma_high_byte | data);
+}
+
+
+READ8_MEMBER( at_state::pc_dma8237_0_dack_r ) { return m_isabus->dack_r(0); }
+READ8_MEMBER( at_state::pc_dma8237_1_dack_r ) { return m_isabus->dack_r(1); }
+READ8_MEMBER( at_state::pc_dma8237_2_dack_r ) { return m_isabus->dack_r(2); }
+READ8_MEMBER( at_state::pc_dma8237_3_dack_r ) { return m_isabus->dack_r(3); }
+READ8_MEMBER( at_state::pc_dma8237_5_dack_r ) { return m_isabus->dack_r(5); }
+READ8_MEMBER( at_state::pc_dma8237_6_dack_r ) { return m_isabus->dack_r(6); }
+READ8_MEMBER( at_state::pc_dma8237_7_dack_r ) { return m_isabus->dack_r(7); }
+
+
+WRITE8_MEMBER( at_state::pc_dma8237_0_dack_w ){ m_isabus->dack_w(0, data); }
+WRITE8_MEMBER( at_state::pc_dma8237_1_dack_w ){ m_isabus->dack_w(1, data); }
+WRITE8_MEMBER( at_state::pc_dma8237_2_dack_w ){ m_isabus->dack_w(2, data); }
+WRITE8_MEMBER( at_state::pc_dma8237_3_dack_w ){ m_isabus->dack_w(3, data); }
+WRITE8_MEMBER( at_state::pc_dma8237_5_dack_w ){ m_isabus->dack_w(5, data); }
+WRITE8_MEMBER( at_state::pc_dma8237_6_dack_w ){ m_isabus->dack_w(6, data); }
+WRITE8_MEMBER( at_state::pc_dma8237_7_dack_w ){ m_isabus->dack_w(7, data); }
+
+WRITE_LINE_MEMBER( at_state::at_dma8237_out_eop ) { m_isabus->eop_w(state == ASSERT_LINE ? 0 : 1 ); }
+
+static void set_dma_channel(device_t *device, int channel, int state)
+{
+ at_state *st = device->machine().driver_data<at_state>();
+ if (!state)
+ st->m_dma_channel = channel;
+}
+
+WRITE_LINE_MEMBER( at_state::pc_dack0_w ) { set_dma_channel(m_dma8237_1, 0, state); }
+WRITE_LINE_MEMBER( at_state::pc_dack1_w ) { set_dma_channel(m_dma8237_1, 1, state); }
+WRITE_LINE_MEMBER( at_state::pc_dack2_w ) { set_dma_channel(m_dma8237_1, 2, state); }
+WRITE_LINE_MEMBER( at_state::pc_dack3_w ) { set_dma_channel(m_dma8237_1, 3, state); }
+WRITE_LINE_MEMBER( at_state::pc_dack4_w ) { m_dma8237_1->hack_w(state ? 0 : 1); } // it's inverted
+WRITE_LINE_MEMBER( at_state::pc_dack5_w ) { set_dma_channel(m_dma8237_2, 5, state); }
+WRITE_LINE_MEMBER( at_state::pc_dack6_w ) { set_dma_channel(m_dma8237_2, 6, state); }
+WRITE_LINE_MEMBER( at_state::pc_dack7_w ) { set_dma_channel(m_dma8237_2, 7, state); }
+
+I8237_INTERFACE( at_dma8237_1_config )
+{
+ DEVCB_DEVICE_LINE_MEMBER("dma8237_2", am9517a_device, dreq0_w),
+ DEVCB_DRIVER_LINE_MEMBER(at_state, at_dma8237_out_eop),
+ DEVCB_DRIVER_MEMBER(at_state, pc_dma_read_byte),
+ DEVCB_DRIVER_MEMBER(at_state, pc_dma_write_byte),
+ { DEVCB_DRIVER_MEMBER(at_state, pc_dma8237_0_dack_r), DEVCB_DRIVER_MEMBER(at_state, pc_dma8237_1_dack_r), DEVCB_DRIVER_MEMBER(at_state, pc_dma8237_2_dack_r), DEVCB_DRIVER_MEMBER(at_state, pc_dma8237_3_dack_r) },
+ { DEVCB_DRIVER_MEMBER(at_state, pc_dma8237_0_dack_w), DEVCB_DRIVER_MEMBER(at_state, pc_dma8237_1_dack_w), DEVCB_DRIVER_MEMBER(at_state, pc_dma8237_2_dack_w), DEVCB_DRIVER_MEMBER(at_state, pc_dma8237_3_dack_w) },
+ { DEVCB_DRIVER_LINE_MEMBER(at_state, pc_dack0_w), DEVCB_DRIVER_LINE_MEMBER(at_state, pc_dack1_w), DEVCB_DRIVER_LINE_MEMBER(at_state, pc_dack2_w), DEVCB_DRIVER_LINE_MEMBER(at_state, pc_dack3_w) }
+};
+
+
+I8237_INTERFACE( at_dma8237_2_config )
+{
+ DEVCB_DRIVER_LINE_MEMBER(at_state, pc_dma_hrq_changed),
+ DEVCB_NULL,
+ DEVCB_DRIVER_MEMBER(at_state, pc_dma_read_word),
+ DEVCB_DRIVER_MEMBER(at_state, pc_dma_write_word),
+ { DEVCB_NULL, DEVCB_DRIVER_MEMBER(at_state, pc_dma8237_5_dack_r), DEVCB_DRIVER_MEMBER(at_state, pc_dma8237_6_dack_r), DEVCB_DRIVER_MEMBER(at_state, pc_dma8237_7_dack_r) },
+ { DEVCB_NULL, DEVCB_DRIVER_MEMBER(at_state, pc_dma8237_5_dack_w), DEVCB_DRIVER_MEMBER(at_state, pc_dma8237_6_dack_w), DEVCB_DRIVER_MEMBER(at_state, pc_dma8237_7_dack_w) },
+ { DEVCB_DRIVER_LINE_MEMBER(at_state, pc_dack4_w), DEVCB_DRIVER_LINE_MEMBER(at_state, pc_dack5_w), DEVCB_DRIVER_LINE_MEMBER(at_state, pc_dack6_w), DEVCB_DRIVER_LINE_MEMBER(at_state, pc_dack7_w) }
+};
+
+READ8_MEMBER( at_state::at_portb_r )
+{
+ UINT8 data = m_at_speaker;
+ data &= ~0xc0; /* AT BIOS don't likes this being set */
+
+ /* This needs fixing/updating not sure what this is meant to fix */
+ if ( --m_poll_delay < 0 )
+ {
+ m_poll_delay = 3;
+ m_at_offset1 ^= 0x10;
+ }
+ data = (data & ~0x10) | ( m_at_offset1 & 0x10 );
+
+ if ( pit8253_get_output(m_pit8254, 2 ) )
+ data |= 0x20;
+ else
+ data &= ~0x20; /* ps2m30 wants this */
+
+ return data;
+}
+
+WRITE8_MEMBER( at_state::at_portb_w )
+{
+ m_at_speaker = data;
+ pit8253_gate2_w(m_pit8254, 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));
+}
+
+
+/**********************************************************
+ *
+ * Init functions
+ *
+ **********************************************************/
+
+static void init_at_common(running_machine &machine)
+{
+ at_state *state = machine.driver_data<at_state>();
+ address_space* space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ // The CS4031 chipset does this itself
+ if (machine.device("cs4031") == NULL)
+ {
+ /* MESS managed RAM */
+ state->membank("bank10")->set_base(machine.device<ram_device>(RAM_TAG)->pointer());
+
+ if (machine.device<ram_device>(RAM_TAG)->size() > 0x0a0000)
+ {
+ offs_t ram_limit = 0x100000 + machine.device<ram_device>(RAM_TAG)->size() - 0x0a0000;
+ space->install_read_bank(0x100000, ram_limit - 1, "bank1");
+ space->install_write_bank(0x100000, ram_limit - 1, "bank1");
+ state->membank("bank1")->set_base(machine.device<ram_device>(RAM_TAG)->pointer() + 0xa0000);
+ }
+ }
+
+ state->m_at_offset1 = 0xff;
+}
+
+DRIVER_INIT_MEMBER(at_state,atcga)
+{
+ init_at_common(machine());
+}
+
+DRIVER_INIT_MEMBER(at_state,atvga)
+{
+ init_at_common(machine());
+}
+
+static IRQ_CALLBACK(at_irq_callback)
+{
+ at_state *st = device->machine().driver_data<at_state>();
+ return pic8259_acknowledge(st->m_pic8259_master);
+}
+
+MACHINE_START( at )
+{
+ device_set_irq_callback(machine.device("maincpu"), at_irq_callback);
+}
+
+MACHINE_RESET( at )
+{
+ at_state *st = machine.driver_data<at_state>();
+ st->m_poll_delay = 4;
+ st->m_at_spkrdata = 0;
+ st->m_at_speaker_input = 0;
+}
diff --git a/src/mess/machine/at29040a.c b/src/mess/machine/at29040a.c
new file mode 100644
index 00000000000..76b9a32bf22
--- /dev/null
+++ b/src/mess/machine/at29040a.c
@@ -0,0 +1,444 @@
+/*
+ Atmel at29c040a flash EEPROM
+
+ 512k*8 FEEPROM, organized in pages of 256 bytes.
+
+ References:
+ Datasheets were found on Atmel's site (www.atmel.com)
+
+ Raphael Nabet 2003
+
+ September 2010: Rewritten as device
+ February 2012: Rewritten as class
+*/
+
+#include "at29040a.h"
+
+#define VERBOSE 2
+#define LOG logerror
+
+#define FEEPROM_SIZE 0x80000
+#define SECTOR_SIZE 0x00100
+#define BOOT_BLOCK_SIZE 0x04000
+
+#define ADDRESS_MASK 0x7ffff
+#define SECTOR_ADDRESS_MASK 0x7ff00
+#define BYTE_ADDRESS_MASK 0x000ff
+
+#define PRG_TIMER 1
+
+#define VERSION 0
+
+/*
+ Constructor.
+*/
+at29040a_device::at29040a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+: device_t(mconfig, AT29040A, "ATMEL 29040A 512K*8 FEEPROM", tag, owner, clock),
+ device_nvram_interface(mconfig, *this)
+{
+}
+
+//-------------------------------------------------
+// nvram_default - called to initialize NVRAM to
+// its default state
+//-------------------------------------------------
+
+void at29040a_device::nvram_default()
+{
+ memset(m_eememory, 0, FEEPROM_SIZE+2);
+}
+
+//-------------------------------------------------
+// nvram_read - called to read NVRAM from the
+// .nv file
+//-------------------------------------------------
+
+void at29040a_device::nvram_read(emu_file &file)
+{
+ file.read(m_eememory, FEEPROM_SIZE+2);
+}
+
+//-------------------------------------------------
+// nvram_write - called to write NVRAM to the
+// .nv file
+//-------------------------------------------------
+
+void at29040a_device::nvram_write(emu_file &file)
+{
+ m_eememory[0] = VERSION;
+ file.write(m_eememory, FEEPROM_SIZE+2);
+}
+
+/*
+ programming timer callback
+*/
+void at29040a_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch (m_pgm)
+ {
+ case PGM_1:
+ /* programming cycle timeout */
+ if (VERBOSE>7) LOG("at29040a: Programming cycle timeout\n");
+ m_pgm = PGM_0;
+ break;
+
+ case PGM_2:
+ /* programming cycle start */
+ if (VERBOSE>7) LOG("at29040a: Sector write start\n");
+ m_pgm = PGM_3;
+ /* max delay 10ms, typical delay 5 to 7 ms */
+ m_programming_timer->adjust(attotime::from_msec(5));
+ break;
+
+ case PGM_3:
+ /* programming cycle end */
+ memcpy(m_eememory + 2 + (m_programming_last_offset & ~0xff), m_programming_buffer, SECTOR_SIZE);
+ if (VERBOSE>7) LOG("at29040a: Sector write completed at location %04x + 2\n", (m_programming_last_offset & ~0xff));
+ if (m_enabling_sdb)
+ {
+ m_sdp = true;
+ }
+ if (m_disabling_sdb)
+ {
+ m_sdp = false;
+ }
+ if (VERBOSE>7) LOG("at29040a: Software data protection = %d\n", m_sdp);
+
+ m_pgm = PGM_0;
+ m_enabling_sdb = false;
+ m_disabling_sdb = false;
+
+ break;
+
+ default:
+ if (VERBOSE>1) LOG("internal error in %s %d\n", __FILE__, __LINE__);
+ break;
+ }
+}
+
+void at29040a_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( at29040a_device::read )
+{
+ int reply;
+
+ offset &= ADDRESS_MASK;
+
+ /* reading in the midst of any command sequence cancels it (right???) */
+ m_cmd = CMD_0;
+ m_long_sequence = false;
+ // m_higher_bbl = true; // who says that?
+
+ sync_flags();
+
+ /* reading before the start of a programming cycle cancels it (right???) */
+ 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)
+ {
+ switch (offset)
+ {
+ case 0x00000:
+ reply = 0x1f; // Manufacturer code
+ break;
+
+ case 0x00001:
+ reply = 0xa4; // Device code
+ break;
+
+ case 0x00002:
+ reply = m_lower_bbl? 0xff : 0xfe;
+ break;
+
+ case 0x7fff2:
+ reply = m_higher_bbl? 0xff : 0xfe;
+ break;
+
+ default:
+ reply = 0;
+ break;
+ }
+ }
+ else if ((m_pgm == PGM_2) || (m_pgm == PGM_3))
+ {
+ if (m_pgm == PGM_2)
+ { // DATA* polling starts the programming cycle (right???)
+ m_pgm = PGM_3;
+ /* max delay 10ms, typical delay 5 to 7 ms */
+ m_programming_timer->adjust(attotime::from_msec(5));
+ }
+
+ reply = m_toggle_bit? 0x02 : 0x00;
+ m_toggle_bit = !m_toggle_bit;
+
+ if ((offset == m_programming_last_offset) && (! (m_programming_buffer[m_programming_last_offset & 0xff] & 0x01)))
+ reply |= 0x01;
+ }
+ else
+ reply = m_eememory[offset+2];
+
+ if (VERBOSE>7) LOG("at29040a: %05x -> %02x\n", offset, reply);
+
+ return reply;
+}
+
+/*
+ Write a byte to FEEPROM
+*/
+WRITE8_MEMBER( at29040a_device::write )
+{
+ offset &= ADDRESS_MASK;
+ if (VERBOSE>7) LOG("at29040a: %05x <- %02x\n", 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)
+ {
+ if (VERBOSE>7) LOG("at29040a: Enabling boot block lockout\n");
+ m_enabling_bbl = false;
+
+ if ((offset == 0x00000) && (data == 0x00))
+ {
+ if (VERBOSE>7) LOG("at29040a: Enabling lower boot block lockout\n");
+ m_lower_bbl = true;
+ sync_flags();
+ return;
+ }
+ else
+ {
+ if ((offset == 0x7ffff) && (data == 0xff))
+ {
+ if (VERBOSE>7) LOG("at29040a: Enabling higher boot block lockout\n");
+ m_higher_bbl = true;
+ sync_flags();
+ return;
+ }
+ else
+ {
+ if (VERBOSE>1) LOG("at29040a: Invalid boot block specification: %05x/%02x\n", offset, data);
+ }
+ }
+ }
+
+ switch (m_cmd)
+ {
+ case CMD_0:
+ if ((cfi_offset == 0x5555) && (data == 0xaa))
+ {
+ if (VERBOSE>7) LOG("at29040a: Command sequence started\n");
+ m_cmd = CMD_1;
+ }
+ else
+ {
+ m_cmd = CMD_0;
+ m_long_sequence = false;
+ }
+ break;
+
+ case CMD_1:
+ if ((cfi_offset == 0x2aaa) && (data == 0x55))
+ {
+ m_cmd = CMD_2;
+ }
+ else
+ {
+ m_cmd = CMD_0;
+ m_long_sequence = false;
+ if (VERBOSE>7) LOG("at29040a: Command sequence aborted\n");
+ }
+ break;
+
+ case CMD_2:
+ if (cfi_offset == 0x5555)
+ {
+ if (!m_long_sequence)
+ if (VERBOSE>7) LOG("at29040a: Command sequence completed\n");
+
+ m_pgm = PGM_0;
+ m_enabling_sdb = false;
+ m_disabling_sdb = false;
+ m_programming_timer->adjust(attotime::never);
+
+ /* process command */
+ switch (data)
+ {
+ case 0x10:
+ /* Software chip erase */
+ if (m_long_sequence)
+ {
+ if (m_lower_bbl || m_higher_bbl)
+ {
+ if (VERBOSE>1) LOG("at29040a: Chip erase sequence deactivated due to previous boot block lockout.\n");
+ }
+ else
+ {
+ if (VERBOSE>7) LOG("at29040a: Erase chip\n");
+ memset(m_eememory+2, 0xff, FEEPROM_SIZE);
+ }
+ }
+ break;
+
+ case 0x20:
+ /* Software data protection disable */
+ if (VERBOSE>7) LOG("at29040a: Software data protection disable\n");
+ // 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)
+ {
+ m_pgm = PGM_1;
+ m_disabling_sdb = true;
+ /* set command timeout (right???) */
+ //m_programming_timer->adjust(attotime::from_usec(150), id, 0.);
+ }
+ break;
+
+ case 0x40:
+ /* Boot block lockout enable */
+ // Complete sequence is aa-55-80-aa-55-40
+ if (VERBOSE>7) LOG("at29040a: Boot block lockout enable\n");
+ if (m_long_sequence) m_enabling_bbl = true;
+ break;
+
+ case 0x80:
+ m_long_sequence = true;
+ break;
+
+ case 0x90:
+ /* Software product identification entry */
+ if (VERBOSE>7) LOG("at29040a: Identification mode (start)\n");
+ m_id_mode = true;
+ break;
+
+ case 0xa0:
+ /* Software data protection enable */
+ if (VERBOSE>7) LOG("at29040a: Software data protection enable\n");
+ m_pgm = PGM_1;
+ m_enabling_sdb = true;
+ /* set command timeout (right???) */
+ //m_programming_timer->adjust(attotime::from_usec(150), id, 0.);
+ break;
+
+ case 0xf0:
+ /* Software product identification exit */
+ if (VERBOSE>7) LOG("at29040a: Identification mode (end)\n");
+ 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)
+ && ((offset & ~0xff) != (m_programming_last_offset & ~0xff)))
+ {
+ /* cancel current programming cycle */
+ if (VERBOSE>7) LOG("at29040a: invalid sector change (from %05x to %05x); cancel programming cycle\n",(offset & ~0xff), (m_programming_last_offset & ~0xff));
+ 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 < BOOT_BLOCK_SIZE) && m_lower_bbl)
+ || ((offset >= FEEPROM_SIZE-BOOT_BLOCK_SIZE) && m_higher_bbl))
+ {
+ // attempt to access a locked out boot block: cancel programming
+ // command if necessary
+ if (VERBOSE>7) LOG("at29040a: attempt to access a locked out boot block: offset = %05x, lowblock=%d, highblock=%d\n", offset, m_lower_bbl, m_higher_bbl);
+
+ m_pgm = PGM_0;
+ m_enabling_sdb = false;
+ m_disabling_sdb = false;
+ }
+ else
+ { /* enter programming mode */
+ if (VERBOSE>7) LOG("at29040a: enter programming mode (m_pgm=%d)\n", m_pgm);
+ memset(m_programming_buffer, 0xff, SECTOR_SIZE);
+ m_pgm = PGM_2;
+ }
+ }
+ if (m_pgm == PGM_2)
+ {
+ /* write data to programming buffer */
+ if (VERBOSE>7) LOG("at29040a: Write data to programming buffer\n");
+ m_programming_buffer[offset & 0xff] = data;
+ m_programming_last_offset = offset;
+ m_programming_timer->adjust(attotime::from_usec(150)); // next byte must be written before the timer expires
+ }
+}
+
+void at29040a_device::device_start(void)
+{
+ m_programming_buffer = (UINT8*)malloc(SECTOR_SIZE);
+ m_programming_timer = timer_alloc(PRG_TIMER);
+
+ m_eememory = (UINT8*)malloc(FEEPROM_SIZE+2);
+}
+
+void at29040a_device::device_stop(void)
+{
+ free(m_programming_buffer);
+ free(m_eememory);
+}
+
+void at29040a_device::device_reset(void)
+{
+ if (m_eememory[0] != VERSION)
+ {
+ if (VERBOSE>1) LOG("AT29040A: Warning: Version mismatch; expected %d but found %d for %s. Resetting.\n", VERSION, m_eememory[0], tag());
+ 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 (VERBOSE>7) LOG("at29040a (%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 AT29040A = &device_creator<at29040a_device>;
diff --git a/src/mess/machine/at29040a.h b/src/mess/machine/at29040a.h
new file mode 100644
index 00000000000..782805b40ad
--- /dev/null
+++ b/src/mess/machine/at29040a.h
@@ -0,0 +1,89 @@
+/*
+ ATMEL 29040a
+
+ Michael Zapf
+ September 2010: Rewritten as device
+ February 2012: Rewritten as class
+*/
+
+#ifndef __AT29040__
+#define __AT29040__
+
+#include "emu.h"
+
+extern const device_type AT29040A;
+
+/*
+ at29c40a state
+
+ Command states (CMD_0 is the initial state):
+ CMD_0: default state
+ CMD_1: state after writing aa to 5555
+ CMD_2: state after writing 55 to 2aaa
+
+ Programming states (s_programming_0 is the initial state):
+ PGM_0: default state
+ PGM_1: a program and enable/disable lock command has been executed, but programming has not actually started.
+ PGM_2: the programming buffer is being written to
+ PGM_3: the programming buffer is being burnt to flash ROM
+*/
+enum s_cmd_t
+{
+ CMD_0 = 0x0,
+ CMD_1 = 0x1,
+ CMD_2 = 0x2
+};
+
+enum s_pgm_t
+{
+ PGM_0 = 0x0,
+ PGM_1 = 0x1,
+ PGM_2 = 0x2,
+ PGM_3 = 0x3
+};
+
+class at29040a_device : public device_t, public device_nvram_interface
+{
+public:
+ at29040a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ DECLARE_READ8_MEMBER( read );
+ DECLARE_WRITE8_MEMBER( write );
+
+protected:
+ void device_start(void);
+ void device_reset(void);
+ void device_stop(void);
+ 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);
+
+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_dirty; /* set when the memory contents should be set */
+ 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;
+};
+
+#define MCFG_AT29040A_ADD(_tag ) \
+ MCFG_DEVICE_ADD(_tag, AT29040A, 0)
+
+#endif
+
diff --git a/src/mess/machine/at45dbxx.c b/src/mess/machine/at45dbxx.c
new file mode 100644
index 00000000000..23b38a9f92e
--- /dev/null
+++ b/src/mess/machine/at45dbxx.c
@@ -0,0 +1,473 @@
+/*
+
+ Atmel Serial DataFlash
+
+ (c) 2001-2007 Tim Schuerewegen
+
+ AT45DB041 - 528 KByte
+ AT45DB081 - 1056 KByte
+ AT45DB161 - 2112 KByte
+
+*/
+
+#include "at45dbxx.h"
+
+enum
+{
+ TYPE_AT45DB041,
+ TYPE_AT45DB081,
+ TYPE_AT45DB161
+};
+
+#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
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct
+{
+ 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
+} AT45DBXX_PINS;
+
+typedef struct
+{
+ UINT8 data[8], size;
+} AT45DBXX_CMD;
+
+typedef struct
+{
+ UINT8 *data;
+ UINT32 size, pos;
+} AT45DBXX_IO;
+
+typedef struct _at45dbxx_t at45dbxx_t;
+struct _at45dbxx_t
+{
+ UINT8 *data;
+ UINT32 size;
+ UINT32 pages, page_size;
+ UINT8 mode, status, devid, *buffer1, *buffer2;
+ AT45DBXX_PINS pin;
+ UINT8 si_byte, si_bits, so_byte, so_bits;
+ AT45DBXX_CMD cmd;
+ AT45DBXX_IO io;
+};
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+INLINE at45dbxx_t *get_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == AT45DB041 || device->type() == AT45DB081 || device->type() == AT45DB161);
+
+ return (at45dbxx_t *) downcast<legacy_device_base *>(device)->token();
+}
+
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+static void common_start(device_t *device, int device_type)
+{
+ at45dbxx_t *flash = get_token(device);
+
+ _logerror( 0, ("at45dbxx_init (%d)\n", device_type));
+ memset(flash, 0, sizeof(at45dbxx_t));
+ switch (device_type)
+ {
+ case TYPE_AT45DB041 : flash->pages = 2048; flash->page_size = 264; flash->devid = 0x18; break;
+ case TYPE_AT45DB081 : flash->pages = 4096; flash->page_size = 264; flash->devid = 0x20; break;
+ case TYPE_AT45DB161 : flash->pages = 4096; flash->page_size = 528; flash->devid = 0x28; break;
+ }
+ flash->size = flash->pages * flash->page_size;
+ flash->data = auto_alloc_array(device->machine(), UINT8, flash->size);
+ flash->buffer1 = auto_alloc_array(device->machine(), UINT8, flash->page_size);
+ flash->buffer2 = auto_alloc_array(device->machine(), UINT8, flash->page_size);
+
+ // data
+ state_save_register_item_pointer(device->machine(), "at45dbxx", device->tag(), 0, flash->data, flash->size);
+ // pins
+ state_save_register_item(device->machine(), "at45dbxx", device->tag(), 0, flash->pin.cs);
+ state_save_register_item(device->machine(), "at45dbxx", device->tag(), 0, flash->pin.sck);
+ state_save_register_item(device->machine(), "at45dbxx", device->tag(), 0, flash->pin.si);
+ state_save_register_item(device->machine(), "at45dbxx", device->tag(), 0, flash->pin.so);
+ state_save_register_item(device->machine(), "at45dbxx", device->tag(), 0, flash->pin.wp);
+ state_save_register_item(device->machine(), "at45dbxx", device->tag(), 0, flash->pin.reset);
+ state_save_register_item(device->machine(), "at45dbxx", device->tag(), 0, flash->pin.busy);
+}
+
+static DEVICE_START( at45db041 )
+{
+ common_start(device, TYPE_AT45DB041);
+}
+
+static DEVICE_START( at45db081 )
+{
+ common_start(device, TYPE_AT45DB081);
+}
+
+static DEVICE_START( at45db161 )
+{
+ common_start(device, TYPE_AT45DB161);
+}
+
+static DEVICE_RESET( at45dbxx )
+{
+ at45dbxx_t *flash = get_token(device);
+ _logerror( 1, ("at45dbxx_reset\n"));
+ // mode
+ flash->mode = FLASH_MODE_SI;
+ // command
+ memset( &flash->cmd.data[0], 0, sizeof( flash->cmd.data));
+ flash->cmd.size = 0;
+ // input/output
+ flash->io.data = NULL;
+ flash->io.size = 0;
+ flash->io.pos = 0;
+ // pins
+ flash->pin.cs = 0;
+ flash->pin.sck = 0;
+ flash->pin.si = 0;
+ flash->pin.so = 0;
+ flash->pin.wp = 0;
+ flash->pin.reset = 0;
+ flash->pin.busy = 0;
+ // output
+ flash->so_byte = 0;
+ flash->so_bits = 0;
+ // input
+ flash->si_byte = 0;
+ flash->si_bits = 0;
+}
+
+static UINT8 at45dbxx_read_byte( device_t *device)
+{
+ UINT8 data;
+ at45dbxx_t *flash = get_token(device);
+ // check mode
+ if ((flash->mode != FLASH_MODE_SO) || (!flash->io.data)) return 0;
+ // read byte
+ data = flash->io.data[flash->io.pos++];
+ _logerror( 2, ("at45dbxx_read_byte (%02X) (%03d/%03d)\n", data, flash->io.pos, flash->io.size));
+ if (flash->io.pos == flash->io.size) flash->io.pos = 0;
+ return data;
+}
+
+static void flash_set_io( device_t *device, UINT8* data, UINT32 size, UINT32 pos)
+{
+ at45dbxx_t *flash = get_token(device);
+ flash->io.data = data;
+ flash->io.size = size;
+ flash->io.pos = pos;
+}
+
+static UINT32 flash_get_page_addr( device_t *device)
+{
+ at45dbxx_t *flash = get_token(device);
+ switch (flash->devid)
+ {
+ case 0x18 : return ((flash->cmd.data[1] & 0x0F) << 7) | ((flash->cmd.data[2] & 0xFE) >> 1);
+ case 0x20 : return ((flash->cmd.data[1] & 0x1F) << 7) | ((flash->cmd.data[2] & 0xFE) >> 1);
+ case 0x28 : return ((flash->cmd.data[1] & 0x3F) << 6) | ((flash->cmd.data[2] & 0xFC) >> 2);
+ default : return 0;
+ }
+}
+
+static UINT32 flash_get_byte_addr( device_t *device)
+{
+ at45dbxx_t *flash = get_token(device);
+ switch (flash->devid)
+ {
+ case 0x18 : // fall-through
+ case 0x20 : return ((flash->cmd.data[2] & 0x01) << 8) | ((flash->cmd.data[3] & 0xFF) >> 0);
+ case 0x28 : return ((flash->cmd.data[2] & 0x03) << 8) | ((flash->cmd.data[3] & 0xFF) >> 0);
+ default : return 0;
+ }
+}
+
+static void at45dbxx_write_byte(device_t *device, UINT8 data)
+{
+ at45dbxx_t *flash = get_token(device);
+ // check mode
+ if (flash->mode != FLASH_MODE_SI) return;
+ // process byte
+ if (flash->cmd.size < 8)
+ {
+ UINT8 opcode;
+ _logerror( 2, ("at45dbxx_write_byte (%02X)\n", data));
+ // add to command buffer
+ flash->cmd.data[flash->cmd.size++] = data;
+ // check opcode
+ opcode = flash->cmd.data[0];
+ switch (opcode)
+ {
+ // status register read
+ case FLASH_CMD_57 :
+ {
+ // 8 bits command
+ if (flash->cmd.size == 1)
+ {
+ _logerror( 1, ("at45dbxx opcode %02X - status register read\n", opcode));
+ flash->status = (flash->status & 0xC7) | flash->devid; // 80 = busy / 40 = compare fail
+ flash_set_io( device, &flash->status, 1, 0);
+ flash->mode = FLASH_MODE_SO;
+ flash->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 (flash->cmd.size == 4)
+ {
+ UINT32 page;
+ UINT8 comp;
+ page = flash_get_page_addr(device);
+ _logerror( 1, ("at45dbxx opcode %02X - main memory page to buffer 1 compare [%04X]\n", opcode, page));
+ comp = memcmp( flash->data + page * flash->page_size, flash->buffer1, flash->page_size) == 0 ? 0 : 1;
+ if (comp) flash->status |= 0x40; else flash->status &= ~0x40;
+ _logerror( 1, ("at45dbxx page compare %s\n", comp ? "failure" : "success"));
+ flash->mode = FLASH_MODE_SI;
+ flash->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 (flash->cmd.size == 8)
+ {
+ UINT32 page, byte;
+ page = flash_get_page_addr(device);
+ byte = flash_get_byte_addr(device);
+ _logerror( 1, ("at45dbxx opcode %02X - main memory page read [%04X/%04X]\n", opcode, page, byte));
+ flash_set_io( device, flash->data + page * flash->page_size, flash->page_size, byte);
+ flash->mode = FLASH_MODE_SO;
+ flash->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 (flash->cmd.size == 4)
+ {
+ UINT32 page, byte;
+ page = flash_get_page_addr(device);
+ byte = flash_get_byte_addr(device);
+ _logerror( 1, ("at45dbxx opcode %02X - main memory page program through buffer 1 [%04X/%04X]\n",opcode, page, byte));
+ flash_set_io( device, flash->buffer1, flash->page_size, byte);
+ memset( flash->buffer1, 0xFF, flash->page_size);
+ flash->mode = FLASH_MODE_SI;
+ flash->cmd.size = 8;
+ }
+ }
+ break;
+ // other
+ default :
+ {
+ _logerror( 1, ("at45dbxx opcode %02X - unknown\n", opcode));
+ flash->cmd.data[0] = 0;
+ flash->cmd.size = 0;
+ }
+ break;
+ }
+ }
+ else
+ {
+ _logerror( 2, ("at45dbxx_write_byte (%02X) (%03d/%03d)\n", data, flash->io.pos + 1, flash->io.size));
+ // store byte
+ flash->io.data[flash->io.pos] = data;
+ flash->io.pos++;
+ if (flash->io.pos == flash->io.size) flash->io.pos = 0;
+ }
+}
+
+int at45dbxx_pin_so( device_t *device)
+{
+ at45dbxx_t *flash = get_token(device);
+ if (flash->pin.cs == 0) return 0;
+ return flash->pin.so;
+}
+
+void at45dbxx_pin_si(device_t *device, int data)
+{
+ at45dbxx_t *flash = get_token(device);
+ if (flash->pin.cs == 0) return;
+ flash->pin.si = data;
+}
+
+void at45dbxx_pin_cs(device_t *device, int data)
+{
+ at45dbxx_t *flash = get_token(device);
+ // check if changed
+ if (flash->pin.cs == data) return;
+ // cs low-to-high
+ if (data != 0)
+ {
+ // complete program command
+ if ((flash->cmd.size >= 4) && (flash->cmd.data[0] == FLASH_CMD_82))
+ {
+ UINT32 page, byte;
+ page = flash_get_page_addr(device);
+ byte = flash_get_byte_addr(device);
+ _logerror( 1, ("at45dbxx - program data stored in buffer 1 into selected page in main memory [%04X/%04X]\n", page, byte));
+ memcpy( flash->data + page * flash->page_size, flash->buffer1, flash->page_size);
+ }
+ // reset
+ DEVICE_RESET_CALL( at45dbxx );
+ }
+ // save cs
+ flash->pin.cs = data;
+}
+
+void at45dbxx_pin_sck(device_t *device, int data)
+{
+ at45dbxx_t *flash = get_token(device);
+ // check if changed
+ if (flash->pin.sck == data) return;
+ // sck high-to-low
+ if (data == 0)
+ {
+ // output (part 1)
+ if (flash->so_bits == 8)
+ {
+ flash->so_bits = 0;
+ flash->so_byte = at45dbxx_read_byte(device);
+ }
+ // input
+ if (flash->pin.si) flash->si_byte = flash->si_byte | (1 << flash->si_bits);
+ flash->si_bits++;
+ if (flash->si_bits == 8)
+ {
+ flash->si_bits = 0;
+ at45dbxx_write_byte( device, flash->si_byte);
+ flash->si_byte = 0;
+ }
+ // output (part 2)
+ flash->pin.so = (flash->so_byte >> flash->so_bits) & 1;
+ flash->so_bits++;
+ }
+ // save sck
+ flash->pin.sck = data;
+}
+
+void at45dbxx_load(device_t *device, emu_file *file)
+{
+ at45dbxx_t *flash = get_token(device);
+ _logerror( 0, ("at45dbxx_load (%p)\n", file));
+ file->read(flash->data, flash->size);
+}
+
+void at45dbxx_save(device_t *device, emu_file *file)
+{
+ at45dbxx_t *flash = get_token(device);
+ _logerror( 0, ("at45dbxx_save (%p)\n", file));
+ file->write(flash->data, flash->size);
+}
+
+#ifdef UNUSED_FUNCTION
+NVRAM_HANDLER( at45dbxx )
+{
+ _logerror( 0, ("nvram_handler_at45dbxx (%p/%d)\n", file, read_or_write));
+ if (read_or_write)
+ {
+ at45dbxx_save( file);
+ }
+ else
+ {
+ if (file)
+ {
+ at45dbxx_load( file);
+ }
+ else
+ {
+ memset( flash->data, 0xFF, flash->size);
+ }
+ }
+}
+#endif
+
+
+/*-------------------------------------------------
+ DEVICE_GET_INFO( at45db041 )
+-------------------------------------------------*/
+
+DEVICE_GET_INFO( at45db041 )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(at45dbxx_t); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(at45db041); break;
+ case DEVINFO_FCT_STOP: /* Nothing */ break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(at45dbxx); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "AT45DB041"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "AT45DBxx"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: /* Nothing */ break;
+ }
+}
+
+DEVICE_GET_INFO( at45db081 )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "AT45DB081"); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(at45db081); break;
+
+ default: DEVICE_GET_INFO_CALL(at45db041); break;
+ }
+}
+
+DEVICE_GET_INFO( at45db161 )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "AT45DB161"); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(at45db161); break;
+
+ default: DEVICE_GET_INFO_CALL(at45db041); break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(AT45DB041, at45db041);
+DEFINE_LEGACY_DEVICE(AT45DB081, at45db081);
+DEFINE_LEGACY_DEVICE(AT45DB161, at45db161);
diff --git a/src/mess/machine/at45dbxx.h b/src/mess/machine/at45dbxx.h
new file mode 100644
index 00000000000..6bd1ff8abcd
--- /dev/null
+++ b/src/mess/machine/at45dbxx.h
@@ -0,0 +1,55 @@
+/*
+
+ 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"
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+DECLARE_LEGACY_DEVICE(AT45DB041, at45db041);
+
+#define MCFG_AT45DB041_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, AT45DB041, 0) \
+
+DECLARE_LEGACY_DEVICE(AT45DB081, at45db081);
+
+#define MCFG_AT45DB081_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, AT45DB081, 0) \
+
+DECLARE_LEGACY_DEVICE(AT45DB161, at45db161);
+
+#define MCFG_AT45DB161_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, AT45DB161, 0) \
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+// pins
+void at45dbxx_pin_cs(device_t *device, int data);
+void at45dbxx_pin_sck(device_t *device, int data);
+void at45dbxx_pin_si(device_t *device, int data);
+int at45dbxx_pin_so(device_t *device);
+
+// load/save
+void at45dbxx_load(device_t *device, emu_file *file);
+void at45dbxx_save(device_t *device, emu_file *file);
+
+// non-volatile ram handler
+//NVRAM_HANDLER( at45dbxx );
+
+#endif
diff --git a/src/mess/machine/at_keybc.c b/src/mess/machine/at_keybc.c
new file mode 100644
index 00000000000..fa54ce16ebf
--- /dev/null
+++ b/src/mess/machine/at_keybc.c
@@ -0,0 +1,229 @@
+/***************************************************************************
+
+ 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<at_keyboard_controller_device>;
+
+// 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
+// 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),
+ m_cpu(NULL)
+{
+ m_shortname = "at_keybc";
+}
+
+//-------------------------------------------------
+// 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);
+}
+
+//-------------------------------------------------
+// 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_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void at_keyboard_controller_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const at_keyboard_controller_interface *intf = reinterpret_cast<const at_keyboard_controller_interface *>(static_config());
+
+ if (intf != NULL)
+ {
+ *static_cast<at_keyboard_controller_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_system_reset_cb, 0, sizeof(m_system_reset_cb));
+ memset(&m_gate_a20_cb, 0, sizeof(m_gate_a20_cb));
+ memset(&m_input_buffer_full_cb, 0, sizeof(m_input_buffer_full_cb));
+ memset(&m_output_buffer_empty_cb, 0, sizeof(m_output_buffer_empty_cb));
+ memset(&m_keyboard_clock_cb, 0, sizeof(m_keyboard_clock_cb));
+ memset(&m_keyboard_data_cb, 0, sizeof(m_keyboard_data_cb));
+ }
+}
+
+/*-------------------------------------------------
+ device_start - device-specific startup
+-------------------------------------------------*/
+
+void at_keyboard_controller_device::device_start()
+{
+ // find our cpu
+ m_cpu = downcast<device_t *>(subdevice("at_keybc"));
+
+ // resolve callbacks
+ m_system_reset_func.resolve(m_system_reset_cb, *this);
+ m_gate_a20_func.resolve(m_gate_a20_cb, *this);
+ m_input_buffer_full_func.resolve(m_input_buffer_full_cb, *this);
+ m_output_buffer_empty_func.resolve(m_output_buffer_empty_cb, *this);
+ m_keyboard_clock_func.resolve(m_keyboard_clock_cb, *this);
+ m_keyboard_data_func.resolve(m_keyboard_data_cb, *this);
+
+ // 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 0xbf;
+}
+
+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_func(BIT(data, 0) ? CLEAR_LINE : ASSERT_LINE);
+ m_gate_a20_func(BIT(data, 1) ? ASSERT_LINE : CLEAR_LINE);
+ m_input_buffer_full_func(BIT(data, 4) ? ASSERT_LINE : CLEAR_LINE);
+ m_output_buffer_empty_func(BIT(data, 5) ? ASSERT_LINE : CLEAR_LINE);
+
+ m_clock_signal = !BIT(data, 6);
+ m_data_signal = BIT(data, 7);
+
+ m_keyboard_data_func(m_data_signal);
+ m_keyboard_clock_func(m_clock_signal);
+}
+
+
+//**************************************************************************
+// READ/WRITE HANDLERS
+//**************************************************************************
+
+READ8_MEMBER( at_keyboard_controller_device::data_r )
+{
+ return upi41_master_r(m_cpu, 0);
+}
+
+WRITE8_MEMBER( at_keyboard_controller_device::data_w )
+{
+ upi41_master_w(m_cpu, 0, data);
+}
+
+READ8_MEMBER( at_keyboard_controller_device::status_r )
+{
+ return upi41_master_r(m_cpu, 1);
+}
+
+WRITE8_MEMBER( at_keyboard_controller_device::command_w )
+{
+ upi41_master_w(m_cpu, 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/mess/machine/at_keybc.h b/src/mess/machine/at_keybc.h
new file mode 100644
index 00000000000..c4efd1097dd
--- /dev/null
+++ b/src/mess/machine/at_keybc.h
@@ -0,0 +1,98 @@
+/***************************************************************************
+
+ IBM PC AT compatibles 8042 keyboard controller
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __AT_KEYBC_H__
+#define __AT_KEYBC_H__
+
+#include "emu.h"
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_AT_KEYBOARD_CONTROLLER_ADD(_tag, _clock, _interface) \
+ MCFG_DEVICE_ADD(_tag, AT_KEYBOARD_CONTROLLER, _clock) \
+ MCFG_DEVICE_CONFIG(_interface)
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> at_keyboard_controller_interface
+
+struct at_keyboard_controller_interface
+{
+ // 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;
+};
+
+// ======================> at_keyboard_controller_device
+
+class at_keyboard_controller_device : public device_t,
+ public at_keyboard_controller_interface
+{
+
+public:
+ // construction/destruction
+ at_keyboard_controller_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // 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 void device_config_complete();
+
+ virtual const rom_entry *device_rom_region() const;
+ virtual machine_config_constructor device_mconfig_additions() const;
+private:
+ // internal state
+ device_t *m_cpu;
+
+ devcb_resolved_write_line m_system_reset_func;
+ devcb_resolved_write_line m_gate_a20_func;
+ devcb_resolved_write_line m_input_buffer_full_func;
+ devcb_resolved_write_line m_output_buffer_empty_func;
+ devcb_resolved_write_line m_keyboard_clock_func;
+ devcb_resolved_write_line m_keyboard_data_func;
+
+ 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/mess/machine/ataricrt.c b/src/mess/machine/ataricrt.c
new file mode 100644
index 00000000000..90713c429d8
--- /dev/null
+++ b/src/mess/machine/ataricrt.c
@@ -0,0 +1,718 @@
+/***************************************************************************
+
+ MESS specific Atari init and Cartridge code for Atari 8 bit systems
+
+***************************************************************************/
+
+#include "emu.h"
+#include "emuopts.h"
+#include "includes/atari.h"
+#include "ataridev.h"
+#include "machine/ram.h"
+#include "hashfile.h"
+
+#define LEFT_CARTSLOT_MOUNTED 1
+#define RIGHT_CARTSLOT_MOUNTED 2
+
+/* PCB */
+enum
+{
+ A800_UNKNOWN = 0,
+ A800_4K, A800_8K, A800_12K, A800_16K,
+ A800_RIGHT_4K, A800_RIGHT_8K,
+ OSS_034M, OSS_M091, PHOENIX_8K, XEGS_32K,
+ BBSB, DIAMOND_64K, WILLIAMS_64K, EXPRESS_64,
+ SPARTADOS_X
+};
+
+static int a800_cart_loaded = 0;
+static int atari = 0;
+static int a800_cart_type = A800_UNKNOWN;
+
+/*************************************
+ *
+ * Generic code
+ *
+ *************************************/
+
+
+// Currently, the drivers have fixed 40k RAM, however the function here is ready for different sizes too
+static void a800_setbank(running_machine &machine, int cart_mounted)
+{
+ offs_t ram_top;
+ // take care of 0x0000-0x7fff: RAM or NOP
+ ram_top = MIN(machine.device<ram_device>(RAM_TAG)->size(), 0x8000) - 1;
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(0x0000, ram_top, "0000");
+ machine.root_device().membank("0000")->set_base(machine.device<ram_device>(RAM_TAG)->pointer());
+
+ // take care of 0x8000-0x9fff: A800 -> either right slot or RAM or NOP, others -> RAM or NOP
+ // is there anything in the right slot?
+ if (cart_mounted & RIGHT_CARTSLOT_MOUNTED)
+ {
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0x8000, 0x9fff, "8000");
+ machine.root_device().membank("8000")->set_base(machine.root_device().memregion("rslot")->base());
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0x8000, 0x9fff);
+ }
+ else if (a800_cart_type != BBSB)
+ {
+ ram_top = MIN(machine.device<ram_device>(RAM_TAG)->size(), 0xa000) - 1;
+ if (ram_top > 0x8000)
+ {
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(0x8000, ram_top, "8000");
+ machine.root_device().membank("8000")->set_base(machine.device<ram_device>(RAM_TAG)->pointer() + 0x8000);
+ }
+ }
+
+ // take care of 0xa000-0xbfff: is there anything in the left slot?
+ if (cart_mounted & LEFT_CARTSLOT_MOUNTED)
+ {
+ // FIXME: this is an hack to keep XL working until we clean up its memory map as well!
+ if (atari == ATARI_800XL)
+ {
+ if (a800_cart_type == A800_16K)
+ {
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0x8000, 0x9fff, "8000");
+ machine.root_device().membank("8000")->set_base(machine.root_device().memregion("lslot")->base());
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0x8000, 0x9fff);
+
+ memcpy(machine.root_device().memregion("maincpu")->base() + 0x10000, machine.root_device().memregion("lslot")->base() + 0x2000, 0x2000);
+ }
+ else if (a800_cart_type == A800_8K)
+ memcpy(machine.root_device().memregion("maincpu")->base() + 0x10000, machine.root_device().memregion("lslot")->base(), 0x2000);
+ else
+ fatalerror("This type of cart is not supported yet in this driver. Please use a400 or a800.\n");
+ }
+ else if (a800_cart_type == A800_16K)
+ {
+ machine.root_device().membank("8000")->set_base(machine.root_device().memregion("lslot")->base());
+ machine.root_device().membank("a000")->set_base(machine.root_device().memregion("lslot")->base() + 0x2000);
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0x8000, 0xbfff);
+ }
+ else if (a800_cart_type == BBSB)
+ {
+ // this requires separate banking in 0x8000 & 0x9000!
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0x8000, 0x8fff, "8000");
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0x9000, 0x9fff, "9000");
+ machine.root_device().membank("8000")->set_base(machine.root_device().memregion("lslot")->base() + 0x0000);
+ machine.root_device().membank("9000")->set_base(machine.root_device().memregion("lslot")->base() + 0x4000);
+ machine.root_device().membank("a000")->set_base(machine.root_device().memregion("lslot")->base() + 0x8000);
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0xa000, 0xbfff);
+ }
+ else if (a800_cart_type == OSS_034M)
+ {
+ // this requires separate banking in 0xa000 & 0xb000!
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0xa000, 0xafff, "a000");
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0xb000, 0xbfff, "b000");
+ machine.root_device().membank("b000")->set_base(machine.root_device().memregion("lslot")->base() + 0x3000);
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0xa000, 0xbfff);
+ }
+ else if (a800_cart_type == OSS_M091)
+ {
+ // this requires separate banking in 0xa000 & 0xb000!
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0xa000, 0xafff, "a000");
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0xb000, 0xbfff, "b000");
+ machine.root_device().membank("b000")->set_base(machine.root_device().memregion("lslot")->base());
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0xa000, 0xbfff);
+ }
+ else if (a800_cart_type == XEGS_32K)
+ {
+ machine.root_device().membank("8000")->set_base(machine.root_device().memregion("lslot")->base());
+ machine.root_device().membank("a000")->set_base(machine.root_device().memregion("lslot")->base() + 0x6000);
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0x8000, 0xbfff);
+ }
+ else
+ {
+ machine.root_device().membank("a000")->set_base(machine.root_device().memregion("lslot")->base());
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0xa000, 0xbfff);
+ }
+ }
+}
+
+/* MESS specific parts that have to be started */
+static void ms_atari_machine_start(running_machine &machine, int type, int has_cart)
+{
+ /* set atari type (temporarily not used) */
+ atari = type;
+ a800_setbank(machine, a800_cart_loaded);
+}
+
+static void ms_atari800xl_machine_start(running_machine &machine, int type, int has_cart)
+{
+ /* set atari type (temporarily not used) */
+ atari = type;
+ a800_setbank(machine, a800_cart_loaded);
+}
+
+/*************************************
+ *
+ * Atari 400
+ *
+ *************************************/
+
+MACHINE_START( a400 )
+{
+ atari_machine_start(machine);
+ ms_atari_machine_start(machine, ATARI_400, TRUE);
+}
+
+
+/*************************************
+ *
+ * Atari 800
+ *
+ *************************************/
+
+MACHINE_START( a800 )
+{
+ atari_machine_start(machine);
+ ms_atari_machine_start(machine, ATARI_800, TRUE);
+}
+
+static WRITE8_HANDLER( x32_bank_w )
+{
+ // printf("written %x\n", data);
+ int bank = data & 0x03;
+ space->machine().root_device().membank("8000")->set_base(space->machine().root_device().memregion("lslot")->base() + bank * 0x2000);
+}
+
+static WRITE8_HANDLER( w64_bank_w )
+{
+// printf("write to %x\n", offset);
+
+ if (offset < 8)
+ space->machine().root_device().membank("a000")->set_base(space->machine().root_device().memregion("lslot")->base() + offset * 0x2000);
+ else
+ space->machine().root_device().membank("a000")->set_base(space->machine().root_device().memregion("maincpu")->base());
+ // FIXME: writes to 0x8-0xf should disable the cart
+}
+
+// this covers Express 64, Diamond 64 and SpartaDOS (same bankswitch, but at different addresses)
+static WRITE8_HANDLER( ex64_bank_w )
+{
+// printf("write to %x\n", offset);
+
+ if (offset < 8)
+ space->machine().root_device().membank("a000")->set_base(space->machine().root_device().memregion("lslot")->base() + (7 - offset) * 0x2000);
+ else
+ space->machine().root_device().membank("a000")->set_base(space->machine().root_device().memregion("maincpu")->base());
+ // FIXME: writes to 0x8-0xf should disable the cart
+}
+
+static WRITE8_HANDLER( bbsb_bankl_w )
+{
+// printf("write to %x\n", 0x8000 + offset);
+ if (offset >= 0xff6 && offset <= 0xff9)
+ space->machine().root_device().membank("8000")->set_base(space->machine().root_device().memregion("lslot")->base() + 0x0000 + (offset - 0xff6) * 0x1000);
+}
+
+static WRITE8_HANDLER( bbsb_bankh_w )
+{
+// printf("write to %x\n", 0x9000 + offset);
+ if (offset >= 0xff6 && offset <= 0xff9)
+ space->machine().root_device().membank("9000")->set_base(space->machine().root_device().memregion("lslot")->base() + 0x4000 + (offset - 0xff6) * 0x1000);
+}
+
+static WRITE8_HANDLER( oss_034m_w )
+{
+ switch (offset & 0x0f)
+ {
+ case 0:
+ case 1:
+ space->machine().root_device().membank("a000")->set_base(space->machine().root_device().memregion("lslot")->base());
+ space->machine().root_device().membank("b000")->set_base(space->machine().root_device().memregion("lslot")->base() + 0x3000);
+ break;
+ case 2:
+ case 6:
+ // docs says this should put 0xff in the 0xa000 bank -> let's point to the end of the cart
+ space->machine().root_device().membank("a000")->set_base(space->machine().root_device().memregion("lslot")->base() + 0x4000);
+ space->machine().root_device().membank("b000")->set_base(space->machine().root_device().memregion("lslot")->base() + 0x3000);
+ break;
+ case 3:
+ case 7:
+ space->machine().root_device().membank("a000")->set_base(space->machine().root_device().memregion("lslot")->base() + 0x1000);
+ space->machine().root_device().membank("b000")->set_base(space->machine().root_device().memregion("lslot")->base() + 0x3000);
+ break;
+ case 4:
+ case 5:
+ space->machine().root_device().membank("a000")->set_base(space->machine().root_device().memregion("lslot")->base() + 0x2000);
+ space->machine().root_device().membank("b000")->set_base(space->machine().root_device().memregion("lslot")->base() + 0x3000);
+ break;
+ default:
+ space->machine().root_device().membank("a000")->set_base(space->machine().root_device().memregion("maincpu")->base() + 0xa000);
+ space->machine().root_device().membank("b000")->set_base(space->machine().root_device().memregion("maincpu")->base() + 0xb000);
+ break;
+ }
+}
+
+static WRITE8_HANDLER( oss_m091_w )
+{
+ switch (offset & 0x09)
+ {
+ case 0:
+ space->machine().root_device().membank("a000")->set_base(space->machine().root_device().memregion("lslot")->base() + 0x1000);
+ space->machine().root_device().membank("b000")->set_base(space->machine().root_device().memregion("lslot")->base());
+ break;
+ case 1:
+ space->machine().root_device().membank("a000")->set_base(space->machine().root_device().memregion("lslot")->base() + 0x3000);
+ space->machine().root_device().membank("b000")->set_base(space->machine().root_device().memregion("lslot")->base());
+ break;
+ case 8:
+ space->machine().root_device().membank("a000")->set_base(space->machine().root_device().memregion("maincpu")->base() + 0xa000);
+ space->machine().root_device().membank("b000")->set_base(space->machine().root_device().memregion("maincpu")->base() + 0xb000);
+ break;
+ case 9:
+ space->machine().root_device().membank("a000")->set_base(space->machine().root_device().memregion("lslot")->base() + 0x2000);
+ space->machine().root_device().membank("b000")->set_base(space->machine().root_device().memregion("lslot")->base());
+ break;
+ }
+}
+
+#if 0
+static int bbsb_bankl = 0;
+static int bbsb_bankh = 0;
+
+static WRITE8_HANDLER( bbsb_bankl_w )
+{
+ bbsb_bankl = offset; // 0,1,2,3
+}
+
+static WRITE8_HANDLER( bbsb_bankh_w )
+{
+ bbsb_bankh = offset; // 4,5,6,7
+}
+
+static READ8_HANDLER( bbsb_bankl_r )
+{
+ // return data from the selected bank (0,1,2,3)
+ UINT8 *mem = space->machine().root_device().memregion("lslot")->base();
+ return &mem[0x0000 + bbsb_bankl * 0x1000];
+}
+
+static READ8_HANDLER( bbsb_bankh_r )
+{
+ // return data from the selected bank (4,5,6,7)
+ UINT8 *mem = space->machine().root_device().memregion("lslot")->base();
+ return &mem[0x4000 + bbsb_bankh * 0x1000];
+}
+#endif
+
+typedef struct _a800_pcb a800_pcb;
+struct _a800_pcb
+{
+ const char *pcb_name;
+ int pcb_id;
+};
+
+// Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it
+// WARNING: most of these are still unsupported by the driver
+static const a800_pcb pcb_list[] =
+{
+ {"standard 4k", A800_8K},
+ {"standard 8k", A800_8K},
+ {"standard 12k", A800_16K},
+ {"standard 16k", A800_16K},
+ {"right slot 4k", A800_RIGHT_4K},
+ {"right slot 8k", A800_RIGHT_8K},
+
+ {"oss 034m", OSS_034M},
+ {"oss m091", OSS_M091},
+ {"phoenix 8k", PHOENIX_8K},
+ {"xegs 32k", XEGS_32K},
+ {"bbsb", BBSB},
+ {"diamond 64k", DIAMOND_64K},
+ {"williams 64k", WILLIAMS_64K},
+ {"express 64", EXPRESS_64},
+ {"spartados x", SPARTADOS_X},
+ {"N/A", A800_UNKNOWN}
+};
+
+static int a800_get_pcb_id(const char *pcb)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_LENGTH(pcb_list); i++)
+ {
+ if (!mame_stricmp(pcb_list[i].pcb_name, pcb))
+ return pcb_list[i].pcb_id;
+ }
+
+ return A800_UNKNOWN;
+}
+
+// currently this does nothing, but it will eventually install the memory handlers required by the mappers
+static void a800_setup_mappers(running_machine &machine, int type)
+{
+ switch (type)
+ {
+ case A800_4K:
+ case A800_RIGHT_4K:
+ case A800_12K:
+ case A800_8K:
+ case A800_16K:
+ case A800_RIGHT_8K:
+ case PHOENIX_8K: // as normal 8k cart, but it can be disabled by writing to 0xd500-0xdfff
+ break;
+ case XEGS_32K:
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xd500, 0xd5ff, FUNC(x32_bank_w));
+ break;
+ case OSS_034M:
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xd500, 0xd5ff, FUNC(oss_034m_w));
+ break;
+ case OSS_M091:
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xd500, 0xd5ff, FUNC(oss_m091_w));
+ break;
+ case BBSB:
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x8000, 0x8fff, FUNC(bbsb_bankl_w));
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x9000, 0x9fff, FUNC(bbsb_bankh_w));
+ break;
+ case WILLIAMS_64K:
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xd500, 0xd50f, FUNC(w64_bank_w));
+ break;
+ case DIAMOND_64K:
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xd5d0, 0xd5df, FUNC(ex64_bank_w));
+ break;
+ case EXPRESS_64:
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xd570, 0xd57f, FUNC(ex64_bank_w));
+ break;
+ case SPARTADOS_X:
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xd5e0, 0xd5ef, FUNC(ex64_bank_w));
+ break;
+ default:
+ break;
+ }
+}
+
+static int a800_get_type(device_image_interface &image)
+{
+ UINT8 header[16];
+ image.fread(header, 0x10);
+ int hdr_type, cart_type = A800_UNKNOWN;
+
+ // add check of CART format
+ if (strncmp((const char *)header, "CART", 4))
+ fatalerror("Invalid header detected!\n");
+
+ hdr_type = (header[4] << 24) + (header[5] << 16) + (header[6] << 8) + (header[7] << 0);
+ switch (hdr_type)
+ {
+ case 1:
+ cart_type = A800_8K;
+ break;
+ case 2:
+ cart_type = A800_16K;
+ break;
+ case 3:
+ cart_type = OSS_034M;
+ break;
+ case 8:
+ cart_type = WILLIAMS_64K;
+ break;
+ case 9:
+ cart_type = DIAMOND_64K;
+ break;
+ case 10:
+ cart_type = EXPRESS_64;
+ break;
+ case 11:
+ cart_type = SPARTADOS_X;
+ break;
+ case 12:
+ cart_type = XEGS_32K;
+ break;
+ case 15:
+ cart_type = OSS_M091;
+ break;
+ case 18:
+ cart_type = BBSB;
+ break;
+ case 21:
+ cart_type = A800_RIGHT_8K;
+ break;
+ case 39:
+ cart_type = PHOENIX_8K;
+ break;
+ case 4:
+ case 6:
+ case 7:
+ case 16:
+ case 19:
+ case 20:
+ fatalerror("Cart type \"%d\" means this is an Atari 5200 cart.\n", hdr_type);
+ break;
+ default:
+ mame_printf_info("Cart type \"%d\" is currently unsupported.\n", hdr_type);
+ break;
+ }
+ return cart_type;
+}
+
+static int a800_check_cart_type(device_image_interface &image)
+{
+ const char *pcb_name;
+ int type = A800_UNKNOWN;
+
+ if (image.software_entry() == NULL)
+ {
+ UINT32 size = image.length();
+
+ // check if there is an header, if so extract cart_type from it, otherwise
+ // try to guess the cart_type from the file size (notice that after the
+ // a800_get_type call, we point at the start of the data)
+ if ((size % 0x1000) == 0x10)
+ type = a800_get_type(image);
+ else if (size == 0x4000)
+ type = A800_16K;
+ else if (size == 0x2000)
+ {
+ if (strcmp(image.device().tag(),":cart2") == 0)
+ type = A800_RIGHT_8K;
+ else
+ type = A800_8K;
+ }
+ }
+ else
+ {
+ if ((pcb_name = image.get_feature("cart_type")) != NULL)
+ type = a800_get_pcb_id(pcb_name);
+
+ switch (type)
+ {
+ case A800_UNKNOWN:
+ case A800_4K:
+ case A800_RIGHT_4K:
+ case A800_12K:
+ case A800_8K:
+ case A800_16K:
+ case A800_RIGHT_8K:
+ break;
+ default:
+ mame_printf_info("Cart type \"%s\" currently unsupported.\n", pcb_name);
+ break;
+ }
+ }
+
+ if ((strcmp(image.device().tag(),":cart2") == 0) && (type != A800_RIGHT_8K))
+ fatalerror("You cannot load this image '%s' in the right slot", image.filename());
+
+ return type;
+}
+
+DEVICE_IMAGE_LOAD( a800_cart )
+{
+ UINT32 size, start = 0;
+
+ a800_cart_loaded = a800_cart_loaded & ~LEFT_CARTSLOT_MOUNTED;
+ a800_cart_type = a800_check_cart_type(image);
+
+ a800_setup_mappers(image.device().machine(), a800_cart_type);
+
+ if (image.software_entry() == NULL)
+ {
+ size = image.length();
+ // if there is an header, skip it
+ if ((size % 0x1000) == 0x10)
+ {
+ size -= 0x10;
+ start = 0x10;
+ }
+ image.fread(image.device().machine().root_device().memregion("lslot")->base(), size - start);
+ }
+ else
+ {
+ size = image.get_software_region_length("rom");
+ memcpy(image.device().machine().root_device().memregion("lslot")->base(), image.get_software_region("rom"), size);
+ }
+
+ a800_cart_loaded |= (size > 0x0000) ? 1 : 0;
+
+ logerror("%s loaded left cartridge '%s' size %dK\n", image.device().machine().system().name, image.filename(), size/1024);
+ return IMAGE_INIT_PASS;
+}
+
+DEVICE_IMAGE_LOAD( a800_cart_right )
+{
+ UINT32 size, start = 0;
+
+ a800_cart_loaded = a800_cart_loaded & ~RIGHT_CARTSLOT_MOUNTED;
+ a800_cart_type = a800_check_cart_type(image);
+
+ a800_setup_mappers(image.device().machine(), a800_cart_type);
+
+ if (image.software_entry() == NULL)
+ {
+ size = image.length();
+ // if there is an header, skip it
+ if ((size % 0x1000) == 0x10)
+ {
+ size -= 0x10;
+ start = 0x10;
+ }
+ image.fread(image.device().machine().root_device().memregion("rslot")->base(), size - start);
+ }
+ else
+ {
+ size = image.get_software_region_length("rom");
+ memcpy(image.device().machine().root_device().memregion("rslot")->base(), image.get_software_region("rom"), size);
+ }
+
+ a800_cart_loaded |= (size > 0x0000) ? 2 : 0;
+
+ logerror("%s loaded right cartridge '%s' size 8K\n", image.device().machine().system().name, image.filename());
+ return IMAGE_INIT_PASS;
+}
+
+DEVICE_IMAGE_UNLOAD( a800_cart )
+{
+ a800_cart_loaded = a800_cart_loaded & ~LEFT_CARTSLOT_MOUNTED;
+ a800_cart_type = A800_UNKNOWN;
+ a800_setbank(image.device().machine(), a800_cart_loaded);
+}
+
+DEVICE_IMAGE_UNLOAD( a800_cart_right )
+{
+ a800_cart_loaded = a800_cart_loaded & ~RIGHT_CARTSLOT_MOUNTED;
+ a800_cart_type = A800_UNKNOWN;
+ a800_setbank(image.device().machine(), a800_cart_loaded);
+}
+
+
+/*************************************
+ *
+ * Atari 800XL
+ *
+ *************************************/
+
+MACHINE_START( a800xl )
+{
+ atari_machine_start(machine);
+ ms_atari800xl_machine_start(machine, ATARI_800XL, TRUE);
+}
+
+/*************************************
+ *
+ * Atari 5200 console
+ *
+ *************************************/
+
+MACHINE_START( a5200 )
+{
+ atari_machine_start(machine);
+ ms_atari_machine_start(machine, ATARI_800XL, TRUE);
+}
+
+
+DEVICE_IMAGE_LOAD( a5200_cart )
+{
+ UINT8 *mem = image.device().machine().root_device().memregion("maincpu")->base();
+ UINT32 size;
+ bool A13_mirr = FALSE;
+
+ if (image.software_entry() == NULL)
+ {
+ /* load an optional (dual) cartidge */
+ size = image.fread(&mem[0x4000], 0x8000);
+ const char *info = hashfile_extrainfo(image);
+ if (info && !strcmp(info, "A13MIRRORING"))
+ A13_mirr = TRUE;
+ }
+ else
+ {
+ size = image.get_software_region_length("rom");
+ memcpy(mem + 0x4000, image.get_software_region("rom"), size);
+ const char *pcb_name = image.get_feature("cart_type");
+ if (pcb_name && !strcmp(pcb_name, "A13MIRRORING"))
+ A13_mirr = TRUE;
+ }
+
+ if (size<0x8000) memmove(mem+0x4000+0x8000-size, mem+0x4000, size);
+ // mirroring of smaller cartridges
+ if (size <= 0x1000) memcpy(mem+0xa000, mem+0xb000, 0x1000);
+ if (size <= 0x2000) memcpy(mem+0x8000, mem+0xa000, 0x2000);
+ if (size <= 0x4000)
+ {
+ memcpy(&mem[0x4000], &mem[0x8000], 0x4000);
+ if (A13_mirr)
+ {
+ memcpy(&mem[0x8000], &mem[0xa000], 0x2000);
+ memcpy(&mem[0x6000], &mem[0x4000], 0x2000);
+ }
+ }
+ logerror("A5200 loaded cartridge '%s' size %dK\n", image.filename() , size/1024);
+ return IMAGE_INIT_PASS;
+}
+
+DEVICE_IMAGE_UNLOAD( a5200_cart )
+{
+ UINT8 *mem = image.device().machine().root_device().memregion("maincpu")->base();
+ /* zap the cartridge memory (again) */
+ memset(&mem[0x4000], 0x00, 0x8000);
+}
+
+/*************************************
+ *
+ * Atari XEGS
+ *
+ *************************************/
+
+static UINT8 xegs_banks = 0;
+static UINT8 xegs_cart = 0;
+
+static WRITE8_HANDLER( xegs_bankswitch )
+{
+ UINT8 *cart = space->machine().root_device().memregion("user1")->base();
+ data &= xegs_banks - 1;
+ space->machine().root_device().membank("bank0")->set_base(cart + data * 0x2000);
+}
+
+MACHINE_START( xegs )
+{
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ UINT8 *cart = space->machine().root_device().memregion("user1")->base();
+ UINT8 *cpu = space->machine().root_device().memregion("maincpu")->base();
+
+ atari_machine_start(machine);
+ space->install_legacy_write_handler(0xd500, 0xd5ff, FUNC(xegs_bankswitch));
+
+ if (xegs_cart)
+ {
+ machine.root_device().membank("bank0")->set_base(cart);
+ machine.root_device().membank("bank1")->set_base(cart + (xegs_banks - 1) * 0x2000);
+ }
+ else
+ {
+ // point to built-in Missile Command (this does not work well, though... FIXME!!)
+ machine.root_device().membank("bank0")->set_base(cpu + 0x10000);
+ machine.root_device().membank("bank1")->set_base(cpu + 0x10000);
+ }
+}
+
+DEVICE_IMAGE_LOAD( xegs_cart )
+{
+ UINT32 size;
+ UINT8 *ptr = image.device().machine().root_device().memregion("user1")->base();
+
+ if (image.software_entry() == NULL)
+ {
+ // skip the header
+ image.fseek(0x10, SEEK_SET);
+ size = image.length() - 0x10;
+ if (image.fread(ptr, size) != size)
+ return IMAGE_INIT_FAIL;
+ }
+ else
+ {
+ size = image.get_software_region_length("rom");
+ memcpy(ptr, image.get_software_region("rom"), size);
+ }
+
+ xegs_banks = size / 0x2000;
+ xegs_cart = 1;
+
+ return IMAGE_INIT_PASS;
+}
+
+DEVICE_IMAGE_UNLOAD( xegs_cart )
+{
+ xegs_cart = 0;
+ xegs_banks = 0;
+}
diff --git a/src/mess/machine/ataridev.h b/src/mess/machine/ataridev.h
new file mode 100644
index 00000000000..01803329509
--- /dev/null
+++ b/src/mess/machine/ataridev.h
@@ -0,0 +1,55 @@
+/*
+ ataridev.h
+
+*/
+
+#ifndef _ATARIDEV_H
+#define _ATARIDEV_H
+
+#define ATARI_5200 0
+#define ATARI_400 1
+#define ATARI_800 2
+#define ATARI_600XL 3
+#define ATARI_800XL 4
+
+/*----------- defined in machine/ataricrt.c -----------*/
+
+MACHINE_START( a400 );
+MACHINE_START( a800 );
+MACHINE_START( a800xl );
+MACHINE_START( a5200 );
+MACHINE_START( xegs );
+
+DEVICE_IMAGE_LOAD( a800_cart );
+DEVICE_IMAGE_UNLOAD( a800_cart );
+
+DEVICE_IMAGE_LOAD( a800_cart_right );
+DEVICE_IMAGE_UNLOAD( a800_cart_right );
+
+DEVICE_IMAGE_LOAD( a5200_cart );
+DEVICE_IMAGE_UNLOAD( a5200_cart );
+
+DEVICE_IMAGE_LOAD( xegs_cart );
+DEVICE_IMAGE_UNLOAD( xegs_cart );
+
+
+/*----------- defined in machine/atarifdc.c -----------*/
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+DECLARE_LEGACY_DEVICE(ATARI_FDC, atari_fdc);
+
+#define MCFG_ATARI_FDC_ADD(_tag) \
+ MCFG_DEVICE_ADD((_tag), ATARI_FDC, 0)
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+READ8_DEVICE_HANDLER( atari_serin_r );
+WRITE8_DEVICE_HANDLER( atari_serout_w );
+WRITE_LINE_DEVICE_HANDLER( atarifdc_pia_cb2_w );
+
+#endif /* _ATARIDEV_H */
+
diff --git a/src/mess/machine/atarifdc.c b/src/mess/machine/atarifdc.c
new file mode 100644
index 00000000000..2b1ebbde2c3
--- /dev/null
+++ b/src/mess/machine/atarifdc.c
@@ -0,0 +1,844 @@
+/***************************************************************************
+
+ Atari 400/800
+
+ Floppy Disk Controller code
+
+ Juergen Buchmueller, June 1998
+
+***************************************************************************/
+
+#include <ctype.h>
+
+#include "emu.h"
+#include "cpu/m6502/m6502.h"
+#include "includes/atari.h"
+#include "ataridev.h"
+#include "sound/pokey.h"
+#include "machine/6821pia.h"
+#include "imagedev/flopdrv.h"
+#include "formats/atari_dsk.h"
+
+#define VERBOSE_SERIAL 0
+#define VERBOSE_CHKSUM 0
+
+typedef struct _atari_drive atari_drive;
+struct _atari_drive
+{
+ UINT8 *image; /* malloc'd image */
+ int type; /* type of image (XFD, ATR, DSK) */
+ int mode; /* 0 read only, != 0 read/write */
+ int density; /* 0 SD, 1 MD, 2 DD */
+ int header_skip; /* number of bytes in format header */
+ int tracks; /* number of tracks (35,40,77,80) */
+ int heads; /* number of heads (1,2) */
+ int spt; /* sectors per track (18,26) */
+ int seclen; /* sector length (128,256) */
+ int bseclen; /* boot sector length (sectors 1..3) */
+ int sectors; /* total sectors, ie. tracks x heads x spt */
+};
+
+typedef struct _atari_fdc_t atari_fdc_t;
+struct _atari_fdc_t
+{
+ int serout_count;
+ int serout_offs;
+ UINT8 serout_buff[512];
+ UINT8 serout_chksum;
+ int serout_delay;
+
+ int serin_count;
+ int serin_offs;
+ UINT8 serin_buff[512];
+ UINT8 serin_chksum;
+ int serin_delay;
+
+ atari_drive drv[4];
+};
+
+/*************************************
+ *
+ * Disk stuff
+ *
+ *************************************/
+
+#define FORMAT_XFD 0
+#define FORMAT_ATR 1
+#define FORMAT_DSK 2
+
+/*****************************************************************************
+ INLINE FUNCTIONS
+*****************************************************************************/
+INLINE atari_fdc_t *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == ATARI_FDC);
+
+ return (atari_fdc_t *)downcast<legacy_device_base *>(device)->token();
+}
+
+/*****************************************************************************
+ * This is the structure I used in my own Atari 800 emulator some years ago
+ * Though it's a bit overloaded, I used it as it is the maximum of all
+ * supported formats:
+ * XFD no header at all
+ * ATR 16 bytes header
+ * DSK this struct
+ * It is used to determine the format of a XFD image by it's size only
+ *****************************************************************************/
+
+typedef struct _dsk_format dsk_format;
+struct _dsk_format
+{
+ UINT8 density;
+ UINT8 tracks;
+ UINT8 door;
+ UINT8 sta1;
+ UINT8 spt;
+ UINT8 doublesided;
+ UINT8 highdensity;
+ UINT8 seclen_hi;
+ UINT8 seclen_lo;
+ UINT8 status;
+ UINT8 sta2;
+ UINT8 sta3;
+ UINT8 sta4;
+ UINT8 cr;
+ UINT8 info[65+1];
+};
+
+/* combined with the size the image should have */
+typedef struct _xfd_format xfd_format;
+struct _xfd_format
+{
+ int size;
+ dsk_format dsk;
+};
+
+/* here's a table of known xfd formats */
+static const xfd_format xfd_formats[] =
+{
+ {35 * 18 * 1 * 128, {0,35,1,0,18,0,0,0,128,255,0,0,0,13,"35 SS/SD"}},
+ {35 * 26 * 1 * 128, {1,35,1,0,26,0,4,0,128,255,0,0,0,13,"35 SS/MD"}},
+ {(35 * 18 * 1 - 3) * 256 + 3 * 128, {2,35,1,0,18,0,4,1, 0,255,0,0,0,13,"35 SS/DD"}},
+ {40 * 18 * 1 * 128, {0,40,1,0,18,0,0,0,128,255,0,0,0,13,"40 SS/SD"}},
+ {40 * 26 * 1 * 128, {1,40,1,0,26,0,4,0,128,255,0,0,0,13,"40 SS/MD"}},
+ {(40 * 18 * 1 - 3) * 256 + 3 * 128, {2,40,1,0,18,0,4,1, 0,255,0,0,0,13,"40 SS/DD"}},
+ {40 * 18 * 2 * 128, {0,40,1,0,18,1,0,0,128,255,0,0,0,13,"40 DS/SD"}},
+ {40 * 26 * 2 * 128, {1,40,1,0,26,1,4,0,128,255,0,0,0,13,"40 DS/MD"}},
+ {(40 * 18 * 2 - 3) * 256 + 3 * 128, {2,40,1,0,18,1,4,1, 0,255,0,0,0,13,"40 DS/DD"}},
+ {77 * 18 * 1 * 128, {0,77,1,0,18,0,0,0,128,255,0,0,0,13,"77 SS/SD"}},
+ {77 * 26 * 1 * 128, {1,77,1,0,26,0,4,0,128,255,0,0,0,13,"77 SS/MD"}},
+ {(77 * 18 * 1 - 3) * 256 + 3 * 128, {2,77,1,0,18,0,4,1, 0,255,0,0,0,13,"77 SS/DD"}},
+ {77 * 18 * 2 * 128, {0,77,1,0,18,1,0,0,128,255,0,0,0,13,"77 DS/SD"}},
+ {77 * 26 * 2 * 128, {1,77,1,0,26,1,4,0,128,255,0,0,0,13,"77 DS/MD"}},
+ {(77 * 18 * 2 - 3) * 256 + 3 * 128, {2,77,1,0,18,1,4,1, 0,255,0,0,0,13,"77 DS/DD"}},
+ {80 * 18 * 2 * 128, {0,80,1,0,18,1,0,0,128,255,0,0,0,13,"80 DS/SD"}},
+ {80 * 26 * 2 * 128, {1,80,1,0,26,1,4,0,128,255,0,0,0,13,"80 DS/MD"}},
+ {(80 * 18 * 2 - 3) * 256 + 3 * 128, {2,80,1,0,18,1,4,1, 0,255,0,0,0,13,"80 DS/DD"}},
+ {0, {0,}}
+};
+
+/*****************************************************************************
+ *
+ * Open a floppy image for drive 'drive' if it is not yet openend
+ * and a name was given. Determine the image geometry depending on the
+ * type of image and store the results into the global drv[] structure
+ *
+ *****************************************************************************/
+
+#define MAXSIZE 5760 * 256 + 80
+static void atari_load_proc(device_image_interface &image)
+{
+ atari_fdc_t *fdc = get_safe_token(image.device().owner());
+ int id = floppy_get_drive(image);
+ int size, i;
+ const char *ext;
+
+ fdc->drv[id].image = auto_alloc_array(image.device().machine(),UINT8,MAXSIZE);
+ if (!fdc->drv[id].image)
+ return;
+
+ /* tell whether the image is writable */
+ fdc->drv[id].mode = !image.is_readonly();
+ /* set up image if it has been created */
+ if (image.has_been_created())
+ {
+ int sector;
+ char buff[256];
+ memset(buff, 0, sizeof(buff));
+ /* default to 720 sectors */
+ for( sector = 0; sector < 720; sector++ )
+ image.fwrite(buff, 256);
+ image.fseek(0, SEEK_SET);
+ }
+
+ size = image.fread(fdc->drv[id].image, MAXSIZE);
+ if( size <= 0 )
+ {
+ fdc->drv[id].image = NULL;
+ return;
+ }
+ /* re allocate the buffer; we don't want to be too lazy ;) */
+ //fdc->drv[id].image = (UINT8*)image.image_realloc(fdc->drv[id].image, size);
+
+ ext = image.filetype();
+ /* no extension: assume XFD format (no header) */
+ if (!ext)
+ {
+ fdc->drv[id].type = FORMAT_XFD;
+ fdc->drv[id].header_skip = 0;
+ }
+ else
+ /* XFD extension */
+ if( toupper(ext[0])=='X' && toupper(ext[1])=='F' && toupper(ext[2])=='D' )
+ {
+ fdc->drv[id].type = FORMAT_XFD;
+ fdc->drv[id].header_skip = 0;
+ }
+ else
+ /* ATR extension */
+ if( toupper(ext[0])=='A' && toupper(ext[1])=='T' && toupper(ext[2])=='R' )
+ {
+ fdc->drv[id].type = FORMAT_ATR;
+ fdc->drv[id].header_skip = 16;
+ }
+ else
+ /* DSK extension */
+ if( toupper(ext[0])=='D' && toupper(ext[1])=='S' && toupper(ext[2])=='K' )
+ {
+ fdc->drv[id].type = FORMAT_DSK;
+ fdc->drv[id].header_skip = sizeof(dsk_format);
+ }
+ else
+ {
+ fdc->drv[id].type = FORMAT_XFD;
+ fdc->drv[id].header_skip = 0;
+ }
+
+ if( fdc->drv[id].type == FORMAT_ATR &&
+ (fdc->drv[id].image[0] != 0x96 || fdc->drv[id].image[1] != 0x02) )
+ {
+ fdc->drv[id].type = FORMAT_XFD;
+ fdc->drv[id].header_skip = 0;
+ }
+
+ switch (fdc->drv[id].type)
+ {
+ /* XFD or unknown format: find a matching size from the table */
+ case FORMAT_XFD:
+ for( i = 0; xfd_formats[i].size; i++ )
+ {
+ if( size == xfd_formats[i].size )
+ {
+ fdc->drv[id].density = xfd_formats[i].dsk.density;
+ fdc->drv[id].tracks = xfd_formats[i].dsk.tracks;
+ fdc->drv[id].spt = xfd_formats[i].dsk.spt;
+ fdc->drv[id].heads = (xfd_formats[i].dsk.doublesided) ? 2 : 1;
+ fdc->drv[id].bseclen = 128;
+ fdc->drv[id].seclen = 256 * xfd_formats[i].dsk.seclen_hi + xfd_formats[i].dsk.seclen_lo;
+ fdc->drv[id].sectors = fdc->drv[id].tracks * fdc->drv[id].heads * fdc->drv[id].spt;
+ break;
+ }
+ }
+ break;
+ /* ATR format: find a size including the 16 bytes header */
+ case FORMAT_ATR:
+ {
+ int s;
+
+ fdc->drv[id].bseclen = 128;
+ /* get sectors from ATR header */
+ s = (size - 16) / 128;
+ /* 3 + odd number of sectors ? */
+ if ( fdc->drv[id].image[4] == 128 || (s % 18) == 0 || (s % 26) == 0 || ((s - 3) % 1) != 0 )
+ {
+ fdc->drv[id].sectors = s;
+ fdc->drv[id].seclen = 128;
+ /* sector size 128 or count not evenly dividable by 26 ? */
+ if( fdc->drv[id].seclen == 128 || (s % 26) != 0 )
+ {
+ /* yup! single density */
+ fdc->drv[id].density = 0;
+ fdc->drv[id].spt = 18;
+ fdc->drv[id].heads = 1;
+ fdc->drv[id].tracks = s / 18;
+ if( s % 18 != 0 )
+ fdc->drv[id].tracks += 1;
+ if( fdc->drv[id].tracks % 2 == 0 && fdc->drv[id].tracks > 80 )
+ {
+ fdc->drv[id].heads = 2;
+ fdc->drv[id].tracks /= 2;
+ }
+ }
+ else
+ {
+ /* yes: medium density */
+ fdc->drv[id].density = 0;
+ fdc->drv[id].spt = 26;
+ fdc->drv[id].heads = 1;
+ fdc->drv[id].tracks = s / 26;
+ if( s % 26 != 0 )
+ fdc->drv[id].tracks += 1;
+ if( fdc->drv[id].tracks % 2 == 0 && fdc->drv[id].tracks > 80 )
+ {
+ fdc->drv[id].heads = 2;
+ fdc->drv[id].tracks /= 2;
+ }
+ }
+ }
+ else
+ {
+ /* it's double density */
+ s = (s - 3) / 2 + 3;
+ fdc->drv[id].sectors = s;
+ fdc->drv[id].density = 2;
+ fdc->drv[id].seclen = 256;
+ fdc->drv[id].spt = 18;
+ fdc->drv[id].heads = 1;
+ fdc->drv[id].tracks = s / 18;
+ if( s % 18 != 0 )
+ fdc->drv[id].tracks += 1;
+ if( fdc->drv[id].tracks % 2 == 0 && fdc->drv[id].tracks > 80 )
+ {
+ fdc->drv[id].heads = 2;
+ fdc->drv[id].tracks /= 2;
+ }
+ }
+ }
+ break;
+ /* DSK format: it's all in the header */
+ case FORMAT_DSK:
+ {
+ dsk_format *dsk = (dsk_format *) fdc->drv[id].image;
+
+ fdc->drv[id].tracks = dsk->tracks;
+ fdc->drv[id].spt = dsk->spt;
+ fdc->drv[id].heads = (dsk->doublesided) ? 2 : 1;
+ fdc->drv[id].seclen = 256 * dsk->seclen_hi + dsk->seclen_lo;
+ fdc->drv[id].bseclen = fdc->drv[id].seclen;
+ fdc->drv[id].sectors = fdc->drv[id].tracks * fdc->drv[id].heads * fdc->drv[id].spt;
+ }
+ break;
+ }
+ logerror("atari opened floppy '%s', %d sectors (%d %s%s) %d bytes/sector\n",
+ image.filename(),
+ fdc->drv[id].sectors,
+ fdc->drv[id].tracks,
+ (fdc->drv[id].heads == 1) ? "SS" : "DS",
+ (fdc->drv[id].density == 0) ? "SD" : (fdc->drv[id].density == 1) ? "MD" : "DD",
+ fdc->drv[id].seclen);
+ return;
+}
+
+
+
+/*****************************************************************************
+ *
+ * This is a description of the data flow between Atari (A) and the
+ * Floppy (F) for the supported commands.
+ *
+ * A->F DEV CMD AUX1 AUX2 CKS
+ * '1' 'S' 00 00 get status
+ * F->A ACK CPL 04 FF E0 00 CKS
+ * ^ ^
+ * | |
+ * | bit 7 : door closed
+ * |
+ * bit7 : MD 128 bytes/sector, 26 sectors/track
+ * bit5 : DD 256 bytes/sector, 18 sectors/track
+ * else : SD 128 bytes/sector, 18 sectors/track
+ *
+ * A->F DEV CMD AUX1 AUX2 CKS
+ * '1' 'R' SECL SECH read sector
+ * F->A ACK command acknowledge
+ * *** now read the sector
+ * F->A CPL complete: sector read
+ * F->A 128/256 byte CKS
+ *
+ * A->F DEV CMD AUX1 AUX2 CKS
+ * '1' 'W' SECL SECH write with verify
+ * F->A ACK command acknowledge
+ * A->F 128/256 data CKS
+ * F->A CPL complete: CKS okay
+ * execute writing the sector
+ * F->A CPL complete: sector written
+ *
+ * A->F DEV CMD AUX1 AUX2 CKS
+ * '1' 'P' SECL SECH put sector
+ * F->A ACK command acknowledge
+ * A->F 128/256 data CKS
+ * F->A CPL complete: CKS okay
+ * execute writing the sector
+ * F->A CPL complete: sector written
+ *
+ * A->F DEV CMD AUX1 AUX2 CKS
+ * '1' '!' xx xx single density format
+ * F->A ACK command acknowledge
+ * execute formatting
+ * F->A CPL complete: format
+ * F->A 128/256 byte CKS bad sector table
+ *
+ *
+ * A->F DEV CMD AUX1 AUX2 CKS
+ * '1' '"' xx xx double density format
+ * F->A ACK command acknowledge
+ * execute formatting
+ * F->A CPL complete: format
+ * F->A 128/256 byte CKS bad sector table
+ *
+ *****************************************************************************/
+static void make_chksum(UINT8 * chksum, UINT8 data)
+{
+ UINT8 newone;
+ newone= *chksum + data;
+ if (newone < *chksum)
+ newone++;
+
+ if (VERBOSE_CHKSUM)
+ logerror("atari chksum old $%02x + data $%02x -> new $%02x\n", *chksum, data, newone);
+
+ *chksum = newone;
+}
+
+static void clr_serout(device_t *device,int expect_data)
+{
+ atari_fdc_t *fdc = get_safe_token(device);
+
+ fdc->serout_chksum = 0;
+ fdc->serout_offs = 0;
+ fdc->serout_count = expect_data + 1;
+}
+
+static void add_serout(device_t *device,int expect_data)
+{
+ atari_fdc_t *fdc = get_safe_token(device);
+
+ fdc->serout_chksum = 0;
+ fdc->serout_count = expect_data + 1;
+}
+
+static void clr_serin(device_t *device, int ser_delay)
+{
+ atari_fdc_t *fdc = get_safe_token(device);
+ pokey_device *pokey = device->machine().device<pokey_device>("pokey");
+ fdc->serin_chksum = 0;
+ fdc->serin_offs = 0;
+ fdc->serin_count = 0;
+ pokey->serin_ready(ser_delay * 40);
+}
+
+static void add_serin(device_t *device,UINT8 data, int with_checksum)
+{
+ atari_fdc_t *fdc = get_safe_token(device);
+ fdc->serin_buff[fdc->serin_count++] = data;
+ if (with_checksum)
+ make_chksum(&fdc->serin_chksum, data);
+}
+
+static void ATTR_PRINTF(2,3) atari_set_frame_message(device_t *device,const char *fmt, ...)
+{
+ va_list arg;
+ va_start(arg, fmt);
+
+ vsprintf(atari_frame_message, fmt, arg);
+ atari_frame_counter = 30; /* FIXME */
+
+ va_end(arg);
+}
+
+static void a800_serial_command(device_t *device)
+{
+ int i, drive, sector, offset;
+ atari_fdc_t *fdc = get_safe_token(device);
+
+ if( !fdc->serout_offs )
+ {
+ if (VERBOSE_SERIAL)
+ logerror("atari serout command offset = 0\n");
+ return;
+ }
+ clr_serin(device, 10);
+
+ if (VERBOSE_SERIAL)
+ {
+ logerror("atari serout command %d: %02X %02X %02X %02X %02X : %02X ",
+ fdc->serout_offs,
+ fdc->serout_buff[0], fdc->serout_buff[1], fdc->serout_buff[2],
+ fdc->serout_buff[3], fdc->serout_buff[4], fdc->serout_chksum);
+ }
+
+ if (fdc->serout_chksum == 0)
+ {
+ if (VERBOSE_SERIAL)
+ logerror("OK\n");
+
+ drive = fdc->serout_buff[0] - '1'; /* drive # */
+ /* sector # */
+ if (drive < 0 || drive > 3) /* ignore unknown drives */
+ {
+ logerror("atari unsupported drive #%d\n", drive+1);
+ atari_set_frame_message(device, "DRIVE #%d not supported", drive+1);
+ return;
+ }
+
+ /* extract sector number from the command buffer */
+ sector = fdc->serout_buff[2] + 256 * fdc->serout_buff[3];
+
+ switch (fdc->serout_buff[1]) /* command ? */
+ {
+ case 'S': /* status */
+ atari_set_frame_message(device, "DRIVE #%d STATUS", drive+1);
+
+ if (VERBOSE_SERIAL)
+ logerror("atari status\n");
+
+ add_serin(device,'A',0);
+ add_serin(device,'C',0);
+ if (!fdc->drv[drive].mode) /* read only mode ? */
+ {
+ if (fdc->drv[drive].spt == 26)
+ add_serin(device,0x80,1); /* MD: 0x80 */
+ else
+ if (fdc->drv[drive].seclen == 128)
+ add_serin(device,0x00,1); /* SD: 0x00 */
+ else
+ add_serin(device,0x20,1); /* DD: 0x20 */
+ }
+ else
+ {
+ if (fdc->drv[drive].spt == 26)
+ add_serin(device,0x84,1); /* MD: 0x84 */
+ else
+ if (fdc->drv[drive].seclen == 128)
+ add_serin(device,0x04,1); /* SD: 0x04 */
+ else
+ add_serin(device,0x24,1); /* DD: 0x24 */
+ }
+ if (fdc->drv[drive].image)
+ add_serin(device,0xff,1); /* door closed: 0xff */
+ else
+ add_serin(device,0x7f,1); /* door open: 0x7f */
+ add_serin(device,0xe0,1); /* dunno */
+ add_serin(device,0x00,1); /* dunno */
+ add_serin(device,fdc->serin_chksum,0);
+ break;
+
+ case 'R': /* read sector */
+ if (VERBOSE_SERIAL)
+ logerror("atari read sector #%d\n", sector);
+
+ if( sector < 1 || sector > fdc->drv[drive].sectors )
+ {
+ atari_set_frame_message(device, "DRIVE #%d READ SECTOR #%3d - ERR", drive+1, sector);
+
+ if (VERBOSE_SERIAL)
+ logerror("atari bad sector #\n");
+
+ add_serin(device,'E',0);
+ break;
+ }
+ add_serin(device,'A',0); /* acknowledge */
+ add_serin(device,'C',0); /* completed */
+ if (sector < 4) /* sector 1 .. 3 might be different length */
+ {
+ atari_set_frame_message(device, "DRIVE #%d READ SECTOR #%3d - SD", drive+1, sector);
+ offset = (sector - 1) * fdc->drv[drive].bseclen + fdc->drv[drive].header_skip;
+ for (i = 0; i < 128; i++)
+ add_serin(device,fdc->drv[drive].image[offset++],1);
+ }
+ else
+ {
+ atari_set_frame_message(device, "DRIVE #%d READ SECTOR #%3d - %cD", drive+1, sector, (fdc->drv[drive].seclen == 128) ? 'S' : 'D');
+ offset = (sector - 1) * fdc->drv[drive].seclen + fdc->drv[drive].header_skip;
+ for (i = 0; i < fdc->drv[drive].seclen; i++)
+ add_serin(device,fdc->drv[drive].image[offset++],1);
+ }
+ add_serin(device,fdc->serin_chksum,0);
+ break;
+
+ case 'W': /* write sector with verify */
+ if (VERBOSE_SERIAL)
+ logerror("atari write sector #%d\n", sector);
+
+ add_serin(device,'A',0);
+ if (sector < 4) /* sector 1 .. 3 might be different length */
+ {
+ add_serout(device,fdc->drv[drive].bseclen);
+ atari_set_frame_message(device, "DRIVE #%d WRITE SECTOR #%3d - SD", drive+1, sector);
+ }
+ else
+ {
+ add_serout(device,fdc->drv[drive].seclen);
+ atari_set_frame_message(device, "DRIVE #%d WRITE SECTOR #%3d - %cD", drive+1, sector, (fdc->drv[drive].seclen == 128) ? 'S' : 'D');
+ }
+ break;
+
+ case 'P': /* put sector (no verify) */
+ if (VERBOSE_SERIAL)
+ logerror("atari put sector #%d\n", sector);
+
+ add_serin(device,'A',0);
+ if (sector < 4) /* sector 1 .. 3 might be different length */
+ {
+ add_serout(device,fdc->drv[drive].bseclen);
+ atari_set_frame_message(device, "DRIVE #%d PUT SECTOR #%3d - SD", drive+1, sector);
+ }
+ else
+ {
+ add_serout(device,fdc->drv[drive].seclen);
+ atari_set_frame_message(device, "DRIVE #%d PUT SECTOR #%3d - %cD", drive+1, sector, (fdc->drv[drive].seclen == 128) ? 'S' : 'D');
+ }
+ break;
+
+ case '!': /* SD format */
+ if (VERBOSE_SERIAL)
+ logerror("atari format SD drive #%d\n", drive+1);
+
+ atari_set_frame_message(device, "DRIVE #%d FORMAT SD", drive+1);
+ add_serin(device,'A',0); /* acknowledge */
+ add_serin(device,'C',0); /* completed */
+ for (i = 0; i < 128; i++)
+ add_serin(device,0,1);
+ add_serin(device,fdc->serin_chksum,0);
+ break;
+
+ case '"': /* DD format */
+ if (VERBOSE_SERIAL)
+ logerror("atari format DD drive #%d\n", drive+1);
+
+ atari_set_frame_message(device, "DRIVE #%d FORMAT DD", drive+1);
+ add_serin(device,'A',0); /* acknowledge */
+ add_serin(device,'C',0); /* completed */
+ for (i = 0; i < 256; i++)
+ add_serin(device,0,1);
+ add_serin(device,fdc->serin_chksum,0);
+ break;
+
+ default:
+ if (VERBOSE_SERIAL)
+ logerror("atari unknown command #%c\n", fdc->serout_buff[1]);
+
+ atari_set_frame_message(device, "DRIVE #%d UNKNOWN CMD '%c'", drive+1, fdc->serout_buff[1]);
+ add_serin(device,'N',0); /* negative acknowledge */
+ }
+ }
+ else
+ {
+ atari_set_frame_message(device, "serial cmd chksum error");
+ if (VERBOSE_SERIAL)
+ logerror("BAD\n");
+
+ add_serin(device,'E',0);
+ }
+ if (VERBOSE_SERIAL)
+ logerror("atari %d bytes to read\n", fdc->serin_count);
+}
+
+static void a800_serial_write(device_t *device)
+{
+ int i, drive, sector, offset;
+ atari_fdc_t *fdc = get_safe_token(device);
+
+ if (VERBOSE_SERIAL)
+ {
+ logerror("atari serout %d bytes written : %02X ",
+ fdc->serout_offs, fdc->serout_chksum);
+ }
+
+ clr_serin(device, 80);
+ if (fdc->serout_chksum == 0)
+ {
+ if (VERBOSE_SERIAL)
+ logerror("OK\n");
+
+ add_serin(device,'C',0);
+ /* write the sector */
+ drive = fdc->serout_buff[0] - '1'; /* drive # */
+ /* not write protected and image available ? */
+ if (fdc->drv[drive].mode && fdc->drv[drive].image)
+ {
+ /* extract sector number from the command buffer */
+ sector = fdc->serout_buff[2] + 256 * fdc->serout_buff[3];
+ if (sector < 4) /* sector 1 .. 3 might be different length */
+ {
+ offset = (sector - 1) * fdc->drv[drive].bseclen + fdc->drv[drive].header_skip;
+
+ if (VERBOSE_SERIAL)
+ logerror("atari storing 128 byte sector %d at offset 0x%08X", sector, offset );
+
+ for (i = 0; i < 128; i++)
+ fdc->drv[drive].image[offset++] = fdc->serout_buff[5+i];
+ atari_set_frame_message(device, "DRIVE #%d WROTE SECTOR #%3d - SD", drive+1, sector);
+ }
+ else
+ {
+ offset = (sector - 1) * fdc->drv[drive].seclen + fdc->drv[drive].header_skip;
+
+ if (VERBOSE_SERIAL)
+ logerror("atari storing %d byte sector %d at offset 0x%08X", fdc->drv[drive].seclen, sector, offset );
+
+ for (i = 0; i < fdc->drv[drive].seclen; i++)
+ fdc->drv[drive].image[offset++] = fdc->serout_buff[5+i];
+ atari_set_frame_message(device, "DRIVE #%d WROTE SECTOR #%3d - %cD", drive+1, sector, (fdc->drv[drive].seclen == 128) ? 'S' : 'D');
+ }
+ add_serin(device,'C',0);
+ }
+ else
+ {
+ add_serin(device,'E',0);
+ }
+ }
+ else
+ {
+ if (VERBOSE_SERIAL)
+ logerror("BAD\n");
+
+ add_serin(device,'E',0);
+ }
+}
+
+READ8_DEVICE_HANDLER ( atari_serin_r )
+{
+ int data = 0x00;
+ int ser_delay = 0;
+ atari_fdc_t *fdc = get_safe_token(device);
+
+ if (fdc->serin_count)
+ {
+ pokey_device *pokey = device->machine().device<pokey_device>("pokey");
+
+ data = fdc->serin_buff[fdc->serin_offs];
+ ser_delay = 2 * 40;
+ if (fdc->serin_offs < 3)
+ {
+ ser_delay = 4 * 40;
+ if (fdc->serin_offs < 2)
+ ser_delay = 200 * 40;
+ }
+ fdc->serin_offs++;
+ if (--fdc->serin_count == 0)
+ fdc->serin_offs = 0;
+ else
+ pokey->serin_ready(ser_delay);
+ }
+
+ if (VERBOSE_SERIAL)
+ logerror("atari serin[$%04x] -> $%02x; delay %d\n", fdc->serin_offs, data, ser_delay);
+
+ return data;
+}
+
+WRITE8_DEVICE_HANDLER ( atari_serout_w )
+{
+ pia6821_device *pia = device->machine().device<pia6821_device>( "pia" );
+ atari_fdc_t *fdc = get_safe_token(device);
+
+ /* ignore serial commands if no floppy image is specified */
+ if( !fdc->drv[0].image )
+ return;
+ if (fdc->serout_count)
+ {
+ /* store data */
+ fdc->serout_buff[fdc->serout_offs] = data;
+
+ if (VERBOSE_SERIAL)
+ logerror("atari serout[$%04x] <- $%02x; count %d\n", fdc->serout_offs, data, fdc->serout_count);
+
+ fdc->serout_offs++;
+ if (--fdc->serout_count == 0)
+ {
+ /* exclusive or written checksum with calculated */
+ fdc->serout_chksum ^= data;
+ /* if the attention line is high, this should be data */
+ if (pia->irq_b_state())
+ a800_serial_write(device);
+ }
+ else
+ {
+ make_chksum(&fdc->serout_chksum, data);
+ }
+ }
+}
+
+WRITE_LINE_DEVICE_HANDLER(atarifdc_pia_cb2_w)
+{
+ atari_fdc_t *fdc = get_safe_token(device);
+ if (!state)
+ {
+ clr_serout(device,4); /* expect 4 command bytes + checksum */
+ }
+ else
+ {
+ fdc->serin_delay = 0;
+ a800_serial_command(device);
+ }
+}
+
+static const floppy_interface atari_floppy_interface =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ FLOPPY_STANDARD_5_25_DSHD,
+ LEGACY_FLOPPY_OPTIONS_NAME(atari_only),
+ NULL,
+ NULL
+};
+
+static MACHINE_CONFIG_FRAGMENT( atari_fdc )
+ MCFG_LEGACY_FLOPPY_4_DRIVES_ADD(atari_floppy_interface)
+MACHINE_CONFIG_END
+
+device_t *atari_floppy_get_device_child(device_t *device,int drive)
+{
+ switch(drive) {
+ case 0 : return device->subdevice(FLOPPY_0);
+ case 1 : return device->subdevice(FLOPPY_1);
+ case 2 : return device->subdevice(FLOPPY_2);
+ case 3 : return device->subdevice(FLOPPY_3);
+ }
+ return NULL;
+}
+
+static DEVICE_START(atari_fdc)
+{
+ int id;
+ for(id=0;id<4;id++)
+ {
+ floppy_install_load_proc(atari_floppy_get_device_child(device, id), atari_load_proc);
+ }
+}
+
+static DEVICE_RESET(atari_fdc)
+{
+}
+
+DEVICE_GET_INFO( atari_fdc )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(atari_fdc_t); break;
+
+ /* --- the following bits of info are returned as pointers --- */
+ case DEVINFO_PTR_MACHINE_CONFIG: info->machine_config = MACHINE_CONFIG_NAME(atari_fdc); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(atari_fdc); break;
+ case DEVINFO_FCT_STOP: /* Nothing */ break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(atari_fdc); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "Atari FDC"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "Atari FDC"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright the MESS Team"); break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(ATARI_FDC, atari_fdc);
diff --git a/src/mess/machine/avr8.h b/src/mess/machine/avr8.h
new file mode 100644
index 00000000000..daf7f94b04d
--- /dev/null
+++ b/src/mess/machine/avr8.h
@@ -0,0 +1,297 @@
+#ifndef __EMU_MACHINE_AVR8_H__
+#define __EMU_MACHINE_AVR8_H__
+
+// Helpful enums and defines for the Atmel 8-bit AVR series of microcontrollers
+
+namespace Avr8
+{
+
+enum
+{
+ REGIDX_R0 = 0,
+ REGIDX_R1,
+ REGIDX_R2,
+ REGIDX_R3,
+ REGIDX_R4,
+ REGIDX_R5,
+ REGIDX_R6,
+ REGIDX_R7,
+ REGIDX_R8,
+ REGIDX_R9,
+ REGIDX_R10,
+ REGIDX_R11,
+ REGIDX_R12,
+ REGIDX_R13,
+ REGIDX_R14,
+ REGIDX_R15,
+ REGIDX_R16,
+ REGIDX_R17,
+ REGIDX_R18,
+ REGIDX_R19,
+ REGIDX_R20,
+ REGIDX_R21,
+ REGIDX_R22,
+ REGIDX_R23,
+ REGIDX_R24,
+ REGIDX_R25,
+ REGIDX_R26,
+ REGIDX_R27,
+ REGIDX_R28,
+ REGIDX_R29,
+ REGIDX_R30,
+ REGIDX_R31,
+
+ REGIDX_PINB = 0x23,
+ REGIDX_DDRB,
+ REGIDX_PORTB,
+ REGIDX_PINC,
+ REGIDX_DDRC,
+ REGIDX_PORTC,
+ REGIDX_PIND,
+ REGIDX_DDRD,
+ REGIDX_PORTD,
+
+ REGIDX_TIFR0 = 0x35,
+ REGIDX_TIFR1,
+ REGIDX_TIFR2,
+
+ REGIDX_PCIFR = 0x3b,
+ REGIDX_EIFR,
+ REGIDX_EIMSK,
+ REGIDX_GPIOR0,
+ REGIDX_EECR,
+ REGIDX_EEDR,
+ REGIDX_EEARL,
+ REGIDX_EEARH,
+ REGIDX_GTCCR,
+ REGIDX_TCCR0A,
+ REGIDX_TCCR0B,
+ REGIDX_TCNT0,
+ REGIDX_OCR0A,
+ REGIDX_OCR0B,
+
+ REGIDX_GPIOR1 = 0x4a,
+ REGIDX_GPIOR2,
+ REGIDX_SPCR,
+ REGIDX_SPSR,
+ REGIDX_SPDR,
+
+ REGIDX_ACSR = 0x50,
+
+ REGIDX_SMCR = 0x53,
+ REGIDX_MCUSR,
+ REGIDX_MCUCR,
+
+ REGIDX_SPMCSR = 0x57,
+
+ REGIDX_SPL = 0x5d,
+ REGIDX_SPH,
+ REGIDX_SREG,
+ REGIDX_WDTCSR,
+ REGIDX_CLKPR,
+
+ REGIDX_PRR = 0x64,
+
+ REGIDX_OSCCAL = 0x66,
+
+ REGIDX_PCICR = 0x68,
+ REGIDX_EICRA,
+
+ REGIDX_PCMSK0 = 0x6B,
+ REGIDX_PCMSK1,
+ REGIDX_PCMSK2,
+ REGIDX_TIMSK0,
+ REGIDX_TIMSK1,
+ REGIDX_TIMSK2,
+
+ REGIDX_ADCL = 0x78,
+ REGIDX_ADCH,
+ REGIDX_ADCSRA,
+ REGIDX_ADCSRB,
+ REGIDX_ADMUX,
+
+ REGIDX_DIDR0 = 0x7e,
+ REGIDX_DIDR1,
+ REGIDX_TCCR1A,
+ REGIDX_TCCR1B,
+ REGIDX_TCCR1C,
+
+ REGIDX_TCNT1L = 0x84,
+ REGIDX_TCNT1H,
+ REGIDX_ICR1L,
+ REGIDX_ICR1H,
+ REGIDX_OCR1AL,
+ REGIDX_OCR1AH,
+ REGIDX_OCR1BL,
+ REGIDX_OCR1BH,
+
+ REGIDX_TCCR2A = 0xb0,
+ REGIDX_TCCR2B,
+ REGIDX_TCNT2,
+ REGIDX_OCR2A,
+ REGIDX_OCR2B,
+
+ REGIDX_ASSR = 0xb6,
+
+ REGIDX_TWBR = 0xb8,
+ REGIDX_TWSR,
+ REGIDX_TWAR,
+ REGIDX_TWDR,
+ REGIDX_TWCR,
+ REGIDX_TWAMR,
+
+ REGIDX_UCSR0A = 0xc0,
+ REGIDX_UCSR0B,
+ REGIDX_UCSR0C,
+
+ REGIDX_UBRR0L = 0xc4,
+ REGIDX_UBRR0H,
+ REGIDX_UDR0
+};
+
+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
+{
+ WGM2_NORMAL = 0,
+ WGM2_PWM_PC,
+ WGM2_CTC_CMP,
+ WGM2_FAST_PWM,
+ WGM2_RESERVED0,
+ WGM2_PWM_PC_CMP,
+ WGM2_RESERVED1,
+ WGM2_FAST_PWM_CMP
+};
+
+} // namespace AVR8
+
+#define AVR8_OCR1BH (state->m_regs[Avr8::REGIDX_OCR1BH])
+#define AVR8_OCR1BL (state->m_regs[Avr8::REGIDX_OCR1BL])
+#define AVR8_OCR1AH (state->m_regs[Avr8::REGIDX_OCR1AH])
+#define AVR8_OCR1AL (state->m_regs[Avr8::REGIDX_OCR1AL])
+#define AVR8_ICR1H (state->m_regs[Avr8::REGIDX_ICR1H])
+#define AVR8_ICR1L (state->m_regs[Avr8::REGIDX_ICR1L])
+#define AVR8_TCNT1H (state->m_regs[Avr8::REGIDX_TCNT1H])
+#define AVR8_TCNT1L (state->m_regs[Avr8::REGIDX_TCNT1L])
+
+#define AVR8_TCCR1B (state->m_regs[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 0x03
+#define AVR8_TCCR1B_CS_SHIFT 0
+
+#define AVR8_TCCR1A (state->m_regs[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_COM1A_MASK) >> AVR8_TCCR1A_COM1A_SHIFT)
+#define AVR8_TCCR1A_WGM1_10 (AVR8_TCCR1A & AVR8_TCCR1A_WGM1_10_MASK)
+
+#define AVR8_TIMSK1 (state->m_regs[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_TCCR2B (state->m_regs[Avr8::REGIDX_TCCR1B])
+#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 0x03
+#define AVR8_TCCR2B_CS_SHIFT 0
+#define AVR8_TIMER2_CLOCK_SELECT ((AVR8_TCCR2B & AVR8_TCCR2B_CS_MASK) >> AVR8_TCCR2B_CS_SHIFT)
+
+#define AVR8_TCCR2A (state->m_regs[Avr8::REGIDX_TCCR1A])
+#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_COM2A_MASK) >> AVR8_TCCR2A_COM2A_SHIFT)
+#define AVR8_TCCR2A_WGM2_10 (AVR8_TCCR2A & AVR8_TCCR1A_WGM2_10_MASK)
+
+#define AVR8_SPSR (state->m_regs[Avr8::REGIDX_SPSR])
+#define AVR8_SPSR_SPIF_MASK 0x80
+#define AVR8_SPSR_SPIF_SHIFT 7
+#define AVR8_SPSR_SPR2X_MASK 0x01
+#define AVR8_SPSR_SPR2X (AVR8_SPSR & AVR8_SPSR_SPR2X_MASK)
+
+#define AVR8_SPCR (state->m_regs[Avr8::REGIDX_SPCR])
+#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
+#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_TIFR1 (state->m_regs[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_DDRD (state->m_regs[Avr8::REGIDX_DDRD])
+#define AVR8_DDRC (state->m_regs[Avr8::REGIDX_DDRC])
+#define AVR8_PORTB (state->m_regs[Avr8::REGIDX_PORTB])
+#define AVR8_DDRB (state->m_regs[Avr8::REGIDX_DDRB])
+
+#define AVR8_OCR1A ((AVR8_OCR1AH << 8) | AVR8_OCR1AL)
+#define AVR8_OCR1B ((AVR8_OCR1BH << 8) | AVR8_OCR1BL)
+#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_OCR2B state->m_regs[Avr8::REGIDX_OCR2B]
+#define AVR8_OCR2A state->m_regs[Avr8::REGIDX_OCR2A]
+#define AVR8_TCNT2 state->m_regs[Avr8::REGIDX_TCNT2]
+#define AVR8_WGM2 (((AVR8_TCCR2B & 0x08) >> 1) | (AVR8_TCCR2A & 0x03))
+
+#endif // __EMU_MACHINE_AVR8_H__
diff --git a/src/mess/machine/ay31015.c b/src/mess/machine/ay31015.c
new file mode 100644
index 00000000000..44afe230a3b
--- /dev/null
+++ b/src/mess/machine/ay31015.c
@@ -0,0 +1,746 @@
+/****************************************************************************
+
+ 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"
+
+typedef enum
+{
+ IDLE,
+ START_BIT,
+ PROCESSING,
+ PARITY_BIT,
+ FIRST_STOP_BIT,
+ SECOND_STOP_BIT,
+ PREP_TIME
+} state_t;
+
+
+typedef struct _ay31015_t ay31015_t;
+struct _ay31015_t
+{
+ const ay31015_config *config;
+
+ int pins[41];
+
+ UINT8 control_reg;
+ UINT8 status_reg;
+ UINT16 second_stop_bit; // 0, 8, 16
+ UINT16 total_pulses; // bits * 16
+ UINT8 internal_sample;
+
+ state_t rx_state;
+ UINT8 rx_data; // byte being received
+ UINT8 rx_buffer; // received byte waiting to be accepted by computer
+ UINT8 rx_bit_count;
+ UINT8 rx_parity;
+ UINT16 rx_pulses; // total pulses left
+ double rx_clock;
+ emu_timer *rx_timer;
+
+ state_t tx_state;
+ UINT8 tx_data; // byte being sent
+ UINT8 tx_buffer; // next byte to send
+ UINT8 tx_parity;
+ UINT16 tx_pulses; // total pulses left
+ double tx_clock;
+ emu_timer *tx_timer;
+};
+
+
+/* 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
+
+
+/*-------------------------------------------------
+ get_safe_token - safely gets the data
+-------------------------------------------------*/
+
+INLINE ay31015_t *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == AY31015);
+ return (ay31015_t *) downcast<legacy_device_base *>(device)->token();
+}
+
+
+INLINE UINT8 ay31015_get_si( device_t *device )
+{
+ ay31015_t *ay31015 = get_safe_token( device );
+
+ if ( ay31015->config->read_si )
+ ay31015->pins[AY31015_SI] = (ay31015->config->read_si)( device, 0 ) ? 1 : 0;
+
+ return ay31015->pins[AY31015_SI];
+}
+
+
+INLINE void ay31015_set_so( device_t *device, int data )
+{
+ ay31015_t *ay31015 = get_safe_token( device );
+
+ ay31015->pins[AY31015_SO] = data ? 1 : 0;
+
+ if ( ay31015->config->write_so )
+ (ay31015->config->write_so)( device, 0, ay31015->pins[AY31015_SO] );
+}
+
+
+INLINE int ay31015_update_status_pin( ay31015_t *ay31015, UINT8 reg_bit, ay31015_output_pin_t pin )
+{
+ int new_value = ( ay31015->status_reg & reg_bit ) ? 1 : 0;
+
+ if ( new_value == ay31015->pins[pin] )
+ return 0;
+
+ ay31015->pins[pin] = new_value;
+ return 1;
+}
+
+
+/*-------------------------------------------------
+ ay31015_update_status_pins - Update the status pins
+-------------------------------------------------*/
+static void ay31015_update_status_pins( device_t *device )
+{
+ ay31015_t *ay31015 = get_safe_token( device );
+ int status_pins_changed = 0;
+
+ /* Should status pins be updated? */
+ if ( ! ay31015->pins[AY31015_SWE] )
+ {
+ status_pins_changed += ay31015_update_status_pin( ay31015, STATUS_PE, AY31015_PE );
+ status_pins_changed += ay31015_update_status_pin( ay31015, STATUS_FE, AY31015_FE );
+ status_pins_changed += ay31015_update_status_pin( ay31015, STATUS_OR, AY31015_OR );
+ status_pins_changed += ay31015_update_status_pin( ay31015, STATUS_DAV, AY31015_DAV );
+ status_pins_changed += ay31015_update_status_pin( ay31015, STATUS_TBMT, AY31015_TBMT );
+ }
+ status_pins_changed += ay31015_update_status_pin( ay31015, STATUS_EOC, AY31015_EOC );
+
+ if ( status_pins_changed && ay31015->config->status_changed )
+ {
+ (ay31015->config->status_changed)( device, 0, status_pins_changed );
+ }
+}
+
+
+/*************************************************** RECEIVE CONTROLS *************************************************/
+
+
+/*-------------------------------------------------
+ ay31015_rx_process - convert serial to parallel
+-------------------------------------------------*/
+static TIMER_CALLBACK( ay31015_rx_process )
+{
+ device_t *device = (device_t *)ptr;
+ ay31015_t *ay31015 = get_safe_token( device );
+
+ switch (ay31015->rx_state)
+ {
+ case PREP_TIME: // assist sync by ensuring high bit occurs
+ ay31015->rx_pulses--;
+ if (ay31015_get_si( device ))
+ ay31015->rx_state = IDLE;
+ return;
+
+ case IDLE:
+ ay31015->rx_pulses--;
+ if (!ay31015_get_si( device ))
+ {
+ ay31015->rx_state = START_BIT;
+ ay31015->rx_pulses = 16;
+ }
+ return;
+
+ case START_BIT:
+ ay31015->rx_pulses--;
+ if (ay31015->rx_pulses == 8) // start bit must be low at sample time
+ {
+ if ( ay31015_get_si( device ) )
+ ay31015->rx_state = IDLE;
+ }
+ else
+ if (!ay31015->rx_pulses) // end of start bit
+ {
+ ay31015->rx_state = PROCESSING;
+ ay31015->rx_pulses = ay31015->total_pulses;
+ ay31015->rx_bit_count = 0;
+ ay31015->rx_parity = 0;
+ ay31015->rx_data = 0;
+ }
+ return;
+
+ case PROCESSING:
+ ay31015->rx_pulses--;
+ if (!ay31015->rx_pulses) // end of a byte
+ {
+ ay31015->rx_pulses = 16;
+ if (ay31015->control_reg & CONTROL_NP) // see if we need to get a parity bit
+ ay31015->rx_state = FIRST_STOP_BIT;
+ else
+ ay31015->rx_state = PARITY_BIT;
+ }
+ else
+ if (!(ay31015->rx_pulses & 15)) // end of a bit
+ ay31015->rx_bit_count++;
+ else
+ if ((ay31015->rx_pulses & 15) == 8) // sample input stream
+ {
+ ay31015->internal_sample = ay31015_get_si( device );
+ ay31015->rx_parity ^= ay31015->internal_sample; // calculate cumulative parity
+ ay31015->rx_data |= ay31015->internal_sample << ay31015->rx_bit_count;
+ }
+ return;
+
+ case PARITY_BIT:
+ ay31015->rx_pulses--;
+
+ if (ay31015->rx_pulses == 8) // sample input stream
+ {
+ ay31015->rx_parity ^= ay31015_get_si( device ); // calculate cumulative parity
+ }
+ else
+ if (!ay31015->rx_pulses) // end of a byte
+ {
+ ay31015->rx_pulses = 16;
+ ay31015->rx_state = FIRST_STOP_BIT;
+
+ if ((!(ay31015->control_reg & CONTROL_EPS)) && (ay31015->rx_parity))
+ ay31015->rx_parity = 0; // odd parity, ok
+ else
+ if ((ay31015->control_reg & CONTROL_EPS) && (!ay31015->rx_parity))
+ ay31015->rx_parity = 0; // even parity, ok
+ else
+ ay31015->rx_parity = 1; // parity error
+ }
+ return;
+
+ case FIRST_STOP_BIT:
+ ay31015->rx_pulses--;
+ if (ay31015->rx_pulses == 8) // sample input stream
+ ay31015->internal_sample = ay31015_get_si( device );
+ else
+ if (ay31015->rx_pulses == 7) // set error flags
+ {
+ if (!ay31015->internal_sample)
+ {
+ ay31015->status_reg |= STATUS_FE; // framing error - the stop bit not high
+ ay31015->rx_state = PREP_TIME; // lost sync - start over
+ // return;
+ }
+ else
+ ay31015->status_reg &= ~STATUS_FE;
+
+ if ((ay31015->rx_parity) && (!(ay31015->control_reg & CONTROL_NP)))
+ ay31015->status_reg |= STATUS_PE; // parity error
+ else
+ ay31015->status_reg &= ~STATUS_PE;
+
+ if (ay31015->status_reg & STATUS_DAV)
+ ay31015->status_reg |= STATUS_OR; // overrun error - previous byte still in buffer
+ else
+ ay31015->status_reg &= ~STATUS_OR;
+
+ ay31015->rx_buffer = ay31015->rx_data; // bring received byte out for computer to read
+
+ ay31015_update_status_pins( device );
+ }
+ else
+ if (ay31015->rx_pulses == 6)
+ {
+ ay31015->status_reg |= STATUS_DAV; // tell computer that new byte is ready
+ ay31015_update_status_pins( device );
+ }
+ else
+ if (ay31015->rx_pulses == 4)
+ {
+ if (ay31015->second_stop_bit)
+ {
+ /* We should wait for the full first stop bit and
+ the beginning of the second stop bit */
+ ay31015->rx_state = SECOND_STOP_BIT;
+ ay31015->rx_pulses += ay31015->second_stop_bit - 7;
+ }
+ else
+ {
+ /* We have seen a STOP bit, go back to PREP_TIME */
+ ay31015->rx_state = PREP_TIME;
+ }
+ }
+ return;
+
+ case SECOND_STOP_BIT:
+ ay31015->rx_pulses--;
+ if (!ay31015->rx_pulses)
+ ay31015->rx_state = PREP_TIME;
+ return;
+
+ }
+}
+
+
+/*************************************************** TRANSMIT CONTROLS *************************************************/
+
+
+/*-------------------------------------------------
+ ay31015_tx_process - convert parallel to serial
+-------------------------------------------------*/
+static TIMER_CALLBACK( ay31015_tx_process )
+{
+ device_t *device = (device_t *)ptr;
+ ay31015_t *ay31015 = get_safe_token( device );
+
+ UINT8 t1;
+ switch (ay31015->tx_state)
+ {
+ case IDLE:
+ if (!(ay31015->status_reg & STATUS_TBMT))
+ {
+ ay31015->tx_state = PREP_TIME; // When idle, see if a byte has been sent to us
+ ay31015->tx_pulses = 1;
+ }
+ return;
+
+ case PREP_TIME: // This phase lets the transmitter regain sync after an idle period
+ ay31015->tx_pulses--;
+ if (!ay31015->tx_pulses)
+ {
+ ay31015->tx_state = START_BIT;
+ ay31015->tx_pulses = 16;
+ }
+ return;
+
+ case START_BIT:
+ if (ay31015->tx_pulses == 16) // beginning of start bit
+ {
+ ay31015->tx_data = ay31015->tx_buffer; // load the shift register
+ ay31015->status_reg |= STATUS_TBMT; // tell computer that another byte can be sent to uart
+ ay31015_set_so( device, 0 ); /* start bit begins now (we are "spacing") */
+ ay31015->status_reg &= ~STATUS_EOC; // we are no longer idle
+ ay31015->tx_parity = 0;
+ ay31015_update_status_pins( device );
+ }
+
+ ay31015->tx_pulses--;
+ if (!ay31015->tx_pulses) // end of start bit
+ {
+ ay31015->tx_state = PROCESSING;
+ ay31015->tx_pulses = ay31015->total_pulses;
+ }
+ return;
+
+ case PROCESSING:
+ if (!(ay31015->tx_pulses & 15)) // beginning of a data bit
+ {
+ if (ay31015->tx_data & 1)
+ {
+ ay31015_set_so( device, 1 );
+ ay31015->tx_parity++; // calculate cumulative parity
+ }
+ else
+ ay31015_set_so( device, 0 );
+
+ ay31015->tx_data >>= 1; // adjust the shift register
+ }
+
+ ay31015->tx_pulses--;
+ if (!ay31015->tx_pulses) // all data bits sent
+ {
+ ay31015->tx_pulses = 16;
+ if (ay31015->control_reg & CONTROL_NP) // see if we need to make a parity bit
+ ay31015->tx_state = FIRST_STOP_BIT;
+ else
+ ay31015->tx_state = PARITY_BIT;
+ }
+
+ return;
+
+ case PARITY_BIT:
+ if (ay31015->tx_pulses == 16)
+ {
+ t1 = (ay31015->control_reg & CONTROL_EPS) ? 0 : 1;
+ t1 ^= (ay31015->tx_parity & 1);
+ if (t1)
+ ay31015_set_so( device, 1 ); /* extra bit to set the correct parity */
+ else
+ ay31015_set_so( device, 0 ); /* it was already correct */
+ }
+
+ ay31015->tx_pulses--;
+ if (!ay31015->tx_pulses)
+ {
+ ay31015->tx_state = FIRST_STOP_BIT;
+ ay31015->tx_pulses = 16;
+ }
+ return;
+
+ case FIRST_STOP_BIT:
+ if (ay31015->tx_pulses == 16)
+ ay31015_set_so( device, 1 ); /* create a stop bit (marking and soon idle) */
+ ay31015->tx_pulses--;
+ if (!ay31015->tx_pulses)
+ {
+ ay31015->status_reg |= STATUS_EOC; // character is completely sent
+ if (ay31015->second_stop_bit)
+ {
+ ay31015->tx_state = SECOND_STOP_BIT;
+ ay31015->tx_pulses = ay31015->second_stop_bit;
+ }
+ else
+ if (ay31015->status_reg & STATUS_TBMT)
+ ay31015->tx_state = IDLE; // if nothing to send, go idle
+ else
+ {
+ ay31015->tx_pulses = 16;
+ ay31015->tx_state = START_BIT; // otherwise immediately start next byte
+ }
+ ay31015_update_status_pins( device );
+ }
+ return;
+
+ case SECOND_STOP_BIT:
+ ay31015->tx_pulses--;
+ if (!ay31015->tx_pulses)
+ {
+ if (ay31015->status_reg & STATUS_TBMT)
+ ay31015->tx_state = IDLE; // if nothing to send, go idle
+ else
+ {
+ ay31015->tx_pulses = 16;
+ ay31015->tx_state = START_BIT; // otherwise immediately start next byte
+ }
+ }
+ return;
+
+ }
+}
+
+
+/*-------------------------------------------------
+ ay31015_reset - reset internal state
+-------------------------------------------------*/
+static void ay31015_reset( device_t *device )
+{
+ ay31015_t *ay31015 = get_safe_token( device );
+
+ /* total pulses = 16 * data-bits */
+ UINT8 t1;
+
+ if ( ay31015->control_reg & CONTROL_NB2 )
+ t1 = ( ay31015->control_reg & CONTROL_NB1 ) ? 8 : 7;
+ else
+ t1 = ( ay31015->control_reg & CONTROL_NB1 ) ? 6 : 5;
+
+ ay31015->total_pulses = t1 << 4; /* total clock pulses to load a byte */
+ ay31015->second_stop_bit = ((ay31015->control_reg & CONTROL_TSB) ? 16 : 0); /* 2nd stop bit */
+ if ((t1 == 5) && (ay31015->second_stop_bit == 16))
+ ay31015->second_stop_bit = 8; /* 5 data bits and 2 stop bits = 1.5 stop bits */
+ ay31015->status_reg = STATUS_EOC | STATUS_TBMT;
+ ay31015->tx_data = 0;
+ ay31015->rx_state = PREP_TIME;
+ ay31015->tx_state = IDLE;
+ ay31015->pins[AY31015_SI] = 1;
+ ay31015_set_so( device, 1 );
+
+ if ( ay31015->config->type == AY_3_1015 )
+ ay31015->rx_data = 0;
+
+}
+
+
+/*-------------------------------------------------
+ ay31015_transfer_control_pins - transfers contents of controls pins to the control register
+-------------------------------------------------*/
+static void ay31015_transfer_control_pins( device_t *device )
+{
+ ay31015_t *ay31015 = get_safe_token( device );
+ UINT8 control = 0;
+
+ control |= ay31015->pins[AY31015_NP ] ? CONTROL_NP : 0;
+ control |= ay31015->pins[AY31015_TSB] ? CONTROL_TSB : 0;
+ control |= ay31015->pins[AY31015_NB1] ? CONTROL_NB1 : 0;
+ control |= ay31015->pins[AY31015_NB2] ? CONTROL_NB2 : 0;
+ control |= ay31015->pins[AY31015_EPS] ? CONTROL_EPS : 0;
+
+ if ( ay31015->control_reg != control )
+ {
+ ay31015->control_reg = control;
+ ay31015_reset( device );
+ }
+}
+
+
+/*-------------------------------------------------
+ ay31015_set_input_pin - set an input pin
+-------------------------------------------------*/
+void ay31015_set_input_pin( device_t *device, ay31015_input_pin_t pin, int data )
+{
+ ay31015_t *ay31015 = get_safe_token(device);
+
+ data = data ? 1 : 0;
+
+ switch ( pin )
+ {
+ case AY31015_SWE:
+ ay31015->pins[pin] = data;
+ ay31015_update_status_pins( device );
+ break;
+ case AY31015_RDAV:
+ ay31015->pins[pin] = data;
+ if ( ! data )
+ {
+ ay31015->status_reg &= ~STATUS_DAV;
+ ay31015->pins[AY31015_DAV] = 0;
+ }
+ break;
+ case AY31015_SI:
+ ay31015->pins[pin] = data;
+ break;
+ case AY31015_XR:
+ ay31015->pins[pin] = data;
+ if ( data )
+ ay31015_reset( device );
+ break;
+ case AY31015_CS:
+ case AY31015_NP:
+ case AY31015_TSB:
+ case AY31015_NB1:
+ case AY31015_NB2:
+ case AY31015_EPS:
+ ay31015->pins[pin] = data;
+ if ( ay31015->pins[AY31015_CS] )
+ ay31015_transfer_control_pins( device );
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+ ay31015_get_output_pin - get the status of an output pin
+-------------------------------------------------*/
+int ay31015_get_output_pin( device_t *device, ay31015_output_pin_t pin )
+{
+ ay31015_t *ay31015 = get_safe_token(device);
+
+ return ay31015->pins[pin];
+}
+
+
+INLINE void ay31015_update_rx_timer( device_t *device )
+{
+ ay31015_t *ay31015 = get_safe_token( device );
+
+ if ( ay31015->rx_clock > 0.0 )
+ {
+ ay31015->rx_timer->adjust( attotime::from_hz( ay31015->rx_clock ), 0, attotime::from_hz( ay31015->rx_clock ) );
+ }
+ else
+ {
+ ay31015->rx_timer->enable( 0 );
+ }
+}
+
+
+INLINE void ay31015_update_tx_timer( device_t *device )
+{
+ ay31015_t *ay31015 = get_safe_token( device );
+
+ if ( ay31015->tx_clock > 0.0 )
+ {
+ ay31015->tx_timer->adjust( attotime::from_hz( ay31015->tx_clock ), 0, attotime::from_hz( ay31015->tx_clock ) );
+ }
+ else
+ {
+ ay31015->tx_timer->enable( 0 );
+ }
+}
+
+
+/*-------------------------------------------------
+ ay31015_set_receiver_clock - set receive clock
+-------------------------------------------------*/
+void ay31015_set_receiver_clock( device_t *device, double new_clock )
+{
+ ay31015_t *ay31015 = get_safe_token(device);
+
+ ay31015->rx_clock = new_clock;
+ ay31015_update_rx_timer( device );
+}
+
+
+/*-------------------------------------------------
+ ay31015_set_transmitter_clock - set transmit clock
+-------------------------------------------------*/
+void ay31015_set_transmitter_clock( device_t *device, double new_clock )
+{
+ ay31015_t *ay31015 = get_safe_token(device);
+
+ ay31015->tx_clock = new_clock;
+ ay31015_update_tx_timer( device );
+}
+
+
+/*-------------------------------------------------
+ ay31015_get_received_data - return a byte to the computer
+-------------------------------------------------*/
+UINT8 ay31015_get_received_data( device_t *device )
+{
+ ay31015_t *ay31015 = get_safe_token(device);
+
+ return ay31015->rx_buffer;
+}
+
+
+/*-------------------------------------------------
+ ay31015_set_transmit_data - accept a byte to transmit, if able
+-------------------------------------------------*/
+void ay31015_set_transmit_data( device_t *device, UINT8 data )
+{
+ ay31015_t *ay31015 = get_safe_token(device);
+
+ if (ay31015->status_reg & STATUS_TBMT)
+ {
+ ay31015->tx_buffer = data;
+ ay31015->status_reg &= ~STATUS_TBMT;
+ ay31015_update_status_pins( device );
+ }
+}
+
+
+static DEVICE_START(ay31015)
+{
+ ay31015_t *ay31015 = get_safe_token(device);
+
+ ay31015->config = (const ay31015_config*)device->static_config();
+
+ ay31015->tx_clock = ay31015->config->transmitter_clock;
+ ay31015->rx_clock = ay31015->config->receiver_clock;
+
+ ay31015->rx_timer = device->machine().scheduler().timer_alloc(FUNC(ay31015_rx_process), (void *)device );
+ ay31015->tx_timer = device->machine().scheduler().timer_alloc(FUNC(ay31015_tx_process), (void *)device );
+
+ ay31015_update_rx_timer( device );
+ ay31015_update_tx_timer( device );
+}
+
+
+static DEVICE_RESET( ay31015 )
+{
+ ay31015_t *ay31015 = get_safe_token(device);
+
+ ay31015->control_reg = 0;
+ ay31015->rx_data = 0;
+
+ ay31015_reset( device );
+}
+
+
+/*-------------------------------------------------
+ DEVICE_GET_INFO(ay31015) - device getinfo
+ function
+-------------------------------------------------*/
+
+DEVICE_GET_INFO( ay31015 )
+{
+ switch(state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(ay31015_t); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(ay31015); break;
+ case DEVINFO_FCT_STOP: /* nothing */ break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME( ay31015 ); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "AY-3-1015"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "AY-3-1015/AY-5-1013 UARTs"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.00"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright the MAME and MESS Teams"); break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(AY31015, ay31015);
diff --git a/src/mess/machine/ay31015.h b/src/mess/machine/ay31015.h
new file mode 100644
index 00000000000..8284c7eb27f
--- /dev/null
+++ b/src/mess/machine/ay31015.h
@@ -0,0 +1,108 @@
+/* ay31015.h
+
+ Written for MESS by Robbbert on May 29th, 2008.
+
+*/
+
+#ifndef __AY31015_H_
+#define __AY31015_H_
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+
+typedef enum
+{
+ /* For AY-3-1014A, AY-3-1015(D) and HD6402 variants */
+ AY_3_1015,
+
+ /* For AY-3-1014, AY-5-1013 and AY-6-1013 variants */
+ AY_5_1013
+} ay31015_type_t;
+
+
+typedef enum
+{
+ 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 */
+} ay31015_input_pin_t;
+
+
+typedef enum
+{
+ 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 */
+} ay31015_output_pin_t;
+
+
+typedef struct _ay31015_config ay31015_config;
+struct _ay31015_config
+{
+ ay31015_type_t type; /* Type of chip */
+ double transmitter_clock; /* TCP - pin 40 */
+ double receiver_clock; /* RCP - pin 17 */
+ read8_device_func read_si; /* SI - pin 20 - This will be called whenever the SI pin is sampled. Optional */
+ write8_device_func write_so; /* SO - pin 25 - This will be called whenever data is put on the SO pin. Optional */
+ write8_device_func status_changed; /* This will be called whenever one of the status pins may have changed. Optional */
+};
+
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+#define MCFG_AY31015_ADD(_tag, _config) \
+ MCFG_DEVICE_ADD(_tag, AY31015, 0) \
+ MCFG_DEVICE_CONFIG(_config)
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* Set an input pin */
+void ay31015_set_input_pin( device_t *device, ay31015_input_pin_t pin, int data );
+
+
+/* Get an output pin */
+int ay31015_get_output_pin( device_t *device, ay31015_output_pin_t pin );
+
+
+/* Set a new transmitter clock (new_clock is in Hz) */
+void ay31015_set_transmitter_clock( device_t *device, double new_clock );
+
+
+/* Set a new receiver clock (new_clock is in Hz) */
+void ay31015_set_receiver_clock( device_t *device, double new_clock );
+
+
+/* Reead the received data */
+/* The received data is available on RD8-RD1 (pins 5-12) */
+UINT8 ay31015_get_received_data( device_t *device );
+
+
+/* Set the transmitter buffer */
+/* The data to transmit is set on DB1-DB8 (pins 26-33) */
+void ay31015_set_transmit_data( device_t *device, UINT8 data );
+
+
+/***************************************************************************
+ DEVICE INTERFACE
+***************************************************************************/
+
+DECLARE_LEGACY_DEVICE(AY31015, ay31015);
+#endif
diff --git a/src/mess/machine/ay3600.c b/src/mess/machine/ay3600.c
new file mode 100644
index 00000000000..39c9cea3159
--- /dev/null
+++ b/src/mess/machine/ay3600.c
@@ -0,0 +1,629 @@
+/***************************************************************************
+
+ AY3600.c
+
+ Machine file to handle emulation of the AY-3600 keyboard controller.
+
+ TODO:
+ -Make the caps lock functional, remove dependency on input_port_1.
+ Caps lock now functional. Barry Nelson 04/05/2001
+ Still dependent on input_port_1 though.
+ -Rename variables from a2 to AY3600
+ Done. Barry Nelson 04/05/2001
+ Find the correct MAGIC_KEY_REPEAT_NUMBER
+ Use the keyboard ROM for building a remapping table?
+
+***************************************************************************/
+
+#include "emu.h"
+#include "machine/ay3600.h"
+#include "includes/apple2.h"
+
+
+/***************************************************************************
+ PARAMETERS
+***************************************************************************/
+
+#ifdef MAME_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif /* MAME_DEBUG */
+
+#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+
+/**************************************************************************/
+
+static TIMER_CALLBACK(AY3600_poll);
+
+static int AY3600_keyboard_queue_chars(running_machine &machine, const unicode_char *text, size_t text_len);
+static bool AY3600_keyboard_accept_char(running_machine &machine, unicode_char ch);
+static bool AY3600_keyboard_charqueue_empty(running_machine &machine);
+static const unsigned char ay3600_key_remap_2[9*8][4] =
+{
+/* norm ctrl shft both */
+ { 0x7f,0x7f,0x7f,0x7f }, /* UNUSED */
+ { 0x08,0x08,0x08,0x08 }, /* Left */
+ { 0x09,0x09,0x09,0x09 }, /* UNUSED */
+ { 0x0a,0x0a,0x0a,0x0a }, /* UNUSED */
+ { 0x0b,0x0b,0x0b,0x0b }, /* UNUSED */
+ { 0x0d,0x0d,0x0d,0x0d }, /* Enter */
+ { 0x15,0x15,0x15,0x15 }, /* Right */
+ { 0x1b,0x1b,0x1b,0x1b }, /* Escape */
+ { 0x20,0x20,0x20,0x20 }, /* Space */
+ { 0x27,0x27,0x22,0x22 }, /* UNUSED */
+ { 0x2c,0x2c,0x3c,0x3c }, /* , < */
+ { 0x3a,0x3a,0x2a,0x2a }, /* : * */
+ { 0x2e,0x2e,0x3e,0x3e }, /* . > */
+ { 0x2f,0x2f,0x3f,0x3f }, /* / ? */
+ { 0x30,0x30,0x30,0x30 }, /* 0 */
+ { 0x31,0x31,0x21,0x21 }, /* 1 ! */
+ { 0x32,0x32,0x22,0x22 }, /* 2 " */
+ { 0x33,0x33,0x23,0x23 }, /* 3 # */
+ { 0x34,0x34,0x24,0x24 }, /* 4 $ */
+ { 0x35,0x35,0x25,0x25 }, /* 5 % */
+ { 0x36,0x36,0x26,0x26 }, /* 6 & */
+ { 0x37,0x37,0x27,0x27 }, /* 7 ' */
+ { 0x38,0x38,0x28,0x28 }, /* 8 ( */
+ { 0x39,0x39,0x29,0x29 }, /* 9 ) */
+ { 0x3b,0x3b,0x2b,0x2b }, /* ; + */
+ { 0x2d,0x2d,0x3d,0x3d }, /* - = */
+ { 0x5b,0x1b,0x7b,0x1b }, /* UNUSED */
+ { 0x5c,0x1c,0x7c,0x1c }, /* UNUSED */
+ { 0x5d,0x1d,0x7d,0x1d }, /* UNUSED */
+ { 0x60,0x60,0x7e,0x7e }, /* UNUSED */
+ { 0x41,0x01,0x41,0x01 }, /* A */
+ { 0x42,0x02,0x42,0x02 }, /* B */
+ { 0x43,0x03,0x43,0x03 }, /* C */
+ { 0x44,0x04,0x44,0x04 }, /* D */
+ { 0x45,0x05,0x45,0x05 }, /* E */
+ { 0x46,0x06,0x46,0x06 }, /* F */
+ { 0x47,0x07,0x47,0x07 }, /* G */
+ { 0x48,0x08,0x48,0x08 }, /* H */
+ { 0x49,0x09,0x49,0x09 }, /* I */
+ { 0x4a,0x0a,0x4a,0x0a }, /* J */
+ { 0x4b,0x0b,0x4b,0x0b }, /* K */
+ { 0x4c,0x0c,0x4c,0x0c }, /* L */
+ { 0x4d,0x0d,0x5d,0x0d }, /* M ] */
+ { 0x4e,0x0e,0x5e,0x1e }, /* N ^ */
+ { 0x4f,0x0f,0x4f,0x0f }, /* O */
+ { 0x50,0x10,0x40,0x00 }, /* P @ */
+ { 0x51,0x11,0x51,0x11 }, /* Q */
+ { 0x52,0x12,0x52,0x12 }, /* R */
+ { 0x53,0x13,0x53,0x13 }, /* S */
+ { 0x54,0x14,0x54,0x14 }, /* T */
+ { 0x55,0x15,0x55,0x15 }, /* U */
+ { 0x56,0x16,0x56,0x16 }, /* V */
+ { 0x57,0x17,0x57,0x17 }, /* W */
+ { 0x58,0x18,0x58,0x18 }, /* X */
+ { 0x59,0x19,0x59,0x19 }, /* Y */
+ { 0x5a,0x1a,0x5a,0x1a } /* Z */
+};
+
+static const unsigned char ay3600_key_remap_2e[2][9*8][4] =
+{
+/* caps lock off norm ctrl shft both */
+ {
+ { 0x7f,0x7f,0x7f,0x7f }, /* Backspace */
+ { 0x08,0x08,0x08,0x08 }, /* Left */
+ { 0x09,0x09,0x09,0x09 }, /* Tab */
+ { 0x0a,0x0a,0x0a,0x0a }, /* Down */
+ { 0x0b,0x0b,0x0b,0x0b }, /* Up */
+ { 0x0d,0x0d,0x0d,0x0d }, /* Enter */
+ { 0x15,0x15,0x15,0x15 }, /* Right */
+ { 0x1b,0x1b,0x1b,0x1b }, /* Escape */
+ { 0x20,0x20,0x20,0x20 }, /* Space */
+ { 0x27,0x27,0x22,0x22 }, /* ' " */
+ { 0x2c,0x2c,0x3c,0x3c }, /* , < */
+ { 0x2d,0x2d,0x5f,0x1f }, /* - _ */
+ { 0x2e,0x2e,0x3e,0x3e }, /* . > */
+ { 0x2f,0x2f,0x3f,0x3f }, /* / ? */
+ { 0x30,0x30,0x29,0x29 }, /* 0 ) */
+ { 0x31,0x31,0x21,0x21 }, /* 1 ! */
+ { 0x32,0x00,0x40,0x00 }, /* 2 @ */
+ { 0x33,0x33,0x23,0x23 }, /* 3 # */
+ { 0x34,0x34,0x24,0x24 }, /* 4 $ */
+ { 0x35,0x35,0x25,0x25 }, /* 5 % */
+ { 0x36,0x1e,0x5e,0x1e }, /* 6 ^ */
+ { 0x37,0x37,0x26,0x26 }, /* 7 & */
+ { 0x38,0x38,0x2a,0x2a }, /* 8 * */
+ { 0x39,0x39,0x28,0x28 }, /* 9 ( */
+ { 0x3b,0x3b,0x3a,0x3a }, /* ; : */
+ { 0x3d,0x3d,0x2b,0x2b }, /* = + */
+ { 0x5b,0x1b,0x7b,0x1b }, /* [ { */
+ { 0x5c,0x1c,0x7c,0x1c }, /* \ | */
+ { 0x5d,0x1d,0x7d,0x1d }, /* ] } */
+ { 0x60,0x60,0x7e,0x7e }, /* ` ~ */
+ { 0x61,0x01,0x41,0x01 }, /* a A */
+ { 0x62,0x02,0x42,0x02 }, /* b B */
+ { 0x63,0x03,0x43,0x03 }, /* c C */
+ { 0x64,0x04,0x44,0x04 }, /* d D */
+ { 0x65,0x05,0x45,0x05 }, /* e E */
+ { 0x66,0x06,0x46,0x06 }, /* f F */
+ { 0x67,0x07,0x47,0x07 }, /* g G */
+ { 0x68,0x08,0x48,0x08 }, /* h H */
+ { 0x69,0x09,0x49,0x09 }, /* i I */
+ { 0x6a,0x0a,0x4a,0x0a }, /* j J */
+ { 0x6b,0x0b,0x4b,0x0b }, /* k K */
+ { 0x6c,0x0c,0x4c,0x0c }, /* l L */
+ { 0x6d,0x0d,0x4d,0x0d }, /* m M */
+ { 0x6e,0x0e,0x4e,0x0e }, /* n N */
+ { 0x6f,0x0f,0x4f,0x0f }, /* o O */
+ { 0x70,0x10,0x50,0x10 }, /* p P */
+ { 0x71,0x11,0x51,0x11 }, /* q Q */
+ { 0x72,0x12,0x52,0x12 }, /* r R */
+ { 0x73,0x13,0x53,0x13 }, /* s S */
+ { 0x74,0x14,0x54,0x14 }, /* t T */
+ { 0x75,0x15,0x55,0x15 }, /* u U */
+ { 0x76,0x16,0x56,0x16 }, /* v V */
+ { 0x77,0x17,0x57,0x17 }, /* w W */
+ { 0x78,0x18,0x58,0x18 }, /* x X */
+ { 0x79,0x19,0x59,0x19 }, /* y Y */
+ { 0x7a,0x1a,0x5a,0x1a }, /* z Z */
+ { 0x30,0x30,0x30,0x30 }, /* 0 (KP) */
+ { 0x31,0x31,0x31,0x31 }, /* 1 (KP) */
+ { 0x32,0x32,0x32,0x32 }, /* 2 (KP) */
+ { 0x33,0x33,0x33,0x33 }, /* 3 (KP) */
+ { 0x34,0x34,0x34,0x34 }, /* 4 (KP) */
+ { 0x35,0x35,0x35,0x35 }, /* 5 (KP) */
+ { 0x36,0x36,0x36,0x36 }, /* 6 (KP) */
+ { 0x37,0x37,0x37,0x37 }, /* 7 (KP) */
+ { 0x38,0x38,0x38,0x38 }, /* 8 (KP) */
+ { 0x39,0x39,0x39,0x39 }, /* 9 (KP) */
+ { 0x2f,0x2f,0x2f,0x2f }, /* / (KP) */
+ { 0x2a,0x2a,0x2a,0x2a }, /* * (KP) */
+ { 0x2d,0x2d,0x2d,0x2d }, /* - (KP) */
+ { 0x2b,0x2b,0x2b,0x2b }, /* + (KP) */
+ { 0x2e,0x2e,0x2e,0x2e }, /* . (KP) */
+ { 0x0d,0x0d,0x0d,0x0d } /* Enter (KP) */
+ },
+/* caps lock on norm ctrl shft both */
+ {
+ { 0x7f,0x7f,0x7f,0x7f }, /* Backspace */
+ { 0x08,0x08,0x08,0x08 }, /* Left */
+ { 0x09,0x09,0x09,0x09 }, /* Tab */
+ { 0x0a,0x0a,0x0a,0x0a }, /* Down */
+ { 0x0b,0x0b,0x0b,0x0b }, /* Up */
+ { 0x0d,0x0d,0x0d,0x0d }, /* Enter */
+ { 0x15,0x15,0x15,0x15 }, /* Right */
+ { 0x1b,0x1b,0x1b,0x1b }, /* Escape */
+ { 0x20,0x20,0x20,0x20 }, /* Space */
+ { 0x27,0x27,0x22,0x22 }, /* ' " */
+ { 0x2c,0x2c,0x3c,0x3c }, /* , < */
+ { 0x2d,0x2d,0x5f,0x1f }, /* - _ */
+ { 0x2e,0x2e,0x3e,0x3e }, /* . > */
+ { 0x2f,0x2f,0x3f,0x3f }, /* / ? */
+ { 0x30,0x30,0x29,0x29 }, /* 0 ) */
+ { 0x31,0x31,0x21,0x21 }, /* 1 ! */
+ { 0x32,0x00,0x40,0x00 }, /* 2 @ */
+ { 0x33,0x33,0x23,0x23 }, /* 3 # */
+ { 0x34,0x34,0x24,0x24 }, /* 4 $ */
+ { 0x35,0x35,0x25,0x25 }, /* 5 % */
+ { 0x36,0x1e,0x5e,0x1e }, /* 6 ^ */
+ { 0x37,0x37,0x26,0x26 }, /* 7 & */
+ { 0x38,0x38,0x2a,0x2a }, /* 8 * */
+ { 0x39,0x39,0x28,0x28 }, /* 9 ( */
+ { 0x3b,0x3b,0x3a,0x3a }, /* ; : */
+ { 0x3d,0x3d,0x2b,0x2b }, /* = + */
+ { 0x5b,0x1b,0x7b,0x1b }, /* [ { */
+ { 0x5c,0x1c,0x7c,0x1c }, /* \ | */
+ { 0x5d,0x1d,0x7d,0x1d }, /* ] } */
+ { 0x60,0x60,0x7e,0x7e }, /* ` ~ */
+ { 0x41,0x01,0x61,0x01 }, /* A a */
+ { 0x42,0x02,0x62,0x02 }, /* B b */
+ { 0x43,0x03,0x63,0x03 }, /* C c */
+ { 0x44,0x04,0x64,0x04 }, /* D d */
+ { 0x45,0x05,0x65,0x05 }, /* E e */
+ { 0x46,0x06,0x66,0x06 }, /* F f */
+ { 0x47,0x07,0x67,0x07 }, /* G g */
+ { 0x48,0x08,0x68,0x08 }, /* H h */
+ { 0x49,0x09,0x69,0x09 }, /* I i */
+ { 0x4a,0x0a,0x6a,0x0a }, /* J j */
+ { 0x4b,0x0b,0x6b,0x0b }, /* K k */
+ { 0x4c,0x0c,0x6c,0x0c }, /* L l */
+ { 0x4d,0x0d,0x6d,0x0d }, /* M m */
+ { 0x4e,0x0e,0x6e,0x0e }, /* N n */
+ { 0x4f,0x0f,0x6f,0x0f }, /* O o */
+ { 0x50,0x10,0x70,0x10 }, /* P p */
+ { 0x51,0x11,0x71,0x11 }, /* Q q */
+ { 0x52,0x12,0x72,0x12 }, /* R r */
+ { 0x53,0x13,0x73,0x13 }, /* S s */
+ { 0x54,0x14,0x74,0x14 }, /* T t */
+ { 0x55,0x15,0x75,0x15 }, /* U u */
+ { 0x56,0x16,0x76,0x16 }, /* V v */
+ { 0x57,0x17,0x77,0x17 }, /* W w */
+ { 0x58,0x18,0x78,0x18 }, /* X x */
+ { 0x59,0x19,0x79,0x19 }, /* Y y */
+ { 0x5a,0x1a,0x7a,0x1a }, /* Z z */
+ { 0x30,0x30,0x30,0x30 }, /* 0 (KP) */
+ { 0x31,0x31,0x31,0x31 }, /* 1 (KP) */
+ { 0x32,0x32,0x32,0x32 }, /* 2 (KP) */
+ { 0x33,0x33,0x33,0x33 }, /* 3 (KP) */
+ { 0x34,0x34,0x34,0x34 }, /* 4 (KP) */
+ { 0x35,0x35,0x35,0x35 }, /* 5 (KP) */
+ { 0x36,0x36,0x36,0x36 }, /* 6 (KP) */
+ { 0x37,0x37,0x37,0x37 }, /* 7 (KP) */
+ { 0x38,0x38,0x38,0x38 }, /* 8 (KP) */
+ { 0x39,0x39,0x39,0x39 }, /* 9 (KP) */
+ { 0x2f,0x2f,0x2f,0x2f }, /* / (KP) */
+ { 0x2a,0x2a,0x2a,0x2a }, /* * (KP) */
+ { 0x2d,0x2d,0x2d,0x2d }, /* - (KP) */
+ { 0x2b,0x2b,0x2b,0x2b }, /* + (KP) */
+ { 0x2e,0x2e,0x2e,0x2e }, /* . (KP) */
+ { 0x0d,0x0d,0x0d,0x0d } /* Enter (KP) */
+ }
+};
+
+#define A2_KEY_NORMAL 0
+#define A2_KEY_CONTROL 1
+#define A2_KEY_SHIFT 2
+#define A2_KEY_BOTH 3
+#define MAGIC_KEY_REPEAT_NUMBER 80
+
+#define AY3600_KEYS_LENGTH 128
+
+// IIgs keymod flags
+#define A2_KEYMOD_SHIFT 1
+#define A2_KEYMOD_CONTROL 2
+#define A2_KEYMOD_CAPSLOCK 4
+#define A2_KEYMOD_REPEAT 8
+#define A2_KEYMOD_KEYPAD 0x10
+#define A2_KEYMOD_MODLATCH 0x20
+#define A2_KEYMOD_COMMAND 0x40
+#define A2_KEYMOD_OPTION 0x80
+
+
+
+/***************************************************************************
+ HELPER FUNCTIONS
+***************************************************************************/
+
+INLINE int a2_has_keypad(running_machine &machine)
+{
+ return machine.root_device().ioport("keypad_1") != NULL;
+}
+
+INLINE int a2_has_reset_dip(running_machine &machine)
+{
+ return machine.root_device().ioport("reset_dip") != NULL;
+}
+
+INLINE int a2_has_repeat(running_machine &machine)
+{
+ return machine.root_device().ioport("keyb_repeat") != NULL;
+}
+
+INLINE int a2_has_capslock(running_machine &machine)
+{
+ return !a2_has_repeat(machine); /* BUG: Doesn't work with Ace */
+}
+
+INLINE int a2_no_ctrl_reset(running_machine &machine)
+{
+ return ((a2_has_repeat(machine) && !a2_has_reset_dip(machine)) ||
+ (a2_has_reset_dip(machine) && !machine.root_device().ioport("reset_dip")->read()));
+}
+
+
+/***************************************************************************
+ AY3600_init
+***************************************************************************/
+
+int AY3600_init(running_machine &machine)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+ /* Init the key remapping table */
+ state->m_ay3600_keys = auto_alloc_array_clear(machine, unsigned int, AY3600_KEYS_LENGTH);
+
+ /* We poll the keyboard periodically to scan the keys. This is
+ actually consistent with how the AY-3600 keyboard controller works. */
+ machine.scheduler().timer_pulse(attotime::from_hz(60), FUNC(AY3600_poll));
+
+ /* Set Caps Lock light to ON, since that's how we default it. */
+ set_led_status(machine,1,1);
+
+ state->m_keywaiting = 0;
+ state->m_keycode = 0;
+ state->m_keystilldown = 0;
+ state->m_keymodreg = A2_KEYMOD_CAPSLOCK; // caps lock on
+
+ state->m_last_key = 0xff; /* necessary for special repeat key behaviour */
+ state->m_last_key_unmodified = 0xff; /* necessary for special repeat key behaviour */
+ state->m_time_until_repeat = MAGIC_KEY_REPEAT_NUMBER;
+
+ machine.ioport().natkeyboard().configure(
+ ioport_queue_chars_delegate(FUNC(AY3600_keyboard_queue_chars), &machine),
+ ioport_accept_char_delegate(FUNC(AY3600_keyboard_accept_char), &machine),
+ ioport_charqueue_empty_delegate(FUNC(AY3600_keyboard_charqueue_empty), &machine));
+
+ return 0;
+}
+
+
+
+/***************************************************************************
+ AY3600_poll
+***************************************************************************/
+
+static TIMER_CALLBACK(AY3600_poll)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+ int switchkey; /* Normal, Shift, Control, or both */
+ int port, num_ports, bit, data;
+ int any_key_pressed = 0; /* Have we pressed a key? True/False */
+ int caps_lock = 0;
+ int curkey;
+ int curkey_unmodified;
+
+
+ static const char *const portnames[] = {
+ "keyb_0", "keyb_1", "keyb_2", "keyb_3", "keyb_4", "keyb_5", "keyb_6",
+ "keypad_1", "keypad_2"
+ };
+
+ /* check for these special cases because they affect the emulated key codes */
+
+ /* only repeat keys on a 2/2+ if special REPT key is pressed */
+ if (a2_has_repeat(machine))
+ state->m_time_until_repeat = machine.root_device().ioport("keyb_repeat")->read() & 0x01 ? 0 : ~0;
+
+ /* check caps lock and set LED here */
+ if (apple2_pressed_specialkey(machine, SPECIALKEY_CAPSLOCK))
+ {
+ caps_lock = 1;
+ set_led_status(machine,1,1);
+ state->m_keymodreg |= A2_KEYMOD_CAPSLOCK;
+ }
+ else
+ {
+ caps_lock = 0;
+ set_led_status(machine,1,0);
+ state->m_keymodreg &= ~A2_KEYMOD_CAPSLOCK;
+ }
+
+ switchkey = A2_KEY_NORMAL;
+
+ /* shift key check */
+ if (apple2_pressed_specialkey(machine, SPECIALKEY_SHIFT))
+ {
+ switchkey |= A2_KEY_SHIFT;
+ state->m_keymodreg |= A2_KEYMOD_SHIFT;
+ }
+ else
+ {
+ state->m_keymodreg &= ~A2_KEYMOD_SHIFT;
+ }
+
+ /* control key check - only one control key on the left side on the Apple */
+ if (apple2_pressed_specialkey(machine, SPECIALKEY_CONTROL))
+ {
+ switchkey |= A2_KEY_CONTROL;
+ state->m_keymodreg |= A2_KEYMOD_CONTROL;
+ }
+ else
+ {
+ state->m_keymodreg &= ~A2_KEYMOD_CONTROL;
+ }
+
+ /* apple key check */
+ if (apple2_pressed_specialkey(machine, SPECIALKEY_BUTTON0))
+ {
+ state->m_keymodreg |= A2_KEYMOD_COMMAND;
+ }
+ else
+ {
+ state->m_keymodreg &= ~A2_KEYMOD_COMMAND;
+ }
+
+ /* option key check */
+ if (apple2_pressed_specialkey(machine, SPECIALKEY_BUTTON1))
+ {
+ state->m_keymodreg |= A2_KEYMOD_OPTION;
+ }
+ else
+ {
+ state->m_keymodreg &= ~A2_KEYMOD_OPTION;
+ }
+
+ /* reset key check */
+ if (apple2_pressed_specialkey(machine, SPECIALKEY_RESET) &&
+ (a2_no_ctrl_reset(machine) || switchkey & A2_KEY_CONTROL))
+ {
+ if (!state->m_reset_flag)
+ {
+ state->m_reset_flag = 1;
+ /* using PULSE_LINE does not allow us to press and hold key */
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_RESET, ASSERT_LINE);
+ }
+ return;
+ }
+ if (state->m_reset_flag)
+ {
+ state->m_reset_flag = 0;
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_RESET, CLEAR_LINE);
+ machine.schedule_soft_reset();
+ }
+
+ /* run through real keys and see what's being pressed */
+ num_ports = a2_has_keypad(machine) ? 9 : 7;
+
+ state->m_keymodreg &= ~A2_KEYMOD_KEYPAD;
+
+ for (port = 0; port < num_ports; port++)
+ {
+ data = machine.root_device().ioport(portnames[port])->read();
+
+ for (bit = 0; bit < 8; bit++)
+ {
+ if (a2_has_capslock(machine))
+ {
+ curkey = ay3600_key_remap_2e[caps_lock][port*8+bit][switchkey];
+ curkey_unmodified = ay3600_key_remap_2e[caps_lock][port*8+bit][0];
+ }
+ else
+ {
+ curkey = ay3600_key_remap_2[port*8+bit][switchkey];
+ curkey_unmodified = ay3600_key_remap_2[port*8+bit][0];
+ }
+ if (data & (1 << bit))
+ {
+ any_key_pressed = 1;
+
+ if (port == 8)
+ {
+ state->m_keymodreg |= A2_KEYMOD_KEYPAD;
+ }
+
+ /* prevent overflow */
+ if (state->m_ay3600_keys[port*8+bit] < 65000)
+ state->m_ay3600_keys[port*8+bit]++;
+
+ /* on every key press, reset the time until repeat and the key to repeat */
+ if ((state->m_ay3600_keys[port*8+bit] == 1) && (curkey_unmodified != state->m_last_key_unmodified))
+ {
+ state->m_time_until_repeat = MAGIC_KEY_REPEAT_NUMBER;
+ state->m_last_key = curkey;
+ state->m_last_key_unmodified = curkey_unmodified;
+ }
+ }
+ else
+ {
+ state->m_ay3600_keys[port*8+bit] = 0;
+ }
+ }
+ }
+
+ state->m_keymodreg &= ~A2_KEYMOD_REPEAT;
+
+ if (!any_key_pressed)
+ {
+ /* If no keys have been pressed, reset the repeat time and return */
+ state->m_time_until_repeat = MAGIC_KEY_REPEAT_NUMBER;
+ state->m_last_key = 0xff;
+ state->m_last_key_unmodified = 0xff;
+ }
+ else
+ {
+ /* Otherwise, count down the repeat time */
+ if (state->m_time_until_repeat > 0)
+ state->m_time_until_repeat--;
+
+ /* Even if a key has been released, repeat it if it was the last key pressed */
+ /* If we should output a key, set the appropriate Apple II data lines */
+ if (state->m_time_until_repeat == 0 ||
+ state->m_time_until_repeat == MAGIC_KEY_REPEAT_NUMBER-1)
+ {
+ state->m_keywaiting = 1;
+ state->m_keycode = state->m_last_key;
+ state->m_keycode_unmodified = state->m_last_key_unmodified;
+ state->m_keymodreg |= A2_KEYMOD_REPEAT;
+ }
+ }
+ state->m_keystilldown = (state->m_last_key_unmodified == state->m_keycode_unmodified);
+}
+
+
+
+/***************************************************************************
+ AY3600_keydata_strobe_r ($C00x)
+***************************************************************************/
+
+int AY3600_keydata_strobe_r(running_machine &machine)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+ int rc;
+ rc = state->m_keycode | (state->m_keywaiting ? 0x80 : 0x00);
+ LOG(("AY3600_keydata_strobe_r(): rc=0x%02x\n", rc));
+ return rc;
+}
+
+
+
+/***************************************************************************
+ AY3600_anykey_clearstrobe_r ($C01x)
+***************************************************************************/
+
+int AY3600_anykey_clearstrobe_r(running_machine &machine)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+ int rc;
+ state->m_keywaiting = 0;
+ rc = state->m_keycode | (state->m_keystilldown ? 0x80 : 0x00);
+ LOG(("AY3600_anykey_clearstrobe_r(): rc=0x%02x\n", rc));
+ return rc;
+}
+
+
+/***************************************************************************
+ AY3600_keymod_r ($C025 - IIgs only)
+***************************************************************************/
+
+int AY3600_keymod_r(running_machine &machine)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+ return state->m_keymodreg;
+}
+
+/***************************************************************************
+ Natural keyboard support
+***************************************************************************/
+
+static UINT8 AY3600_get_keycode(unicode_char ch)
+{
+ UINT8 result;
+
+ switch(ch)
+ {
+ case UCHAR_MAMEKEY(UP):
+ result = 0x0B;
+ break;
+ case UCHAR_MAMEKEY(DOWN):
+ result = 0x0A;
+ break;
+ case UCHAR_MAMEKEY(LEFT):
+ result = 0x08;
+ break;
+ case UCHAR_MAMEKEY(RIGHT):
+ result = 0x15;
+ break;
+
+ default:
+ if (ch <= 0x7F)
+ result = (UINT8) ch;
+ else
+ result = 0;
+ break;
+ }
+
+ return result;
+}
+
+
+
+static int AY3600_keyboard_queue_chars(running_machine &machine, const unicode_char *text, size_t text_len)
+{
+ apple2_state *state = machine.driver_data<apple2_state>();
+
+ if (state->m_keywaiting)
+ return 0;
+ state->m_keycode = AY3600_get_keycode(text[0]);
+ state->m_keywaiting = 1;
+ return 1;
+}
+
+
+
+static bool AY3600_keyboard_accept_char(running_machine &machine, unicode_char ch)
+{
+ return AY3600_get_keycode(ch) != 0;
+}
+
+static bool AY3600_keyboard_charqueue_empty(running_machine &machine)
+{
+ return true;
+}
+
+
+
diff --git a/src/mess/machine/ay3600.h b/src/mess/machine/ay3600.h
new file mode 100644
index 00000000000..2bb2ab3712b
--- /dev/null
+++ b/src/mess/machine/ay3600.h
@@ -0,0 +1,20 @@
+/***************************************************************************
+
+ ay3600.h
+
+ Include file for AY3600 keyboard; used by Apple IIs
+
+***************************************************************************/
+
+#ifndef AY3600_H
+#define AY3600_H
+
+
+/*----------- defined in machine/ay3600.c -----------*/
+
+int AY3600_init(running_machine &machine);
+int AY3600_anykey_clearstrobe_r(running_machine &machine);
+int AY3600_keydata_strobe_r(running_machine &machine);
+int AY3600_keymod_r(running_machine &machine);
+
+#endif /* AY3600_H */
diff --git a/src/mess/machine/b2m.c b/src/mess/machine/b2m.c
new file mode 100644
index 00000000000..89d7611b614
--- /dev/null
+++ b/src/mess/machine/b2m.c
@@ -0,0 +1,377 @@
+/***************************************************************************
+
+ Bashkiria-2M machine driver by Miodrag Milanovic
+
+ 28/03/2008 Preliminary driver.
+
+****************************************************************************/
+
+
+#include "emu.h"
+#include "cpu/i8085/i8085.h"
+#include "imagedev/cassette.h"
+#include "machine/i8255.h"
+#include "machine/pit8253.h"
+#include "machine/wd17xx.h"
+#include "machine/pic8259.h"
+#include "machine/i8251.h"
+#include "includes/b2m.h"
+#include "machine/ram.h"
+#include "imagedev/flopdrv.h"
+
+READ8_MEMBER(b2m_state::b2m_keyboard_r)
+{
+ UINT8 key = 0x00;
+ if (offset < 0x100) {
+ if ((offset & 0x01)!=0) { key |= ioport("LINE0")->read(); }
+ if ((offset & 0x02)!=0) { key |= ioport("LINE1")->read(); }
+ if ((offset & 0x04)!=0) { key |= ioport("LINE2")->read(); }
+ if ((offset & 0x08)!=0) { key |= ioport("LINE3")->read(); }
+ if ((offset & 0x10)!=0) { key |= ioport("LINE4")->read(); }
+ if ((offset & 0x20)!=0) { key |= ioport("LINE5")->read(); }
+ if ((offset & 0x40)!=0) { key |= ioport("LINE6")->read(); }
+ if ((offset & 0x80)!=0) { key |= ioport("LINE7")->read(); }
+ } else {
+ if ((offset & 0x01)!=0) { key |= ioport("LINE8")->read(); }
+ if ((offset & 0x02)!=0) { key |= ioport("LINE9")->read(); }
+ if ((offset & 0x04)!=0) { key |= ioport("LINE10")->read(); }
+ }
+ return key;
+}
+
+
+static void b2m_set_bank(running_machine &machine,int bank)
+{
+ UINT8 *rom;
+ b2m_state *state = machine.driver_data<b2m_state>();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ UINT8 *ram = machine.device<ram_device>(RAM_TAG)->pointer();
+
+ space->install_write_bank(0x0000, 0x27ff, "bank1");
+ space->install_write_bank(0x2800, 0x2fff, "bank2");
+ space->install_write_bank(0x3000, 0x6fff, "bank3");
+ space->install_write_bank(0x7000, 0xdfff, "bank4");
+ space->install_write_bank(0xe000, 0xffff, "bank5");
+
+ rom = state->memregion("maincpu")->base();
+ switch(bank) {
+ case 0 :
+ case 1 :
+ space->unmap_write(0xe000, 0xffff);
+
+ state->membank("bank1")->set_base(ram);
+ state->membank("bank2")->set_base(ram + 0x2800);
+ state->membank("bank3")->set_base(ram + 0x3000);
+ state->membank("bank4")->set_base(ram + 0x7000);
+ state->membank("bank5")->set_base(rom + 0x10000);
+ break;
+#if 0
+ case 1 :
+ space->unmap_write(0x3000, 0x6fff);
+ space->unmap_write(0xe000, 0xffff);
+
+ state->membank("bank1")->set_base(ram);
+ state->membank("bank2")->set_base(ram + 0x2800);
+ state->membank("bank3")->set_base(rom + 0x12000);
+ state->membank("bank4")->set_base(rom + 0x16000);
+ state->membank("bank5")->set_base(rom + 0x10000);
+ break;
+#endif
+ case 2 :
+ space->unmap_write(0x2800, 0x2fff);
+ space->unmap_write(0xe000, 0xffff);
+
+ state->membank("bank1")->set_base(ram);
+ space->install_read_handler(0x2800, 0x2fff, read8_delegate(FUNC(b2m_state::b2m_keyboard_r),state));
+ state->membank("bank3")->set_base(ram + 0x10000);
+ state->membank("bank4")->set_base(ram + 0x7000);
+ state->membank("bank5")->set_base(rom + 0x10000);
+ break;
+ case 3 :
+ space->unmap_write(0x2800, 0x2fff);
+ space->unmap_write(0xe000, 0xffff);
+
+ state->membank("bank1")->set_base(ram);
+ space->install_read_handler(0x2800, 0x2fff, read8_delegate(FUNC(b2m_state::b2m_keyboard_r),state));
+ state->membank("bank3")->set_base(ram + 0x14000);
+ state->membank("bank4")->set_base(ram + 0x7000);
+ state->membank("bank5")->set_base(rom + 0x10000);
+ break;
+ case 4 :
+ space->unmap_write(0x2800, 0x2fff);
+ space->unmap_write(0xe000, 0xffff);
+
+ state->membank("bank1")->set_base(ram);
+ space->install_read_handler(0x2800, 0x2fff, read8_delegate(FUNC(b2m_state::b2m_keyboard_r),state));
+ state->membank("bank3")->set_base(ram + 0x18000);
+ state->membank("bank4")->set_base(ram + 0x7000);
+ state->membank("bank5")->set_base(rom + 0x10000);
+
+ break;
+ case 5 :
+ space->unmap_write(0x2800, 0x2fff);
+ space->unmap_write(0xe000, 0xffff);
+
+ state->membank("bank1")->set_base(ram);
+ space->install_read_handler(0x2800, 0x2fff, read8_delegate(FUNC(b2m_state::b2m_keyboard_r),state));
+ state->membank("bank3")->set_base(ram + 0x1c000);
+ state->membank("bank4")->set_base(ram + 0x7000);
+ state->membank("bank5")->set_base(rom + 0x10000);
+
+ break;
+ case 6 :
+ state->membank("bank1")->set_base(ram);
+ state->membank("bank2")->set_base(ram + 0x2800);
+ state->membank("bank3")->set_base(ram + 0x3000);
+ state->membank("bank4")->set_base(ram + 0x7000);
+ state->membank("bank5")->set_base(ram + 0xe000);
+ break;
+ case 7 :
+ space->unmap_write(0x0000, 0x27ff);
+ space->unmap_write(0x2800, 0x2fff);
+ space->unmap_write(0x3000, 0x6fff);
+ space->unmap_write(0x7000, 0xdfff);
+ space->unmap_write(0xe000, 0xffff);
+
+ state->membank("bank1")->set_base(rom + 0x10000);
+ state->membank("bank2")->set_base(rom + 0x10000);
+ state->membank("bank3")->set_base(rom + 0x10000);
+ state->membank("bank4")->set_base(rom + 0x10000);
+ state->membank("bank5")->set_base(rom + 0x10000);
+ break;
+ }
+}
+
+
+static WRITE_LINE_DEVICE_HANDLER(bm2_pit_out1)
+{
+ b2m_state *st = device->machine().driver_data<b2m_state>();
+ speaker_level_w(st->m_speaker, state);
+}
+
+const struct pit8253_config b2m_pit8253_intf =
+{
+ {
+ {
+ 0,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE("pic8259", pic8259_ir1_w)
+ },
+ {
+ 2000000,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE("pit8253", bm2_pit_out1)
+ },
+ {
+ 2000000,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE("pit8253", pit8253_clk0_w)
+ }
+ }
+};
+
+static WRITE8_DEVICE_HANDLER (b2m_8255_porta_w )
+{
+ b2m_state *state = device->machine().driver_data<b2m_state>();
+ state->m_b2m_8255_porta = data;
+}
+static WRITE8_DEVICE_HANDLER (b2m_8255_portb_w )
+{
+ b2m_state *state = device->machine().driver_data<b2m_state>();
+ state->m_b2m_video_scroll = data;
+}
+
+static WRITE8_DEVICE_HANDLER (b2m_8255_portc_w )
+{
+ b2m_state *state = device->machine().driver_data<b2m_state>();
+
+ state->m_b2m_8255_portc = data;
+ b2m_set_bank(device->machine(), state->m_b2m_8255_portc & 7);
+ state->m_b2m_video_page = (state->m_b2m_8255_portc >> 7) & 1;
+}
+
+static READ8_DEVICE_HANDLER (b2m_8255_portb_r )
+{
+ b2m_state *state = device->machine().driver_data<b2m_state>();
+ return state->m_b2m_video_scroll;
+}
+
+I8255A_INTERFACE( b2m_ppi8255_interface_1 )
+{
+ DEVCB_NULL,
+ DEVCB_DEVICE_HANDLER("ppi8255_1", b2m_8255_porta_w),
+ DEVCB_DEVICE_HANDLER("ppi8255_1", b2m_8255_portb_r),
+ DEVCB_DEVICE_HANDLER("ppi8255_1", b2m_8255_portb_w),
+ DEVCB_NULL,
+ DEVCB_DEVICE_HANDLER("ppi8255_1", b2m_8255_portc_w)
+};
+
+
+
+static WRITE8_DEVICE_HANDLER (b2m_ext_8255_portc_w )
+{
+ UINT8 drive = ((data >> 1) & 1) ^ 1;
+ UINT8 side = (data & 1) ^ 1;
+ b2m_state *state = device->machine().driver_data<b2m_state>();
+ floppy_mon_w(floppy_get_device(device->machine(), 0), 1);
+ floppy_mon_w(floppy_get_device(device->machine(), 1), 1);
+
+ if (state->m_b2m_drive!=drive) {
+ wd17xx_set_drive(state->m_fdc,drive);
+ floppy_mon_w(floppy_get_device(device->machine(), 0), 0);
+ floppy_drive_set_ready_state(floppy_get_device(device->machine(), 0), 1, 1);
+ state->m_b2m_drive = drive;
+ }
+ if (state->m_b2m_side!=side) {
+ wd17xx_set_side(state->m_fdc,side);
+ floppy_mon_w(floppy_get_device(device->machine(), 1), 0);
+ floppy_drive_set_ready_state(floppy_get_device(device->machine(), 1), 1, 1);
+ state->m_b2m_side = side;
+ }
+ wd17xx_dden_w(state->m_fdc, 0);
+}
+
+I8255A_INTERFACE( b2m_ppi8255_interface_2 )
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_HANDLER("ppi8255_2", b2m_ext_8255_portc_w)
+};
+
+static READ8_DEVICE_HANDLER (b2m_romdisk_porta_r )
+{
+ b2m_state *state = device->machine().driver_data<b2m_state>();
+
+ UINT8 *romdisk = state->memregion("maincpu")->base() + 0x12000;
+ return romdisk[state->m_b2m_romdisk_msb*256+state->m_b2m_romdisk_lsb];
+}
+
+static WRITE8_DEVICE_HANDLER (b2m_romdisk_portb_w )
+{
+ b2m_state *state = device->machine().driver_data<b2m_state>();
+ state->m_b2m_romdisk_lsb = data;
+}
+
+static WRITE8_DEVICE_HANDLER (b2m_romdisk_portc_w )
+{
+ b2m_state *state = device->machine().driver_data<b2m_state>();
+ state->m_b2m_romdisk_msb = data & 0x7f;
+}
+
+I8255A_INTERFACE( b2m_ppi8255_interface_3 )
+{
+ DEVCB_DEVICE_HANDLER("ppi8255_3", b2m_romdisk_porta_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_HANDLER("ppi8255_3", b2m_romdisk_portb_w),
+ DEVCB_NULL,
+ DEVCB_DEVICE_HANDLER("ppi8255_3", b2m_romdisk_portc_w)
+};
+
+static WRITE_LINE_DEVICE_HANDLER( b2m_pic_set_int_line )
+{
+ cputag_set_input_line(device->machine(), "maincpu", 0, state ? HOLD_LINE : CLEAR_LINE);
+}
+
+/* Driver initialization */
+DRIVER_INIT_MEMBER(b2m_state,b2m)
+{
+ m_vblank_state = 0;
+}
+
+WRITE8_MEMBER(b2m_state::b2m_palette_w)
+{
+
+ UINT8 b = (3 - ((data >> 6) & 3)) * 0x55;
+ UINT8 g = (3 - ((data >> 4) & 3)) * 0x55;
+ UINT8 r = (3 - ((data >> 2) & 3)) * 0x55;
+
+ UINT8 bw = (3 - (data & 3)) * 0x55;
+
+ m_b2m_color[offset & 3] = data;
+
+ if (ioport("MONITOR")->read()==1) {
+ palette_set_color_rgb(machine(),offset, r, g, b);
+ } else {
+ palette_set_color_rgb(machine(),offset, bw, bw, bw);
+ }
+}
+
+READ8_MEMBER(b2m_state::b2m_palette_r)
+{
+ return m_b2m_color[offset];
+}
+
+WRITE8_MEMBER(b2m_state::b2m_localmachine_w)
+{
+ m_b2m_localmachine = data;
+}
+
+READ8_MEMBER(b2m_state::b2m_localmachine_r)
+{
+ return m_b2m_localmachine;
+}
+
+static void b2m_postload(b2m_state *state)
+{
+ b2m_set_bank(state->machine(), state->m_b2m_8255_portc & 7);
+}
+
+MACHINE_START(b2m)
+{
+ b2m_state *state = machine.driver_data<b2m_state>();
+ state->m_pic = machine.device("pic8259");
+ state->m_fdc = machine.device("wd1793");
+ state->m_speaker = machine.device(SPEAKER_TAG);
+
+ wd17xx_set_pause_time(state->m_fdc,10);
+
+ /* register for state saving */
+ state->save_item(NAME(state->m_b2m_8255_porta));
+ state->save_item(NAME(state->m_b2m_video_scroll));
+ state->save_item(NAME(state->m_b2m_8255_portc));
+ state->save_item(NAME(state->m_b2m_video_page));
+ state->save_item(NAME(state->m_b2m_drive));
+ state->save_item(NAME(state->m_b2m_side));
+ state->save_item(NAME(state->m_b2m_romdisk_lsb));
+ state->save_item(NAME(state->m_b2m_romdisk_msb));
+ state->save_pointer(NAME(state->m_b2m_color), 4);
+ state->save_item(NAME(state->m_b2m_localmachine));
+ state->save_item(NAME(state->m_vblank_state));
+
+ machine.save().register_postload(save_prepost_delegate(FUNC(b2m_postload), state));
+}
+
+static IRQ_CALLBACK(b2m_irq_callback)
+{
+ b2m_state *state = device->machine().driver_data<b2m_state>();
+ return pic8259_acknowledge(state->m_pic);
+}
+
+const struct pic8259_interface b2m_pic8259_config =
+{
+ DEVCB_LINE(b2m_pic_set_int_line),
+ DEVCB_LINE_VCC,
+ DEVCB_NULL
+};
+
+INTERRUPT_GEN( b2m_vblank_interrupt )
+{
+ b2m_state *state = device->machine().driver_data<b2m_state>();
+ state->m_vblank_state++;
+ if (state->m_vblank_state>1) state->m_vblank_state=0;
+ pic8259_ir0_w(state->m_pic, state->m_vblank_state);
+}
+
+MACHINE_RESET(b2m)
+{
+ b2m_state *state = machine.driver_data<b2m_state>();
+ state->m_b2m_side = 0;
+ state->m_b2m_drive = 0;
+
+ device_set_irq_callback(machine.device("maincpu"), b2m_irq_callback);
+ b2m_set_bank(machine, 7);
+}
diff --git a/src/mess/machine/bbc.c b/src/mess/machine/bbc.c
new file mode 100644
index 00000000000..a346403c5e2
--- /dev/null
+++ b/src/mess/machine/bbc.c
@@ -0,0 +1,2136 @@
+/******************************************************************************
+ BBC Model B
+
+ MESS Driver By:
+
+ Gordon Jefferyes
+ mess_bbc@romvault.com
+
+******************************************************************************/
+
+#include <ctype.h>
+#include "emu.h"
+#include "cpu/m6502/m6502.h"
+#include "sound/sn76496.h"
+#include "sound/tms5220.h"
+#include "machine/6522via.h"
+#include "machine/wd17xx.h"
+#include "imagedev/flopdrv.h"
+#include "includes/bbc.h"
+#include "machine/upd7002.h"
+#include "machine/i8271.h"
+#include "machine/mc146818.h"
+#include "machine/mc6854.h"
+#include "machine/ctronics.h"
+#include "imagedev/cassette.h"
+
+
+void bbc_state::check_interrupts()
+{
+ m_maincpu->set_input_line(M6502_IRQ_LINE, m_via_system_irq || m_via_user_irq || !m_acia_irq || m_ACCCON_IRR);
+}
+
+/*************************
+Model A memory handling functions
+*************************/
+
+/* for the model A just address the 4 on board ROM sockets */
+WRITE8_MEMBER(bbc_state::bbc_page_selecta_w)
+{
+ membank("bank4")->set_base(machine().root_device().memregion("user1")->base()+((data&0x03)<<14));
+}
+
+
+WRITE8_MEMBER(bbc_state::bbc_memorya1_w)
+{
+ memregion("maincpu")->base()[offset]=data;
+}
+
+/*************************
+Model B memory handling functions
+*************************/
+
+/* the model B address all 16 of the ROM sockets */
+/* I have set bank 1 as a special case to load different DFS roms selectable from MESS's DIP settings var:bbc_DFSTypes */
+WRITE8_MEMBER(bbc_state::bbc_page_selectb_w)
+{
+ m_rombank=data&0x0f;
+ if (m_rombank!=1)
+ {
+ membank("bank4")->set_base(machine().root_device().memregion("user1")->base() + (m_rombank << 14));
+ }
+ else
+ {
+ membank("bank4")->set_base(machine().root_device().memregion("user2")->base() + ((m_DFSType) << 14));
+ }
+}
+
+
+WRITE8_MEMBER(bbc_state::bbc_memoryb3_w)
+{
+ if (m_RAMSize)
+ {
+ memregion("maincpu")->base()[offset + 0x4000] = data;
+ }
+ else
+ {
+ memregion("maincpu")->base()[offset] = data;
+ }
+
+}
+
+/* I have setup 3 types of sideways ram:
+0: none
+1: 128K (bank 8 to 15) Solidisc sidewaysram userport bank latch
+2: 64K (banks 4 to 7) for Acorn sideways ram FE30 bank latch
+3: 128K (banks 8 to 15) for Acown sideways ram FE30 bank latch
+*/
+static const unsigned short bbc_SWRAMtype1[16]={0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1};
+static const unsigned short bbc_SWRAMtype2[16]={0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0};
+static const unsigned short bbc_SWRAMtype3[16]={0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1};
+
+WRITE8_MEMBER(bbc_state::bbc_memoryb4_w)
+{
+ if (m_rombank == 1)
+ {
+ // special DFS case for Acorn DFS E00 Hack that can write to the DFS RAM Bank;
+ if (m_DFSType == 3) memregion("user2")->base()[((m_DFSType) << 14) + offset] = data;
+ } else
+ {
+ switch (m_SWRAMtype)
+ {
+ case 1: if (bbc_SWRAMtype1[m_userport]) memregion("user1")->base()[(m_userport << 14) + offset] = data;
+ case 2: if (bbc_SWRAMtype2[m_rombank]) memregion("user1")->base()[(m_rombank << 14) + offset] = data;
+ case 3: if (bbc_SWRAMtype3[m_rombank]) memregion("user1")->base()[(m_rombank << 14) + offset] = data;
+ }
+ }
+}
+
+/****************************************/
+/* BBC B Plus memory handling function */
+/****************************************/
+
+
+/* this function should return true if
+ the instruction is in the VDU driver address ranged
+ these are set when:
+ PC is in the range c000 to dfff
+ or if pagedRAM set and PC is in the range a000 to afff
+*/
+static int vdudriverset(running_machine &machine)
+{
+ bbc_state *state = machine.driver_data<bbc_state>();
+ int PC;
+ PC = cpu_get_pc(machine.device("maincpu")); // this needs to be set to the 6502 program counter
+ return (((PC >= 0xc000) && (PC <= 0xdfff)) || ((state->m_pagedRAM) && ((PC >= 0xa000) && (PC <= 0xafff))));
+}
+
+
+/* the model B Plus addresses all 16 of the ROM sockets plus the extra 12K of ram at 0x8000
+ and 20K of shadow ram at 0x3000 */
+WRITE8_MEMBER(bbc_state::bbc_page_selectbp_w)
+{
+ if ((offset&0x04)==0)
+ {
+ m_pagedRAM = (data >> 7) & 0x01;
+ m_rombank = data & 0x0f;
+
+ if (m_pagedRAM)
+ {
+ /* if paged ram then set 8000 to afff to read from the ram 8000 to afff */
+ membank("bank4")->set_base(machine().root_device().memregion("maincpu")->base() + 0x8000);
+ }
+ else
+ {
+ /* if paged rom then set the rom to be read from 8000 to afff */
+ membank("bank4")->set_base(machine().root_device().memregion("user1")->base() + (m_rombank << 14));
+ };
+
+ /* set the rom to be read from b000 to bfff */
+ membank("bank6")->set_entry(m_rombank);
+ }
+ else
+ {
+ //the video display should now use this flag to display the shadow ram memory
+ m_vdusel=(data>>7)&0x01;
+ bbcbp_setvideoshadow(machine(), m_vdusel);
+ //need to make the video display do a full screen refresh for the new memory area
+ membank("bank2")->set_base(machine().root_device().memregion("maincpu")->base()+0x3000);
+ }
+}
+
+
+/* write to the normal memory from 0x0000 to 0x2fff
+ the writes to this memory are just done the normal
+ way */
+
+WRITE8_MEMBER(bbc_state::bbc_memorybp1_w)
+{
+ memregion("maincpu")->base()[offset]=data;
+}
+
+
+/* the next two function handle reads and write to the shadow video ram area
+ between 0x3000 and 0x7fff
+
+ when vdusel is set high the video display uses the shadow ram memory
+ the processor only reads and write to the shadow ram when vdusel is set
+ and when the instruction being executed is stored in a set range of memory
+ addresses known as the VDU driver instructions.
+*/
+
+
+DIRECT_UPDATE_MEMBER(bbc_state::bbcbp_direct_handler)
+{
+ UINT8 *ram = memregion("maincpu")->base();
+ if (m_vdusel == 0)
+ {
+ // not in shadow ram mode so just read normal ram
+ membank("bank2")->set_base(ram + 0x3000);
+ }
+ else
+ {
+ if (vdudriverset(machine()))
+ {
+ // if VDUDriver set then read from shadow ram
+ membank("bank2")->set_base(ram + 0xb000);
+ }
+ else
+ {
+ // else read from normal ram
+ membank("bank2")->set_base(ram + 0x3000);
+ }
+ }
+ return address;
+}
+
+
+WRITE8_MEMBER(bbc_state::bbc_memorybp2_w)
+{
+ UINT8 *ram = memregion("maincpu")->base();
+ if (m_vdusel==0)
+ {
+ // not in shadow ram mode so just write to normal ram
+ ram[offset + 0x3000] = data;
+ }
+ else
+ {
+ if (vdudriverset(machine()))
+ {
+ // if VDUDriver set then write to shadow ram
+ ram[offset + 0xb000] = data;
+ }
+ else
+ {
+ // else write to normal ram
+ ram[offset + 0x3000] = data;
+ }
+ }
+}
+
+
+/* if the pagedRAM is set write to RAM between 0x8000 to 0xafff
+otherwise this area contains ROM so no write is required */
+WRITE8_MEMBER(bbc_state::bbc_memorybp4_w)
+{
+ if (m_pagedRAM)
+ {
+ memregion("maincpu")->base()[offset+0x8000]=data;
+ }
+}
+
+
+/* the BBC B plus 128K had extra ram mapped in replacing the
+rom bank 0,1,c and d.
+The function memorybp3_128_w handles memory writes from 0x8000 to 0xafff
+which could either be sideways ROM, paged RAM, or sideways RAM.
+The function memorybp4_128_w handles memory writes from 0xb000 to 0xbfff
+which could either be sideways ROM or sideways RAM */
+
+
+static const unsigned short bbc_b_plus_sideways_ram_banks[16]={ 1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0 };
+
+
+WRITE8_MEMBER(bbc_state::bbc_memorybp4_128_w)
+{
+ if (m_pagedRAM)
+ {
+ memregion("maincpu")->base()[offset+0x8000]=data;
+ }
+ else
+ {
+ if (bbc_b_plus_sideways_ram_banks[m_rombank])
+ {
+ memregion("user1")->base()[offset+(m_rombank<<14)]=data;
+ }
+ }
+}
+
+WRITE8_MEMBER(bbc_state::bbc_memorybp6_128_w)
+{
+ if (bbc_b_plus_sideways_ram_banks[m_rombank])
+ {
+ memregion("user1")->base()[offset+(m_rombank<<14)+0x3000]=data;
+ }
+}
+
+
+
+/****************************************/
+/* BBC Master functions */
+/****************************************/
+
+/*
+ROMSEL - &FE30 write Only
+B7 RAM 1=Page in ANDY &8000-&8FFF
+ 0=Page in ROM &8000-&8FFF
+B6 Not Used
+B5 Not Used
+B4 Not Used
+B3-B0 Rom/Ram Bank Select
+
+ACCCON
+
+b7 IRR 1=Causes an IRQ to the processor
+b6 TST 1=Selects &FC00-&FEFF read from OS-ROM
+b5 IFJ 1=Internal 1 MHz bus
+ 0=External 1MHz bus
+b4 ITU 1=Internal Tube
+ 0=External Tube
+b3 Y 1=Read/Write HAZEL &C000-&DFFF RAM
+ 0=Read/Write ROM &C000-&DFFF OS-ROM
+b2 X 1=Read/Write LYNNE
+ 0=Read/WRITE main memory &3000-&8000
+b1 E 1=Causes shadow if VDU code
+ 0=Main all the time
+b0 D 1=Display LYNNE as screen
+ 0=Display main RAM screen
+
+ACCCON is a read/write register
+
+HAZEL is the 8K of RAM used by the MOS,filling system, and other Roms at &C000-&DFFF
+
+ANDY is the name of the 4K of RAM used by the MOS at &8000-&8FFF
+
+b7:This causes an IRQ to occur. If you set this bit, you must write a routine on IRQ2V to clear it.
+
+b6:If set, this switches in the ROM at &FD00-&FEFF for reading, writes to these addresses are still directed to the I/O
+The MOS will not work properly with this but set. the Masters OS uses this feature to place some of the reset code in this area,
+which is run at powerup.
+
+b3:If set, access to &C000-&DFFF are directed to HAZEL, an 8K bank of RAM. IF clear, then operating system ROM is read.
+
+b2:If set, read/write access to &3000-&7FFF are directed to the LYNNE, the shadow screen RAM. If clear access is made to the main RAM.
+
+b1:If set, when the program counter is between &C000 and &DFFF, read/write access is directed to the LYNNE shadow RAM.
+if the program counter is anywhere else main ram is accessed.
+
+*/
+
+
+READ8_MEMBER(bbc_state::bbcm_ACCCON_read)
+{
+ logerror("ACCCON read %d\n",offset);
+ return m_ACCCON;
+}
+
+WRITE8_MEMBER(bbc_state::bbcm_ACCCON_write)
+{
+ int tempIRR;
+ m_ACCCON=data;
+
+ logerror("ACCCON write %d %d \n",offset,data);
+
+ tempIRR=m_ACCCON_IRR;
+
+
+ m_ACCCON_IRR=(data>>7)&1;
+ m_ACCCON_TST=(data>>6)&1;
+ m_ACCCON_IFJ=(data>>5)&1;
+ m_ACCCON_ITU=(data>>4)&1;
+ m_ACCCON_Y =(data>>3)&1;
+ m_ACCCON_X =(data>>2)&1;
+ m_ACCCON_E =(data>>1)&1;
+ m_ACCCON_D =(data>>0)&1;
+
+ if (tempIRR!=m_ACCCON_IRR)
+ {
+ check_interrupts();
+ }
+
+ if (m_ACCCON_Y)
+ {
+ membank("bank7")->set_base(machine().root_device().memregion("maincpu")->base() + 0x9000);
+ }
+ else
+ {
+ membank("bank7")->set_base(machine().root_device().memregion("user1")->base() + 0x40000);
+ }
+
+ bbcbp_setvideoshadow(machine(), m_ACCCON_D);
+
+
+ if (m_ACCCON_X)
+ {
+ membank("bank2")->set_base(machine().root_device().memregion( "maincpu" )->base() + 0xb000 );
+ }
+ else
+ {
+ membank("bank2")->set_base(machine().root_device().memregion( "maincpu" )->base() + 0x3000 );
+ }
+
+ /* ACCCON_TST controls paging of rom reads in the 0xFC00-0xFEFF reigon */
+ /* if 0 the I/O is paged for both reads and writes */
+ /* if 1 the the ROM is paged in for reads but writes still go to I/O */
+ if (m_ACCCON_TST)
+ {
+ membank("bank8")->set_base(machine().root_device().memregion("user1")->base()+0x43c00);
+ space.install_read_bank(0xFC00,0xFEFF,"bank8");
+ }
+ else
+ {
+ space.install_read_handler(0xFC00,0xFEFF,read8_delegate(FUNC(bbc_state::bbcm_r),this));
+ }
+
+}
+
+
+static int bbcm_vdudriverset(running_machine &machine)
+{
+ int PC;
+ PC = cpu_get_pc(machine.device("maincpu"));
+ return ((PC >= 0xc000) && (PC <= 0xdfff));
+}
+
+
+WRITE8_MEMBER(bbc_state::page_selectbm_w)
+{
+ m_pagedRAM = (data & 0x80) >> 7;
+ m_rombank = data & 0x0f;
+
+ if (m_pagedRAM)
+ {
+ membank("bank4")->set_base(machine().root_device().memregion("maincpu")->base() + 0x8000);
+ membank("bank5")->set_entry(m_rombank);
+ }
+ else
+ {
+ membank("bank4")->set_base(machine().root_device().memregion("user1")->base() + ((m_rombank) << 14));
+ membank("bank5")->set_entry(m_rombank);
+ }
+}
+
+
+
+WRITE8_MEMBER(bbc_state::bbc_memorybm1_w)
+{
+ memregion("maincpu")->base()[offset] = data;
+}
+
+
+DIRECT_UPDATE_MEMBER(bbc_state::bbcm_direct_handler)
+{
+ if (m_ACCCON_X)
+ {
+ membank( "bank2" )->set_base( memregion( "maincpu" )->base() + 0xb000 );
+ }
+ else
+ {
+ if (m_ACCCON_E && bbcm_vdudriverset(machine()))
+ {
+ membank( "bank2" )->set_base( machine().root_device().memregion( "maincpu" )->base() + 0xb000 );
+ }
+ else
+ {
+ membank( "bank2" )->set_base( machine().root_device().memregion( "maincpu" )->base() + 0x3000 );
+ }
+ }
+
+ return address;
+}
+
+
+
+WRITE8_MEMBER(bbc_state::bbc_memorybm2_w)
+{
+ UINT8 *ram = memregion("maincpu")->base();
+ if (m_ACCCON_X)
+ {
+ ram[offset + 0xb000] = data;
+ }
+ else
+ {
+ if (m_ACCCON_E && bbcm_vdudriverset(machine()))
+ {
+ ram[offset + 0xb000] = data;
+ }
+ else
+ {
+ ram[offset + 0x3000] = data;
+ }
+ }
+}
+
+static const unsigned short bbc_master_sideways_ram_banks[16]=
+{
+ 0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0
+};
+
+
+WRITE8_MEMBER(bbc_state::bbc_memorybm4_w)
+{
+ if (m_pagedRAM)
+ {
+ memregion("maincpu")->base()[offset+0x8000]=data;
+ }
+ else
+ {
+ if (bbc_master_sideways_ram_banks[m_rombank])
+ {
+ memregion("user1")->base()[offset+(m_rombank<<14)]=data;
+ }
+ }
+}
+
+
+WRITE8_MEMBER(bbc_state::bbc_memorybm5_w)
+{
+ if (bbc_master_sideways_ram_banks[m_rombank])
+ {
+ memregion("user1")->base()[offset+(m_rombank<<14)+0x1000]=data;
+ }
+}
+
+
+WRITE8_MEMBER(bbc_state::bbc_memorybm7_w)
+{
+ if (m_ACCCON_Y)
+ {
+ memregion("maincpu")->base()[offset+0x9000]=data;
+ }
+}
+
+
+
+/******************************************************************************
+&FC00-&FCFF FRED
+&FD00-&FDFF JIM
+&FE00-&FEFF SHEILA Read Write
+&00-&07 6845 CRTC Video controller Video Controller 8 ( 2 bytes x 4 )
+&08-&0F 6850 ACIA Serial controller Serial Controller 8 ( 2 bytes x 4 )
+&10-&17 Serial ULA - Serial system chip 8 ( 1 byte x 8 )
+&18-&1F uPD7002 A to D converter A to D converter 8 ( 4 bytes x 2 )
+&20-&23 Video ULA - Video system chip 4 ( 2 bytes x 2 )
+&24-&27 FDC Latch 1770 Control latch 1770 Control latch 4 ( 1 byte x 4 )
+&28-&2F 1770 registers 1770 Disc Controller 1170 Disc Controller 8 ( 4 bytes x 2 )
+&30-&33 ROMSEL - ROM Select 4 ( 1 byte x 4 )
+&34-&37 ACCCON ACCCON select reg. ACCCON select reg 4 ( 1 byte x 4 )
+&38-&3F NC - -
+&40-&5F 6522 VIA SYSTEM VIA SYSTEM VIA 32 (16 bytes x 2 ) 1MHz
+&60-&7F 6522 VIA USER VIA USER VIA 32 (16 bytes x 2 ) 1MHz
+&80-&9F Int. Modem Int. Modem Int Modem
+&A0-&BF 68B54 ADLC ECONET controller ECONET controller 32 ( 4 bytes x 8 ) 2MHz
+&C0-&DF NC - -
+&E0-&FF Tube ULA Tube system interface Tube system interface 32 (32 bytes x 1 ) 2MHz
+******************************************************************************/
+
+READ8_MEMBER(bbc_state::bbcm_r)
+{
+long myo;
+
+ /* Now handled in bbcm_ACCCON_write PHS - 2008-10-11 */
+// if ( m_ACCCON_TST )
+// {
+// return memregion("user1")->base()[offset+0x43c00];
+// };
+
+ if (offset<=0x0ff) /* FRED */
+ {
+ return 0xff;
+ };
+
+ if ((offset>=0x100) && (offset<=0x1ff)) /* JIM */
+ {
+ return 0xff;
+ };
+
+
+ if ((offset>=0x200) && (offset<=0x2ff)) /* SHEILA */
+ {
+ via6522_device *via_0 = machine().device<via6522_device>("via6522_0");
+ via6522_device *via_1 = machine().device<via6522_device>("via6522_1");
+ device_t *adlc = machine().device("mc6854");
+
+ myo=offset-0x200;
+ if ((myo>=0x00) && (myo<=0x07)) return bbc_6845_r(space, myo-0x00); /* Video Controller */
+ if ((myo>=0x08) && (myo<=0x0f))
+ {
+ acia6850_device *acia = machine().device<acia6850_device>("acia6850");
+
+ if ((myo - 0x08) & 1)
+ return acia->status_read(space,0);
+ else
+ return acia->data_read(space,0);
+ }
+ if ((myo>=0x10) && (myo<=0x17)) return 0xfe; /* Serial System Chip */
+ if ((myo>=0x18) && (myo<=0x1f)) return uPD7002_r(machine().device("upd7002"), myo-0x18); /* A to D converter */
+ if ((myo>=0x20) && (myo<=0x23)) return 0xfe; /* VideoULA */
+ if ((myo>=0x24) && (myo<=0x27)) return bbcm_wd1770l_read(space, myo-0x24); /* 1770 */
+ if ((myo>=0x28) && (myo<=0x2f)) return bbcm_wd1770_read(space, myo-0x28); /* disc control latch */
+ if ((myo>=0x30) && (myo<=0x33)) return 0xfe; /* page select */
+ if ((myo>=0x34) && (myo<=0x37)) return bbcm_ACCCON_read(space, myo-0x34); /* ACCCON */
+ if ((myo>=0x38) && (myo<=0x3f)) return 0xfe; /* NC ?? */
+ if ((myo>=0x40) && (myo<=0x5f)) return via_0->read(space,myo-0x40);
+ if ((myo>=0x60) && (myo<=0x7f)) return via_1->read(space,myo-0x60);
+ if ((myo>=0x80) && (myo<=0x9f)) return 0xfe;
+ if ((myo>=0xa0) && (myo<=0xbf)) return mc6854_r(adlc, myo & 0x03);
+ if ((myo>=0xc0) && (myo<=0xdf)) return 0xfe;
+ if ((myo>=0xe0) && (myo<=0xff)) return 0xfe;
+ }
+
+ return 0xfe;
+}
+
+WRITE8_MEMBER(bbc_state::bbcm_w)
+{
+long myo;
+
+ if ((offset>=0x200) && (offset<=0x2ff)) /* SHEILA */
+ {
+ via6522_device *via_0 = machine().device<via6522_device>("via6522_0");
+ via6522_device *via_1 = machine().device<via6522_device>("via6522_1");
+ device_t *adlc = machine().device("mc6854");
+
+ myo=offset-0x200;
+ if ((myo>=0x00) && (myo<=0x07)) bbc_6845_w(space, myo-0x00,data); /* Video Controller */
+ if ((myo>=0x08) && (myo<=0x0f))
+ {
+ acia6850_device *acia = machine().device<acia6850_device>("acia6850");
+
+ if ((myo - 0x08) & 1)
+ acia->control_write(space, 0, data);
+ else
+ acia->data_write(space, 0, data);
+ }
+ if ((myo>=0x10) && (myo<=0x17)) bbc_SerialULA_w(space, myo-0x10,data); /* Serial System Chip */
+ if ((myo>=0x18) && (myo<=0x1f)) uPD7002_w(machine().device("upd7002"),myo-0x18,data); /* A to D converter */
+ if ((myo>=0x20) && (myo<=0x23)) bbc_videoULA_w(space, myo-0x20,data); /* VideoULA */
+ if ((myo>=0x24) && (myo<=0x27)) bbcm_wd1770l_write(space, myo-0x24,data); /* 1770 */
+ if ((myo>=0x28) && (myo<=0x2f)) bbcm_wd1770_write(space, myo-0x28,data); /* disc control latch */
+ if ((myo>=0x30) && (myo<=0x33)) page_selectbm_w(space, myo-0x30,data); /* page select */
+ if ((myo>=0x34) && (myo<=0x37)) bbcm_ACCCON_write(space, myo-0x34,data); /* ACCCON */
+ //if ((myo>=0x38) && (myo<=0x3f)) /* NC ?? */
+ if ((myo>=0x40) && (myo<=0x5f)) via_0->write(space,myo-0x40, data);
+ if ((myo>=0x60) && (myo<=0x7f)) via_1->write(space,myo-0x60, data);
+ //if ((myo>=0x80) && (myo<=0x9f))
+ if ((myo>=0xa0) && (myo<=0xbf)) mc6854_w(adlc, myo & 0x03, data);
+ //if ((myo>=0xc0) && (myo<=0xdf))
+ //if ((myo>=0xe0) && (myo<=0xff))
+ }
+
+}
+
+
+/******************************************************************************
+
+System VIA 6522
+
+PA0-PA7
+Port A forms a slow data bus to the keyboard sound and speech processors
+PortA Keyboard
+D0 Pin 8
+D1 Pin 9
+D2 Pin 10
+D3 Pin 11
+D4 Pin 5
+D5 Pin 6
+D6 Pin 7
+D7 Pin 12
+
+PB0-PB2 outputs
+---------------
+These 3 outputs form the address to an 8 bit addressable latch.
+(IC32 74LS259)
+
+
+PB3 output
+----------
+This output holds the data to be written to the selected
+addressable latch bit.
+
+
+PB4 and PB5 inputs
+These are the inputs from the joystick FIRE buttons. They are
+normally at logic 1 with no button pressed and change to 0
+when a button is pressed.
+
+
+PB6 and PB7 inputs from the speech processor
+PB6 is the speech processor 'ready' output and PB7 is from the
+speech processor 'interrupt' output.
+
+
+CA1 input
+This is the vertical sync input from the 6845. CA1 is set up to
+interrupt the 6502 every 20ms (50Hz) as a vertical sync from
+the video circuity is detected. The operation system changes
+the flash colours on the display in this interrupt time so that
+they maintain synchronisation with the rest of the picture.
+----------------------------------------------------------------
+This is required for a lot of time function within the machine
+and must be triggered every 20ms. (Should check at some point
+how this 20ms signal is made, and see if none standard shapped
+screen modes change this time period.)
+
+
+CB1 input
+The CB1 input is the end of conversion (EOC) signal from the
+7002 analogue to digital converter. It can be used to interrupt
+the 6502 whenever a conversion is complete.
+
+
+CA2 input
+This input comes from the keyboard circuit, and is used to
+generate an interrupt whenever a key is pressed. See the
+keyboard circuit section for more details.
+
+
+
+CB2 input
+This is the light pen strobe signal (LPSTB) from the light pen.
+If also connects to the 6845 video processor,
+CB2 can be programmed to interrupt the processor whenever
+a light pen strobe occurs.
+----------------------------------------------------------------
+CB2 is not needed in the initial emulation
+and should be set to logic low, should be mapped through to
+a light pen emulator later.
+
+IRQ output
+This connects to the IRQ line of the 6502
+
+
+The addressable latch
+This 8 bit addressable latch is operated from port B lines 0-3.
+PB0-PB2 are set to the required address of the output bit to be set.
+PB3 is set to the value which should be programmed at that bit.
+The function of the 8 output bits from this latch are:-
+
+B0 - Write Enable to the sound generator IC
+B1 - READ select on the speech processor
+B2 - WRITE select on the speech processor
+B3 - Keyboard write enable
+B4,B5 - these two outputs define the number to be added to the
+start of screen address in hardware to control hardware scrolling:-
+Mode Size Start of screen Number to add B5 B4
+0,1,2 20K &3000 12K 1 1
+3 16K &4000 16K 0 0
+4,5 10K &5800 (or &1800) 22K 1 0
+6 8K &6000 (or &2000) 24K 0 1
+B6 - Operates the CAPS lock LED (Pin 17 keyboard connector)
+B7 - Operates the SHIFT lock LED (Pin 16 keyboard connector)
+******************************************************************************/
+
+
+
+INTERRUPT_GEN( bbcb_keyscan )
+{
+ bbc_state *state = device->machine().driver_data<bbc_state>();
+ static const char *const colnames[] = {
+ "COL0", "COL1", "COL2", "COL3", "COL4",
+ "COL5", "COL6", "COL7", "COL8", "COL9"
+ };
+ via6522_device *via_0 = device->machine().device<via6522_device>("via6522_0");
+
+ /* only do auto scan if keyboard is not enabled */
+ if (state->m_b3_keyboard == 1)
+ {
+ /* KBD IC1 4 bit addressable counter */
+ /* KBD IC3 4 to 10 line decoder */
+ /* keyboard not enabled so increment counter */
+ state->m_column = (state->m_column + 1) % 16;
+ if (state->m_column < 10)
+ {
+ /* KBD IC4 8 input NAND gate */
+ /* set the value of via_system ca2, by checking for any keys
+ being pressed on the selected state->m_column */
+ if ((device->machine().root_device().ioport(colnames[state->m_column])->read() | 0x01) != 0xff)
+ {
+ via_0->write_ca2(1);
+ }
+ else
+ {
+ via_0->write_ca2(0);
+ }
+
+ }
+ else
+ {
+ via_0->write_ca2(0);
+ }
+ }
+}
+
+
+INTERRUPT_GEN( bbcm_keyscan )
+{
+ bbc_state *state = device->machine().driver_data<bbc_state>();
+ static const char *const colnames[] = {
+ "COL0", "COL1", "COL2", "COL3", "COL4",
+ "COL5", "COL6", "COL7", "COL8", "COL9"
+ };
+ via6522_device *via_0 = device->machine().device<via6522_device>("via6522_0");
+
+ /* only do auto scan if keyboard is not enabled */
+ if (state->m_b3_keyboard == 1)
+ {
+ /* KBD IC1 4 bit addressable counter */
+ /* KBD IC3 4 to 10 line decoder */
+ /* keyboard not enabled so increment counter */
+ state->m_column = (state->m_column + 1) % 16;
+
+ /* this IF should be removed as soon as the dip switches (keyboard keys) are set for the master */
+ if (state->m_column < 10)
+ {
+ /* KBD IC4 8 input NAND gate */
+ /* set the value of via_system ca2, by checking for any keys
+ being pressed on the selected state->m_column */
+ if ((device->machine().root_device().ioport(colnames[state->m_column])->read() | 0x01) != 0xff)
+ {
+ via_0->write_ca2(1);
+ }
+ else
+ {
+ via_0->write_ca2(0);
+ }
+
+ }
+ else
+ {
+ via_0->write_ca2(0);
+ }
+ }
+}
+
+
+
+static int bbc_keyboard(address_space *space, int data)
+{
+ bbc_state *state = space->machine().driver_data<bbc_state>();
+ int bit;
+ int row;
+ int res;
+ static const char *const colnames[] = {
+ "COL0", "COL1", "COL2", "COL3", "COL4",
+ "COL5", "COL6", "COL7", "COL8", "COL9"
+ };
+ via6522_device *via_0 = space->machine().device<via6522_device>("via6522_0");
+
+ state->m_column = data & 0x0f;
+ row = (data>>4) & 0x07;
+
+ bit = 0;
+
+ if (state->m_column < 10)
+ {
+ res = space->machine().root_device().ioport(colnames[state->m_column])->read();
+ }
+ else
+ {
+ res = 0xff;
+ }
+
+ /* Normal keyboard result */
+ if ((res & (1<<row)) == 0)
+ {
+ bit = 1;
+ }
+
+ if ((res | 1) != 0xff)
+ {
+ via_0->write_ca2(1);
+ }
+ else
+ {
+ via_0->write_ca2(0);
+ }
+
+ return (data & 0x7f) | (bit<<7);
+}
+
+
+static void bbcb_IC32_initialise(bbc_state *state)
+{
+ state->m_b0_sound=0x01; // Sound is negative edge trigered
+ state->m_b1_speech_read=0x01; // ????
+ state->m_b2_speech_write=0x01; // ????
+ state->m_b3_keyboard=0x01; // Keyboard is negative edge trigered
+ state->m_b4_video0=0x01;
+ state->m_b5_video1=0x01;
+ state->m_b6_caps_lock_led=0x01;
+ state->m_b7_shift_lock_led=0x01;
+
+}
+
+
+/* This the BBC Masters Real Time Clock and NVRam IC */
+static void MC146818_set(address_space *space)
+{
+ bbc_state *state = space->machine().driver_data<bbc_state>();
+ logerror ("146181 WR=%d DS=%d AS=%d CE=%d \n",state->m_MC146818_WR,state->m_MC146818_DS,state->m_MC146818_AS,state->m_MC146818_CE);
+ mc146818_device *rtc = space->machine().device<mc146818_device>("rtc");
+
+ // if chip enabled
+ if (state->m_MC146818_CE)
+ {
+ // if data select is set then access the data in the 146818
+ if (state->m_MC146818_DS)
+ {
+ if (state->m_MC146818_WR)
+ {
+ state->m_via_system_porta=rtc->read(*space, 1);
+ //logerror("read 146818 data %d \n",state->m_via_system_porta);
+ }
+ else
+ {
+ rtc->write(*space, 1, state->m_via_system_porta);
+ //logerror("write 146818 data %d \n",state->m_via_system_porta);
+ }
+ }
+
+ // if address select is set then set the address in the 146818
+ if (state->m_MC146818_AS)
+ {
+ rtc->write(*space, 0, state->m_via_system_porta);
+ //logerror("write 146818 address %d \n",state->m_via_system_porta);
+ }
+ }
+}
+
+
+static WRITE8_DEVICE_HANDLER( bbcb_via_system_write_porta )
+{
+ bbc_state *state = device->machine().driver_data<bbc_state>();
+ address_space *space = device->machine().device("maincpu")->memory().space(AS_PROGRAM);
+ //logerror("SYSTEM write porta %d\n",data);
+
+ state->m_via_system_porta = data;
+ if (state->m_b0_sound == 0)
+ {
+ //logerror("Doing an unsafe write to the sound chip %d \n",data);
+ sn76496_w(device->machine().device("sn76489"), 0,state->m_via_system_porta);
+ }
+ if (state->m_b3_keyboard == 0)
+ {
+ //logerror("Doing an unsafe write to the keyboard %d \n",data);
+ state->m_via_system_porta = bbc_keyboard(space, state->m_via_system_porta);
+ }
+ if (state->m_Master) MC146818_set(space);
+}
+
+
+static WRITE8_DEVICE_HANDLER( bbcb_via_system_write_portb )
+{
+ bbc_state *state = device->machine().driver_data<bbc_state>();
+ address_space *space = device->machine().device("maincpu")->memory().space(AS_PROGRAM);
+ int bit, value;
+ bit = data & 0x07;
+ value = (data >> 3) & 0x01;
+
+
+ //logerror("SYSTEM write portb %d %d %d\n",data,bit,value);
+
+ if (value)
+ {
+ switch (bit)
+ {
+ case 0:
+ if (state->m_b0_sound == 0)
+ {
+ state->m_b0_sound = 1;
+ }
+ break;
+ case 1:
+ if (state->m_Master)
+ {
+ if (state->m_MC146818_WR == 0)
+ {
+ /* BBC MASTER has NV RAM Here */
+ state->m_MC146818_WR = 1;
+ MC146818_set(space);
+ }
+ }
+ else
+ {
+ if (state->m_b1_speech_read == 0)
+ {
+ /* VSP TMS 5220 */
+ state->m_b1_speech_read = 1;
+ }
+ }
+ break;
+ case 2:
+ if (state->m_Master)
+ {
+ if (state->m_MC146818_DS == 0)
+ {
+ /* BBC MASTER has NV RAM Here */
+ state->m_MC146818_DS = 1;
+ MC146818_set(space);
+ }
+ }
+ else
+ {
+ if (state->m_b2_speech_write == 0)
+ {
+ /* VSP TMS 5220 */
+ state->m_b2_speech_write = 1;
+ }
+ }
+ break;
+ case 3:
+ if (state->m_b3_keyboard == 0)
+ {
+ state->m_b3_keyboard = 1;
+ }
+ break;
+ case 4:
+ if (state->m_b4_video0 == 0)
+ {
+ state->m_b4_video0 = 1;
+ }
+ break;
+ case 5:
+ if (state->m_b5_video1 == 0)
+ {
+ state->m_b5_video1 = 1;
+ }
+ break;
+ case 6:
+ if (state->m_b6_caps_lock_led == 0)
+ {
+ state->m_b6_caps_lock_led = 1;
+ /* call caps lock led update */
+ }
+ break;
+ case 7:
+ if (state->m_b7_shift_lock_led == 0)
+ {
+ state->m_b7_shift_lock_led = 1;
+ /* call shift lock led update */
+ }
+ break;
+ }
+ }
+ else
+ {
+ switch (bit)
+ {
+ case 0:
+ if (state->m_b0_sound == 1)
+ {
+ state->m_b0_sound = 0;
+ sn76496_w(space->machine().device("sn76489"), 0, state->m_via_system_porta);
+ }
+ break;
+ case 1:
+ if (state->m_Master)
+ {
+ if (state->m_MC146818_WR == 1)
+ {
+ /* BBC MASTER has NV RAM Here */
+ state->m_MC146818_WR = 0;
+ MC146818_set(space);
+ }
+ }
+ else
+ {
+ if (state->m_b1_speech_read == 1)
+ {
+ /* VSP TMS 5220 */
+ state->m_b1_speech_read = 0;
+ }
+ }
+ break;
+ case 2:
+ if (state->m_Master)
+ {
+ if (state->m_MC146818_DS == 1)
+ {
+ /* BBC MASTER has NV RAM Here */
+ state->m_MC146818_DS = 0;
+ MC146818_set(space);
+ }
+ }
+ else
+ {
+ if (state->m_b2_speech_write == 1)
+ {
+ /* VSP TMS 5220 */
+ state->m_b2_speech_write = 0;
+ }
+ }
+ break;
+ case 3:
+ if (state->m_b3_keyboard == 1)
+ {
+ state->m_b3_keyboard = 0;
+ /* *** call keyboard enabled *** */
+ state->m_via_system_porta=bbc_keyboard(space, state->m_via_system_porta);
+ }
+ break;
+ case 4:
+ if (state->m_b4_video0 == 1)
+ {
+ state->m_b4_video0 = 0;
+ }
+ break;
+ case 5:
+ if (state->m_b5_video1 == 1)
+ {
+ state->m_b5_video1 = 0;
+ }
+ break;
+ case 6:
+ if (state->m_b6_caps_lock_led == 1)
+ {
+ state->m_b6_caps_lock_led = 0;
+ /* call caps lock led update */
+ }
+ break;
+ case 7:
+ if (state->m_b7_shift_lock_led == 1)
+ {
+ state->m_b7_shift_lock_led = 0;
+ /* call shift lock led update */
+ }
+ break;
+ }
+ }
+
+
+
+ if (state->m_Master)
+ {
+ //set the Address Select
+ if (state->m_MC146818_AS != ((data>>7)&1))
+ {
+ state->m_MC146818_AS=(data>>7)&1;
+ MC146818_set(space);
+ }
+
+ //if CE changes
+ if (state->m_MC146818_CE != ((data>>6)&1))
+ {
+ state->m_MC146818_CE=(data>>6)&1;
+ MC146818_set(space);
+ }
+ }
+}
+
+
+static READ8_DEVICE_HANDLER( bbcb_via_system_read_porta )
+{
+ bbc_state *state = device->machine().driver_data<bbc_state>();
+ //logerror("SYSTEM read porta %d\n",state->m_via_system_porta);
+ return state->m_via_system_porta;
+}
+
+// D4 of portb is joystick fire button 1
+// D5 of portb is joystick fire button 2
+// D6 VSPINT
+// D7 VSPRDY
+
+/* this is the interupt and ready signal from the BBC B Speech processor */
+static const int TMSint=1;
+static const int TMSrdy=1;
+
+#ifdef UNUSED_FUNCTION
+void bbc_TMSint(int status)
+{
+ TMSint=(!status)&1;
+ TMSrdy=(!tms5220_readyq_r())&1;
+ via_0_portb_w(0,(0xf | machine.root_device().ioport("IN0")->read()|(TMSint<<6)|(TMSrdy<<7)));
+}
+#endif
+
+
+static READ8_DEVICE_HANDLER( bbcb_via_system_read_portb )
+{
+ //TMSint=(!tms5220_int_r())&1;
+ //TMSrdy=(!tms5220_readyq_r())&1;
+
+ //logerror("SYSTEM read portb %d\n",0xf | input_port(machine, "IN0")|(TMSint<<6)|(TMSrdy<<7));
+
+ return (0xf | device->machine().root_device().ioport("IN0")->read()|(TMSint<<6)|(TMSrdy<<7));
+}
+
+
+/* vertical sync pulse from video circuit */
+static READ8_DEVICE_HANDLER( bbcb_via_system_read_ca1 )
+{
+ return 0x01;
+}
+
+
+/* joystick EOC */
+static READ8_DEVICE_HANDLER( bbcb_via_system_read_cb1 )
+{
+ return uPD7002_EOC_r(device->machine().device("upd7002"),0);
+}
+
+
+/* keyboard pressed detect */
+static READ8_DEVICE_HANDLER( bbcb_via_system_read_ca2 )
+{
+ return 0x01;
+}
+
+
+/* light pen strobe detect (not emulated) */
+static READ8_DEVICE_HANDLER( bbcb_via_system_read_cb2 )
+{
+ return 0x01;
+}
+
+
+static WRITE_LINE_DEVICE_HANDLER( bbcb_via_system_irq_w )
+{
+ bbc_state *driver_state = device->machine().driver_data<bbc_state>();
+ driver_state->m_via_system_irq = state;
+
+ driver_state->check_interrupts();
+}
+
+const via6522_interface bbcb_system_via =
+{
+ DEVCB_HANDLER(bbcb_via_system_read_porta),
+ DEVCB_HANDLER(bbcb_via_system_read_portb),
+ DEVCB_HANDLER(bbcb_via_system_read_ca1),
+ DEVCB_HANDLER(bbcb_via_system_read_cb1),
+ DEVCB_HANDLER(bbcb_via_system_read_ca2),
+ DEVCB_HANDLER(bbcb_via_system_read_cb2),
+ DEVCB_HANDLER(bbcb_via_system_write_porta),
+ DEVCB_HANDLER(bbcb_via_system_write_portb),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_LINE(bbcb_via_system_irq_w)
+};
+
+
+/**********************************************************************
+USER VIA
+Port A output is buffered before being connected to the printer connector.
+This means that they can only be operated as output lines.
+CA1 is pulled high by a 4K7 resistor. CA1 normally acts as an acknowledge
+line when a printer is used. CA2 is buffered so that it has become an open
+collector output only. It usially acts as the printer strobe line.
+***********************************************************************/
+
+/* USER VIA 6522 port B is connected to the BBC user port */
+static READ8_DEVICE_HANDLER( bbcb_via_user_read_portb )
+{
+ return 0xff;
+}
+
+static WRITE8_DEVICE_HANDLER( bbcb_via_user_write_portb )
+{
+ bbc_state *state = device->machine().driver_data<bbc_state>();
+ state->m_userport = data;
+}
+
+static WRITE_LINE_DEVICE_HANDLER( bbcb_via_user_irq_w )
+{
+ bbc_state *driver_state = device->machine().driver_data<bbc_state>();
+ driver_state->m_via_user_irq = state;
+
+ driver_state->check_interrupts();
+}
+
+const via6522_interface bbcb_user_via =
+{
+ DEVCB_NULL, //via_user_read_porta,
+ DEVCB_HANDLER(bbcb_via_user_read_portb),
+ DEVCB_NULL, //via_user_read_ca1,
+ DEVCB_NULL, //via_user_read_cb1,
+ DEVCB_NULL, //via_user_read_ca2,
+ DEVCB_NULL, //via_user_read_cb2,
+ DEVCB_DEVICE_MEMBER("centronics", centronics_device, write),
+ DEVCB_HANDLER(bbcb_via_user_write_portb),
+ DEVCB_NULL, //via_user_write_ca1
+ DEVCB_NULL, //via_user_write_cb1
+ DEVCB_DEVICE_LINE_MEMBER("centronics", centronics_device, strobe_w),
+ DEVCB_NULL, //via_user_write_cb2,
+ DEVCB_LINE(bbcb_via_user_irq_w)
+};
+
+
+/**************************************
+BBC Joystick Support
+**************************************/
+
+static UPD7002_GET_ANALOGUE(BBC_get_analogue_input)
+{
+ switch(channel_number)
+ {
+ case 0:
+ return ((0xff-device->machine().root_device().ioport("JOY0")->read())<<8);
+ case 1:
+ return ((0xff-device->machine().root_device().ioport("JOY1")->read())<<8);
+ case 2:
+ return ((0xff-device->machine().root_device().ioport("JOY2")->read())<<8);
+ case 3:
+ return ((0xff-device->machine().root_device().ioport("JOY3")->read())<<8);
+ }
+
+ return 0;
+}
+
+static UPD7002_EOC(BBC_uPD7002_EOC)
+{
+ via6522_device *via_0 = device->machine().device<via6522_device>("via6522_0");
+ via_0->write_cb1(data);
+}
+
+const uPD7002_interface bbc_uPD7002 =
+{
+ BBC_get_analogue_input,
+ BBC_uPD7002_EOC
+};
+
+
+/***************************************
+ BBC 2C199 Serial Interface Cassette
+****************************************/
+
+
+
+static void MC6850_Receive_Clock(running_machine &machine, int new_clock)
+{
+ bbc_state *state = machine.driver_data<bbc_state>();
+ if (!state->m_mc6850_clock && new_clock)
+ {
+ acia6850_device *acia = machine.device<acia6850_device>("acia6850");
+ acia->tx_clock_in();
+ }
+ state->m_mc6850_clock = new_clock;
+}
+
+static TIMER_CALLBACK(bbc_tape_timer_cb)
+{
+ bbc_state *state = machine.driver_data<bbc_state>();
+
+ double dev_val;
+ dev_val=machine.device<cassette_image_device>(CASSETTE_TAG)->input();
+
+ // look for rising edges on the cassette wave
+ if (((dev_val>=0.0) && (state->m_last_dev_val<0.0)) || ((dev_val<0.0) && (state->m_last_dev_val>=0.0)))
+ {
+ if (state->m_wav_len>(9*3))
+ {
+ //this is to long to recive anything so reset the serial IC. This is a hack, this should be done as a timer in the MC6850 code.
+ logerror ("Cassette length %d\n",state->m_wav_len);
+ state->m_len0=0;
+ state->m_len1=0;
+ state->m_len2=0;
+ state->m_len3=0;
+ state->m_wav_len=0;
+
+ }
+
+ state->m_len3=state->m_len2;
+ state->m_len2=state->m_len1;
+ state->m_len1=state->m_len0;
+ state->m_len0=state->m_wav_len;
+
+ state->m_wav_len=0;
+ logerror ("cassette %d %d %d %d\n",state->m_len3,state->m_len2,state->m_len1,state->m_len0);
+
+ if ((state->m_len0+state->m_len1)>=(18+18-5))
+ {
+ /* Clock a 0 onto the serial line */
+ logerror("Serial value 0\n");
+ MC6850_Receive_Clock(machine, 0);
+ state->m_len0=0;
+ state->m_len1=0;
+ state->m_len2=0;
+ state->m_len3=0;
+ }
+
+ if (((state->m_len0+state->m_len1+state->m_len2+state->m_len3)<=41) && (state->m_len3!=0))
+ {
+ /* Clock a 1 onto the serial line */
+ logerror("Serial value 1\n");
+ MC6850_Receive_Clock(machine, 1);
+ state->m_len0=0;
+ state->m_len1=0;
+ state->m_len2=0;
+ state->m_len3=0;
+ }
+
+
+ }
+
+ state->m_wav_len++;
+ state->m_last_dev_val=dev_val;
+
+}
+
+static void BBC_Cassette_motor(running_machine &machine, unsigned char status)
+{
+ bbc_state *state = machine.driver_data<bbc_state>();
+ if (status)
+ {
+ machine.device<cassette_image_device>(CASSETTE_TAG)->change_state(CASSETTE_MOTOR_ENABLED, CASSETTE_MASK_MOTOR);
+ state->m_tape_timer->adjust(attotime::zero, 0, attotime::from_hz(44100));
+ }
+ else
+ {
+ machine.device<cassette_image_device>(CASSETTE_TAG)->change_state(CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR);
+ state->m_tape_timer->reset();
+ state->m_len0 = 0;
+ state->m_len1 = 0;
+ state->m_len2 = 0;
+ state->m_len3 = 0;
+ state->m_wav_len = 0;
+ }
+}
+
+
+
+WRITE8_MEMBER(bbc_state::bbc_SerialULA_w)
+{
+ BBC_Cassette_motor(machine(), (data & 0x80) >> 7);
+}
+
+/**************************************
+ i8271 disc control function
+***************************************/
+
+
+static void bbc_i8271_interrupt(device_t *device, int state)
+{
+ bbc_state *drvstate = device->machine().driver_data<bbc_state>();
+ /* I'm assuming that the nmi is edge triggered */
+ /* a interrupt from the fdc will cause a change in line state, and
+ the nmi will be triggered, but when the state changes because the int
+ is cleared this will not cause another nmi */
+ /* I'll emulate it like this to be sure */
+
+ if (state!=drvstate->m_previous_i8271_int_state)
+ {
+ if (state)
+ {
+ /* I'll pulse it because if I used hold-line I'm not sure
+ it would clear - to be checked */
+ device_set_input_line(device->machine().device("maincpu"), INPUT_LINE_NMI,PULSE_LINE);
+ }
+ }
+
+ drvstate->m_previous_i8271_int_state = state;
+}
+
+
+const i8271_interface bbc_i8271_interface=
+{
+ bbc_i8271_interrupt,
+ NULL,
+ {FLOPPY_0, FLOPPY_1}
+};
+
+
+READ8_MEMBER(bbc_state::bbc_i8271_read)
+{
+ int ret;
+ device_t *i8271 = machine().device("i8271");
+ logerror("i8271 read %d ",offset);
+ switch (offset)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ /* 8271 registers */
+ ret=i8271_r(i8271, offset);
+ logerror(" %d\n",ret);
+ break;
+ case 4:
+ ret=i8271_data_r(i8271, offset);
+ logerror(" %d\n",ret);
+ break;
+ default:
+ ret=0x0ff;
+ break;
+ }
+ logerror(" void\n");
+ return ret;
+}
+
+WRITE8_MEMBER(bbc_state::bbc_i8271_write)
+{
+ device_t *i8271 = machine().device("i8271");
+ logerror("i8271 write %d %d\n",offset,data);
+
+ switch (offset)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ /* 8271 registers */
+ i8271_w(i8271, offset, data);
+ return;
+ case 4:
+ i8271_data_w(i8271, offset, data);
+ return;
+ default:
+ break;
+ }
+}
+
+
+
+/**************************************
+ WD1770 disc control function
+***************************************/
+
+
+
+
+/*
+ B/ B+ drive control:
+
+ Bit Meaning
+ -----------------
+ 7,6 Not used.
+ 5 Reset drive controller chip. (0 = reset controller, 1 = no reset)
+ 4 Interrupt Enable (0 = enable int, 1 = disable int)
+ 3 Double density select (0 = double, 1 = single).
+ 2 Side select (0 = side 0, 1 = side 1).
+ 1 Drive select 1.
+ 0 Drive select 0.
+*/
+
+/*
+density select
+single density is as the 8271 disc format
+double density is as the 8271 disc format but with 16 sectors per track
+
+At some point we need to check the size of the disc image to work out if it is a single or double
+density disc image
+*/
+
+
+/* wd177x_IRQ_SET and latch bit 4 (nmi_enable) are NAND'ED together
+ wd177x_DRQ_SET and latch bit 4 (nmi_enable) are NAND'ED together
+ the output of the above two NAND gates are then OR'ED together and sent to the 6502 NMI line.
+ DRQ and IRQ are active low outputs from wd177x. We use wd177x_DRQ_SET for DRQ = 0,
+ and wd177x_DRQ_CLR for DRQ = 1. Similarly wd177x_IRQ_SET for IRQ = 0 and wd177x_IRQ_CLR
+ for IRQ = 1.
+
+ The above means that if IRQ or DRQ are set, a interrupt should be generated.
+ The nmi_enable decides if interrupts are actually triggered.
+ The nmi is edge triggered, and triggers on a +ve edge.
+*/
+
+static void bbc_update_fdq_int(running_machine &machine, int state)
+{
+ bbc_state *drvstate = machine.driver_data<bbc_state>();
+ int bbc_state;
+
+ /* if drq or irq is set, and interrupt is enabled */
+ if ((drvstate->m_wd177x_irq_state || drvstate->m_wd177x_drq_state) && (drvstate->m_1770_IntEnabled))
+ {
+ /* int trigger */
+ bbc_state = 1;
+ }
+ else
+ {
+ /* do not trigger int */
+ bbc_state = 0;
+ }
+
+ /* nmi is edge triggered, and triggers when the state goes from clear->set.
+ Here we are checking this transition before triggering the nmi */
+ if (bbc_state!=drvstate->m_previous_wd177x_int_state)
+ {
+ if (bbc_state)
+ {
+ /* I'll pulse it because if I used hold-line I'm not sure
+ it would clear - to be checked */
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_NMI,PULSE_LINE);
+ }
+ }
+
+ drvstate->m_previous_wd177x_int_state = bbc_state;
+}
+
+static WRITE_LINE_DEVICE_HANDLER( bbc_wd177x_intrq_w )
+{
+ bbc_state *drvstate = device->machine().driver_data<bbc_state>();
+ drvstate->m_wd177x_irq_state = state;
+ bbc_update_fdq_int(device->machine(), state);
+}
+
+static WRITE_LINE_DEVICE_HANDLER( bbc_wd177x_drq_w )
+{
+ bbc_state *drvstate = device->machine().driver_data<bbc_state>();
+ drvstate->m_wd177x_drq_state = state;
+ bbc_update_fdq_int(device->machine(), state);
+}
+
+const wd17xx_interface bbc_wd17xx_interface =
+{
+ DEVCB_NULL,
+ DEVCB_LINE(bbc_wd177x_intrq_w),
+ DEVCB_LINE(bbc_wd177x_drq_w),
+ {FLOPPY_0, FLOPPY_1, NULL, NULL}
+};
+
+WRITE8_MEMBER(bbc_state::bbc_wd177x_status_w)
+{
+ device_t *fdc = machine().device("wd177x");
+ m_drive_control = data;
+
+ /* set drive */
+ if ((data>>0) & 0x01) wd17xx_set_drive(fdc,0);
+ if ((data>>1) & 0x01) wd17xx_set_drive(fdc,1);
+
+ /* set side */
+ wd17xx_set_side(fdc,(data>>2) & 0x01);
+
+ /* set density */
+ wd17xx_dden_w(fdc, BIT(data, 3));
+
+ m_1770_IntEnabled=(((data>>4) & 0x01)==0);
+
+}
+
+
+
+READ8_MEMBER(bbc_state::bbc_wd1770_read)
+{
+ int retval=0xff;
+ device_t *fdc = machine().device("wd177x");
+ switch (offset)
+ {
+ case 4:
+ retval=wd17xx_status_r(fdc, 0);
+ break;
+ case 5:
+ retval=wd17xx_track_r(fdc, 0);
+ break;
+ case 6:
+ retval=wd17xx_sector_r(fdc, 0);
+ break;
+ case 7:
+ retval=wd17xx_data_r(fdc, 0);
+ break;
+ default:
+ break;
+ }
+ logerror("wd177x read: $%02X $%02X\n", offset,retval);
+
+ return retval;
+}
+
+WRITE8_MEMBER(bbc_state::bbc_wd1770_write)
+{
+ device_t *fdc = machine().device("wd177x");
+ logerror("wd177x write: $%02X $%02X\n", offset,data);
+ switch (offset)
+ {
+ case 0:
+ bbc_wd177x_status_w(space, 0, data);
+ break;
+ case 4:
+ wd17xx_command_w(fdc, 0, data);
+ break;
+ case 5:
+ wd17xx_track_w(fdc, 0, data);
+ break;
+ case 6:
+ wd17xx_sector_w(fdc, 0, data);
+ break;
+ case 7:
+ wd17xx_data_w(fdc, 0, data);
+ break;
+ default:
+ break;
+ }
+}
+
+
+/*********************************************
+OPUS CHALLENGER MEMORY MAP
+ Read Write
+
+&FCF8 1770 Status register 1770 command register
+&FCF9 1770 track register
+&FCFA 1770 sector register
+&FCFB 1770 data register
+&FCFC 1770 drive control
+
+
+drive control register bits
+0 select side 0= side 0 1= side 1
+1 select drive 0
+2 select drive 1
+3 ?unused?
+4 ?Always Set
+5 Density Select 0=double, 1=single
+6 ?unused?
+7 ?unused?
+
+The RAM is accessible through JIM (page &FD). One page is visible in JIM at a time.
+The selected page is controlled by the two paging registers:
+
+&FCFE Paging register MSB
+&FCFF Paging register LSB
+
+256K model has 1024 pages &000 to &3ff
+512K model has 2048 pages &000 to &7ff
+
+AM_RANGE(0xfc00, 0xfdff) AM_READWRITE(bbc_opus_read , bbc_opus_write )
+
+
+**********************************************/
+
+
+WRITE8_MEMBER(bbc_state::bbc_opus_status_w)
+{
+ device_t *fdc = machine().device("wd177x");
+ m_drive_control = data;
+
+ /* set drive */
+ if ((data>>1) & 0x01) wd17xx_set_drive(fdc,0);
+ if ((data>>2) & 0x01) wd17xx_set_drive(fdc,1);
+
+ /* set side */
+ wd17xx_set_side(fdc,(data>>0) & 0x01);
+
+ /* set density */
+ wd17xx_dden_w(fdc, BIT(data, 5));
+
+ m_1770_IntEnabled=(data>>4) & 0x01;
+
+}
+
+READ8_MEMBER(bbc_state::bbc_opus_read)
+{
+ device_t *fdc = machine().device("wd177x");
+ logerror("wd177x read: $%02X\n", offset);
+
+ if (m_DFSType==6)
+ {
+ if (offset<0x100)
+ {
+ switch (offset)
+ {
+ case 0xf8:
+ return wd17xx_status_r(fdc, 0);
+ case 0xf9:
+ return wd17xx_track_r(fdc, 0);
+ case 0xfa:
+ return wd17xx_sector_r(fdc, 0);
+ case 0xfb:
+ return wd17xx_data_r(fdc, 0);
+ }
+
+ }
+ else
+ {
+ return memregion("disks")->base()[offset + (m_opusbank << 8)];
+ }
+ }
+ return 0xff;
+}
+
+WRITE8_MEMBER(bbc_state::bbc_opus_write)
+{
+ device_t *fdc = machine().device("wd177x");
+ logerror("wd177x write: $%02X $%02X\n", offset,data);
+
+ if (m_DFSType==6)
+ {
+ if (offset<0x100)
+ {
+ switch (offset)
+ {
+ case 0xf8:
+ wd17xx_command_w(fdc, 0, data);
+ break;
+ case 0xf9:
+ wd17xx_track_w(fdc, 0, data);
+ break;
+ case 0xfa:
+ wd17xx_sector_w(fdc, 0, data);
+ break;
+ case 0xfb:
+ wd17xx_data_w(fdc, 0, data);
+ break;
+ case 0xfc:
+ bbc_opus_status_w(space, 0,data);
+ break;
+ case 0xfe:
+ m_opusbank=(m_opusbank & 0xff) | (data<<8);
+ break;
+ case 0xff:
+ m_opusbank=(m_opusbank & 0xff00) | data;
+ break;
+ }
+ }
+ else
+ {
+ memregion("disks")->base()[offset + (m_opusbank << 8)] = data;
+ }
+ }
+}
+
+
+/***************************************
+BBC MASTER DISC SUPPORT
+***************************************/
+
+
+READ8_MEMBER(bbc_state::bbcm_wd1770_read)
+{
+ int retval=0xff;
+ device_t *fdc = machine().device("wd177x");
+ switch (offset)
+ {
+ case 0:
+ retval=wd17xx_status_r(fdc, 0);
+ break;
+ case 1:
+ retval=wd17xx_track_r(fdc, 0);
+ break;
+ case 2:
+ retval=wd17xx_sector_r(fdc, 0);
+ break;
+ case 3:
+ retval=wd17xx_data_r(fdc, 0);
+ break;
+ default:
+ break;
+ }
+ return retval;
+}
+
+
+WRITE8_MEMBER(bbc_state::bbcm_wd1770_write)
+{
+ device_t *fdc = machine().device("wd177x");
+ //logerror("wd177x write: $%02X $%02X\n", offset,data);
+ switch (offset)
+ {
+ case 0:
+ wd17xx_command_w(fdc, 0, data);
+ break;
+ case 1:
+ wd17xx_track_w(fdc, 0, data);
+ break;
+ case 2:
+ wd17xx_sector_w(fdc, 0, data);
+ break;
+ case 3:
+ wd17xx_data_w(fdc, 0, data);
+ break;
+ default:
+ break;
+ }
+}
+
+
+READ8_MEMBER(bbc_state::bbcm_wd1770l_read)
+{
+ return m_drive_control;
+}
+
+WRITE8_MEMBER(bbc_state::bbcm_wd1770l_write)
+{
+ device_t *fdc = machine().device("wd177x");
+ m_drive_control = data;
+
+ /* set drive */
+ if ((data>>0) & 0x01) wd17xx_set_drive(fdc,0);
+ if ((data>>1) & 0x01) wd17xx_set_drive(fdc,1);
+
+ /* set side */
+ wd17xx_set_side(fdc,(data>>4) & 0x01);
+
+ /* set density */
+ wd17xx_dden_w(fdc, BIT(data, 5));
+
+// m_1770_IntEnabled=(((data>>4) & 0x01)==0);
+ m_1770_IntEnabled=1;
+
+}
+
+
+/**************************************
+DFS Hardware mapping for different Disc Controller types
+***************************************/
+
+READ8_MEMBER(bbc_state::bbc_disc_r)
+{
+ switch (m_DFSType){
+ /* case 0 to 3 are all standard 8271 interfaces */
+ case 0: case 1: case 2: case 3:
+ return bbc_i8271_read(space, offset);
+ /* case 4 is the acown 1770 interface */
+ case 4:
+ return bbc_wd1770_read(space, offset);
+ /* case 5 is the watford 1770 interface */
+ case 5:
+ return bbc_wd1770_read(space, offset);
+ /* case 6 is the Opus challenger interface */
+ case 6:
+ /* not connected here, opus drive is connected via the 1MHz Bus */
+ break;
+ /* case 7 in no disc controller */
+ case 7:
+ break;
+ }
+ return 0x0ff;
+}
+
+WRITE8_MEMBER(bbc_state::bbc_disc_w)
+{
+ switch (m_DFSType){
+ /* case 0 to 3 are all standard 8271 interfaces */
+ case 0: case 1: case 2: case 3:
+ bbc_i8271_write(space, offset,data);
+ break;
+ /* case 4 is the acown 1770 interface */
+ case 4:
+ bbc_wd1770_write(space, offset,data);
+ break;
+ /* case 5 is the watford 1770 interface */
+ case 5:
+ bbc_wd1770_write(space, offset,data);
+ break;
+ /* case 6 is the Opus challenger interface */
+ case 6:
+ /* not connected here, opus drive is connected via the 1MHz Bus */
+ break;
+ /* case 7 in no disc controller */
+ case 7:
+ break;
+ }
+}
+
+
+
+/**************************************
+ BBC B Rom loading functions
+***************************************/
+DEVICE_IMAGE_LOAD( bbcb_cart )
+{
+ UINT8 *mem = image.device().machine().root_device().memregion("user1")->base();
+ int size, read_;
+ int addr = 0;
+ int index = 0;
+
+ size = image.length();
+
+ if (strcmp(image.device().tag(),":cart1") == 0)
+ {
+ index = 0;
+ }
+ if (strcmp(image.device().tag(),":cart2") == 0)
+ {
+ index = 1;
+ }
+ if (strcmp(image.device().tag(),":cart3") == 0)
+ {
+ index = 2;
+ }
+ if (strcmp(image.device().tag(),":cart4") == 0)
+ {
+ index = 3;
+ }
+ addr = 0x8000 + (0x4000 * index);
+
+
+ logerror("loading rom %s at %.4x size:%.4x\n", image.filename(), addr, size);
+
+
+ switch (size)
+ {
+ case 0x2000:
+ read_ = image.fread(mem + addr, size);
+ if (read_ != size)
+ return 1;
+ image.fseek(0, SEEK_SET);
+ read_ = image.fread(mem + addr + 0x2000, size);
+ break;
+ case 0x4000:
+ read_ = image.fread(mem + addr, size);
+ break;
+ default:
+ read_ = 0;
+ logerror("bad rom file size of %.4x\n", size);
+ break;
+ }
+
+ if (read_ != size)
+ return 1;
+ return 0;
+}
+
+
+
+
+/**************************************
+ Machine Initialisation functions
+***************************************/
+
+DRIVER_INIT_MEMBER(bbc_state,bbc)
+{
+ m_Master=0;
+ m_tape_timer = machine().scheduler().timer_alloc(FUNC(bbc_tape_timer_cb));
+}
+DRIVER_INIT_MEMBER(bbc_state,bbcm)
+{
+ m_Master=1;
+ m_tape_timer = machine().scheduler().timer_alloc(FUNC(bbc_tape_timer_cb));
+}
+
+MACHINE_START( bbca )
+{
+}
+
+MACHINE_RESET( bbca )
+{
+ bbc_state *state = machine.driver_data<bbc_state>();
+ UINT8 *ram = machine.root_device().memregion("maincpu")->base();
+ state->m_RAMSize = 1;
+ state->membank("bank1")->set_base(ram);
+ state->membank("bank3")->set_base(ram);
+
+ state->membank("bank4")->set_base(machine.root_device().memregion("user1")->base()); /* bank 4 is the paged ROMs from 8000 to bfff */
+ state->membank("bank7")->set_base(state->memregion("user1")->base()+0x10000); /* bank 7 points at the OS rom from c000 to ffff */
+
+ bbcb_IC32_initialise(state);
+}
+
+MACHINE_START( bbcb )
+{
+ bbc_state *state = machine.driver_data<bbc_state>();
+ state->m_mc6850_clock = 0;
+ //removed from here because MACHINE_START can no longer read DIP swiches.
+ //put in MACHINE_RESET instead.
+ //state->m_DFSType= (machine.root_device().ioport("BBCCONFIG")->read()>>0)&0x07;
+ //state->m_SWRAMtype=(machine.root_device().ioport("BBCCONFIG")->read()>>3)&0x03;
+ //state->m_RAMSize= (machine.root_device().ioport("BBCCONFIG")->read()>>5)&0x01;
+
+ /*set up the required disc controller*/
+ //switch (state->m_DFSType) {
+ //case 0: case 1: case 2: case 3:
+ state->m_previous_i8271_int_state=0;
+ // break;
+ //case 4: case 5: case 6:
+ state->m_previous_wd177x_int_state=1;
+ // break;
+ //}
+}
+
+MACHINE_RESET( bbcb )
+{
+ bbc_state *state = machine.driver_data<bbc_state>();
+ UINT8 *ram = state->memregion("maincpu")->base();
+ state->m_DFSType= (machine.root_device().ioport("BBCCONFIG")->read() >> 0) & 0x07;
+ state->m_SWRAMtype = (machine.root_device().ioport("BBCCONFIG")->read() >> 3) & 0x03;
+ state->m_RAMSize= (machine.root_device().ioport("BBCCONFIG")->read() >> 5) & 0x01;
+
+ state->membank("bank1")->set_base(ram);
+ if (state->m_RAMSize)
+ {
+ /* 32K Model B */
+ state->membank("bank3")->set_base(ram + 0x4000);
+ state->m_memorySize=32;
+ }
+ else
+ {
+ /* 16K just repeat the lower 16K*/
+ state->membank("bank3")->set_base(ram);
+ state->m_memorySize=16;
+ }
+
+ state->membank("bank4")->set_base(machine.root_device().memregion("user1")->base()); /* bank 4 is the paged ROMs from 8000 to bfff */
+ state->membank("bank7")->set_base(machine.root_device().memregion("user1")->base() + 0x40000); /* bank 7 points at the OS rom from c000 to ffff */
+
+ bbcb_IC32_initialise(state);
+
+
+ state->m_opusbank = 0;
+ /*set up the required disc controller*/
+ //switch (state->m_DFSType) {
+ //case 0: case 1: case 2: case 3:
+ // break;
+ //case 4: case 5: case 6:
+ // break;
+ //}
+}
+
+
+MACHINE_START( bbcbp )
+{
+ bbc_state *state = machine.driver_data<bbc_state>();
+ state->m_mc6850_clock = 0;
+
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->set_direct_update_handler(direct_update_delegate(FUNC(bbc_state::bbcbp_direct_handler), state));
+
+ /* bank 6 is the paged ROMs from b000 to bfff */
+ state->membank("bank6")->configure_entries(0, 16, state->memregion("user1")->base() + 0x3000, 1<<14);
+}
+
+MACHINE_RESET( bbcbp )
+{
+ bbc_state *state = machine.driver_data<bbc_state>();
+ state->membank("bank1")->set_base(machine.root_device().memregion("maincpu")->base());
+ state->membank("bank2")->set_base(machine.root_device().memregion("maincpu")->base()+0x03000); /* bank 2 screen/shadow ram from 3000 to 7fff */
+ state->membank("bank4")->set_base(machine.root_device().memregion("user1")->base()); /* bank 4 is paged ROM or RAM from 8000 to afff */
+ state->membank("bank6")->set_entry(0);
+ state->membank("bank7")->set_base(state->memregion("user1")->base()+0x40000); /* bank 7 points at the OS rom from c000 to ffff */
+
+ bbcb_IC32_initialise(state);
+
+
+ state->m_previous_wd177x_int_state=1;
+}
+
+
+
+MACHINE_START( bbcm )
+{
+ bbc_state *state = machine.driver_data<bbc_state>();
+ state->m_mc6850_clock = 0;
+
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->set_direct_update_handler(direct_update_delegate(FUNC(bbc_state::bbcm_direct_handler), state));
+
+ /* bank 5 is the paged ROMs from 9000 to bfff */
+ state->membank("bank5")->configure_entries(0, 16, machine.root_device().memregion("user1")->base()+0x01000, 1<<14);
+
+ /* Set ROM/IO bank to point to rom */
+ state->membank( "bank8" )->set_base( state->memregion("user1")->base()+0x43c00);
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0xFC00, 0xFEFF, "bank8");
+}
+
+MACHINE_RESET( bbcm )
+{
+ bbc_state *state = machine.driver_data<bbc_state>();
+ state->membank("bank1")->set_base(machine.root_device().memregion("maincpu")->base()); /* bank 1 regular lower ram from 0000 to 2fff */
+ state->membank("bank2")->set_base(machine.root_device().memregion("maincpu")->base() + 0x3000); /* bank 2 screen/shadow ram from 3000 to 7fff */
+ state->membank("bank4")->set_base(machine.root_device().memregion("user1")->base()); /* bank 4 is paged ROM or RAM from 8000 to 8fff */
+ state->membank("bank5")->set_entry(0);
+ state->membank("bank7")->set_base(state->memregion("user1")->base() + 0x40000); /* bank 6 OS rom of RAM from c000 to dfff */
+
+ bbcb_IC32_initialise(state);
+
+
+ state->m_previous_wd177x_int_state=1;
+}
diff --git a/src/mess/machine/bebox.c b/src/mess/machine/bebox.c
new file mode 100644
index 00000000000..3e7200e17c0
--- /dev/null
+++ b/src/mess/machine/bebox.c
@@ -0,0 +1,1093 @@
+/***************************************************************************
+
+ machine/bebox.c
+
+ BeBox
+
+ Memory map:
+
+ 00000000 - 3FFFFFFF Physical RAM
+ 40000000 - 7FFFFFFF Motherboard glue registers
+ 80000000 - 807FFFFF ISA I/O
+ 81000000 - BF7FFFFF PCI I/O
+ BFFFFFF0 - BFFFFFFF PCI/ISA interrupt acknowledge
+ FF000000 - FFFFFFFF ROM/flash
+
+ In ISA space, peripherals are generally in similar places as they are on
+ standard PC hardware (e.g. - the keyboard is 80000060 and 80000064). The
+ following table shows more:
+
+ Keyboard/Mouse (Intel 8242) 80000060, 80000064
+ Real Time Clock (BQ3285) 80000070, 80000074
+ IDE ATA Interface 800001F0-F7, 800003F6-7
+ COM2 800002F8-F
+ GeekPort A/D Control 80000360-1
+ GeekPort A/D Data 80000362-3
+ GeekPort A/D Rate 80000364
+ GeekPort OE 80000366
+ Infrared Interface 80000368-A
+ COM3 80000380-7
+ COM4 80000388-F
+ GeekPort D/A 80000390-3
+ GeekPort GPA/GPB 80000394
+ Joystick Buttons 80000397
+ SuperIO Config (PReP standard) 80000398-9
+ MIDI Port 1 800003A0-7
+ MIDI Port 2 800003A8-F
+ Parallel 800003BC-E
+ Floppy 800003F0-7
+ COM1 800003F8-F
+ AD1848 80000830-4
+
+
+ Interrupt bit masks:
+
+ bit 31 - N/A (used to set/clear masks)
+ bit 30 - SMI interrupt to CPU 0 (CPU 0 only)
+ bit 29 - SMI interrupt to CPU 1 (CPU 1 only)
+ bit 28 - Unused
+ bit 27 - COM1 (PC IRQ #4)
+ bit 26 - COM2 (PC IRQ #3)
+ bit 25 - COM3
+ bit 24 - COM4
+ bit 23 - MIDI1
+ bit 22 - MIDI2
+ bit 21 - SCSI
+ bit 20 - PCI Slot #1
+ bit 19 - PCI Slot #2
+ bit 18 - PCI Slot #3
+ bit 17 - Sound
+ bit 16 - Keyboard (PC IRQ #1)
+ bit 15 - Real Time Clock (PC IRQ #8)
+ bit 14 - PC IRQ #5
+ bit 13 - Floppy Disk (PC IRQ #6)
+ bit 12 - Parallel Port (PC IRQ #7)
+ bit 11 - PC IRQ #9
+ bit 10 - PC IRQ #10
+ bit 9 - PC IRQ #11
+ bit 8 - Mouse (PC IRQ #12)
+ bit 7 - IDE (PC IRQ #14)
+ bit 6 - PC IRQ #15
+ bit 5 - PIC8259
+ bit 4 - Infrared Controller
+ bit 3 - Analog To Digital
+ bit 2 - GeekPort
+ bit 1 - Unused
+ bit 0 - Unused
+
+ Be documentation uses PowerPC bit numbering conventions (i.e. - bit #0 is
+ the most significant bit)
+
+ PCI Devices:
+ #0 Motorola MPC105
+ #11 Intel 82378 PCI/ISA bridge
+ #12 NCR 53C810 SCSI
+
+ More hardware information at http://www.netbsd.org/Ports/bebox/hardware.html
+
+***************************************************************************/
+
+/* Core includes */
+#include "emu.h"
+#include "memconv.h"
+#include "includes/bebox.h"
+
+/* Components */
+#include "video/pc_vga.h"
+#include "video/cirrus.h"
+#include "cpu/powerpc/ppc.h"
+#include "machine/ins8250.h"
+#include "machine/pc_fdc.h"
+#include "machine/mc146818.h"
+#include "machine/pic8259.h"
+#include "machine/pit8253.h"
+#include "machine/8237dma.h"
+#include "machine/idectrl.h"
+#include "machine/pci.h"
+#include "machine/intelfsh.h"
+#include "machine/8042kbdc.h"
+#include "machine/53c810.h"
+#include "machine/ram.h"
+
+#define LOG_CPUIMASK 1
+#define LOG_UART 1
+#define LOG_INTERRUPTS 1
+
+
+
+/*************************************
+ *
+ * Interrupts and Motherboard Registers
+ *
+ *************************************/
+
+static void bebox_update_interrupts(running_machine &machine);
+
+static void bebox_mbreg32_w(UINT32 *target, UINT64 data, UINT64 mem_mask)
+{
+ int i;
+
+ for (i = 1; i < 32; i++)
+ {
+ if ((data >> (63 - i)) & 1)
+ {
+ if ((data >> 63) & 1)
+ *target |= 0x80000000 >> i;
+ else
+ *target &= ~(0x80000000 >> i);
+ }
+ }
+}
+
+
+READ64_HANDLER( bebox_cpu0_imask_r )
+{
+ bebox_state *state = space->machine().driver_data<bebox_state>();
+ return ((UINT64) state->m_cpu_imask[0]) << 32;
+}
+
+READ64_HANDLER( bebox_cpu1_imask_r )
+{
+ bebox_state *state = space->machine().driver_data<bebox_state>();
+ return ((UINT64) state->m_cpu_imask[1]) << 32;
+}
+
+READ64_HANDLER( bebox_interrupt_sources_r )
+{
+ bebox_state *state = space->machine().driver_data<bebox_state>();
+ return ((UINT64) state->m_interrupts) << 32;
+}
+
+WRITE64_HANDLER( bebox_cpu0_imask_w )
+{
+ bebox_state *state = space->machine().driver_data<bebox_state>();
+ UINT32 old_imask = state->m_cpu_imask[0];
+
+ bebox_mbreg32_w(&state->m_cpu_imask[0], data, mem_mask);
+
+ if (old_imask != state->m_cpu_imask[0])
+ {
+ if (LOG_CPUIMASK)
+ {
+ logerror("BeBox CPU #0 pc=0x%08X imask=0x%08x\n",
+ (unsigned) cpu_get_pc( &space->device()), state->m_cpu_imask[0]);
+ }
+ bebox_update_interrupts(space->machine());
+ }
+}
+
+WRITE64_HANDLER( bebox_cpu1_imask_w )
+{
+ bebox_state *state = space->machine().driver_data<bebox_state>();
+ UINT32 old_imask = state->m_cpu_imask[1];
+
+ bebox_mbreg32_w(&state->m_cpu_imask[1], data, mem_mask);
+
+ if (old_imask != state->m_cpu_imask[1])
+ {
+ if (LOG_CPUIMASK)
+ {
+ logerror("BeBox CPU #1 pc=0x%08X imask=0x%08x\n",
+ (unsigned) cpu_get_pc( &space->device() ), state->m_cpu_imask[1]);
+ }
+ bebox_update_interrupts(space->machine());
+ }
+}
+
+READ64_HANDLER( bebox_crossproc_interrupts_r )
+{
+ bebox_state *state = space->machine().driver_data<bebox_state>();
+ UINT32 result;
+ result = state->m_crossproc_interrupts;
+
+ /* return a different result depending on which CPU is accessing this handler */
+ if (space != space->machine().device("ppc1")->memory().space(AS_PROGRAM))
+ result |= 0x02000000;
+ else
+ result &= ~0x02000000;
+
+ return ((UINT64) result) << 32;
+}
+
+WRITE64_HANDLER( bebox_crossproc_interrupts_w )
+{
+ bebox_state *state = space->machine().driver_data<bebox_state>();
+ static const struct
+ {
+ UINT32 mask;
+ int cpunum;
+ int active_high;
+ int inputline;
+ } crossproc_map[] =
+ {
+ { 0x40000000, 0, 1, 0/*PPC_INPUT_LINE_SMI*/ },
+ { 0x20000000, 1, 1, 0/*PPC_INPUT_LINE_SMI*/ },
+ { 0x08000000, 0, 0, 0/*PPC_INPUT_LINE_TLBISYNC*/ },
+ { 0x04000000, 1, 0, 0/*PPC_INPUT_LINE_TLBISYNC*/ }
+ };
+ int i, line;
+ UINT32 old_crossproc_interrupts = state->m_crossproc_interrupts;
+ static const char *const cputags[] = { "ppc1", "ppc2" };
+
+ bebox_mbreg32_w(&state->m_crossproc_interrupts, data, mem_mask);
+
+ for (i = 0; i < ARRAY_LENGTH(crossproc_map); i++)
+ {
+ if ((old_crossproc_interrupts ^ state->m_crossproc_interrupts) & crossproc_map[i].mask)
+ {
+ if (state->m_crossproc_interrupts & crossproc_map[i].mask)
+ line = crossproc_map[i].active_high ? ASSERT_LINE : CLEAR_LINE;
+ else
+ line = crossproc_map[i].active_high ? CLEAR_LINE : ASSERT_LINE;
+
+ if (LOG_INTERRUPTS)
+ {
+/*
+ logerror("bebox_crossproc_interrupts_w(): CPU #%d %s %s\n",
+ crossproc_map[i].cpunum, line ? "Asserting" : "Clearing",
+ (crossproc_map[i].inputline == PPC_INPUT_LINE_SMI) ? "SMI" : "TLBISYNC");
+ */
+ }
+
+ cputag_set_input_line(space->machine(), cputags[crossproc_map[i].cpunum], crossproc_map[i].inputline, line);
+ }
+ }
+}
+
+WRITE64_HANDLER( bebox_processor_resets_w )
+{
+ UINT8 b = (UINT8) (data >> 56);
+
+ if (b & 0x20)
+ {
+ cputag_set_input_line(space->machine(), "ppc2", INPUT_LINE_RESET, (b & 0x80) ? CLEAR_LINE : ASSERT_LINE);
+ }
+}
+
+
+static void bebox_update_interrupts(running_machine &machine)
+{
+ bebox_state *state = machine.driver_data<bebox_state>();
+ int cpunum;
+ UINT32 interrupt;
+ static const char *const cputags[] = { "ppc1", "ppc2" };
+
+ for (cpunum = 0; cpunum < 2; cpunum++)
+ {
+ interrupt = state->m_interrupts & state->m_cpu_imask[cpunum];
+
+ if (LOG_INTERRUPTS)
+ {
+ logerror("\tbebox_update_interrupts(): CPU #%d [%08X|%08X] IRQ %s\n", cpunum,
+ state->m_interrupts, state->m_cpu_imask[cpunum], interrupt ? "on" : "off");
+ }
+
+ cputag_set_input_line(machine, cputags[cpunum], INPUT_LINE_IRQ0, interrupt ? ASSERT_LINE : CLEAR_LINE);
+ }
+}
+
+
+static void bebox_set_irq_bit(running_machine &machine, unsigned int interrupt_bit, int val)
+{
+ bebox_state *state = machine.driver_data<bebox_state>();
+ static const char *const interrupt_names[32] =
+ {
+ NULL,
+ NULL,
+ "GEEKPORT",
+ "ADC",
+ "IR",
+ "PIC8259",
+ "PCIRQ 15",
+ "IDE",
+ "MOUSE",
+ "PCIRQ 11",
+ "PCIRQ 10",
+ "PCIRQ 9",
+ "PARALLEL",
+ "FLOPPY",
+ "PCIRQ 5",
+ "RTC",
+ "KEYBOARD",
+ "SOUND",
+ "PCI3",
+ "PCI2",
+ "PCI1",
+ "SCSI",
+ "MIDI2",
+ "MIDI1",
+ "COM4",
+ "COM3",
+ "COM2",
+ "COM1",
+ NULL,
+ "SMI1",
+ "SMI0",
+ NULL
+ };
+ UINT32 old_interrupts;
+
+ if (LOG_INTERRUPTS)
+ {
+ /* make sure that we don't shoot ourself in the foot */
+ assert_always((interrupt_bit < ARRAY_LENGTH(interrupt_names)) && (interrupt_names[interrupt_bit] != NULL), "Raising invalid interrupt");
+
+ logerror("bebox_set_irq_bit(): pc[0]=0x%08x pc[1]=0x%08x %s interrupt #%u (%s)\n",
+ (unsigned) cpu_get_reg(machine.device("ppc1"), STATE_GENPC),
+ (unsigned) cpu_get_reg(machine.device("ppc2"), STATE_GENPC),
+ val ? "Asserting" : "Clearing",
+ interrupt_bit, interrupt_names[interrupt_bit]);
+ }
+
+ old_interrupts = state->m_interrupts;
+ if (val)
+ state->m_interrupts |= 1 << interrupt_bit;
+ else
+ state->m_interrupts &= ~(1 << interrupt_bit);
+
+ /* if interrupt values have changed, update the lines */
+ if (state->m_interrupts != old_interrupts)
+ bebox_update_interrupts(machine);
+}
+
+
+/*************************************
+ *
+ * COM ports
+ *
+ *************************************/
+
+const ins8250_interface bebox_uart_inteface_0 =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+const ins8250_interface bebox_uart_inteface_1 =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+const ins8250_interface bebox_uart_inteface_2 =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+const ins8250_interface bebox_uart_inteface_3 =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+
+/*************************************
+ *
+ * Floppy Disk Controller
+ *
+ *************************************/
+
+static void bebox_fdc_interrupt(running_machine &machine, int state)
+{
+ bebox_state *drvstate = machine.driver_data<bebox_state>();
+ bebox_set_irq_bit(machine, 13, state);
+ if ( drvstate->m_devices.pic8259_master ) {
+ pic8259_ir6_w(drvstate->m_devices.pic8259_master, state);
+ }
+}
+
+
+static void bebox_fdc_dma_drq(running_machine &machine, int state)
+{
+ bebox_state *drvstate = machine.driver_data<bebox_state>();
+ if ( drvstate->m_devices.dma8237_1 ) {
+ i8237_dreq2_w(drvstate->m_devices.dma8237_1, state);
+ }
+}
+
+
+static device_t *bebox_fdc_get_image(running_machine &machine, int floppy_index)
+{
+ /* the BeBox boot ROM seems to query for floppy #1 when it should be
+ * querying for floppy #0 */
+ return floppy_get_device(machine, 0);
+}
+
+static device_t * bebox_get_device(running_machine &machine )
+{
+ return machine.device("smc37c78");
+}
+
+
+static const struct pc_fdc_interface bebox_fdc_interface =
+{
+ bebox_fdc_interrupt,
+ bebox_fdc_dma_drq,
+ bebox_fdc_get_image,
+ bebox_get_device
+};
+
+
+/*************************************
+ *
+ * 8259 PIC
+ *
+ *************************************/
+
+READ64_HANDLER( bebox_interrupt_ack_r )
+{
+ bebox_state *state = space->machine().driver_data<bebox_state>();
+ int result;
+ result = pic8259_acknowledge( state->m_devices.pic8259_master );
+ bebox_set_irq_bit(space->machine(), 5, 0); /* HACK */
+ return ((UINT64) result) << 56;
+}
+
+
+/*************************************************************
+ *
+ * pic8259 configuration
+ *
+ *************************************************************/
+
+static WRITE_LINE_DEVICE_HANDLER( bebox_pic8259_master_set_int_line )
+{
+ bebox_set_irq_bit(device->machine(), 5, state);
+}
+
+static WRITE_LINE_DEVICE_HANDLER( bebox_pic8259_slave_set_int_line )
+{
+ bebox_state *drvstate = device->machine().driver_data<bebox_state>();
+ if (drvstate->m_devices.pic8259_master)
+ pic8259_ir2_w(drvstate->m_devices.pic8259_master, state);
+}
+
+static READ8_DEVICE_HANDLER( get_slave_ack )
+{
+ bebox_state *state = device->machine().driver_data<bebox_state>();
+ if (offset==2) { // IRQ = 2
+ return pic8259_acknowledge(state->m_devices.pic8259_slave);
+ }
+ return 0x00;
+}
+
+const struct pic8259_interface bebox_pic8259_master_config =
+{
+ DEVCB_LINE(bebox_pic8259_master_set_int_line),
+ DEVCB_LINE_VCC,
+ DEVCB_HANDLER(get_slave_ack)
+};
+
+const struct pic8259_interface bebox_pic8259_slave_config =
+{
+ DEVCB_LINE(bebox_pic8259_slave_set_int_line),
+ DEVCB_LINE_GND,
+ DEVCB_NULL
+};
+
+
+/*************************************
+ *
+ * Floppy/IDE/ATA
+ *
+ *************************************/
+
+static device_t *ide_device(running_machine &machine)
+{
+ return machine.device("ide");
+}
+
+READ8_HANDLER( bebox_800001F0_r ) { return ide_controller_r(ide_device(space->machine()), offset + 0x1F0, 1); }
+WRITE8_HANDLER( bebox_800001F0_w ) { ide_controller_w(ide_device(space->machine()), offset + 0x1F0, 1, data); }
+
+READ64_HANDLER( bebox_800003F0_r )
+{
+ UINT64 result = read64be_with_read8_handler(pc_fdc_r, space, offset, mem_mask | 0xFFFF);
+
+ if (((mem_mask >> 8) & 0xFF) == 0)
+ {
+ result &= ~(0xFF << 8);
+ result |= ide_controller_r(ide_device(space->machine()), 0x3F6, 1) << 8;
+ }
+
+ if (((mem_mask >> 0) & 0xFF) == 0)
+ {
+ result &= ~(0xFF << 0);
+ result |= ide_controller_r(ide_device(space->machine()), 0x3F7, 1) << 0;
+ }
+ return result;
+}
+
+
+WRITE64_HANDLER( bebox_800003F0_w )
+{
+ write64be_with_write8_handler(pc_fdc_w, space, offset, data, mem_mask | 0xFFFF);
+
+ if (((mem_mask >> 8) & 0xFF) == 0)
+ ide_controller_w(ide_device(space->machine()), 0x3F6, 1, (data >> 8) & 0xFF);
+
+ if (((mem_mask >> 0) & 0xFF) == 0)
+ ide_controller_w(ide_device(space->machine()), 0x3F7, 1, (data >> 0) & 0xFF);
+}
+
+
+void bebox_ide_interrupt(device_t *device, int state)
+{
+ bebox_state *drvstate = device->machine().driver_data<bebox_state>();
+ bebox_set_irq_bit(device->machine(), 7, state);
+ if ( drvstate->m_devices.pic8259_master ) {
+ pic8259_ir6_w(drvstate->m_devices.pic8259_master, state);
+ }
+}
+
+
+/*************************************
+ *
+ * Video card (Cirrus Logic CL-GD5430)
+ *
+ *************************************/
+
+static READ64_HANDLER( bebox_video_r )
+{
+ const UINT64 *mem = (const UINT64 *) pc_vga_memory();
+ return BIG_ENDIANIZE_INT64(mem[offset]);
+}
+
+
+static WRITE64_HANDLER( bebox_video_w )
+{
+ UINT64 *mem = (UINT64 *) pc_vga_memory();
+ data = BIG_ENDIANIZE_INT64(data);
+ mem_mask = BIG_ENDIANIZE_INT64(mem_mask);
+ COMBINE_DATA(&mem[offset]);
+}
+
+/*************************************
+ *
+ * 8237 DMA
+ *
+ *************************************/
+
+
+READ8_HANDLER(bebox_page_r)
+{
+ bebox_state *state = space->machine().driver_data<bebox_state>();
+ UINT8 data = state->m_at_pages[offset % 0x10];
+
+ switch(offset % 8)
+ {
+ case 1:
+ data = state->m_dma_offset[(offset / 8) & 1][2];
+ break;
+ case 2:
+ data = state->m_dma_offset[(offset / 8) & 1][3];
+ break;
+ case 3:
+ data = state->m_dma_offset[(offset / 8) & 1][1];
+ break;
+ case 7:
+ data = state->m_dma_offset[(offset / 8) & 1][0];
+ break;
+ }
+ return data;
+}
+
+
+WRITE8_HANDLER(bebox_page_w)
+{
+ bebox_state *state = space->machine().driver_data<bebox_state>();
+ state->m_at_pages[offset % 0x10] = data;
+
+ switch(offset % 8)
+ {
+ case 1:
+ state->m_dma_offset[(offset / 8) & 1][2] &= 0xFF00;
+ state->m_dma_offset[(offset / 8) & 1][2] |= ((UINT16 ) data) << 0;
+ break;
+ case 2:
+ state->m_dma_offset[(offset / 8) & 1][3] &= 0xFF00;
+ state->m_dma_offset[(offset / 8) & 1][3] |= ((UINT16 ) data) << 0;
+ break;
+ case 3:
+ state->m_dma_offset[(offset / 8) & 1][1] &= 0xFF00;
+ state->m_dma_offset[(offset / 8) & 1][1] |= ((UINT16 ) data) << 0;
+ break;
+ case 7:
+ state->m_dma_offset[(offset / 8) & 1][0] &= 0xFF00;
+ state->m_dma_offset[(offset / 8) & 1][0] |= ((UINT16 ) data) << 0;
+ break;
+ }
+}
+
+
+WRITE8_HANDLER(bebox_80000480_w)
+{
+ bebox_state *state = space->machine().driver_data<bebox_state>();
+ switch(offset % 8)
+ {
+ case 1:
+ state->m_dma_offset[(offset / 8) & 1][2] &= 0x00FF;
+ state->m_dma_offset[(offset / 8) & 1][2] |= ((UINT16 ) data) << 8;
+ break;
+ case 2:
+ state->m_dma_offset[(offset / 8) & 1][3] &= 0x00FF;
+ state->m_dma_offset[(offset / 8) & 1][3] |= ((UINT16 ) data) << 8;
+ break;
+ case 3:
+ state->m_dma_offset[(offset / 8) & 1][1] &= 0x00FF;
+ state->m_dma_offset[(offset / 8) & 1][1] |= ((UINT16 ) data) << 8;
+ break;
+ case 7:
+ state->m_dma_offset[(offset / 8) & 1][0] &= 0x00FF;
+ state->m_dma_offset[(offset / 8) & 1][0] |= ((UINT16 ) data) << 8;
+ break;
+ }
+}
+
+
+READ8_HANDLER(bebox_80000480_r)
+{
+ fatalerror("NYI");
+}
+
+
+static WRITE_LINE_DEVICE_HANDLER( bebox_dma_hrq_changed )
+{
+ cputag_set_input_line(device->machine(), "ppc1", INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE);
+
+ /* Assert HLDA */
+ i8237_hlda_w( device, state );
+}
+
+
+static READ8_HANDLER( bebox_dma_read_byte )
+{
+ bebox_state *state = space->machine().driver_data<bebox_state>();
+ offs_t page_offset = (((offs_t) state->m_dma_offset[0][state->m_dma_channel]) << 16)
+ & 0x7FFF0000;
+ return space->read_byte(page_offset + offset);
+}
+
+
+static WRITE8_HANDLER( bebox_dma_write_byte )
+{
+ bebox_state *state = space->machine().driver_data<bebox_state>();
+ offs_t page_offset = (((offs_t) state->m_dma_offset[0][state->m_dma_channel]) << 16)
+ & 0x7FFF0000;
+ space->write_byte(page_offset + offset, data);
+}
+
+
+static READ8_DEVICE_HANDLER( bebox_dma8237_fdc_dack_r ) {
+ return pc_fdc_dack_r(device->machine());
+}
+
+
+static WRITE8_DEVICE_HANDLER( bebox_dma8237_fdc_dack_w ) {
+ pc_fdc_dack_w( device->machine(), data );
+}
+
+
+static WRITE_LINE_DEVICE_HANDLER( bebox_dma8237_out_eop ) {
+ pc_fdc_set_tc_state( device->machine(), state );
+}
+
+static void set_dma_channel(device_t *device, int channel, int state)
+{
+ bebox_state *drvstate = device->machine().driver_data<bebox_state>();
+ if (!state) drvstate->m_dma_channel = channel;
+}
+
+static WRITE_LINE_DEVICE_HANDLER( pc_dack0_w ) { set_dma_channel(device, 0, state); }
+static WRITE_LINE_DEVICE_HANDLER( pc_dack1_w ) { set_dma_channel(device, 1, state); }
+static WRITE_LINE_DEVICE_HANDLER( pc_dack2_w ) { set_dma_channel(device, 2, state); }
+static WRITE_LINE_DEVICE_HANDLER( pc_dack3_w ) { set_dma_channel(device, 3, state); }
+
+
+I8237_INTERFACE( bebox_dma8237_1_config )
+{
+ DEVCB_LINE(bebox_dma_hrq_changed),
+ DEVCB_LINE(bebox_dma8237_out_eop),
+ DEVCB_MEMORY_HANDLER("ppc1", PROGRAM, bebox_dma_read_byte),
+ DEVCB_MEMORY_HANDLER("ppc1", PROGRAM, bebox_dma_write_byte),
+ { DEVCB_NULL, DEVCB_NULL, DEVCB_HANDLER(bebox_dma8237_fdc_dack_r), DEVCB_NULL },
+ { DEVCB_NULL, DEVCB_NULL, DEVCB_HANDLER(bebox_dma8237_fdc_dack_w), DEVCB_NULL },
+ { DEVCB_LINE(pc_dack0_w), DEVCB_LINE(pc_dack1_w), DEVCB_LINE(pc_dack2_w), DEVCB_LINE(pc_dack3_w) }
+};
+
+
+I8237_INTERFACE( bebox_dma8237_2_config )
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ { DEVCB_NULL, DEVCB_NULL, DEVCB_NULL, DEVCB_NULL },
+ { DEVCB_NULL, DEVCB_NULL, DEVCB_NULL, DEVCB_NULL },
+ { DEVCB_NULL, DEVCB_NULL, DEVCB_NULL, DEVCB_NULL }
+};
+
+
+/*************************************
+ *
+ * 8254 PIT
+ *
+ *************************************/
+
+static WRITE_LINE_DEVICE_HANDLER( bebox_timer0_w )
+{
+ bebox_state *drvstate = device->machine().driver_data<bebox_state>();
+ if (drvstate->m_devices.pic8259_master)
+ pic8259_ir0_w(drvstate->m_devices.pic8259_master, state);
+}
+
+
+const struct pit8253_config bebox_pit8254_config =
+{
+ {
+ {
+ 4772720/4, /* heartbeat IRQ */
+ DEVCB_NULL,
+ DEVCB_LINE(bebox_timer0_w)
+ },
+ {
+ 4772720/4, /* dram refresh */
+ DEVCB_NULL,
+ DEVCB_NULL
+ },
+ {
+ 4772720/4, /* pio port c pin 4, and speaker polling enough */
+ DEVCB_NULL,
+ DEVCB_NULL
+ }
+ }
+};
+
+
+/*************************************
+ *
+ * Flash ROM
+ *
+ *************************************/
+
+READ8_HANDLER( bebox_flash_r )
+{
+ fujitsu_29f016a_device *flash = space->machine().device<fujitsu_29f016a_device>("flash");
+ offset = (offset & ~7) | (7 - (offset & 7));
+ return flash->read(offset);
+}
+
+
+WRITE8_HANDLER( bebox_flash_w )
+{
+ fujitsu_29f016a_device *flash = space->machine().device<fujitsu_29f016a_device>("flash");
+ offset = (offset & ~7) | (7 - (offset & 7));
+ flash->write(offset, data);
+}
+
+/*************************************
+ *
+ * Keyboard
+ *
+ *************************************/
+
+static void bebox_keyboard_interrupt(running_machine &machine,int state)
+{
+ bebox_state *drvstate = machine.driver_data<bebox_state>();
+ bebox_set_irq_bit(machine, 16, state);
+ if ( drvstate->m_devices.pic8259_master ) {
+ pic8259_ir1_w(drvstate->m_devices.pic8259_master, state);
+ }
+}
+
+static int bebox_get_out2(running_machine &machine) {
+ return pit8253_get_output(machine.device("pit8254"), 2 );
+}
+
+static const struct kbdc8042_interface bebox_8042_interface =
+{
+ KBDC8042_STANDARD,
+ NULL,
+ bebox_keyboard_interrupt,
+ NULL,
+ bebox_get_out2
+};
+
+
+/*************************************
+ *
+ * SCSI
+ *
+ *************************************/
+
+
+static READ64_HANDLER( scsi53c810_r )
+{
+ int reg = offset*8;
+ UINT64 r = 0;
+ if (!(mem_mask & U64(0xff00000000000000))) {
+ r |= (UINT64)lsi53c810_reg_r(space, reg+0) << 56;
+ }
+ if (!(mem_mask & U64(0x00ff000000000000))) {
+ r |= (UINT64)lsi53c810_reg_r(space, reg+1) << 48;
+ }
+ if (!(mem_mask & U64(0x0000ff0000000000))) {
+ r |= (UINT64)lsi53c810_reg_r(space, reg+2) << 40;
+ }
+ if (!(mem_mask & U64(0x000000ff00000000))) {
+ r |= (UINT64)lsi53c810_reg_r(space, reg+3) << 32;
+ }
+ if (!(mem_mask & U64(0x00000000ff000000))) {
+ r |= (UINT64)lsi53c810_reg_r(space, reg+4) << 24;
+ }
+ if (!(mem_mask & U64(0x0000000000ff0000))) {
+ r |= (UINT64)lsi53c810_reg_r(space, reg+5) << 16;
+ }
+ if (!(mem_mask & U64(0x000000000000ff00))) {
+ r |= (UINT64)lsi53c810_reg_r(space, reg+6) << 8;
+ }
+ if (!(mem_mask & U64(0x00000000000000ff))) {
+ r |= (UINT64)lsi53c810_reg_r(space, reg+7) << 0;
+ }
+
+ return r;
+}
+
+
+static WRITE64_HANDLER( scsi53c810_w )
+{
+ int reg = offset*8;
+ if (!(mem_mask & U64(0xff00000000000000))) {
+ lsi53c810_reg_w(space, reg+0, data >> 56);
+ }
+ if (!(mem_mask & U64(0x00ff000000000000))) {
+ lsi53c810_reg_w(space, reg+1, data >> 48);
+ }
+ if (!(mem_mask & U64(0x0000ff0000000000))) {
+ lsi53c810_reg_w(space, reg+2, data >> 40);
+ }
+ if (!(mem_mask & U64(0x000000ff00000000))) {
+ lsi53c810_reg_w(space, reg+3, data >> 32);
+ }
+ if (!(mem_mask & U64(0x00000000ff000000))) {
+ lsi53c810_reg_w(space, reg+4, data >> 24);
+ }
+ if (!(mem_mask & U64(0x0000000000ff0000))) {
+ lsi53c810_reg_w(space, reg+5, data >> 16);
+ }
+ if (!(mem_mask & U64(0x000000000000ff00))) {
+ lsi53c810_reg_w(space, reg+6, data >> 8);
+ }
+ if (!(mem_mask & U64(0x00000000000000ff))) {
+ lsi53c810_reg_w(space, reg+7, data >> 0);
+ }
+}
+
+
+#define BYTE_REVERSE32(x) (((x >> 24) & 0xff) | \
+ ((x >> 8) & 0xff00) | \
+ ((x << 8) & 0xff0000) | \
+ ((x << 24) & 0xff000000))
+
+static UINT32 scsi53c810_fetch(running_machine &machine, UINT32 dsp)
+{
+ UINT32 result;
+ result = machine.device("ppc1")->memory().space(AS_PROGRAM)->read_dword(dsp & 0x7FFFFFFF);
+ return BYTE_REVERSE32(result);
+}
+
+
+static void scsi53c810_irq_callback(running_machine &machine, int value)
+{
+ bebox_set_irq_bit(machine, 21, value);
+}
+
+
+static void scsi53c810_dma_callback(running_machine &machine, UINT32 src, UINT32 dst, int length, int byteswap)
+{
+}
+
+
+UINT32 scsi53c810_pci_read(device_t *busdevice, device_t *device, int function, int offset, UINT32 mem_mask)
+{
+ bebox_state *state = device->machine().driver_data<bebox_state>();
+ UINT32 result = 0;
+
+ if (function == 0)
+ {
+ switch(offset)
+ {
+ case 0x00: /* vendor/device ID */
+ result = 0x00011000;
+ break;
+
+ case 0x08:
+ result = 0x01000000;
+ break;
+
+ default:
+ result = state->m_scsi53c810_data[offset / 4];
+ break;
+ }
+ }
+ return result;
+}
+
+
+void scsi53c810_pci_write(device_t *busdevice, device_t *device, int function, int offset, UINT32 data, UINT32 mem_mask)
+{
+ bebox_state *state = device->machine().driver_data<bebox_state>();
+ offs_t addr;
+
+ if (function == 0)
+ {
+ state->m_scsi53c810_data[offset / 4] = data;
+
+ switch(offset)
+ {
+ case 0x04:
+ /* command
+ *
+ * bit 8: SERR/ Enable
+ * bit 6: Enable Parity Response
+ * bit 4: Write and Invalidate Mode
+ * bit 2: Enable Bus Mastering
+ * bit 1: Enable Memory Space
+ * bit 0: Enable IO Space
+ */
+ if (data & 0x02)
+ {
+ /* brutal ugly hack; at some point the PCI code should be handling this stuff */
+ if (state->m_scsi53c810_data[5] != 0xFFFFFFF0)
+ {
+ address_space *space = device->machine().device("ppc1")->memory().space(AS_PROGRAM);
+
+ addr = (state->m_scsi53c810_data[5] | 0xC0000000) & ~0xFF;
+ space->install_legacy_read_handler(addr, addr + 0xFF, FUNC(scsi53c810_r));
+ space->install_legacy_write_handler(addr, addr + 0xFF, FUNC(scsi53c810_w));
+ }
+ }
+ break;
+ }
+ }
+}
+
+
+static const SCSIConfigTable dev_table =
+{
+ 2, /* 2 SCSI devices */
+ {
+ { SCSI_ID_0, "harddisk1" }, /* SCSI ID 0, using HD 0, HD */
+ { SCSI_ID_3, "cdrom" } /* SCSI ID 3, using CHD 0, CD-ROM */
+ }
+};
+
+static const struct LSI53C810interface scsi53c810_intf =
+{
+ &dev_table, /* SCSI device table */
+ &scsi53c810_irq_callback,
+ &scsi53c810_dma_callback,
+ &scsi53c810_fetch,
+};
+
+
+static TIMER_CALLBACK( bebox_get_devices ) {
+ bebox_state *state = machine.driver_data<bebox_state>();
+ state->m_devices.pic8259_master = machine.device("pic8259_master");
+ state->m_devices.pic8259_slave = machine.device("pic8259_slave");
+ state->m_devices.dma8237_1 = machine.device("dma8237_1");
+ state->m_devices.dma8237_2 = machine.device("dma8237_2");
+}
+
+
+/*************************************
+ *
+ * Driver main
+ *
+ *************************************/
+
+MACHINE_RESET( bebox )
+{
+ bebox_state *state = machine.driver_data<bebox_state>();
+ state->m_devices.pic8259_master = NULL;
+ state->m_devices.pic8259_slave = NULL;
+ state->m_devices.dma8237_1 = NULL;
+ state->m_devices.dma8237_2 = NULL;
+
+ machine.scheduler().timer_set(attotime::zero, FUNC(bebox_get_devices));
+
+ cputag_set_input_line(machine, "ppc1", INPUT_LINE_RESET, CLEAR_LINE);
+ cputag_set_input_line(machine, "ppc2", INPUT_LINE_RESET, ASSERT_LINE);
+
+ memcpy(machine.device<fujitsu_29f016a_device>("flash")->space()->get_read_ptr(0),state->memregion("user1")->base(),0x200000);
+}
+
+MACHINE_START( bebox )
+{
+ pc_fdc_init(machine, &bebox_fdc_interface);
+ /* SCSI */
+ lsi53c810_init(machine, &scsi53c810_intf);
+}
+
+DRIVER_INIT_MEMBER(bebox_state,bebox)
+{
+ address_space *space_0 = machine().device("ppc1")->memory().space(AS_PROGRAM);
+ address_space *space_1 = machine().device("ppc2")->memory().space(AS_PROGRAM);
+ offs_t vram_begin;
+ offs_t vram_end;
+
+ /* set up boot and flash ROM */
+ membank("bank2")->set_base(machine().root_device().memregion("user2")->base());
+
+ /* install MESS managed RAM */
+ space_0->install_readwrite_bank(0, machine().device<ram_device>(RAM_TAG)->size() - 1, 0, 0x02000000, "bank3");
+ space_1->install_readwrite_bank(0, machine().device<ram_device>(RAM_TAG)->size() - 1, 0, 0x02000000, "bank3");
+ membank("bank3")->set_base(machine().device<ram_device>(RAM_TAG)->pointer());
+
+ kbdc8042_init(machine(), &bebox_8042_interface);
+
+ /* install VGA memory */
+ vram_begin = 0xC1000000;
+ vram_end = vram_begin + pc_vga_memory_size() - 1;
+ space_0->install_legacy_readwrite_handler(vram_begin, vram_end, FUNC(bebox_video_r), FUNC(bebox_video_w));
+ space_1->install_legacy_readwrite_handler(vram_begin, vram_end, FUNC(bebox_video_r), FUNC(bebox_video_w));
+
+ /* The following is a verrrry ugly hack put in to support NetBSD for
+ * NetBSD. When NetBSD/bebox it does most of its work on CPU #0 and then
+ * lets CPU #1 go. However, it seems that CPU #1 jumps into never-never
+ * land, crashes, and then goes into NetBSD's crash handler which catches
+ * it. The current PowerPC core cannot catch this trip into never-never
+ * land properly, and MESS crashes. In the interim, this "mitten" catches
+ * the crash
+ */
+ {
+ static UINT64 ops[2] =
+ {
+ /* li r0, 0x0700 */
+ /* mtspr ctr, r0 */
+ U64(0x380007007C0903A6),
+
+ /* bcctr 0x14, 0 */
+ U64(0x4E80042000000000)
+ };
+ space_1->install_read_bank(0x9421FFF0, 0x9421FFFF, "bank1");
+ membank("bank1")->set_base(ops);
+ }
+}
diff --git a/src/mess/machine/beta.c b/src/mess/machine/beta.c
new file mode 100644
index 00000000000..784eaf2adb9
--- /dev/null
+++ b/src/mess/machine/beta.c
@@ -0,0 +1,362 @@
+/*********************************************************************
+
+ beta.h
+
+ Implementation of Beta disk drive support for Spectrum and clones
+
+ 04/05/2008 Created by Miodrag Milanovic
+
+*********************************************************************/
+#include "emu.h"
+#include "imagedev/flopdrv.h"
+#include "formats/trd_dsk.h"
+#include "machine/wd17xx.h"
+#include "machine/beta.h"
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _beta_disk_state beta_disk_state;
+struct _beta_disk_state
+{
+ UINT8 betadisk_status;
+ UINT8 betadisk_active;
+
+ device_t *wd179x;
+};
+
+
+/*****************************************************************************
+ INLINE FUNCTIONS
+*****************************************************************************/
+INLINE beta_disk_state *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == BETA_DISK);
+
+ return (beta_disk_state *)downcast<legacy_device_base *>(device)->token();
+}
+
+
+int betadisk_is_active(device_t *device)
+{
+ beta_disk_state *beta = get_safe_token(device);
+
+ return beta->betadisk_active;
+}
+
+void betadisk_enable(device_t *device)
+{
+ beta_disk_state *beta = get_safe_token(device);
+
+ beta->betadisk_active = 1;
+}
+
+void betadisk_disable(device_t *device)
+{
+ beta_disk_state *beta = get_safe_token(device);
+
+ beta->betadisk_active = 0;
+}
+
+void betadisk_clear_status(device_t *device)
+{
+ beta_disk_state *beta = get_safe_token(device);
+
+ beta->betadisk_status = 0;
+}
+
+static WRITE_LINE_DEVICE_HANDLER( betadisk_wd179x_intrq_w )
+{
+ beta_disk_state *beta = get_safe_token(device->owner());
+
+ if (state)
+ beta->betadisk_status |= (1<<7);
+ else
+ beta->betadisk_status &=~(1<<7);
+}
+
+static WRITE_LINE_DEVICE_HANDLER( betadisk_wd179x_drq_w )
+{
+ beta_disk_state *beta = get_safe_token(device->owner());
+
+ if (state)
+ beta->betadisk_status |= (1<<6);
+ else
+ beta->betadisk_status &=~(1<<6);
+}
+
+static const wd17xx_interface beta_wd17xx_interface =
+{
+ DEVCB_NULL,
+ DEVCB_LINE(betadisk_wd179x_intrq_w),
+ DEVCB_LINE(betadisk_wd179x_drq_w),
+ {FLOPPY_0, FLOPPY_1, FLOPPY_2, FLOPPY_3}
+};
+
+READ8_DEVICE_HANDLER(betadisk_status_r)
+{
+ beta_disk_state *beta = get_safe_token(device);
+
+ if (beta->betadisk_active==1) {
+ return wd17xx_status_r(beta->wd179x, offset);
+ } else {
+ return 0xff;
+ }
+}
+
+READ8_DEVICE_HANDLER(betadisk_track_r)
+{
+ beta_disk_state *beta = get_safe_token(device);
+
+ if (beta->betadisk_active==1) {
+ return wd17xx_track_r(beta->wd179x, offset);
+ } else {
+ return 0xff;
+ }
+}
+
+READ8_DEVICE_HANDLER(betadisk_sector_r)
+{
+ beta_disk_state *beta = get_safe_token(device);
+
+ if (beta->betadisk_active==1) {
+ return wd17xx_sector_r(beta->wd179x, offset);
+ } else {
+ return 0xff;
+ }
+}
+
+READ8_DEVICE_HANDLER(betadisk_data_r)
+{
+
+ beta_disk_state *beta = get_safe_token(device);
+
+ if (beta->betadisk_active==1) {
+ return wd17xx_data_r(beta->wd179x, offset);
+ } else {
+ return 0xff;
+ }
+}
+
+READ8_DEVICE_HANDLER(betadisk_state_r)
+{
+ beta_disk_state *beta = get_safe_token(device);
+
+ if (beta->betadisk_active==1) {
+ return beta->betadisk_status;
+ } else {
+ return 0xff;
+ }
+}
+
+WRITE8_DEVICE_HANDLER(betadisk_param_w)
+{
+ beta_disk_state *beta = get_safe_token(device);
+
+ if (beta->betadisk_active==1) {
+ wd17xx_set_drive(beta->wd179x, data & 3);
+ wd17xx_set_side (beta->wd179x,(data & 0x10) ? 0 : 1 );
+ wd17xx_dden_w(beta->wd179x, !BIT(data, 5));
+ if ((data & 0x04) == 0) // reset
+ {
+ wd17xx_reset(beta->wd179x);
+ }
+ beta->betadisk_status = (data & 0x3f) | beta->betadisk_status;
+ }
+}
+
+WRITE8_DEVICE_HANDLER(betadisk_command_w)
+{
+ beta_disk_state *beta = get_safe_token(device);
+
+ if (beta->betadisk_active==1) {
+ wd17xx_command_w(beta->wd179x, offset, data);
+ }
+}
+
+WRITE8_DEVICE_HANDLER(betadisk_track_w)
+{
+ beta_disk_state *beta = get_safe_token(device);
+
+ if (beta->betadisk_active==1) {
+ wd17xx_track_w(beta->wd179x, offset, data);
+ }
+}
+
+WRITE8_DEVICE_HANDLER(betadisk_sector_w)
+{
+ beta_disk_state *beta = get_safe_token(device);
+
+ if (beta->betadisk_active==1) {
+ wd17xx_sector_w(beta->wd179x, offset, data);
+ }
+}
+
+WRITE8_DEVICE_HANDLER(betadisk_data_w)
+{
+ beta_disk_state *beta = get_safe_token(device);
+
+ if (beta->betadisk_active==1) {
+ wd17xx_data_w(beta->wd179x, offset, data);
+ }
+}
+
+static const floppy_interface beta_floppy_interface =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ FLOPPY_STANDARD_5_25_DSHD,
+ LEGACY_FLOPPY_OPTIONS_NAME(trd),
+ NULL,
+ NULL
+};
+
+static MACHINE_CONFIG_FRAGMENT( beta_disk )
+ MCFG_WD2793_ADD("wd179x", beta_wd17xx_interface ) // KR1818VG93
+ MCFG_LEGACY_FLOPPY_4_DRIVES_ADD(beta_floppy_interface)
+MACHINE_CONFIG_END
+
+ROM_START( beta_disk )
+ ROM_REGION( 0x60000, "beta", 0 )
+ ROM_LOAD( "trd501.rom", 0x00000, 0x4000, CRC(3e3cdd4c) SHA1(8303ba0cc79daa6c04cd1e6ce27e8b6886a3f0de))
+
+ ROM_LOAD( "trd503zxvgs.rom",0x00000, 0x4000, CRC(b90ee684) SHA1(c78e1b36812fb2b3e7a62e66049c850d27de74a6))
+ ROM_LOAD( "trd503m.rom", 0x00000, 0x4000, CRC(2f97fe06) SHA1(6b9decc07d5d7322c6c283f5fe950f530a42d70d))
+ ROM_LOAD( "trd503[a].rom", 0x00000, 0x4000, CRC(c43d717f) SHA1(0a74bd34538a03d0e1d214b425d95c14ad10c8c4))
+ ROM_LOAD( "trd503[a2].rom", 0x00000, 0x4000, CRC(121889b0) SHA1(c9d69cf3a0219f6e37e7eb5046961fa8fa8eb2c6))
+ ROM_LOAD( "trd503[a3].rom", 0x00000, 0x4000, CRC(1c5a25b1) SHA1(4a6fbabd82a6a8f3986ac77e7157d1a2551ed40d))
+ ROM_LOAD( "trd503beta3.rom",0x00000, 0x4000, CRC(561662f2) SHA1(4cea8a361eb848cf0ad59605c83d57c30521cfd5))
+ ROM_LOAD( "trd503beta4.rom",0x00000, 0x4000, CRC(23dbc387) SHA1(74b80d3f07dc95e9f09b83c3df4724f063f47116))
+ ROM_LOAD( "trd503all.rom", 0x00000, 0x4000, CRC(4c0187ab) SHA1(21f611e5e0bbf5d6450606e30b470f7c2c9640f1))
+ ROM_LOAD( "trd503aut.rom", 0x00000, 0x4000, CRC(7ff90178) SHA1(2261144bdb5046cb8013f744a5b0721be8577dc7))
+ ROM_LOAD( "trd503ext.rom", 0x00000, 0x4000, CRC(abb139e7) SHA1(3c1736857655a48375d30b3865963090ba635635))
+ ROM_LOAD( "trd503kay.rom", 0x00000, 0x4000, CRC(77baccbb) SHA1(9c5fb89b57643f723246453809dad3f669bf59a3))
+ ROM_LOAD( "trd503xbios.rom",0x00000, 0x4000, CRC(8be427cc) SHA1(78f423fd200e720aa6b857f00969fa1f8c7da20e))
+ ROM_LOAD( "trd503[a4].rom", 0x00000, 0x4000, CRC(c2387608) SHA1(93e0b92a3f38b59cc006d22f9c9299f5377b15e5))
+
+
+ ROM_LOAD( "trd504.rom", 0x00000, 0x4000, CRC(ba310874) SHA1(05e55e37df8eee6c68601ba9cf6c92195852ce3f))
+ ROM_LOAD( "trd504s.rom", 0x00000, 0x4000, CRC(c5ca0423) SHA1(cb2da2c4575bc54454e4f97073c5bb37505487fe))
+ ROM_LOAD( "trd504s2.rom", 0x00000, 0x4000, CRC(1e9b59aa) SHA1(d6eb0eeb429c70d1f8f9a23ca4e2feb5f73d3120))
+ ROM_LOAD( "trd504s3.rom", 0x00000, 0x4000, CRC(1fe1d003) SHA1(33703e97cc93b7edfcc0334b64233cf81b7930db))
+
+
+ ROM_LOAD( "trd504tm.rom", 0x00000, 0x4000, CRC(2334b8c6) SHA1(2fd8944e067140324e998b59aab766f16eb5c7fb))
+ ROM_LOAD( "trd504t.rom", 0x00000, 0x4000, CRC(e212d1e0) SHA1(745e9caf576e64a5386ad845256d28593d34cc40))
+ ROM_LOAD( "trd504tb2.rom", 0x00000, 0x4000, CRC(8d943e6b) SHA1(bf6ab329791258f02c5f695b0c7448998b709435))
+ ROM_LOAD( "trd504s4.rom", 0x00000, 0x4000, CRC(522ebbd6) SHA1(eede6a988ed453e506b27a8d09470e0a8d97d1aa))
+ ROM_LOAD( "trd504f.rom", 0x00000, 0x4000, CRC(ab3100d8) SHA1(33646525ae1c579cddc0dd84d3218095950965b8))
+ ROM_LOAD( "trd504em.rom", 0x00000, 0x4000, CRC(0d3f8b43) SHA1(d6783983a16b17b79337c22e9460e1cfde3744ae))
+ ROM_LOAD( "trd504-1.rom", 0x00000, 0x4000, CRC(da170c65) SHA1(80f0fe79cbf393ac91ff971d31ff9eab0c9a959e))
+ ROM_LOAD( "trd504m.rom", 0x00000, 0x4000, CRC(2f2cb630) SHA1(40b1f87f8be4e09630d7eb7c14561dde0b85c0c9))
+ ROM_LOAD( "trd504em[a].rom",0x00000, 0x4000, CRC(fcbf11e8) SHA1(8050d371d7049e0c3e946964643396a39aa5ab0f))
+ ROM_LOAD( "trd5043.rom", 0x00000, 0x4000, CRC(165d5ef8) SHA1(99d25234154e4a8b3ad5e06f260b6c41c253b333))
+
+ ROM_LOAD( "trd505.rom", 0x00000, 0x4000, CRC(fdff3810) SHA1(0a0e284d4764a542aa3e5d7c43d0291036e16c35))
+ ROM_LOAD( "trd505[a].rom", 0x00000, 0x4000, CRC(03b76c8f) SHA1(ef2a07767d3b229aa4573dcfee905156a83bc32d))
+ ROM_LOAD( "trd505h.rom", 0x00000, 0x4000, CRC(9ba15549) SHA1(5908784cdfb782066bde08f186f0bbb6f6b80545))
+ ROM_LOAD( "trd505d.rom", 0x00000, 0x4000, CRC(31e4be08) SHA1(dd08bdea8b5caa35569f49770e380d16bb37502b))
+ ROM_LOAD( "trd505[a2].rom", 0x00000, 0x4000, CRC(a102e726) SHA1(a3f0ef7b7d8b3022f306be8d9e8a51ae699097df))
+
+ ROM_LOAD( "trd56661.rom", 0x00000, 0x4000, CRC(8528c789) SHA1(1332a01137bd537fee696ba7adddc0a15b3237c4))
+ ROM_LOAD( "trd5666hte.rom", 0x00000, 0x4000, CRC(03841161) SHA1(4e523768231130947a81247e116fc049bd6da963))
+ ROM_LOAD( "trd5613.rom", 0x00000, 0x4000, CRC(d66cda49) SHA1(dac3c8396fc4f85b5673076cc647afbe439ad17a))
+
+ ROM_LOAD( "trd512.rom", 0x00000, 0x4000, CRC(b615d6c4) SHA1(4abb90243f66df19caa84f82d0b880a6ce344eca))
+ ROM_LOAD( "trd512f.rom", 0x00000, 0x4000, CRC(edb74f8c) SHA1(c5b2cd18926dde4a68bcd8c360ba33d6c11b8801))
+
+ ROM_LOAD( "trd513f.rom", 0x00000, 0x4000, CRC(6b1c17f3) SHA1(5c14c0c389e29521cb59672d93d3e8a74f0184cc))
+ ROM_LOAD( "trd513fm.rom", 0x00000, 0x4000, CRC(bad0c0a0) SHA1(da88e756302f83991774730012601ebf3c61aed9))
+ ROM_LOAD( "trd513p.rom", 0x00000, 0x4000, CRC(eb3196fe) SHA1(7c85b9b562d288155677f20f5e41e679c073379b))
+
+ ROM_LOAD( "trd604.rom", 0x00000, 0x4000, CRC(d8882a8c) SHA1(282eb7bc819aad2a12fd954e76f7838a4e1a7929))
+ ROM_LOAD( "trd604m.rom", 0x00000, 0x4000, CRC(e73394cb) SHA1(5b1336e8534513df0a71f8fedca38bc67174f03c))
+
+ ROM_LOAD( "trd605r.rom", 0x00000, 0x4000, CRC(f8816a47) SHA1(98c9b63835e559f38f6a8d1344992f02cb899add))
+ ROM_LOAD( "trd605e.rom", 0x00000, 0x4000, CRC(56d3c2db) SHA1(adc21492d216da1aca4119972f2110a23fdd23a7))
+ ROM_LOAD( "trd605h.rom", 0x00000, 0x4000, CRC(53bb1b4a) SHA1(fc899901fd59c84c9aa6c402b67d76b225ab8e5b))
+ ROM_LOAD( "trd605e-2.rom", 0x00000, 0x4000, CRC(a064b7f2) SHA1(46ac75e88375d313fdd5e873800bf82c179eb226))
+ ROM_LOAD( "trd605e-3.rom", 0x00000, 0x4000, CRC(cff3d06b) SHA1(0fca9c61cb94a4cab78118c66ba54ce6bc6dcf65))
+
+ ROM_LOAD( "trd606h.rom", 0x00000, 0x4000, CRC(6b44fdd7) SHA1(4ca7ea2bc0e62c98c9ba86a304aee3cbf88d6b09))
+
+ ROM_LOAD( "trd607m.rom", 0x00000, 0x4000, CRC(5a062f03) SHA1(bbd68481c76e8a3f2f26847faa72c42df013b617))
+
+ ROM_LOAD( "trd608.rom", 0x00000, 0x4000, CRC(5c998d53) SHA1(c65a972e75e627336c44ea184cb9ae81dfa2069b))
+ ROM_LOAD( "trd608-2.rom", 0x00000, 0x4000, CRC(3541b280) SHA1(2b93c1887f485639ec15860b5503dc7efb6d31d6))
+ ROM_LOAD( "trd608-3.rom", 0x00000, 0x4000, CRC(d3e91d69) SHA1(5e367d3601d07bd2af1d6255561a5983c0e9fb5d))
+
+ ROM_LOAD( "trd609.rom", 0x00000, 0x4000, CRC(91028924) SHA1(fa5433f73aab93c58c891ceee2cdfed0a979dfbb))
+ ROM_LOAD( "trd609e.rom", 0x00000, 0x4000, CRC(46312c8c) SHA1(0ce69fe76e17a875c287e3725f6209f1c59d8bd9))
+
+ ROM_LOAD( "trd610e.rom", 0x00000, 0x4000, CRC(95395ca4) SHA1(8cda2efbf2360cd675ea8b04b43cf1746fb41f35))
+
+ ROM_LOAD( "trd701.rom", 0x00000, 0x4000, CRC(47f39c0d) SHA1(53d8b8959c321618caaef5aeb270e530e8f8ada3))
+
+ //Default for now
+ ROM_LOAD( "trd503.rom", 0x00000, 0x4000, CRC(10751aba) SHA1(21695e3f2a8f796386ce66eea8a246b0ac44810c))
+ROM_END
+
+
+/*-------------------------------------------------
+ DEVICE_START( beta_disk )
+-------------------------------------------------*/
+
+static DEVICE_START( beta_disk )
+{
+ beta_disk_state *beta = get_safe_token(device);
+ astring tempstring;
+
+ /* validate arguments */
+ assert(device->tag() != NULL);
+
+ /* find our WD179x */
+ tempstring.printf("%s:%s", device->tag(), "wd179x");
+ beta->wd179x = device->machine().device(tempstring);
+}
+
+/*-------------------------------------------------
+ DEVICE_RESET( beta_disk )
+-------------------------------------------------*/
+
+static DEVICE_RESET( beta_disk )
+{
+}
+
+/*-------------------------------------------------
+ DEVICE_GET_INFO( beta_disk )
+-------------------------------------------------*/
+
+DEVICE_GET_INFO( beta_disk )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(beta_disk_state); break;
+
+ /* --- the following bits of info are returned as pointers --- */
+ case DEVINFO_PTR_ROM_REGION: info->romregion = ROM_NAME(beta_disk); break;
+ case DEVINFO_PTR_MACHINE_CONFIG: info->machine_config = MACHINE_CONFIG_NAME(beta_disk); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(beta_disk); break;
+ case DEVINFO_FCT_STOP: /* Nothing */ break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(beta_disk); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "Beta Disk Interface"); break;
+ case DEVINFO_STR_SHORTNAME: strcpy(info->s, "betadisk"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "Beta Disk Interface"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright the MESS Team"); break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(BETA_DISK, beta_disk);
diff --git a/src/mess/machine/beta.h b/src/mess/machine/beta.h
new file mode 100644
index 00000000000..82b6df43c98
--- /dev/null
+++ b/src/mess/machine/beta.h
@@ -0,0 +1,40 @@
+/*********************************************************************
+
+ beta.h
+
+ Implementation of Beta disk drive support for Spectrum and clones
+
+ 04/05/2008 Created by Miodrag Milanovic
+
+*********************************************************************/
+#ifndef __BETA_H__
+#define __BETA_H__
+
+
+int betadisk_is_active(device_t *device);
+void betadisk_enable(device_t *device);
+void betadisk_disable(device_t *device);
+void betadisk_clear_status(device_t *device);
+
+#define BETA_DISK_TAG "beta"
+
+DECLARE_LEGACY_DEVICE(BETA_DISK, beta_disk);
+
+#define MCFG_BETA_DISK_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, BETA_DISK, 0)
+
+#define MCFG_BETA_DISK_REMOVE(_tag) \
+ MCFG_DEVICE_REMOVE(_tag)
+
+READ8_DEVICE_HANDLER(betadisk_status_r);
+READ8_DEVICE_HANDLER(betadisk_track_r);
+READ8_DEVICE_HANDLER(betadisk_sector_r);
+READ8_DEVICE_HANDLER(betadisk_data_r);
+READ8_DEVICE_HANDLER(betadisk_state_r);
+
+WRITE8_DEVICE_HANDLER(betadisk_param_w);
+WRITE8_DEVICE_HANDLER(betadisk_command_w);
+WRITE8_DEVICE_HANDLER(betadisk_track_w);
+WRITE8_DEVICE_HANDLER(betadisk_sector_w);
+WRITE8_DEVICE_HANDLER(betadisk_data_w);
+#endif /* __BETA_H__ */
diff --git a/src/mess/machine/bk.c b/src/mess/machine/bk.c
new file mode 100644
index 00000000000..ef58b7595a2
--- /dev/null
+++ b/src/mess/machine/bk.c
@@ -0,0 +1,172 @@
+/***************************************************************************
+
+ BK machine driver by Miodrag Milanovic
+
+ 10/03/2008 Preliminary driver.
+
+****************************************************************************/
+
+
+#include "emu.h"
+#include "imagedev/cassette.h"
+#include "machine/i8255.h"
+#include "includes/bk.h"
+
+
+static TIMER_CALLBACK(keyboard_callback)
+{
+ bk_state *state = machine.driver_data<bk_state>();
+ UINT8 code, i, j;
+ static const char *const keynames[] = {
+ "LINE1", "LINE2", "LINE3", "LINE4", "LINE5", "LINE6",
+ "LINE7", "LINE8", "LINE9", "LINE10", "LINE11"
+ };
+
+ for(i = 1; i < 12; i++)
+ {
+ code = machine.root_device().ioport(keynames[i-1])->read();
+ if (code != 0)
+ {
+ for(j = 0; j < 8; j++)
+ {
+ if (code == (1 << j))
+ {
+ state->m_key_code = j + i*8;
+ break;
+ }
+ }
+ if ((machine.root_device().ioport("LINE0")->read() & 4) == 4)
+ {
+ if (i==6 || i==7)
+ {
+ state->m_key_code -= 16;
+ }
+
+ }
+ if ((machine.root_device().ioport("LINE0")->read() & 4) == 4)
+ {
+ if (i>=8 && i<=11)
+ {
+ state->m_key_code += 32;
+ }
+ }
+ state->m_key_pressed = 0x40;
+ if ((machine.root_device().ioport("LINE0")->read() & 2) == 0)
+ {
+ state->m_key_irq_vector = 0x30;
+ }
+ else
+ {
+ state->m_key_irq_vector = 0xBC;
+ }
+ cputag_set_input_line(machine, "maincpu", 0, ASSERT_LINE);
+ break;
+ }
+ }
+}
+
+
+MACHINE_START(bk0010)
+{
+ machine.scheduler().timer_pulse(attotime::from_hz(2400), FUNC(keyboard_callback));
+}
+
+static IRQ_CALLBACK(bk0010_irq_callback)
+{
+ bk_state *state = device->machine().driver_data<bk_state>();
+ device_set_input_line(device, 0, CLEAR_LINE);
+ return state->m_key_irq_vector;
+}
+
+MACHINE_RESET( bk0010 )
+{
+ bk_state *state = machine.driver_data<bk_state>();
+ device_set_irq_callback(machine.device("maincpu"), bk0010_irq_callback);
+
+ state->m_kbd_state = 0;
+ state->m_scrool = 01330;
+}
+
+READ16_MEMBER(bk_state::bk_key_state_r)
+{
+ return m_kbd_state;
+}
+READ16_MEMBER(bk_state::bk_key_code_r)
+{
+ m_kbd_state &= ~0x80; // mark reading done
+ m_key_pressed = 0;
+ return m_key_code;
+}
+READ16_MEMBER(bk_state::bk_vid_scrool_r)
+{
+ return m_scrool;
+}
+
+READ16_MEMBER(bk_state::bk_key_press_r)
+{
+ double level = (machine().device<cassette_image_device>(CASSETTE_TAG)->input());
+ UINT16 cas;
+ if (level < 0)
+ {
+ cas = 0x00;
+ }
+ else
+ {
+ cas = 0x20;
+ }
+
+ return 0x8080 | m_key_pressed | cas;
+}
+
+WRITE16_MEMBER(bk_state::bk_key_state_w)
+{
+ m_kbd_state = (m_kbd_state & ~0x40) | (data & 0x40);
+}
+
+WRITE16_MEMBER(bk_state::bk_vid_scrool_w)
+{
+ m_scrool = data;
+}
+
+WRITE16_MEMBER(bk_state::bk_key_press_w)
+{
+}
+
+READ16_MEMBER(bk_state::bk_floppy_cmd_r)
+{
+ return 0;
+}
+
+WRITE16_MEMBER(bk_state::bk_floppy_cmd_w)
+{
+ if ((data & 1) == 1)
+ {
+ m_drive = 0;
+ }
+ if ((data & 2) == 2)
+ {
+ m_drive = 1;
+ }
+ if ((data & 4) == 4)
+ {
+ m_drive = 2;
+ }
+ if ((data & 8) == 8)
+ {
+ m_drive = 3;
+ }
+ if (data == 0)
+ {
+ m_drive = -1;
+ }
+}
+
+READ16_MEMBER(bk_state::bk_floppy_data_r)
+{
+ return 0;
+}
+
+WRITE16_MEMBER(bk_state::bk_floppy_data_w)
+{
+}
+
diff --git a/src/mess/machine/c128.c b/src/mess/machine/c128.c
new file mode 100644
index 00000000000..8299ba56a03
--- /dev/null
+++ b/src/mess/machine/c128.c
@@ -0,0 +1,1307 @@
+/***************************************************************************
+
+ commodore c128 home computer
+
+ peter.trauner@jk.uni-linz.ac.at
+ documentation:
+ iDOC (http://www.softwolves.pp.se/idoc)
+ Christian Janoff mepk@c64.org
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/c128.h"
+#include "includes/c64_legacy.h"
+#include "includes/cbm.h"
+#include "machine/cbmiec.h"
+#include "cpu/m6502/m6502.h"
+#include "imagedev/cassette.h"
+#include "machine/6526cia.h"
+#include "sound/sid6581.h"
+#include "video/vic6567.h"
+#include "video/vdc8563.h"
+
+#define MMU_PAGE1 ((((state->m_mmu[10]&0xf)<<8)|state->m_mmu[9])<<8)
+#define MMU_PAGE0 ((((state->m_mmu[8]&0xf)<<8)|state->m_mmu[7])<<8)
+#define MMU_VIC_ADDR ((state->m_mmu[6]&0xc0)<<10)
+#define MMU_RAM_RCR_ADDR ((state->m_mmu[6]&0x30)<<14)
+#define MMU_SIZE (c128_mmu_helper[state->m_mmu[6]&3])
+#define MMU_BOTTOM (state->m_mmu[6]&4)
+#define MMU_TOP (state->m_mmu[6]&8)
+#define MMU_CPU8502 (state->m_mmu[5]&1) /* else z80 */
+/* fastio output (c128_mmu[5]&8) else input */
+#define MMU_FSDIR(s) ((s)->m_mmu[5]&0x08)
+#define MMU_GAME_IN (state->m_mmu[5]&0x10)
+#define MMU_EXROM_IN (state->m_mmu[5]&0x20)
+#define MMU_64MODE (state->m_mmu[5]&0x40)
+#define MMU_40_IN (state->m_mmu[5]&0x80)
+
+#define MMU_RAM_CR_ADDR ((state->m_mmu[0]&0xc0)<<10)
+#define MMU_RAM_LO (state->m_mmu[0]&2) /* else rom at 0x4000 */
+#define MMU_RAM_MID ((state->m_mmu[0]&0xc)==0xc) /* 0x8000 - 0xbfff */
+#define MMU_ROM_MID ((state->m_mmu[0]&0xc)==0)
+#define MMU_EXTERNAL_ROM_MID ((state->m_mmu[0]&0xc)==8)
+#define MMU_INTERNAL_ROM_MID ((state->m_mmu[0]&0xc)==4)
+
+#define MMU_IO_ON (!(state->m_mmu[0]&1)) /* io window at 0xd000 */
+#define MMU_ROM_HI ((state->m_mmu[0]&0x30)==0) /* rom at 0xc000 */
+#define MMU_EXTERNAL_ROM_HI ((state->m_mmu[0]&0x30)==0x20)
+#define MMU_INTERNAL_ROM_HI ((state->m_mmu[0]&0x30)==0x10)
+#define MMU_RAM_HI ((state->m_mmu[0]&0x30)==0x30)
+
+#define MMU_RAM_ADDR (MMU_RAM_RCR_ADDR|MMU_RAM_CR_ADDR)
+
+static const int c128_mmu_helper[4] =
+{0x400, 0x1000, 0x2000, 0x4000};
+
+#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)
+
+/*
+ two cpus share 1 memory system, only 1 cpu can run
+ controller is the mmu
+
+ mame has different memory subsystems for each cpu
+*/
+
+
+/* m8502 port
+ in c128 mode
+ bit 0 color
+ bit 1 lores
+ bit 2 hires
+ 3 textmode
+ 5 graphics (turned on ram at 0x1000 for video chip
+*/
+
+
+
+
+
+
+
+static void c128_nmi( running_machine &machine )
+{
+ c128_state *state = machine.driver_data<c128_state>();
+ device_t *cia_1 = machine.device("cia_1");
+ int cia1irq = mos6526_irq_r(cia_1);
+
+ if (state->m_nmilevel != (machine.root_device().ioport("SPECIAL")->read() & 0x80) || cia1irq) /* KEY_RESTORE */
+ {
+ if (1) // this was never valid, there is no active CPU during a timer firing! cpu_getactivecpu() == 0)
+ {
+ /* z80 */
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_NMI, (machine.root_device().ioport("SPECIAL")->read() & 0x80) || cia1irq);
+ }
+ else
+ {
+ cputag_set_input_line(machine, "m8502", INPUT_LINE_NMI, (machine.root_device().ioport("SPECIAL")->read() & 0x80) || cia1irq);
+ }
+
+ state->m_nmilevel = (machine.root_device().ioport("SPECIAL")->read() & 0x80) || cia1irq;
+ }
+}
+
+/***********************************************
+
+ CIA Interfaces
+
+***********************************************/
+
+/*
+ * CIA 0 - Port A keyboard line select
+ * CIA 0 - Port B keyboard line read
+ *
+ * flag cassette read input, serial request in
+ * irq to irq connected
+ *
+ * see machine/cbm.c
+ */
+
+static READ8_DEVICE_HANDLER( c128_cia0_port_a_r )
+{
+ UINT8 cia0portb = mos6526_pb_r(device->machine().device("cia_0"), 0);
+
+ return cbm_common_cia0_port_a_r(device, cia0portb);
+}
+
+static READ8_DEVICE_HANDLER( c128_cia0_port_b_r )
+{
+ c128_state *state = device->machine().driver_data<c128_state>();
+ UINT8 value = 0xff;
+ UINT8 cia0porta = mos6526_pa_r(device->machine().device("cia_0"), 0);
+ device_t *vic2e = device->machine().device("vic2e");
+
+ value &= cbm_common_cia0_port_b_r(device, cia0porta);
+
+ if (!vic2e_k0_r(vic2e))
+ value &= state->m_keyline[0];
+ if (!vic2e_k1_r(vic2e))
+ value &= state->m_keyline[1];
+ if (!vic2e_k2_r(vic2e))
+ value &= state->m_keyline[2];
+
+ return value;
+}
+
+static WRITE8_DEVICE_HANDLER( c128_cia0_port_b_w )
+{
+ device_t *vic2e = device->machine().device("vic2e");
+ vic2_lightpen_write(vic2e, data & 0x10);
+}
+
+static void c128_irq( running_machine &machine, int level )
+{
+ c128_state *state = machine.driver_data<c128_state>();
+ if (level != state->m_old_level)
+ {
+ DBG_LOG(machine, 3, "mos6510", ("irq %s\n", level ? "start" : "end"));
+
+ if (0) // && (cpu_getactivecpu() == 0))
+ {
+ cputag_set_input_line(machine, "maincpu", 0, level);
+ }
+ else
+ {
+ cputag_set_input_line(machine, "m8502", M6510_IRQ_LINE, level);
+ }
+
+ state->m_old_level = level;
+ }
+}
+
+static void c128_cia0_interrupt( device_t *device, int level )
+{
+ c128_state *state = device->machine().driver_data<c128_state>();
+ c128_irq(device->machine(), level || state->m_vicirq);
+}
+
+WRITE_LINE_MEMBER( c128_state::vic_interrupt )
+{
+ device_t *cia_0 = machine().device("cia_0");
+#if 1
+ if (state != m_vicirq)
+ {
+ c128_irq (machine(), state || mos6526_irq_r(cia_0));
+ m_vicirq = state;
+ }
+#endif
+}
+
+static void c128_iec_data_out_w(running_machine &machine)
+{
+ c128_state *state = machine.driver_data<c128_state>();
+ int data = !state->m_data_out;
+
+ /* fast serial data */
+ if (MMU_FSDIR(state)) data &= state->m_sp1;
+
+ state->m_iec->data_w(data);
+}
+
+static void c128_iec_srq_out_w(running_machine &machine)
+{
+ c128_state *state = machine.driver_data<c128_state>();
+ int srq = 1;
+
+ /* fast serial clock */
+ if (MMU_FSDIR(state)) srq &= state->m_cnt1;
+
+ state->m_iec->srq_w(srq);
+}
+
+static WRITE_LINE_DEVICE_HANDLER( cia0_cnt_w )
+{
+ c128_state *drvstate = device->machine().driver_data<c128_state>();
+ /* fast clock out */
+ drvstate->m_cnt1 = state;
+ c128_iec_srq_out_w(device->machine());
+}
+
+static WRITE_LINE_DEVICE_HANDLER( cia0_sp_w )
+{
+ c128_state *drvstate = device->machine().driver_data<c128_state>();
+ /* fast data out */
+ drvstate->m_sp1 = state;
+ c128_iec_data_out_w(device->machine());
+}
+
+const mos6526_interface c128_ntsc_cia0 =
+{
+ 60,
+ DEVCB_LINE(c128_cia0_interrupt),
+ DEVCB_NULL, /* pc_func */
+ DEVCB_LINE(cia0_cnt_w),
+ DEVCB_LINE(cia0_sp_w),
+ DEVCB_HANDLER(c128_cia0_port_a_r),
+ DEVCB_NULL,
+ DEVCB_HANDLER(c128_cia0_port_b_r),
+ DEVCB_HANDLER(c128_cia0_port_b_w)
+};
+
+const mos6526_interface c128_pal_cia0 =
+{
+ 50,
+ DEVCB_LINE(c128_cia0_interrupt),
+ DEVCB_NULL, /* pc_func */
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(c128_cia0_port_a_r),
+ DEVCB_NULL,
+ DEVCB_HANDLER(c128_cia0_port_b_r),
+ DEVCB_HANDLER(c128_cia0_port_b_w)
+};
+
+WRITE_LINE_DEVICE_HANDLER( c128_iec_srq_w )
+{
+ c128_state *drvstate = device->machine().driver_data<c128_state>();
+
+ if (!MMU_FSDIR(drvstate))
+ {
+ mos6526_flag_w(device, state);
+ mos6526_cnt_w(device, state);
+ }
+}
+
+WRITE_LINE_DEVICE_HANDLER( c128_iec_data_w )
+{
+ c128_state *drvstate = device->machine().driver_data<c128_state>();
+
+ if (!MMU_FSDIR(drvstate))
+ {
+ mos6526_sp_w(device, state);
+ }
+}
+
+/*
+ * CIA 1 - Port A
+ * bit 7 serial bus data input
+ * bit 6 serial bus clock input
+ * bit 5 serial bus data output
+ * bit 4 serial bus clock output
+ * bit 3 serial bus atn output
+ * bit 2 rs232 data output
+ * bits 1-0 vic-chip system memory bank select
+ *
+ * CIA 1 - Port B
+ * bit 7 user rs232 data set ready
+ * bit 6 user rs232 clear to send
+ * bit 5 user
+ * bit 4 user rs232 carrier detect
+ * bit 3 user rs232 ring indicator
+ * bit 2 user rs232 data terminal ready
+ * bit 1 user rs232 request to send
+ * bit 0 user rs232 received data
+ *
+ * flag restore key or rs232 received data input
+ * irq to nmi connected ?
+ */
+static READ8_DEVICE_HANDLER( c128_cia1_port_a_r )
+{
+ c128_state *state = device->machine().driver_data<c128_state>();
+ UINT8 value = 0xff;
+
+ if (!state->m_iec->clk_r())
+ value &= ~0x40;
+
+ if (!state->m_iec->data_r())
+ value &= ~0x80;
+
+ return value;
+}
+
+static WRITE8_DEVICE_HANDLER( c128_cia1_port_a_w )
+{
+ c128_state *state = device->machine().driver_data<c128_state>();
+ static const int helper[4] = {0xc000, 0x8000, 0x4000, 0x0000};
+
+ state->m_data_out = BIT(data, 5);
+ c128_iec_data_out_w(device->machine());
+
+ state->m_iec->clk_w(!BIT(data, 4));
+
+ state->m_iec->atn_w(!BIT(data, 3));
+
+ state->m_vicaddr = state->m_memory + helper[data & 0x03];
+ state->m_c128_vicaddr = state->m_memory + helper[data & 0x03] + state->m_va1617;
+}
+
+static void c128_cia1_interrupt( device_t *device, int level )
+{
+ c128_nmi(device->machine());
+}
+
+const mos6526_interface c128_ntsc_cia1 =
+{
+ 60,
+ DEVCB_LINE(c128_cia1_interrupt),
+ DEVCB_NULL, /* pc_func */
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(c128_cia1_port_a_r),
+ DEVCB_HANDLER(c128_cia1_port_a_w),
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+const mos6526_interface c128_pal_cia1 =
+{
+ 50,
+ DEVCB_LINE(c128_cia1_interrupt),
+ DEVCB_NULL, /* pc_func */
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(c128_cia1_port_a_r),
+ DEVCB_HANDLER(c128_cia1_port_a_w),
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+/***********************************************
+
+ Memory Handlers
+
+***********************************************/
+static WRITE8_HANDLER( c128_dma8726_port_w )
+{
+ DBG_LOG(space->machine(), 1, "dma write", ("%.3x %.2x\n",offset,data));
+}
+
+static READ8_HANDLER( c128_dma8726_port_r )
+{
+ DBG_LOG(space->machine(), 1, "dma read", ("%.3x\n",offset));
+ return 0xff;
+}
+
+WRITE8_HANDLER( c128_write_d000 )
+{
+ c128_state *state = space->machine().driver_data<c128_state>();
+ device_t *cia_0 = space->machine().device("cia_0");
+ device_t *cia_1 = space->machine().device("cia_1");
+ device_t *sid = space->machine().device("sid6581");
+ device_t *vic2e = space->machine().device("vic2e");
+ device_t *vdc8563 = space->machine().device("vdc8563");
+
+ UINT8 c64_port6510 = m6510_get_port(space->machine().device<legacy_cpu_device>("m8502"));
+
+ if (!state->m_write_io)
+ {
+ if (offset + 0xd000 >= state->m_ram_top)
+ state->m_memory[0xd000 + offset] = data;
+ else
+ state->m_ram[0xd000 + offset] = data;
+ }
+ else
+ {
+ switch ((offset&0xf00)>>8)
+ {
+ case 0:case 1: case 2: case 3:
+ vic2_port_w(vic2e, offset & 0x3ff, data);
+ break;
+ case 4:
+ sid6581_w(sid, offset & 0x3f, data);
+ break;
+ case 5:
+ c128_mmu8722_port_w(space, offset & 0xff, data);
+ break;
+ case 6:case 7:
+ vdc8563_port_w(vdc8563, offset & 0xff, data);
+ break;
+ case 8: case 9: case 0xa: case 0xb:
+ if (state->m_c64mode)
+ state->m_colorram[(offset & 0x3ff)] = data | 0xf0;
+ else
+ state->m_colorram[(offset & 0x3ff)|((c64_port6510&3)<<10)] = data | 0xf0; // maybe all 8 bit connected!
+ break;
+ case 0xc:
+ mos6526_w(cia_0, offset, data);
+ break;
+ case 0xd:
+ mos6526_w(cia_1, offset, data);
+ break;
+ case 0xf:
+ c128_dma8726_port_w(space, offset&0xff,data);
+ break;
+ case 0xe:
+ DBG_LOG(space->machine(), 1, "io write", ("%.3x %.2x\n", offset, data));
+ break;
+ }
+ }
+}
+
+
+
+static READ8_HANDLER( c128_read_io )
+{
+ c128_state *state = space->machine().driver_data<c128_state>();
+ device_t *cia_0 = space->machine().device("cia_0");
+ device_t *cia_1 = space->machine().device("cia_1");
+ device_t *sid = space->machine().device("sid6581");
+ device_t *vic2e= space->machine().device("vic2e");
+ device_t *vdc8563 = space->machine().device("vdc8563");
+
+ if (offset < 0x400)
+ return vic2_port_r(vic2e, offset & 0x3ff);
+ else if (offset < 0x500)
+ return sid6581_r(sid, offset & 0xff);
+ else if (offset < 0x600)
+ return c128_mmu8722_port_r(space, offset & 0xff);
+ else if (offset < 0x800)
+ return vdc8563_port_r(vdc8563, offset & 0xff);
+ else if (offset < 0xc00)
+ return state->m_colorram[offset & 0x3ff];
+ else if (offset == 0xc00)
+ {
+ cia_set_port_mask_value(cia_0, 0, state->ioport("CTRLSEL")->read() & 0x80 ? c64_keyline[8] : c64_keyline[9] );
+ return mos6526_r(cia_0, offset);
+ }
+ else if (offset == 0xc01)
+ {
+ cia_set_port_mask_value(cia_0, 1, space->machine().root_device().ioport("CTRLSEL")->read() & 0x80 ? c64_keyline[9] : c64_keyline[8] );
+ return mos6526_r(cia_0, offset);
+ }
+ else if (offset < 0xd00)
+ return mos6526_r(cia_0, offset);
+ else if (offset < 0xe00)
+ return mos6526_r(cia_1, offset);
+ else if ((offset >= 0xf00) & (offset <= 0xfff))
+ return c128_dma8726_port_r(space, offset&0xff);
+ DBG_LOG(space->machine(), 1, "io read", ("%.3x\n", offset));
+ return 0xff;
+}
+
+void c128_bankswitch_64( running_machine &machine, int reset )
+{
+ c128_state *state = machine.driver_data<c128_state>();
+ int data, loram, hiram, charen;
+
+ if (!state->m_c64mode)
+ return;
+
+ data = m6510_get_port(machine.device<legacy_cpu_device>("m8502")) & 0x07;
+ if ((state->m_old_data == data) && (state->m_old_exrom == state->m_exrom) && (state->m_old_game == state->m_game) && !reset)
+ return;
+
+ DBG_LOG(machine, 1, "bankswitch", ("%d\n", data & 7));
+ loram = (data & 1) ? 1 : 0;
+ hiram = (data & 2) ? 1 : 0;
+ charen = (data & 4) ? 1 : 0;
+
+ if ((!state->m_game && state->m_exrom) || (loram && hiram && !state->m_exrom))
+ state->membank("bank8")->set_base(state->m_roml);
+ else
+ state->membank("bank8")->set_base(state->m_memory + 0x8000);
+
+ if ((!state->m_game && state->m_exrom && hiram) || (!state->m_exrom))
+ state->membank("bank9")->set_base(state->m_romh);
+ else if (loram && hiram)
+ state->membank("bank9")->set_base(state->m_basic);
+ else
+ state->membank("bank9")->set_base(state->m_memory + 0xa000);
+
+ if ((!state->m_game && state->m_exrom) || (charen && (loram || hiram)))
+ {
+ machine.device("m8502")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0xd000, 0xdfff, FUNC(c128_read_io));
+ state->m_write_io = 1;
+ }
+ else
+ {
+ machine.device("m8502")->memory().space(AS_PROGRAM)->install_read_bank(0xd000, 0xdfff, "bank5");
+ state->m_write_io = 0;
+ if ((!charen && (loram || hiram)))
+ state->membank("bank13")->set_base(state->m_chargen);
+ else
+ state->membank("bank13")->set_base(state->m_memory + 0xd000);
+ }
+
+ if (!state->m_game && state->m_exrom)
+ {
+ state->membank("bank14")->set_base(state->m_romh);
+ state->membank("bank15")->set_base(state->m_romh+0x1f00);
+ state->membank("bank16")->set_base(state->m_romh+0x1f05);
+ }
+ else
+ {
+ if (hiram)
+ {
+ state->membank("bank14")->set_base(state->m_kernal);
+ state->membank("bank15")->set_base(state->m_kernal+0x1f00);
+ state->membank("bank16")->set_base(state->m_kernal+0x1f05);
+ }
+ else
+ {
+ state->membank("bank14")->set_base(state->m_memory + 0xe000);
+ state->membank("bank15")->set_base(state->m_memory + 0xff00);
+ state->membank("bank16")->set_base(state->m_memory + 0xff05);
+ }
+ }
+ state->m_old_data = data;
+ state->m_old_exrom = state->m_exrom;
+ state->m_old_game =state->m_game;
+}
+
+/* typical z80 configuration
+ 0x3f 0x3f 0x7f 0x3e 0x7e 0xb0 0x0b 0x00 0x00 0x01 0x00 */
+static void c128_bankswitch_z80( running_machine &machine )
+{
+ c128_state *state = machine.driver_data<c128_state>();
+ state->m_ram = state->m_memory + MMU_RAM_ADDR;
+ state->m_va1617 = MMU_VIC_ADDR;
+#if 1
+ state->membank("bank10")->set_base(state->m_z80);
+ state->membank("bank11")->set_base(state->m_ram + 0x1000);
+ if ( (( (machine.root_device().ioport("SPECIAL")->read() & 0x06) == 0x02 ) && (MMU_RAM_ADDR >= 0x40000))
+ || (( (machine.root_device().ioport("SPECIAL")->read() & 0x06) == 0x00) && (MMU_RAM_ADDR >= 0x20000)) )
+ state->m_ram = NULL;
+#else
+ if (MMU_BOTTOM)
+ state->m_ram_bottom = MMU_SIZE;
+ else
+ state->m_ram_bottom = 0;
+
+ if (MMU_RAM_ADDR==0) { /* this is used in z80 mode for rom on/off switching !*/
+ state->membank("bank10")->set_base(state->m_z80);
+ state->membank("bank11")->set_base(state->m_z80 + 0x400);
+ }
+ else
+ {
+ state->membank("bank10")->set_base((state->m_ram_bottom > 0 ? state->m_memory : state->m_ram));
+ state->membank("bank11")->set_base((state->m_ram_bottom > 0x400 ? state->m_memory : state->m_ram) + 0x400);
+ }
+
+ state->membank("bank1")->set_base((state->m_ram_bottom > 0 ? state->m_memory : state->m_ram));
+ state->membank("bank2")->set_base((state->m_ram_bottom > 0x400 ? state->m_memory : state->m_ram) + 0x400);
+
+ state->membank("bank3")->set_base((state->m_ram_bottom > 0x1000 ? state->m_memory : state->m_ram) + 0x1000);
+ state->membank("bank4")->set_base((state->m_ram_bottom > 0x2000 ? state->m_memory : state->m_ram) + 0x2000);
+ state->membank("bank5")->set_base(state->m_ram + 0x4000);
+
+ if (MMU_TOP)
+ state->m_ram_top = 0x10000 - MMU_SIZE;
+ else
+ state->m_ram_top = 0x10000;
+
+ if (state->m_ram_top > 0xc000)
+ state->membank("bank6")->set_base(state->m_ram + 0xc000);
+ else
+ state->membank("bank6")->set_base(state->m_memory + 0xc000);
+
+ if (state->m_ram_top > 0xe000)
+ state->membank("bank7")->set_base(state->m_ram + 0xe000);
+ else
+ state->membank("bank7")->set_base(state->m_memory + 0xd000);
+
+ if (state->m_ram_top > 0xf000)
+ state->membank("bank8")->set_base(state->m_ram + 0xf000);
+ else
+ state->membank("bank8")->set_base(state->m_memory + 0xe000);
+
+ if (state->m_ram_top > 0xff05)
+ state->membank("bank9")->set_base(state->m_ram + 0xff05);
+ else
+ state->membank("bank9")->set_base(state->m_memory + 0xff05);
+
+ if ( (( (machine.root_device().ioport("SPECIAL")->read() & 0x06) == 0x02 ) && (MMU_RAM_ADDR >= 0x40000))
+ || (( (machine.root_device().ioport("SPECIAL")->read() & 0x06) == 0x00) && (MMU_RAM_ADDR >= 0x20000)) )
+ state->m_ram = NULL;
+#endif
+}
+
+static void c128_bankswitch_128( running_machine &machine, int reset )
+{
+ c128_state *state = machine.driver_data<c128_state>();
+ state->m_c64mode = MMU_64MODE;
+ if (state->m_c64mode)
+ {
+ /* mmu works also in c64 mode, but this can wait */
+ state->m_ram = state->m_memory;
+ state->m_va1617 = 0;
+ state->m_ram_bottom = 0;
+ state->m_ram_top = 0x10000;
+
+ state->membank("bank1")->set_base(state->m_memory);
+ state->membank("bank2")->set_base(state->m_memory + 0x100);
+
+ state->membank("bank3")->set_base(state->m_memory + 0x200);
+ state->membank("bank4")->set_base(state->m_memory + 0x400);
+ state->membank("bank5")->set_base(state->m_memory + 0x1000);
+ state->membank("bank6")->set_base(state->m_memory + 0x2000);
+
+ state->membank("bank7")->set_base(state->m_memory + 0x4000);
+
+ state->membank("bank12")->set_base(state->m_memory + 0xc000);
+
+ c128_bankswitch_64(machine, reset);
+ }
+ else
+ {
+ state->m_ram = state->m_memory + MMU_RAM_ADDR;
+ state->m_va1617 = MMU_VIC_ADDR;
+ state->membank("bank1")->set_base(state->m_memory + state->m_mmu_page0);
+ state->membank("bank2")->set_base(state->m_memory + state->m_mmu_page1);
+ if (MMU_BOTTOM)
+ {
+ state->m_ram_bottom = MMU_SIZE;
+ }
+ else
+ state->m_ram_bottom = 0;
+ state->membank("bank3")->set_base((state->m_ram_bottom > 0x200 ? state->m_memory : state->m_ram) + 0x200);
+ state->membank("bank4")->set_base((state->m_ram_bottom > 0x400 ? state->m_memory : state->m_ram) + 0x400);
+ state->membank("bank5")->set_base((state->m_ram_bottom > 0x1000 ? state->m_memory : state->m_ram) + 0x1000);
+ state->membank("bank6")->set_base((state->m_ram_bottom > 0x2000 ? state->m_memory : state->m_ram) + 0x2000);
+
+ if (MMU_RAM_LO)
+ {
+ state->membank("bank7")->set_base(state->m_ram + 0x4000);
+ }
+ else
+ {
+ state->membank("bank7")->set_base(state->m_c128_basic);
+ }
+
+ if (MMU_RAM_MID)
+ {
+ state->membank("bank8")->set_base(state->m_ram + 0x8000);
+ state->membank("bank9")->set_base(state->m_ram + 0xa000);
+ }
+ else if (MMU_ROM_MID)
+ {
+ state->membank("bank8")->set_base(state->m_c128_basic + 0x4000);
+ state->membank("bank9")->set_base(state->m_c128_basic + 0x6000);
+ }
+ else if (MMU_INTERNAL_ROM_MID)
+ {
+ state->membank("bank8")->set_base(state->m_internal_function);
+ state->membank("bank9")->set_base(state->m_internal_function + 0x2000);
+ }
+ else
+ {
+ state->membank("bank8")->set_base(state->m_external_function);
+ state->membank("bank9")->set_base(state->m_external_function + 0x2000);
+ }
+
+ if (MMU_TOP)
+ {
+ state->m_ram_top = 0x10000 - MMU_SIZE;
+ }
+ else
+ state->m_ram_top = 0x10000;
+
+ machine.device("m8502")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0xff00, 0xff04, FUNC(c128_mmu8722_ff00_r));
+
+ if (MMU_IO_ON)
+ {
+ state->m_write_io = 1;
+ machine.device("m8502")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0xd000, 0xdfff, FUNC(c128_read_io));
+ }
+ else
+ {
+ state->m_write_io = 0;
+ machine.device("m8502")->memory().space(AS_PROGRAM)->install_read_bank(0xd000, 0xdfff, "bank13");
+ }
+
+
+ if (MMU_RAM_HI)
+ {
+ if (state->m_ram_top > 0xc000)
+ {
+ state->membank("bank12")->set_base(state->m_ram + 0xc000);
+ }
+ else
+ {
+ state->membank("bank12")->set_base(state->m_memory + 0xc000);
+ }
+ if (!MMU_IO_ON)
+ {
+ if (state->m_ram_top > 0xd000)
+ {
+ state->membank("bank13")->set_base(state->m_ram + 0xd000);
+ }
+ else
+ {
+ state->membank("bank13")->set_base(state->m_memory + 0xd000);
+ }
+ }
+ if (state->m_ram_top > 0xe000)
+ {
+ state->membank("bank14")->set_base(state->m_ram + 0xe000);
+ }
+ else
+ {
+ state->membank("bank14")->set_base(state->m_memory + 0xe000);
+ }
+ if (state->m_ram_top > 0xff05)
+ {
+ state->membank("bank16")->set_base(state->m_ram + 0xff05);
+ }
+ else
+ {
+ state->membank("bank16")->set_base(state->m_memory + 0xff05);
+ }
+ }
+ else if (MMU_ROM_HI)
+ {
+ state->membank("bank12")->set_base(state->m_editor);
+ if (!MMU_IO_ON) {
+ state->membank("bank13")->set_base(state->m_c128_chargen);
+ }
+ state->membank("bank14")->set_base(state->m_c128_kernal);
+ state->membank("bank16")->set_base(state->m_c128_kernal + 0x1f05);
+ }
+ else if (MMU_INTERNAL_ROM_HI)
+ {
+ state->membank("bank12")->set_base(state->m_internal_function);
+ if (!MMU_IO_ON) {
+ state->membank("bank13")->set_base(state->m_internal_function + 0x1000);
+ }
+ state->membank("bank14")->set_base(state->m_internal_function + 0x2000);
+ state->membank("bank16")->set_base(state->m_internal_function + 0x3f05);
+ }
+ else /*if (MMU_EXTERNAL_ROM_HI) */
+ {
+ state->membank("bank12")->set_base(state->m_external_function);
+ if (!MMU_IO_ON) {
+ state->membank("bank13")->set_base(state->m_external_function + 0x1000);
+ }
+ state->membank("bank14")->set_base(state->m_external_function + 0x2000);
+ state->membank("bank16")->set_base(state->m_external_function + 0x3f05);
+ }
+
+ if ( (( (machine.root_device().ioport("SPECIAL")->read() & 0x06) == 0x02 ) && (MMU_RAM_ADDR >= 0x40000))
+ || (( (machine.root_device().ioport("SPECIAL")->read() & 0x06) == 0x00) && (MMU_RAM_ADDR >= 0x20000)) )
+ state->m_ram = NULL;
+ }
+}
+
+// 128u4
+// FIX-ME: are the bankswitch functions working in the expected way without the memory_set_context?
+static void c128_bankswitch( running_machine &machine, int reset )
+{
+ c128_state *state = machine.driver_data<c128_state>();
+ if (state->m_mmu_cpu != MMU_CPU8502)
+ {
+ if (!MMU_CPU8502)
+ {
+// DBG_LOG(machine, 1, "switching to z80", ("active %d\n",cpu_getactivecpu()) );
+// memory_set_context(machine, 0);
+ c128_bankswitch_z80(machine);
+// memory_set_context(machine, 1);
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_HALT, CLEAR_LINE);
+ cputag_set_input_line(machine, "m8502", INPUT_LINE_HALT, ASSERT_LINE);
+ }
+ else
+ {
+// DBG_LOG(machine, 1, "switching to m6502", ("active %d\n",cpu_getactivecpu()) );
+// memory_set_context(machine, 1);
+ c128_bankswitch_128(machine, reset);
+// memory_set_context(machine, 0);
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_HALT, ASSERT_LINE);
+ cputag_set_input_line(machine, "m8502", INPUT_LINE_HALT, CLEAR_LINE);
+
+ /* NPW 19-Nov-2005 - In the C128, CPU #0 starts out and hands over
+ * control to CPU #1. CPU #1 seems to execute garbage from 0x0000
+ * up to 0x1100, at which point it finally hits some code
+ * (presumably set up by CPU #1.) This always worked, but when I
+ * changed the m8502 CPU core to use an internal memory map, it
+ * started BRK-ing forever when trying to execute 0x0000.
+ *
+ * I am not sure whether the C128 actually executes this invalid
+ * memory or if this is a bug in the C128 driver. In any case, the
+ * driver used to work with this behavior, so I am doing this hack
+ * where I set CPU #1's PC to 0x1100 on reset.
+ */
+ if (cpu_get_reg(machine.device("m8502"), STATE_GENPC) == 0x0000)
+ cpu_set_reg(machine.device("m8502"), STATE_GENPC, 0x1100);
+ }
+ state->m_mmu_cpu = MMU_CPU8502;
+ return;
+ }
+ if (!MMU_CPU8502)
+ c128_bankswitch_z80(machine);
+ else
+ c128_bankswitch_128(machine, reset);
+}
+
+static void c128_mmu8722_reset( running_machine &machine )
+{
+ c128_state *state = machine.driver_data<c128_state>();
+ memset(state->m_mmu, 0, sizeof (state->m_mmu));
+ state->m_mmu[5] |= 0x38;
+ state->m_mmu[10] = 1;
+ state->m_mmu_cpu = 0;
+ state->m_mmu_page0 = 0;
+ state->m_mmu_page1 = 0x0100;
+ c128_bankswitch (machine, 1);
+}
+
+WRITE8_HANDLER( c128_mmu8722_port_w )
+{
+ c128_state *state = space->machine().driver_data<c128_state>();
+ offset &= 0xf;
+ switch (offset)
+ {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 8:
+ case 10:
+ state->m_mmu[offset] = data;
+ break;
+ case 5:
+ state->m_mmu[offset] = data;
+ c128_bankswitch (space->machine(), 0);
+ c128_iec_srq_out_w(space->machine());
+ c128_iec_data_out_w(space->machine());
+ break;
+ case 0:
+ case 6:
+ state->m_mmu[offset] = data;
+ c128_bankswitch (space->machine(), 0);
+ break;
+ case 7:
+ state->m_mmu[offset] = data;
+ state->m_mmu_page0=MMU_PAGE0;
+ break;
+ case 9:
+ state->m_mmu[offset] = data;
+ state->m_mmu_page1=MMU_PAGE1;
+ c128_bankswitch (space->machine(), 0);
+ break;
+ case 0xb:
+ break;
+ case 0xc:
+ case 0xd:
+ case 0xe:
+ case 0xf:
+ break;
+ }
+}
+
+READ8_HANDLER( c128_mmu8722_port_r )
+{
+ c128_state *state = space->machine().driver_data<c128_state>();
+ int data;
+
+ offset &= 0x0f;
+ switch (offset)
+ {
+ case 5:
+ data = state->m_mmu[offset] | 6;
+ if ( /*disk enable signal */ 0)
+ data &= ~8;
+ if (!state->m_game)
+ data &= ~0x10;
+ if (!state->m_exrom)
+ data &= ~0x20;
+ if (space->machine().root_device().ioport("SPECIAL")->read() & 0x10)
+ data &= ~0x80;
+ break;
+ case 0xb:
+ /* hinybble number of 64 kb memory blocks */
+ if ((space->machine().root_device().ioport("SPECIAL")->read() & 0x06) == 0x02) // 256KB RAM
+ data = 0x4f;
+ else if ((state->ioport("SPECIAL")->read() & 0x06) == 0x04) // 1MB
+ data = 0xf;
+ else
+ data = 0x2f;
+ break;
+ case 0xc:
+ case 0xd:
+ case 0xe:
+ case 0xf:
+ data=0xff;
+ break;
+ default:
+ data=state->m_mmu[offset];
+ }
+ return data;
+}
+
+WRITE8_HANDLER( c128_mmu8722_ff00_w )
+{
+ c128_state *state = space->machine().driver_data<c128_state>();
+ switch (offset)
+ {
+ case 0:
+ state->m_mmu[offset] = data;
+ c128_bankswitch (space->machine(), 0);
+ break;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+#if 1
+ state->m_mmu[0]= state->m_mmu[offset];
+#else
+ state->m_mmu[0]|= state->m_mmu[offset];
+#endif
+ c128_bankswitch (space->machine(), 0);
+ break;
+ }
+}
+
+ READ8_HANDLER( c128_mmu8722_ff00_r )
+{
+ c128_state *state = space->machine().driver_data<c128_state>();
+ return state->m_mmu[offset];
+}
+
+WRITE8_HANDLER( c128_write_0000 )
+{
+ c128_state *state = space->machine().driver_data<c128_state>();
+ if (state->m_ram != NULL)
+ state->m_ram[0x0000 + offset] = data;
+}
+
+WRITE8_HANDLER( c128_write_1000 )
+{
+ c128_state *state = space->machine().driver_data<c128_state>();
+ if (state->m_ram != NULL)
+ state->m_ram[0x1000 + offset] = data;
+}
+
+WRITE8_HANDLER( c128_write_4000 )
+{
+ c128_state *state = space->machine().driver_data<c128_state>();
+ if (state->m_ram != NULL)
+ state->m_ram[0x4000 + offset] = data;
+}
+
+WRITE8_HANDLER( c128_write_8000 )
+{
+ c128_state *state = space->machine().driver_data<c128_state>();
+ if (state->m_ram != NULL)
+ state->m_ram[0x8000 + offset] = data;
+}
+
+WRITE8_HANDLER( c128_write_a000 )
+{
+ c128_state *state = space->machine().driver_data<c128_state>();
+ if (state->m_ram != NULL)
+ state->m_ram[0xa000 + offset] = data;
+}
+
+WRITE8_HANDLER( c128_write_c000 )
+{
+ c128_state *state = space->machine().driver_data<c128_state>();
+ if (state->m_ram != NULL)
+ state->m_ram[0xc000 + offset] = data;
+}
+
+WRITE8_HANDLER( c128_write_e000 )
+{
+ c128_state *state = space->machine().driver_data<c128_state>();
+ if (offset + 0xe000 >= state->m_ram_top)
+ state->m_memory[0xe000 + offset] = data;
+ else if (state->m_ram != NULL)
+ state->m_ram[0xe000 + offset] = data;
+}
+
+WRITE8_HANDLER( c128_write_ff00 )
+{
+ c128_state *state = space->machine().driver_data<c128_state>();
+ if (!state->m_c64mode)
+ c128_mmu8722_ff00_w(space, offset, data);
+ else if (state->m_ram!=NULL)
+ state->m_memory[0xff00 + offset] = data;
+}
+
+WRITE8_HANDLER( c128_write_ff05 )
+{
+ c128_state *state = space->machine().driver_data<c128_state>();
+ if (offset + 0xff05 >= state->m_ram_top)
+ state->m_memory[0xff05 + offset] = data;
+ else if (state->m_ram!=NULL)
+ state->m_ram[0xff05 + offset] = data;
+}
+
+/*
+ * only 14 address lines
+ * a15 and a14 portlines
+ * 0x1000-0x1fff, 0x9000-0x9fff char rom
+ */
+READ8_MEMBER( c128_state::vic_dma_read )
+{
+ UINT8 c64_port6510 = m6510_get_port(machine().device<legacy_cpu_device>("m8502"));
+
+ /* main memory configuration to include */
+ if (m_c64mode)
+ {
+ if (!m_game && m_exrom)
+ {
+ if (offset < 0x3000)
+ return m_memory[offset];
+ return m_romh[offset & 0x1fff];
+ }
+ if (((m_vicaddr - m_memory + offset) & 0x7000) == 0x1000)
+ return m_chargen[offset & 0xfff];
+ return m_vicaddr[offset];
+ }
+ if (!(c64_port6510 & 4) && (((m_c128_vicaddr - m_memory + offset) & 0x7000) == 0x1000))
+ return m_c128_chargen[offset & 0xfff];
+ return m_c128_vicaddr[offset];
+}
+
+READ8_MEMBER( c128_state::vic_dma_read_color )
+{
+ UINT8 c64_port6510 = m6510_get_port(machine().device<legacy_cpu_device>("m8502"));
+
+ if (m_c64mode)
+ return m_colorram[offset & 0x3ff] & 0xf;
+ else
+ return m_colorram[(offset & 0x3ff)|((c64_port6510 & 0x3) << 10)] & 0xf;
+}
+
+/* 2008-09-01
+ We need here the m6510 port handlers from c64, otherwise c128_common_driver_init
+ seems unable to use correctly the timer.
+ This will be probably fixed in a future clean up.
+*/
+
+
+WRITE8_DEVICE_HANDLER(c128_m6510_port_write)
+{
+ c128_state *state = device->machine().driver_data<c128_state>();
+
+ UINT8 direction = offset; // HACK ALERT!
+
+ /* if line is marked as input then keep current value */
+ data = (state->m_c64_port_data & ~direction) | (data & direction);
+
+ /* resistors make P0,P1,P2 go high when respective line is changed to input */
+ if (!(direction & 0x04))
+ data |= 0x04;
+
+ if (!(direction & 0x02))
+ data |= 0x02;
+
+ if (!(direction & 0x01))
+ data |= 0x01;
+
+ state->m_c64_port_data = data;
+
+ if (state->m_tape_on)
+ {
+ if (direction & 0x08)
+ {
+ device->machine().device<cassette_image_device>(CASSETTE_TAG)->output((data & 0x08) ? -(0x5a9e >> 1) : +(0x5a9e >> 1));
+ }
+
+ if (direction & 0x20)
+ {
+ if (!(data & 0x20))
+ {
+ device->machine().device<cassette_image_device>(CASSETTE_TAG)->change_state(CASSETTE_MOTOR_ENABLED,CASSETTE_MASK_MOTOR);
+ state->m_datasette_timer->adjust(attotime::zero, 0, attotime::from_hz(44100));
+ }
+ else
+ {
+ device->machine().device<cassette_image_device>(CASSETTE_TAG)->change_state(CASSETTE_MOTOR_DISABLED ,CASSETTE_MASK_MOTOR);
+ state->m_datasette_timer->reset();
+ }
+ }
+ }
+
+ c128_bankswitch_64(device->machine(), 0);
+
+ state->m_memory[0x000] = device->memory().space(AS_PROGRAM)->read_byte(0);
+ state->m_memory[0x001] = device->memory().space(AS_PROGRAM)->read_byte(1);
+
+}
+
+READ8_DEVICE_HANDLER(c128_m6510_port_read)
+{
+ c128_state *state = device->machine().driver_data<c128_state>();
+ UINT8 data = state->m_c64_port_data;
+
+ if ((device->machine().device<cassette_image_device>(CASSETTE_TAG)->get_state() & CASSETTE_MASK_UISTATE) != CASSETTE_STOPPED)
+ data &= ~0x10;
+ else
+ data |= 0x10;
+
+ if (state->ioport("SPECIAL")->read() & 0x20) /* Check Caps Lock */
+ data &= ~0x40;
+ else
+ data |= 0x40;
+
+ return data;
+}
+
+static void c128_common_driver_init( running_machine &machine )
+{
+ c128_state *state = machine.driver_data<c128_state>();
+ UINT8 *gfx=machine.root_device().memregion("gfx1")->base();
+ UINT8 *ram = state->memregion("maincpu")->base();
+ int i;
+
+ state->m_memory = ram;
+
+ state->m_c128_basic = ram + 0x100000;
+ state->m_basic = ram + 0x108000;
+ state->m_kernal = ram + 0x10a000;
+ state->m_editor = ram + 0x10c000;
+ state->m_z80 = ram + 0x10d000;
+ state->m_c128_kernal = ram + 0x10e000;
+ state->m_internal_function = ram + 0x110000;
+ state->m_external_function = ram + 0x118000;
+ state->m_chargen = ram + 0x120000;
+ state->m_c128_chargen = ram + 0x121000;
+ state->m_colorram = ram + 0x122000;
+ state->m_vdcram = ram + 0x122800;
+ state->m_c64_roml = auto_alloc_array(machine, UINT8, 0x2000);
+ state->m_c64_romh = auto_alloc_array(machine, UINT8, 0x2000);
+
+ state->m_tape_on = 1;
+ state->m_game = 1;
+ state->m_exrom = 1;
+ state->m_pal = 0;
+ state->m_c64mode = 0;
+ state->m_vicirq = 0;
+
+ state->m_monitor = -1;
+ state->m_cnt1 = 1;
+ state->m_sp1 = 1;
+ cbm_common_init();
+ state->m_keyline[0] = state->m_keyline[1] = state->m_keyline[2] = 0xff;
+
+ for (i = 0; i < 0x100; i++)
+ gfx[i] = i;
+
+ if (state->m_tape_on)
+ state->m_datasette_timer = machine.scheduler().timer_alloc(FUNC(c64_tape_timer));
+}
+
+DRIVER_INIT_MEMBER(c128_state,c128)
+{
+ device_t *vic2e = machine().device("vic2e");
+ device_t *vdc8563 = machine().device("vdc8563");
+
+ c128_common_driver_init(machine());
+
+ vic2_set_rastering(vic2e, 0);
+ vdc8563_set_rastering(vdc8563, 1);
+}
+
+DRIVER_INIT_MEMBER(c128_state,c128pal)
+{
+ device_t *vic2e = machine().device("vic2e");
+ device_t *vdc8563 = machine().device("vdc8563");
+
+ c128_common_driver_init(machine());
+ m_pal = 1;
+
+ vic2_set_rastering(vic2e, 1);
+ vdc8563_set_rastering(vdc8563, 0);
+}
+
+DRIVER_INIT_MEMBER(c128_state,c128d)
+{
+ DRIVER_INIT_CALL( c128 );
+}
+
+DRIVER_INIT_MEMBER(c128_state,c128dpal)
+{
+ DRIVER_INIT_CALL( c128pal );
+}
+
+DRIVER_INIT_MEMBER(c128_state,c128dcr)
+{
+ DRIVER_INIT_CALL( c128 );
+}
+
+DRIVER_INIT_MEMBER(c128_state,c128dcrp)
+{
+ DRIVER_INIT_CALL( c128pal );
+}
+
+DRIVER_INIT_MEMBER(c128_state,c128d81)
+{
+ DRIVER_INIT_CALL( c128 );
+}
+
+MACHINE_START( c128 )
+{
+ c128_state *state = machine.driver_data<c128_state>();
+// This was in MACHINE_START( c64 ), but never called
+// TO DO: find its correct use, when fixing c64 mode
+ if (state->m_c64mode)
+ c128_bankswitch_64(machine, 1);
+}
+
+MACHINE_RESET( c128 )
+{
+ c128_state *state = machine.driver_data<c128_state>();
+ state->m_c128_vicaddr = state->m_vicaddr = state->m_memory;
+ state->m_c64mode = 0;
+ c128_mmu8722_reset(machine);
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_HALT, CLEAR_LINE);
+ cputag_set_input_line(machine, "m8502", INPUT_LINE_HALT, ASSERT_LINE);
+}
+
+
+INTERRUPT_GEN( c128_frame_interrupt )
+{
+ c128_state *state = device->machine().driver_data<c128_state>();
+ static const char *const c128ports[] = { "KP0", "KP1", "KP2" };
+ int i, value;
+ device_t *vic2e = device->machine().device("vic2e");
+ device_t *vdc8563 = device->machine().device("vdc8563");
+
+ c128_nmi(device->machine());
+
+ if ((device->machine().root_device().ioport("SPECIAL")->read() & 0x08) != state->m_monitor)
+ {
+ if (device->machine().root_device().ioport("SPECIAL")->read() & 0x08)
+ {
+ vic2_set_rastering(vic2e, 0);
+ vdc8563_set_rastering(vdc8563, 1);
+ device->machine().primary_screen->set_visible_area(0, 655, 0, 215);
+ }
+ else
+ {
+ vic2_set_rastering(vic2e, 1);
+ vdc8563_set_rastering(vdc8563, 0);
+ if (state->m_pal)
+ device->machine().primary_screen->set_visible_area(0, VIC6569_VISIBLECOLUMNS - 1, 0, VIC6569_VISIBLELINES - 1);
+ else
+ device->machine().primary_screen->set_visible_area(0, VIC6567_VISIBLECOLUMNS - 1, 0, VIC6567_VISIBLELINES - 1);
+ }
+ state->m_monitor = device->machine().root_device().ioport("SPECIAL")->read() & 0x08;
+ }
+
+
+ /* common keys input ports */
+ cbm_common_interrupt(device);
+
+ /* Fix Me! Currently, neither left Shift nor Shift Lock work in c128, but reading the correspondent input produces a bug!
+ Hence, we overwrite the actual reading as it never happens */
+ if ((device->machine().root_device().ioport("SPECIAL")->read() & 0x40)) //
+ c64_keyline[1] |= 0x80;
+
+ /* c128 specific: keypad input ports */
+ for (i = 0; i < 3; i++)
+ {
+ value = 0xff;
+ value &= ~device->machine().root_device().ioport(c128ports[i])->read();
+ state->m_keyline[i] = value;
+ }
+}
+
+SCREEN_UPDATE_IND16( c128 )
+{
+ device_t *vic2e = screen.machine().device("vic2e");
+ device_t *vdc8563 = screen.machine().device("vdc8563");
+
+ vdc8563_video_update(vdc8563, bitmap, cliprect);
+ vic2_video_update(vic2e, bitmap, cliprect);
+ return 0;
+}
diff --git a/src/mess/machine/c128_comal80.c b/src/mess/machine/c128_comal80.c
new file mode 100644
index 00000000000..77e1c51970f
--- /dev/null
+++ b/src/mess/machine/c128_comal80.c
@@ -0,0 +1,101 @@
+/**********************************************************************
+
+ Commodore 128 COMAL 80 cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c128_comal80.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C128_COMAL80 = &device_creator<c128_comal80_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ device_c64_expansion_card_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ if (!romh)
+ {
+ offs_t addr = (m_bank << 14) | (offset & 0x3fff);
+ data = m_roml[addr];
+ }
+
+ 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 ba, int roml, int romh, int io1, int io2)
+{
+ if (!io1)
+ {
+ /*
+
+ bit description
+
+ 0
+ 1
+ 2
+ 3
+ 4 A14
+ 5 ROM select bit 0
+ 6 ROM select bit 1
+ 7
+
+ */
+
+ m_bank = (data >> 4) & 0x07;
+ }
+}
diff --git a/src/mess/machine/c128_comal80.h b/src/mess/machine/c128_comal80.h
new file mode 100644
index 00000000000..e9120b54d06
--- /dev/null
+++ b/src/mess/machine/c128_comal80.h
@@ -0,0 +1,53 @@
+/**********************************************************************
+
+ Commodore 128 COMAL 80 cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __C128_COMAL80__
+#define __C128_COMAL80__
+
+
+#include "emu.h"
+#include "machine/c64exp.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();
+ virtual void device_config_complete() { m_shortname = "c128_comal80"; }
+
+ // device_c64_expansion_card_interface overrides
+ virtual UINT8 c64_cd_r(address_space &space, offs_t offset, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, 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/mess/machine/c1541.c b/src/mess/machine/c1541.c
new file mode 100644
index 00000000000..86447186f70
--- /dev/null
+++ b/src/mess/machine/c1541.c
@@ -0,0 +1,1030 @@
+/**********************************************************************
+
+ Commodore 1540/1541/1541C/1541-II Single Disk Drive emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ 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"
+
+
+
+//**************************************************************************
+// 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 C1540 = &device_creator<c1540_device>;
+const device_type C1541 = &device_creator<c1541_device>;
+const device_type C1541C = &device_creator<c1541c_device>;
+const device_type C1541II = &device_creator<c1541ii_device>;
+const device_type SX1541 = &device_creator<sx1541_device>;
+const device_type FSD2 = &device_creator<fsd2_device>;
+const device_type C1541_DOLPHIN_DOS = &device_creator<c1541_dolphin_dos_device>;
+const device_type C1541_PROFESSIONAL_DOS_V1 = &device_creator<c1541_professional_dos_v1_device>;
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void base_c1541_device::device_config_complete()
+{
+ switch (m_variant)
+ {
+ case TYPE_1540:
+ m_shortname = "c1540";
+ break;
+
+ default:
+ case TYPE_1541:
+ m_shortname = "c1541";
+ break;
+
+ case TYPE_1541C:
+ m_shortname = "c1541c";
+ break;
+
+ case TYPE_1541II:
+ m_shortname = "c1541ii";
+ break;
+
+ case TYPE_SX1541:
+ m_shortname = "sx1541";
+ break;
+
+ case TYPE_FSD2:
+ m_shortname = "fsd2";
+ break;
+
+ case TYPE_1541_DOLPHIN_DOS:
+ m_shortname = "c1541dd";
+ break;
+
+ case TYPE_1541_PROFESSIONAL_DOS_V1:
+ m_shortname = "c1541pd";
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// 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( 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_END
+
+
+//-------------------------------------------------
+// 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( 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( 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( 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_END
+
+
+//-------------------------------------------------
+// ROM( c1541dd )
+//-------------------------------------------------
+
+ROM_START( c1541dd )
+ ROM_REGION( 0x8000, M6502_TAG, 0 )
+ ROM_LOAD( "dd20.bin", 0x0000, 0x8000, CRC(94c7fe19) SHA1(e4d5b9ad6b719dd988276214aa4536d3525d313c) )
+ROM_END
+
+
+//-------------------------------------------------
+// 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 *base_c1541_device::device_rom_region() const
+{
+ switch (m_variant)
+ {
+ case TYPE_1540:
+ return ROM_NAME( c1540 );
+
+ default:
+ case TYPE_1541:
+ return ROM_NAME( c1541 );
+
+ case TYPE_1541C:
+ return ROM_NAME( c1541c );
+
+ case TYPE_1541II:
+ return ROM_NAME( c1541ii );
+
+ case TYPE_SX1541:
+ return ROM_NAME( sx1541 );
+
+ case TYPE_FSD2: // aka Excelerator PLUS / Oceanic OC-118N
+ return ROM_NAME( fsd2 );
+
+ case TYPE_1541_DOLPHIN_DOS:
+ return ROM_NAME( c1541dd );
+
+ case TYPE_1541_PROFESSIONAL_DOS_V1:
+ return ROM_NAME( c1541pd );
+ }
+}
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( c1541_mem )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( c1541_mem, AS_PROGRAM, 8, base_c1541_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
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( c1541dd_mem )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( c1541dd_mem, AS_PROGRAM, 8, base_c1541_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, 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, base_c1541_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, 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
+
+
+//-------------------------------------------------
+// via6522_interface via0_intf
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( base_c1541_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( base_c1541_device::via0_pa_r )
+{
+ // dummy read to acknowledge ATN IN interrupt
+ return m_parallel_data;
+}
+
+WRITE8_MEMBER( base_c1541_device::via0_pa_w )
+{
+ if (m_other != NULL)
+ {
+ m_other->parallel_data_w(data);
+ }
+}
+
+READ8_MEMBER( base_c1541_device::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_address - 8) << 5;
+
+ // attention in
+ data |= !m_bus->atn_r() << 7;
+
+ return data;
+}
+
+WRITE8_MEMBER( base_c1541_device::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));
+}
+
+READ_LINE_MEMBER( base_c1541_device::atn_in_r )
+{
+ return !m_bus->atn_r();
+}
+
+WRITE_LINE_MEMBER( base_c1541_device::via0_ca2_w )
+{
+ if (m_other != NULL)
+ {
+ m_other->parallel_strobe_w(state);
+ }
+}
+
+static const via6522_interface c1541_via0_intf =
+{
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c1541_device, via0_pa_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c1541_device, via0_pb_r),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_c1541_device, atn_in_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c1541_device, via0_pa_w),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c1541_device, via0_pb_w),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_c1541_device, via0_ca2_w),
+ DEVCB_NULL,
+
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_c1541_device, via0_irq_w)
+};
+
+
+//-------------------------------------------------
+// via6522_interface c1541c_via0_intf
+//-------------------------------------------------
+
+READ8_MEMBER( c1541c_device::via0_pa_r )
+{
+ /*
+
+ bit description
+
+ PA0 TR00 SENCE
+ PA1
+ PA2
+ PA3
+ PA4
+ PA5
+ PA6
+ PA7
+
+ */
+
+ return !floppy_tk00_r(m_image);
+}
+
+static const via6522_interface c1541c_via0_intf =
+{
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c1541c_device, via0_pa_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c1541_device, via0_pb_r),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_c1541_device, atn_in_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c1541_device, via0_pb_w),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_c1541_device, via0_irq_w)
+};
+
+
+//-------------------------------------------------
+// via6522_interface via1_intf
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( base_c1541_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( base_c1541_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 |= !floppy_wpt_r(m_image) << 4;
+
+ // SYNC detect line
+ data |= m_ga->sync_r() << 7;
+
+ return data;
+}
+
+WRITE8_MEMBER( base_c1541_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);
+}
+
+static const via6522_interface c1541_via1_intf =
+{
+ DEVCB_DEVICE_MEMBER(C64H156_TAG, c64h156_device, yb_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c1541_device, via1_pb_r),
+ DEVCB_DEVICE_LINE_MEMBER(C64H156_TAG, c64h156_device, byte_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+
+ DEVCB_DEVICE_MEMBER(C64H156_TAG, c64h156_device, yb_w),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c1541_device, via1_pb_w),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(C64H156_TAG, c64h156_device, soe_w),
+ DEVCB_DEVICE_LINE_MEMBER(C64H156_TAG, c64h156_device, oe_w),
+
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_c1541_device, via1_irq_w)
+};
+
+
+//-------------------------------------------------
+// C64H156_INTERFACE( ga_intf )
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( base_c1541_device::atn_w )
+{
+ set_iec_data();
+}
+
+WRITE_LINE_MEMBER( base_c1541_device::byte_w )
+{
+ m_maincpu->set_input_line(M6502_SET_OVERFLOW, state);
+
+ m_via1->write_ca1(state);
+}
+
+static C64H156_INTERFACE( ga_intf )
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_c1541_device, atn_w),
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_c1541_device, byte_w)
+};
+
+
+//-------------------------------------------------
+// LEGACY_FLOPPY_OPTIONS( c1541 )
+//-------------------------------------------------
+
+LEGACY_FLOPPY_OPTIONS_START( c1541 )
+ LEGACY_FLOPPY_OPTION( c1541, "g64", "Commodore 1541 GCR Disk Image", g64_dsk_identify, g64_dsk_construct, NULL, NULL )
+ LEGACY_FLOPPY_OPTION( c1541, "d64", "Commodore 1541 Disk Image", d64_dsk_identify, d64_dsk_construct, NULL, NULL )
+LEGACY_FLOPPY_OPTIONS_END
+
+
+//-------------------------------------------------
+// floppy_interface c1541_floppy_interface
+//-------------------------------------------------
+
+const floppy_interface c1541_floppy_interface =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ FLOPPY_STANDARD_5_25_SSDD,
+ LEGACY_FLOPPY_OPTIONS_NAME(c1541),
+ "floppy_5_25",
+ NULL
+};
+
+
+//-------------------------------------------------
+// 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_VIA6522_ADD(M6522_0_TAG, XTAL_16MHz/16, c1541_via0_intf)
+ MCFG_VIA6522_ADD(M6522_1_TAG, XTAL_16MHz/16, c1541_via1_intf)
+
+ MCFG_LEGACY_FLOPPY_DRIVE_ADD(FLOPPY_0, c1541_floppy_interface)
+ MCFG_64H156_ADD(C64H156_TAG, XTAL_16MHz, ga_intf)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( c1541c )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( c1541c )
+ MCFG_CPU_ADD(M6502_TAG, M6502, XTAL_16MHz/16)
+ MCFG_CPU_PROGRAM_MAP(c1541_mem)
+ MCFG_QUANTUM_PERFECT_CPU(M6502_TAG)
+
+ MCFG_VIA6522_ADD(M6522_0_TAG, XTAL_16MHz/16, c1541c_via0_intf)
+ MCFG_VIA6522_ADD(M6522_1_TAG, XTAL_16MHz/16, c1541_via1_intf)
+
+ MCFG_LEGACY_FLOPPY_DRIVE_ADD(FLOPPY_0, c1541_floppy_interface)
+ MCFG_64H156_ADD(C64H156_TAG, XTAL_16MHz, ga_intf)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( c1541dd )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( c1541dd )
+ MCFG_CPU_ADD(M6502_TAG, M6502, XTAL_16MHz/16)
+ MCFG_CPU_PROGRAM_MAP(c1541dd_mem)
+ MCFG_QUANTUM_PERFECT_CPU(M6502_TAG)
+
+ MCFG_VIA6522_ADD(M6522_0_TAG, XTAL_16MHz/16, c1541_via0_intf)
+ MCFG_VIA6522_ADD(M6522_1_TAG, XTAL_16MHz/16, c1541_via1_intf)
+
+ MCFG_LEGACY_FLOPPY_DRIVE_ADD(FLOPPY_0, c1541_floppy_interface)
+ MCFG_64H156_ADD(C64H156_TAG, XTAL_16MHz, ga_intf)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( c1541pd )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( c1541pd )
+ MCFG_CPU_ADD(M6502_TAG, M6502, XTAL_16MHz/16)
+ MCFG_CPU_PROGRAM_MAP(c1541pd_mem)
+ MCFG_QUANTUM_PERFECT_CPU(M6502_TAG)
+
+ MCFG_VIA6522_ADD(M6522_0_TAG, XTAL_16MHz/16, c1541_via0_intf)
+ MCFG_VIA6522_ADD(M6522_1_TAG, XTAL_16MHz/16, c1541_via1_intf)
+
+ MCFG_LEGACY_FLOPPY_DRIVE_ADD(FLOPPY_0, c1541_floppy_interface)
+ MCFG_64H156_ADD(C64H156_TAG, XTAL_16MHz, ga_intf)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor base_c1541_device::device_mconfig_additions() const
+{
+ switch (m_variant)
+ {
+ default:
+ return MACHINE_CONFIG_NAME( c1541 );
+
+ case TYPE_1541C:
+ return MACHINE_CONFIG_NAME( c1541c );
+
+ case TYPE_1541_DOLPHIN_DOS:
+ return MACHINE_CONFIG_NAME( c1541dd );
+
+ case TYPE_1541_PROFESSIONAL_DOS_V1:
+ return MACHINE_CONFIG_NAME( c1541pd );
+ }
+}
+
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// set_iec_data -
+//-------------------------------------------------
+
+inline void base_c1541_device::set_iec_data()
+{
+ int data = !m_data_out && !m_ga->atn_r();
+
+ m_bus->data_w(this, data);
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// base_c1541_device - constructor
+//-------------------------------------------------
+
+base_c1541_device::base_c1541_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant)
+ : device_t(mconfig, type, name, tag, owner, clock),
+ 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_image(*this, FLOPPY_0),
+ m_data_out(1),
+ m_via0_irq(CLEAR_LINE),
+ m_via1_irq(CLEAR_LINE),
+ m_variant(variant)
+{
+}
+
+
+//-------------------------------------------------
+// c1540_device - constructor
+//-------------------------------------------------
+
+c1540_device::c1540_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ :base_c1541_device(mconfig, C1540, "C1540", tag, owner, clock, TYPE_1540) { }
+
+
+//-------------------------------------------------
+// c1541_device - constructor
+//-------------------------------------------------
+
+c1541_device::c1541_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ :base_c1541_device(mconfig, C1541, "C1541", tag, owner, clock, TYPE_1541) { }
+
+
+//-------------------------------------------------
+// c1541c_device - constructor
+//-------------------------------------------------
+
+c1541c_device::c1541c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ :base_c1541_device(mconfig, C1541C, "C1541C", tag, owner, clock, TYPE_1541C) { }
+
+
+//-------------------------------------------------
+// c1541ii_device - constructor
+//-------------------------------------------------
+
+c1541ii_device::c1541ii_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ :base_c1541_device(mconfig, C1541II, "C1541-II", tag, owner, clock, TYPE_1541II) { }
+
+
+//-------------------------------------------------
+// sx1541_device - constructor
+//-------------------------------------------------
+
+sx1541_device::sx1541_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ :base_c1541_device(mconfig, SX1541, "SX1541", tag, owner, clock, TYPE_SX1541) { }
+
+
+//-------------------------------------------------
+// fsd2_device - constructor
+//-------------------------------------------------
+
+fsd2_device::fsd2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ :base_c1541_device(mconfig, FSD2, "FSD-2", tag, owner, clock, TYPE_FSD2) { }
+
+
+//-------------------------------------------------
+// c1541_dolphin_dos_device - constructor
+//-------------------------------------------------
+
+c1541_dolphin_dos_device::c1541_dolphin_dos_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ :base_c1541_device(mconfig, C1541_DOLPHIN_DOS, "C1541 Dolphin-DOS 2.0", tag, owner, clock, TYPE_1541_DOLPHIN_DOS) { }
+
+
+//-------------------------------------------------
+// c1541_professional_dos_v1_device - constructor
+//-------------------------------------------------
+
+c1541_professional_dos_v1_device::c1541_professional_dos_v1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ :base_c1541_device(mconfig, C1541_PROFESSIONAL_DOS_V1, "C1541 Professional-DOS v1", tag, owner, clock, TYPE_1541_PROFESSIONAL_DOS_V1) { }
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void base_c1541_device::device_start()
+{
+ // install image callbacks
+ floppy_install_unload_proc(m_image, base_c1541_device::on_disk_change);
+ floppy_install_load_proc(m_image, base_c1541_device::on_disk_change);
+
+ // register for state saving
+ save_item(NAME(m_data_out));
+ save_item(NAME(m_via0_irq));
+ save_item(NAME(m_via1_irq));
+}
+
+void fsd2_device::device_start()
+{
+ base_c1541_device::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 base_c1541_device::device_reset()
+{
+ m_maincpu->reset();
+
+ m_via0->reset();
+ m_via1->reset();
+}
+
+
+//-------------------------------------------------
+// iec_atn_w -
+//-------------------------------------------------
+
+void base_c1541_device::cbm_iec_atn(int state)
+{
+ m_via0->write_ca1(!state);
+ m_ga->atni_w(!state);
+
+ set_iec_data();
+}
+
+
+//-------------------------------------------------
+// iec_reset_w -
+//-------------------------------------------------
+
+void base_c1541_device::cbm_iec_reset(int state)
+{
+ if (!state)
+ {
+ device_reset();
+ }
+}
+
+
+//-------------------------------------------------
+// parallel_data_w -
+//-------------------------------------------------
+
+void base_c1541_device::parallel_data_w(UINT8 data)
+{
+ m_parallel_data = data;
+}
+
+
+//-------------------------------------------------
+// parallel_strobe_w -
+//-------------------------------------------------
+
+void base_c1541_device::parallel_strobe_w(int state)
+{
+ m_via0->write_cb1(state);
+}
+
+
+//-------------------------------------------------
+// on_disk_change -
+//-------------------------------------------------
+
+void base_c1541_device::on_disk_change(device_image_interface &image)
+{
+ base_c1541_device *c1541 = static_cast<base_c1541_device *>(image.device().owner());
+
+ int wp = floppy_wpt_r(image);
+ c1541->m_ga->on_disk_changed(wp);
+}
diff --git a/src/mess/machine/c1541.h b/src/mess/machine/c1541.h
new file mode 100644
index 00000000000..a6af2d1044d
--- /dev/null
+++ b/src/mess/machine/c1541.h
@@ -0,0 +1,220 @@
+/**********************************************************************
+
+ Commodore 1540/1541/1541C/1541-II Single Disk Drive emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __C1541__
+#define __C1541__
+
+
+#include "emu.h"
+#include "cpu/m6502/m6502.h"
+#include "imagedev/flopdrv.h"
+#include "formats/d64_dsk.h"
+#include "formats/g64_dsk.h"
+#include "machine/64h156.h"
+#include "machine/6522via.h"
+#include "machine/cbmiec.h"
+#include "machine/c64_bn1541.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define C1541_TAG "c1541"
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> base_c1541_device
+
+class base_c1541_device : public device_t,
+ public device_cbm_iec_interface,
+ public device_c64_floppy_parallel_interface
+{
+public:
+ // construction/destruction
+ base_c1541_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant);
+
+ enum
+ {
+ TYPE_1540 = 0,
+ TYPE_1541,
+ TYPE_1541C,
+ TYPE_1541II,
+ TYPE_SX1541,
+ TYPE_FSD2,
+
+ // extended hardware
+ TYPE_1541_DOLPHIN_DOS,
+ TYPE_1541_PROFESSIONAL_DOS_V1
+ };
+
+ // not really public
+ static void on_disk_change(device_image_interface &image);
+
+ 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( via0_ca2_w );
+ DECLARE_READ_LINE_MEMBER( atn_in_r );
+ 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 );
+
+ // 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_config_complete();
+ 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);
+
+ inline void set_iec_data();
+
+ required_device<cpu_device> m_maincpu;
+ required_device<via6522_device> m_via0;
+ required_device<via6522_device> m_via1;
+ required_device<c64h156_device> m_ga;
+ required_device<legacy_floppy_image_device> m_image;
+
+ // 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
+
+ int m_variant;
+};
+
+
+// ======================> c1540_device
+
+class c1540_device : public base_c1541_device
+{
+public:
+ // construction/destruction
+ c1540_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+// ======================> c1541_device
+
+class c1541_device : public base_c1541_device
+{
+public:
+ // construction/destruction
+ c1541_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+// ======================> c1541c_device
+
+class c1541c_device : public base_c1541_device
+{
+public:
+ // construction/destruction
+ c1541c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // not really public
+ DECLARE_READ8_MEMBER( via0_pa_r );
+};
+
+
+// ======================> c1541ii_device
+
+class c1541ii_device : public base_c1541_device
+{
+public:
+ // construction/destruction
+ c1541ii_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+// ======================> sx1541_device
+
+class sx1541_device : public base_c1541_device
+{
+public:
+ // construction/destruction
+ sx1541_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+// ======================> fsd2_device
+
+class fsd2_device : public base_c1541_device
+{
+public:
+ // construction/destruction
+ fsd2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+};
+
+
+// ======================> c1541_dolphin_dos_device
+
+class c1541_dolphin_dos_device : public base_c1541_device
+{
+public:
+ // construction/destruction
+ c1541_dolphin_dos_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+// ======================> c1541_professional_dos_v1_device
+
+class c1541_professional_dos_v1_device : public base_c1541_device
+{
+public:
+ // construction/destruction
+ c1541_professional_dos_v1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+// 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 FSD2;
+extern const device_type C1541_DOLPHIN_DOS;
+extern const device_type C1541_PROFESSIONAL_DOS_V1;
+
+
+// floppy interface
+LEGACY_FLOPPY_OPTIONS_EXTERN( c1541 );
+extern const floppy_interface c1541_floppy_interface;
+
+
+
+#endif
diff --git a/src/mess/machine/c1551.c b/src/mess/machine/c1551.c
new file mode 100644
index 00000000000..0cc50d84330
--- /dev/null
+++ b/src/mess/machine/c1551.c
@@ -0,0 +1,574 @@
+/**********************************************************************
+
+ Commodore 1551 Single Disk Drive emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ TODO:
+
+ - byte latching does not match hardware behavior
+ (CPU skips data bytes if implemented per schematics)
+
+*/
+
+#include "c1541.h"
+#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"
+
+enum
+{
+ LED_POWER = 0,
+ LED_ACT
+};
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C1551 = &device_creator<c1551_device>;
+
+
+//-------------------------------------------------
+// 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_device::device_rom_region() const
+{
+ return ROM_NAME( c1551 );
+}
+
+
+//-------------------------------------------------
+// m6502_interface m6510t_intf
+//-------------------------------------------------
+
+READ8_MEMBER( c1551_device::port_r )
+{
+ /*
+
+ bit description
+
+ P0
+ P1
+ P2
+ P3
+ P4 WPS
+ P5
+ P6
+ P7 BYTE LTCHED
+
+ */
+
+ UINT8 data = 0;
+
+ // write protect sense
+ data |= !floppy_wpt_r(m_image) << 4;
+
+ // byte latched
+ data |= m_ga->atn_r() << 7;
+
+ return data;
+}
+
+
+WRITE8_MEMBER( c1551_device::port_w )
+{
+ /*
+
+ bit description
+
+ P0 STP0A
+ P1 STP0B
+ P2 MTR0
+ P3 ACT0
+ P4
+ P5 DS0
+ P6 DS1
+ P7
+
+ */
+
+ // 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);
+}
+
+
+static const m6502_interface m6510t_intf =
+{
+ NULL, // read_indexed_func
+ NULL, // write_indexed_func
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c1551_device, port_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c1551_device, port_w)
+};
+
+
+//-------------------------------------------------
+// tpi6525_interface tpi0_intf
+//-------------------------------------------------
+
+READ8_MEMBER( c1551_device::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_device::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_device::tpi0_pc_r )
+{
+ /*
+
+ bit description
+
+ PC0
+ PC1
+ PC2
+ PC3
+ PC4
+ PC5 JP1
+ PC6 _SYNC
+ PC7 TCBM DAV
+
+ */
+
+ UINT8 data = 0;
+
+ // JP1
+ data |= ioport("JP1")->read() << 5;
+
+ // SYNC detect line
+ data |= m_ga->sync_r() << 6;
+
+ // TCBM data valid
+ data |= m_dav << 7;
+
+ return data;
+}
+
+
+WRITE8_MEMBER( c1551_device::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));
+}
+
+
+static const tpi6525_interface tpi0_intf =
+{
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c1551_device, tcbm_data_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c1551_device, tcbm_data_w),
+ DEVCB_DEVICE_MEMBER(C64H156_TAG, c64h156_device, yb_r),
+ DEVCB_DEVICE_MEMBER(C64H156_TAG, c64h156_device, yb_w),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c1551_device, tpi0_pc_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c1551_device, tpi0_pc_w),
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// tpi6525_interface tpi1_intf
+//-------------------------------------------------
+
+READ8_MEMBER( c1551_device::tpi1_pb_r )
+{
+ /*
+
+ bit description
+
+ PB0 STATUS0
+ PB1 STATUS1
+ PB2
+ PB3
+ PB4
+ PB5
+ PB6
+ PB7
+
+ */
+
+ return m_status & 0x03;
+}
+
+
+READ8_MEMBER( c1551_device::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_device::tpi1_pc_w )
+{
+ /*
+
+ bit description
+
+ PC0
+ PC1
+ PC2
+ PC3
+ PC4
+ PC5
+ PC6 TCBM DAV
+ PC7
+
+ */
+
+ // TCBM data valid
+ m_dav = BIT(data, 6);
+}
+
+
+static const tpi6525_interface tpi1_intf =
+{
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c1551_device, tcbm_data_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c1551_device, tcbm_data_w),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c1551_device, tpi1_pb_r),
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c1551_device, tpi1_pc_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c1551_device, tpi1_pc_w),
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( c1551_mem )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( c1551_mem, AS_PROGRAM, 8, c1551_device )
+ AM_RANGE(0x0000, 0x07ff) AM_MIRROR(0x0800) AM_RAM
+ AM_RANGE(0x4000, 0x4007) AM_MIRROR(0x3ff8) AM_DEVREADWRITE_LEGACY(M6523_0_TAG, tpi6525_r, tpi6525_w)
+ AM_RANGE(0xc000, 0xffff) AM_ROM AM_REGION(M6510T_TAG, 0)
+ADDRESS_MAP_END
+
+
+//-------------------------------------------------
+// C64H156_INTERFACE( ga_intf )
+//-------------------------------------------------
+
+static C64H156_INTERFACE( ga_intf )
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(C64H156_TAG, c64h156_device, atni_w)
+};
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( c1551 )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( c1551 )
+ MCFG_CPU_ADD(M6510T_TAG, M6510T, XTAL_16MHz/8)
+ MCFG_CPU_PROGRAM_MAP(c1551_mem)
+ MCFG_CPU_CONFIG(m6510t_intf)
+ MCFG_QUANTUM_PERFECT_CPU(M6510T_TAG)
+
+ MCFG_PLS100_ADD(PLA_TAG)
+ MCFG_TPI6525_ADD(M6523_0_TAG, tpi0_intf)
+ MCFG_TPI6525_ADD(M6523_1_TAG, tpi1_intf)
+
+ MCFG_LEGACY_FLOPPY_DRIVE_ADD(FLOPPY_0, c1541_floppy_interface)
+ MCFG_64H156_ADD(C64H156_TAG, XTAL_16MHz, ga_intf)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor c1551_device::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_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( c1551 );
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// c1551_device - constructor
+//-------------------------------------------------
+
+c1551_device::c1551_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, C1551, "C1551", tag, owner, clock),
+ 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_image(*this, FLOPPY_0),
+ m_tcbm_data(0xff),
+ m_status(1),
+ m_dav(1),
+ m_ack(1),
+ m_dev(0)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void c1551_device::device_start()
+{
+ // allocate timers
+ m_irq_timer = timer_alloc();
+ m_irq_timer->adjust(attotime::zero, CLEAR_LINE);
+
+ // install image callbacks
+ floppy_install_unload_proc(m_image, c1551_device::on_disk_change);
+ floppy_install_load_proc(m_image, c1551_device::on_disk_change);
+
+ // 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));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void c1551_device::device_reset()
+{
+ m_maincpu->reset();
+
+ m_tpi0->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_device::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);
+ }
+}
+
+
+//-------------------------------------------------
+// plus4_cd_r - cartridge data read
+//-------------------------------------------------
+
+UINT8 c1551_device::plus4_cd_r(address_space &space, offs_t offset, int ba, int cs0, int c1l, int c2l, int cs1, int c1h, int c2h)
+{
+ UINT8 data = 0;
+
+ offs_t start_address = m_dev ? 0xfef0 : 0xfec0;
+
+ if (offset >= start_address && offset < (start_address + 8))
+ {
+ data = tpi6525_r(m_tpi1, offset & 0x07);
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// plus4_cd_w - cartridge data write
+//-------------------------------------------------
+
+void c1551_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)
+{
+ offs_t start_address = m_dev ? 0xfef0 : 0xfec0;
+
+ if (offset >= start_address && offset < (start_address + 8))
+ {
+ tpi6525_w(m_tpi1, offset & 0x07, data);
+ }
+}
+
+
+//-------------------------------------------------
+// plus4_breset_w - buffered reset write
+//-------------------------------------------------
+
+void c1551_device::plus4_breset_w(int state)
+{
+ if (state == ASSERT_LINE)
+ {
+ device_reset();
+ }
+}
+
+
+//-------------------------------------------------
+// on_disk_change -
+//-------------------------------------------------
+
+void c1551_device::on_disk_change(device_image_interface &image)
+{
+ c1551_device *c1551 = static_cast<c1551_device *>(image.device().owner());
+
+ int wp = floppy_wpt_r(image);
+ c1551->m_ga->on_disk_changed(wp);
+}
diff --git a/src/mess/machine/c1551.h b/src/mess/machine/c1551.h
new file mode 100644
index 00000000000..0b532f01049
--- /dev/null
+++ b/src/mess/machine/c1551.h
@@ -0,0 +1,100 @@
+/**********************************************************************
+
+ Commodore 1551 Single Disk Drive emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __C1551__
+#define __C1551__
+
+
+#include "emu.h"
+#include "cpu/m6502/m6502.h"
+#include "imagedev/flopdrv.h"
+#include "formats/d64_dsk.h"
+#include "formats/g64_dsk.h"
+#include "machine/64h156.h"
+#include "machine/6525tpi.h"
+#include "machine/pls100.h"
+#include "machine/plus4exp.h"
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> c1551_device
+
+class c1551_device : public device_t,
+ public device_plus4_expansion_card_interface
+{
+public:
+ // construction/destruction
+ c1551_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
+ static void on_disk_change(device_image_interface &image);
+
+ 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( 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 );
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "c1551"; }
+ 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, 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<cpu_device> m_maincpu;
+ required_device<device_t> m_tpi0;
+ required_device<device_t> m_tpi1;
+ required_device<c64h156_device> m_ga;
+ required_device<legacy_floppy_image_device> m_image;
+
+ // 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/mess/machine/c1571.c b/src/mess/machine/c1571.c
new file mode 100644
index 00000000000..6773991fe8c
--- /dev/null
+++ b/src/mess/machine/c1571.c
@@ -0,0 +1,881 @@
+/**********************************************************************
+
+ Commodore 1570/1571/1571CR Single Disk Drive emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ TODO:
+
+ - fast serial
+ - 1541/1571 Alignment shows drive speed as 266 rpm, should be 310
+ - CP/M disks
+
+*/
+
+#include "c1541.h"
+#include "c1571.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define M6502_TAG "u1"
+#define M6522_0_TAG "u9"
+#define M6522_1_TAG "u4"
+#define M6526_TAG "u20"
+#define WD1770_TAG "u11"
+#define C64H156_TAG "u6"
+
+
+enum
+{
+ LED_POWER = 0,
+ LED_ACT
+};
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C1570 = &device_creator<c1570_device>;
+const device_type C1571 = &device_creator<c1571_device>;
+const device_type C1571CR = &device_creator<c1571cr_device>;
+const device_type MINI_CHIEF = &device_creator<mini_chief_device>;
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void base_c1571_device::device_config_complete()
+{
+ switch (m_variant)
+ {
+ case TYPE_1570:
+ m_shortname = "c1570";
+ break;
+
+ default:
+ case TYPE_1571:
+ m_shortname = "c1571";
+ break;
+
+ case TYPE_1571CR:
+ m_shortname = "c1571cr";
+ break;
+
+ case TYPE_MINI_CHIEF:
+ m_shortname = "minichif";
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// 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( 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( 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( 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 *base_c1571_device::device_rom_region() const
+{
+ switch (m_variant)
+ {
+ case TYPE_1570:
+ return ROM_NAME( c1570 );
+
+ default:
+ case TYPE_1571:
+ return ROM_NAME( c1571 );
+
+ case TYPE_1571CR:
+ return ROM_NAME( c1571cr );
+
+ case TYPE_MINI_CHIEF:
+ return ROM_NAME( minichief );
+ }
+}
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( c1571_mem )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( c1571_mem, AS_PROGRAM, 8, base_c1571_device )
+ 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_DEVREADWRITE(M6522_1_TAG, via6522_device, read, write)
+ AM_RANGE(0x2000, 0x2003) AM_MIRROR(0x1ffc) AM_DEVREADWRITE_LEGACY(WD1770_TAG, wd17xx_r, wd17xx_w)
+ AM_RANGE(0x4000, 0x400f) AM_MIRROR(0x3ff0) AM_DEVREADWRITE_LEGACY(M6526_TAG, mos6526_r, mos6526_w)
+ AM_RANGE(0x8000, 0xffff) AM_ROM AM_REGION(M6502_TAG, 0)
+ADDRESS_MAP_END
+
+
+//-------------------------------------------------
+// via6522_interface via0_intf
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( base_c1571_device::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( base_c1571_device::via0_pa_r )
+{
+ /*
+
+ bit description
+
+ PA0 TRK0 SNS
+ PA1
+ PA2
+ PA3
+ PA4
+ PA5
+ PA6
+ PA7 BYTE RDY
+
+ */
+
+ UINT8 data = 0;
+
+ // track 0 sense
+ data |= floppy_tk00_r(m_image);
+
+ // byte ready
+ data |= m_ga->byte_r() << 7;
+
+ return data;
+}
+
+WRITE8_MEMBER( base_c1571_device::via0_pa_w )
+{
+ /*
+
+ bit description
+
+ PA0
+ PA1 SER DIR
+ PA2 SIDE
+ PA3
+ PA4
+ PA5 _1/2 MHZ
+ PA6 ATN OUT
+ PA7
+
+ */
+
+ // 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;
+ }
+
+ // fast serial direction
+ int ser_dir = BIT(data, 1);
+
+ if (m_ser_dir != ser_dir)
+ {
+ m_ser_dir = ser_dir;
+
+ set_iec_data();
+ set_iec_srq();
+
+ if (!m_ser_dir)
+ {
+ //m_cia->cnt_w(m_bus->srq_r());
+ //m_cia->sp_w(m_bus->data_r());
+ }
+ }
+
+ // side select
+ m_ga->set_side(BIT(data, 2));
+
+ // attention out
+ m_bus->atn_w(this, !BIT(data, 6));
+}
+
+READ8_MEMBER( base_c1571_device::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_address - 8) << 5;
+
+ // attention in
+ data |= !m_bus->atn_r() << 7;
+
+ return data;
+}
+
+WRITE8_MEMBER( base_c1571_device::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);
+
+ // attention acknowledge
+ m_ga->atna_w(BIT(data, 4));
+
+ // clock out
+ m_bus->clk_w(this, !BIT(data, 3));
+}
+
+READ_LINE_MEMBER( base_c1571_device::atn_in_r )
+{
+ return !m_bus->atn_r();
+}
+
+READ_LINE_MEMBER( base_c1571_device::wprt_r )
+{
+ return !floppy_wpt_r(m_image);
+}
+
+static const via6522_interface via0_intf =
+{
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c1571_device, via0_pa_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c1571_device, via0_pb_r),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_c1571_device, atn_in_r),
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_c1571_device, wprt_r),
+ DEVCB_NULL,
+
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c1571_device, via0_pa_w),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c1571_device, via0_pb_w),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_c1571_device, via0_irq_w)
+};
+
+
+//-------------------------------------------------
+// via6522_interface via1_intf
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( base_c1571_device::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( base_c1571_device::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 |= !floppy_wpt_r(m_image) << 4;
+
+ // SYNC detect line
+ data |= m_ga->sync_r() << 7;
+
+ return data;
+}
+
+WRITE8_MEMBER( base_c1571_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
+
+ */
+
+ // 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);
+}
+
+static const via6522_interface via1_intf =
+{
+ DEVCB_DEVICE_MEMBER(C64H156_TAG, c64h156_device, yb_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c1571_device, via1_pb_r),
+ DEVCB_DEVICE_LINE_MEMBER(C64H156_TAG, c64h156_device, byte_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+
+ DEVCB_DEVICE_MEMBER(C64H156_TAG, c64h156_device, yb_w),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c1571_device, via1_pb_w),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(C64H156_TAG, c64h156_device, soe_w),
+ DEVCB_DEVICE_LINE_MEMBER(C64H156_TAG, c64h156_device, oe_w),
+
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_c1571_device, via1_irq_w)
+};
+
+
+//-------------------------------------------------
+// mos6526_interface cia_intf
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( base_c1571_device::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( base_c1571_device::cia_pc_w )
+{
+ if (m_other != NULL)
+ {
+ m_other->parallel_strobe_w(state);
+ }
+}
+
+WRITE_LINE_MEMBER( base_c1571_device::cia_cnt_w )
+{
+ // fast serial clock out
+ m_cnt_out = state;
+ set_iec_srq();
+}
+
+WRITE_LINE_MEMBER( base_c1571_device::cia_sp_w )
+{
+ // fast serial data out
+ m_sp_out = state;
+ set_iec_data();
+}
+
+READ8_MEMBER( base_c1571_device::cia_pb_r )
+{
+ return m_parallel_data;
+}
+
+WRITE8_MEMBER( base_c1571_device::cia_pb_w )
+{
+ if (m_other != NULL)
+ {
+ m_other->parallel_data_w(data);
+ }
+}
+
+static MOS6526_INTERFACE( cia_intf )
+{
+ 0,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_c1571_device, cia_irq_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_c1571_device, cia_pc_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_c1571_device, cia_cnt_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_c1571_device, cia_sp_w),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c1571_device, cia_pb_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c1571_device, cia_pb_w)
+};
+
+
+//-------------------------------------------------
+// C64H156_INTERFACE( ga_intf )
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( base_c1571_device::atn_w )
+{
+ set_iec_data();
+}
+
+WRITE_LINE_MEMBER( base_c1571_device::byte_w )
+{
+ m_maincpu->set_input_line(M6502_SET_OVERFLOW, state);
+
+ m_via1->write_ca1(state);
+}
+
+static C64H156_INTERFACE( ga_intf )
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_c1571_device, atn_w),
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_c1571_device, byte_w)
+};
+
+
+//-------------------------------------------------
+// wd17xx_interface fdc_intf
+//-------------------------------------------------
+
+static const wd17xx_interface fdc_intf =
+{
+ DEVCB_LINE_GND,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ { FLOPPY_0, NULL, NULL, NULL }
+};
+
+
+//-------------------------------------------------
+// LEGACY_FLOPPY_OPTIONS( c1571 )
+//-------------------------------------------------
+
+static LEGACY_FLOPPY_OPTIONS_START( c1571 )
+ LEGACY_FLOPPY_OPTION( c1571, "g64", "Commodore 1541 GCR Disk Image", g64_dsk_identify, g64_dsk_construct, NULL, NULL )
+ LEGACY_FLOPPY_OPTION( c1571, "d64", "Commodore 1541 Disk Image", d64_dsk_identify, d64_dsk_construct, NULL, NULL )
+ LEGACY_FLOPPY_OPTION( c1571, "d71", "Commodore 1571 Disk Image", d71_dsk_identify, d64_dsk_construct, NULL, NULL )
+LEGACY_FLOPPY_OPTIONS_END
+
+
+//-------------------------------------------------
+// floppy_interface c1571_floppy_interface
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( base_c1571_device::wpt_w )
+{
+ m_via0->write_ca2(!state);
+}
+
+static const floppy_interface c1571_floppy_interface =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_c1571_device, wpt_w),
+ DEVCB_NULL,
+ FLOPPY_STANDARD_5_25_DSDD,
+ LEGACY_FLOPPY_OPTIONS_NAME(c1571),
+ "floppy_5_25",
+ NULL
+};
+
+
+//-------------------------------------------------
+// floppy_interface c1570_floppy_interface
+//-------------------------------------------------
+
+static const floppy_interface c1570_floppy_interface =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_c1571_device, wpt_w),
+ DEVCB_NULL,
+ FLOPPY_STANDARD_5_25_SSDD,
+ LEGACY_FLOPPY_OPTIONS_NAME(c1541),
+ "floppy_5_25",
+ NULL
+};
+
+
+//-------------------------------------------------
+// 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_VIA6522_ADD(M6522_0_TAG, XTAL_16MHz/16, via0_intf)
+ MCFG_VIA6522_ADD(M6522_1_TAG, XTAL_16MHz/16, via1_intf)
+ MCFG_MOS6526R1_ADD(M6526_TAG, XTAL_16MHz/16, cia_intf)
+ MCFG_WD1770_ADD(WD1770_TAG, /* XTAL_16MHz/2, */ fdc_intf)
+
+ MCFG_LEGACY_FLOPPY_DRIVE_ADD(FLOPPY_0, c1571_floppy_interface)
+ MCFG_64H156_ADD(C64H156_TAG, XTAL_16MHz, ga_intf)
+MACHINE_CONFIG_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_VIA6522_ADD(M6522_0_TAG, XTAL_16MHz/16, via0_intf)
+ MCFG_VIA6522_ADD(M6522_1_TAG, XTAL_16MHz/16, via1_intf)
+ MCFG_MOS6526R1_ADD(M6526_TAG, XTAL_16MHz/16, cia_intf)
+ MCFG_WD1770_ADD(WD1770_TAG, /* XTAL_16MHz/2, */ fdc_intf)
+
+ MCFG_LEGACY_FLOPPY_DRIVE_ADD(FLOPPY_0, c1570_floppy_interface)
+ MCFG_64H156_ADD(C64H156_TAG, XTAL_16MHz, ga_intf)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor base_c1571_device::device_mconfig_additions() const
+{
+ switch (m_variant)
+ {
+ case TYPE_1570:
+ return MACHINE_CONFIG_NAME( c1570 );
+
+ default:
+ return MACHINE_CONFIG_NAME( c1571 );
+ }
+}
+
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// base_c1571_device - constructor
+//-------------------------------------------------
+
+inline void base_c1571_device::set_iec_data()
+{
+ int data = !m_data_out && !m_ga->atn_r();
+
+ // fast serial data
+ if (m_ser_dir) data &= m_sp_out;
+
+ m_bus->data_w(this, data);
+}
+
+
+//-------------------------------------------------
+// base_c1571_device - constructor
+//-------------------------------------------------
+
+inline void base_c1571_device::set_iec_srq()
+{
+ int srq = 1;
+
+ // fast serial clock
+ if (m_ser_dir) srq &= m_cnt_out;
+
+ m_bus->srq_w(this, srq);
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// base_c1571_device - constructor
+//-------------------------------------------------
+
+base_c1571_device::base_c1571_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant)
+ : device_t(mconfig, type, name, tag, owner, clock),
+ 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_image(*this, FLOPPY_0),
+ 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),
+ m_variant(variant)
+{
+}
+
+
+//-------------------------------------------------
+// c1570_device - constructor
+//-------------------------------------------------
+
+c1570_device::c1570_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : base_c1571_device(mconfig, C1570, "C1570", tag, owner, clock, TYPE_1570) { }
+
+
+//-------------------------------------------------
+// c1571_device - constructor
+//-------------------------------------------------
+
+c1571_device::c1571_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : base_c1571_device(mconfig, C1571, "C1571", tag, owner, clock, TYPE_1571) { }
+
+
+//-------------------------------------------------
+// c1571cr_device - constructor
+//-------------------------------------------------
+
+c1571cr_device::c1571cr_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : base_c1571_device(mconfig, C1571CR, "C1571CR", tag, owner, clock, TYPE_1571CR) { }
+
+
+//-------------------------------------------------
+// mini_chief_device - constructor
+//-------------------------------------------------
+
+mini_chief_device::mini_chief_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : base_c1571_device(mconfig, MINI_CHIEF, "ICT Mini Chief", tag, owner, clock, TYPE_MINI_CHIEF) { }
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void base_c1571_device::device_start()
+{
+ // install image callbacks
+ floppy_install_unload_proc(m_image, base_c1571_device::on_disk_change);
+ floppy_install_load_proc(m_image, base_c1571_device::on_disk_change);
+
+ // 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 base_c1571_device::device_reset()
+{
+ m_maincpu->reset();
+
+ m_via0->reset();
+ m_via1->reset();
+ m_cia->reset();
+
+ wd17xx_mr_w(m_fdc, 0);
+ wd17xx_mr_w(m_fdc, 1);
+
+ m_sp_out = 1;
+ set_iec_data();
+
+ m_cnt_out = 1;
+ set_iec_srq();
+}
+
+
+//-------------------------------------------------
+// cbm_iec_srq -
+//-------------------------------------------------
+
+void base_c1571_device::cbm_iec_srq(int state)
+{
+ if (!m_ser_dir)
+ {
+ m_cia->cnt_w(state);
+ }
+}
+
+
+//-------------------------------------------------
+// cbm_iec_atn -
+//-------------------------------------------------
+
+void base_c1571_device::cbm_iec_atn(int state)
+{
+ m_via0->write_ca1(!state);
+ m_ga->atni_w(!state);
+
+ set_iec_data();
+}
+
+
+//-------------------------------------------------
+// cbm_iec_data -
+//-------------------------------------------------
+
+void base_c1571_device::cbm_iec_data(int state)
+{
+ if (!m_ser_dir)
+ {
+ m_cia->sp_w(state);
+ }
+}
+
+
+//-------------------------------------------------
+// cbm_iec_reset -
+//-------------------------------------------------
+
+void base_c1571_device::cbm_iec_reset(int state)
+{
+ if (!state)
+ {
+ device_reset();
+ }
+}
+
+
+//-------------------------------------------------
+// parallel_data_w -
+//-------------------------------------------------
+
+void base_c1571_device::parallel_data_w(UINT8 data)
+{
+ m_parallel_data = data;
+}
+
+
+//-------------------------------------------------
+// parallel_strobe_w -
+//-------------------------------------------------
+
+void base_c1571_device::parallel_strobe_w(int state)
+{
+ m_cia->flag_w(state);
+}
+
+
+//-------------------------------------------------
+// on_disk_change -
+//-------------------------------------------------
+
+void base_c1571_device::on_disk_change(device_image_interface &image)
+{
+ base_c1571_device *c1571 = static_cast<base_c1571_device *>(image.device().owner());
+
+ int wp = floppy_wpt_r(image);
+ c1571->m_ga->on_disk_changed(wp);
+}
diff --git a/src/mess/machine/c1571.h b/src/mess/machine/c1571.h
new file mode 100644
index 00000000000..5de832b1d63
--- /dev/null
+++ b/src/mess/machine/c1571.h
@@ -0,0 +1,180 @@
+/**********************************************************************
+
+ Commodore 1570/1571/1571CR Single Disk Drive emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __C1571__
+#define __C1571__
+
+
+#include "emu.h"
+#include "cpu/m6502/m6502.h"
+#include "imagedev/flopdrv.h"
+#include "formats/d64_dsk.h"
+#include "formats/g64_dsk.h"
+#include "machine/64h156.h"
+#include "machine/6522via.h"
+#include "machine/6526cia.h"
+#include "machine/c64_bn1541.h"
+#include "machine/cbmiec.h"
+#include "machine/wd17xx.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define C1571_TAG "c1571"
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> c1571_device
+
+class base_c1571_device : public device_t,
+ public device_cbm_iec_interface,
+ public device_c64_floppy_parallel_interface
+{
+public:
+ enum
+ {
+ TYPE_1570,
+ TYPE_1571,
+ TYPE_1571CR,
+ TYPE_MINI_CHIEF
+ };
+
+ // construction/destruction
+ base_c1571_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant);
+
+ // optional information overrides
+ virtual const rom_entry *device_rom_region() const;
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+ // not really public
+ static void on_disk_change(device_image_interface &image);
+
+ 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_READ_LINE_MEMBER( atn_in_r );
+ DECLARE_READ_LINE_MEMBER( wprt_r );
+ 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( atn_w );
+ DECLARE_WRITE_LINE_MEMBER( byte_w );
+ DECLARE_WRITE_LINE_MEMBER( wpt_w );
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+ 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);
+
+ inline void set_iec_data();
+ inline void set_iec_srq();
+
+ required_device<cpu_device> m_maincpu;
+ required_device<via6522_device> m_via0;
+ required_device<via6522_device> m_via1;
+ required_device<mos6526_device> m_cia;
+ required_device<device_t> m_fdc;
+ required_device<c64h156_device> m_ga;
+ required_device<legacy_floppy_image_device> m_image;
+
+ // 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
+
+ int m_variant;
+};
+
+
+// ======================> c1570_device
+
+class c1570_device : public base_c1571_device
+{
+public:
+ // construction/destruction
+ c1570_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+// ======================> c1571_device
+
+class c1571_device : public base_c1571_device
+{
+public:
+ // construction/destruction
+ c1571_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+// ======================> c1571cr_device
+
+class c1571cr_device : public base_c1571_device
+{
+public:
+ // construction/destruction
+ c1571cr_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+// ======================> mini_chief_device
+
+class mini_chief_device : public base_c1571_device
+{
+public:
+ // construction/destruction
+ mini_chief_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+// 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/mess/machine/c1581.c b/src/mess/machine/c1581.c
new file mode 100644
index 00000000000..f1c649538db
--- /dev/null
+++ b/src/mess/machine/c1581.c
@@ -0,0 +1,503 @@
+/**********************************************************************
+
+ Commodore 1581/1563 Single Disk Drive emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c1581.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 C1563 = &device_creator<c1563_device>;
+const device_type C1581 = &device_creator<c1581_device>;
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void base_c1581_device::device_config_complete()
+{
+ switch (m_variant)
+ {
+ default:
+ case TYPE_1581:
+ m_shortname = "c1581";
+ break;
+
+ case TYPE_1563:
+ m_shortname = "c1563";
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// ROM( c1581 )
+//-------------------------------------------------
+
+ROM_START( c1581 )
+ ROM_REGION( 0x8000, M6502_TAG, 0 )
+ ROM_DEFAULT_BIOS("r2")
+ 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( 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 *base_c1581_device::device_rom_region() const
+{
+ switch (m_variant)
+ {
+ default:
+ case TYPE_1581:
+ return ROM_NAME( c1581 );
+
+ case TYPE_1563:
+ return ROM_NAME( c1563 );
+ }
+}
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( c1581_mem )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( c1581_mem, AS_PROGRAM, 8, base_c1581_device )
+ AM_RANGE(0x0000, 0x1fff) AM_MIRROR(0x2000) AM_RAM
+ AM_RANGE(0x4000, 0x400f) AM_MIRROR(0x1ff0) AM_DEVREADWRITE_LEGACY(M8520_TAG, mos6526_r, mos6526_w)
+ AM_RANGE(0x6000, 0x6003) AM_MIRROR(0x1ffc) AM_DEVREADWRITE_LEGACY(WD1770_TAG, wd17xx_r, wd17xx_w)
+ AM_RANGE(0x8000, 0xffff) AM_ROM AM_REGION(M6502_TAG, 0)
+ADDRESS_MAP_END
+
+
+//-------------------------------------------------
+// MOS8520_INTERFACE( cia_intf )
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( base_c1581_device::cnt_w )
+{
+ // fast serial clock out
+ m_cnt_out = state;
+
+ set_iec_srq();
+}
+
+WRITE_LINE_MEMBER( base_c1581_device::sp_w )
+{
+ // fast serial data out
+ m_sp_out = state;
+
+ set_iec_data();
+}
+
+READ8_MEMBER( base_c1581_device::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 |= !(floppy_drive_get_flag_state(m_image, FLOPPY_DRIVE_READY) == FLOPPY_DRIVE_READY) << 1;
+
+ // device number
+ data |= (m_address - 8) << 3;
+
+ // disk change
+ data |= floppy_dskchg_r(m_image) << 7;
+
+ return data;
+}
+
+WRITE8_MEMBER( base_c1581_device::cia_pa_w )
+{
+ /*
+
+ bit description
+
+ PA0 SIDE0
+ PA1
+ PA2 /MOTOR
+ PA3
+ PA4
+ PA5 POWER LED
+ PA6 ACT LED
+ PA7
+
+ */
+
+ // side 0
+ wd17xx_set_side(m_fdc, !BIT(data, 0));
+
+ // motor
+ int motor = BIT(data, 2);
+ floppy_mon_w(m_image, motor);
+ floppy_drive_set_ready_state(m_image, !motor, 1);
+
+ // power led
+ output_set_led_value(LED_POWER, BIT(data, 5));
+
+ // activity led
+ output_set_led_value(LED_ACT, BIT(data, 6));
+}
+
+READ8_MEMBER( base_c1581_device::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 |= !floppy_wpt_r(m_image) << 6;
+
+ // attention in
+ data |= !m_bus->atn_r() << 7;
+
+ return data;
+}
+
+WRITE8_MEMBER( base_c1581_device::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);
+
+ set_iec_data();
+ set_iec_srq();
+}
+
+static MOS8520_INTERFACE( cia_intf )
+{
+ XTAL_16MHz/8,
+ DEVCB_CPU_INPUT_LINE(M6502_TAG, INPUT_LINE_IRQ0),
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_c1581_device, cnt_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_c1581_device, sp_w),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c1581_device, cia_pa_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c1581_device, cia_pa_w),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c1581_device, cia_pb_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c1581_device, cia_pb_w)
+};
+
+
+//-------------------------------------------------
+// wd17xx_interface fdc_intf
+//-------------------------------------------------
+
+static const wd17xx_interface fdc_intf =
+{
+ DEVCB_LINE_GND,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ { FLOPPY_0, NULL, NULL, NULL }
+};
+
+
+//-------------------------------------------------
+// LEGACY_FLOPPY_OPTIONS( c1581 )
+//-------------------------------------------------
+
+static LEGACY_FLOPPY_OPTIONS_START( c1581 )
+ LEGACY_FLOPPY_OPTION( c1581, "d81", "Commodore 1581 Disk Image", d81_dsk_identify, d81_dsk_construct, NULL, NULL )
+LEGACY_FLOPPY_OPTIONS_END
+
+
+//-------------------------------------------------
+// floppy_interface c1581_floppy_interface
+//-------------------------------------------------
+
+static const floppy_interface c1581_floppy_interface =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ FLOPPY_STANDARD_3_5_DSDD,
+ LEGACY_FLOPPY_OPTIONS_NAME(c1581),
+ "floppy_3_5",
+ NULL
+};
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( c1581 )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( c1581 )
+ MCFG_CPU_ADD(M6502_TAG, M6502, XTAL_16MHz/8)
+ MCFG_CPU_PROGRAM_MAP(c1581_mem)
+
+ MCFG_MOS8520_ADD(M8520_TAG, XTAL_16MHz/8, cia_intf)
+ MCFG_WD1770_ADD(WD1770_TAG, /*XTAL_16MHz/2,*/ fdc_intf)
+
+ MCFG_LEGACY_FLOPPY_DRIVE_ADD(FLOPPY_0, c1581_floppy_interface)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor base_c1581_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( c1581 );
+}
+
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// base_c1581_device - constructor
+//-------------------------------------------------
+
+inline void base_c1581_device::set_iec_data()
+{
+ int atn = m_bus->atn_r();
+ int data = !m_data_out && !(m_atn_ack && !atn);
+
+ // fast serial data
+ if (m_fast_ser_dir) data &= m_sp_out;
+
+ m_bus->data_w(this, data);
+}
+
+
+//-------------------------------------------------
+// base_c1581_device - constructor
+//-------------------------------------------------
+
+inline void base_c1581_device::set_iec_srq()
+{
+ int srq = 1;
+
+ // fast serial clock
+ if (m_fast_ser_dir) srq &= m_cnt_out;
+
+ m_bus->srq_w(this, srq);
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// base_c1581_device - constructor
+//-------------------------------------------------
+
+base_c1581_device::base_c1581_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant)
+ : device_t(mconfig, type, name, tag, owner, clock),
+ device_cbm_iec_interface(mconfig, *this),
+ m_maincpu(*this, M6502_TAG),
+ m_cia(*this, M8520_TAG),
+ m_fdc(*this, WD1770_TAG),
+ m_image(*this, FLOPPY_0),
+ m_variant(variant)
+{
+}
+
+
+//-------------------------------------------------
+// c1563_device - constructor
+//-------------------------------------------------
+
+c1563_device::c1563_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : base_c1581_device(mconfig, C1563, "C1563", tag, owner, clock, TYPE_1563) { }
+
+
+//-------------------------------------------------
+// c1581_device - constructor
+//-------------------------------------------------
+
+c1581_device::c1581_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : base_c1581_device(mconfig, C1581, "C1581", tag, owner, clock, TYPE_1581) { }
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void base_c1581_device::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 base_c1581_device::device_reset()
+{
+ m_maincpu->reset();
+
+ m_cia->reset();
+
+ wd17xx_mr_w(m_fdc, 0);
+ wd17xx_mr_w(m_fdc, 1);
+
+ m_sp_out = 1;
+ m_cnt_out = 1;
+}
+
+
+//-------------------------------------------------
+// cbm_iec_srq -
+//-------------------------------------------------
+
+void base_c1581_device::cbm_iec_srq(int state)
+{
+ if (!m_fast_ser_dir)
+ {
+ m_cia->cnt_w(state);
+ }
+}
+
+
+//-------------------------------------------------
+// cbm_iec_atn -
+//-------------------------------------------------
+
+void base_c1581_device::cbm_iec_atn(int state)
+{
+ m_cia->flag_w(state);
+
+ set_iec_data();
+}
+
+
+//-------------------------------------------------
+// cbm_iec_data -
+//-------------------------------------------------
+
+void base_c1581_device::cbm_iec_data(int state)
+{
+ if (!m_fast_ser_dir)
+ {
+ m_cia->sp_w(state);
+ }
+}
+
+
+//-------------------------------------------------
+// cbm_iec_reset -
+//-------------------------------------------------
+
+void base_c1581_device::cbm_iec_reset(int state)
+{
+ if (!state)
+ {
+ device_reset();
+ }
+}
diff --git a/src/mess/machine/c1581.h b/src/mess/machine/c1581.h
new file mode 100644
index 00000000000..ee3855f2b28
--- /dev/null
+++ b/src/mess/machine/c1581.h
@@ -0,0 +1,122 @@
+/**********************************************************************
+
+ Commodore 1581/1563 Single Disk Drive emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __C1581__
+#define __C1581__
+
+
+#include "emu.h"
+#include "cpu/m6502/m6502.h"
+#include "imagedev/flopdrv.h"
+#include "formats/d81_dsk.h"
+#include "machine/6526cia.h"
+#include "machine/cbmiec.h"
+#include "machine/wd17xx.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define C1581_TAG "c1581"
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> base_c1581_device
+
+class base_c1581_device : public device_t,
+ public device_cbm_iec_interface
+{
+
+public:
+ // construction/destruction
+ base_c1581_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant);
+
+ enum
+ {
+ TYPE_1563,
+ TYPE_1581
+ };
+
+ // optional information overrides
+ virtual const rom_entry *device_rom_region() const;
+ virtual machine_config_constructor device_mconfig_additions() 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 );
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+ 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);
+
+ inline void set_iec_data();
+ inline void set_iec_srq();
+
+ required_device<cpu_device> m_maincpu;
+ required_device<mos6526_device> m_cia;
+ required_device<device_t> m_fdc;
+ required_device<legacy_floppy_image_device> m_image;
+
+ 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
+
+ int m_variant;
+};
+
+
+// ======================> c1563_device
+
+class c1563_device : public base_c1581_device
+{
+public:
+ // construction/destruction
+ c1563_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+// ======================> c1581_device
+
+class c1581_device : public base_c1581_device
+{
+public:
+ // construction/destruction
+ c1581_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+// device type definition
+extern const device_type C1563;
+extern const device_type C1581;
+
+
+
+#endif
diff --git a/src/mess/machine/c16.c b/src/mess/machine/c16.c
new file mode 100644
index 00000000000..be6fbcf048b
--- /dev/null
+++ b/src/mess/machine/c16.c
@@ -0,0 +1,715 @@
+/***************************************************************************
+
+ commodore c16 home computer
+
+ peter.trauner@jk.uni-linz.ac.at
+ documentation
+ www.funet.fi
+
+***************************************************************************/
+
+#include "emu.h"
+#include "audio/ted7360.h"
+#include "cpu/m6502/m6502.h"
+#include "imagedev/cassette.h"
+#include "imagedev/cartslot.h"
+#include "machine/ram.h"
+#include "includes/c16.h"
+#include "machine/cbmiec.h"
+#include "sound/sid6581.h"
+
+#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)
+
+
+/*
+ * tia6523
+ *
+ * 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
+ */
+
+/*
+ ddr bit 1 port line is output
+ port bit 1 port line is high
+
+ serial bus
+ 1 serial srq in (ignored)
+ 2 gnd
+ 3 atn out (pull up)
+ 4 clock in/out (pull up)
+ 5 data in/out (pull up)
+ 6 /reset (pull up) hardware
+
+
+ p0 negated serial bus pin 5 /data out
+ p1 negated serial bus pin 4 /clock out, cassette write
+ p2 negated serial bus pin 3 /atn out
+ p3 cassette motor out
+
+ p4 cassette read
+ p5 not connected (or not available on MOS7501?)
+ p6 serial clock in
+ p7 serial data in, serial bus 5
+*/
+
+WRITE8_DEVICE_HANDLER(c16_m7501_port_write)
+{
+ c16_state *state = device->machine().driver_data<c16_state>();
+
+ /* bit zero then output 0 */
+ state->m_iec->atn_w(!BIT(data, 2));
+ state->m_iec->clk_w(!BIT(data, 1));
+ state->m_iec->data_w(!BIT(data, 0));
+
+ state->m_cassette->output(!BIT(data, 1) ? -(0x5a9e >> 1) : +(0x5a9e >> 1));
+
+ state->m_cassette->change_state(BIT(data, 7) ? CASSETTE_MOTOR_DISABLED : CASSETTE_MOTOR_ENABLED, CASSETTE_MASK_MOTOR);
+}
+
+READ8_DEVICE_HANDLER(c16_m7501_port_read)
+{
+ c16_state *state = device->machine().driver_data<c16_state>();
+ UINT8 data = 0xff;
+ UINT8 c16_port7501 = m6510_get_port(state->m_maincpu);
+
+ if (BIT(c16_port7501, 0) || !state->m_iec->data_r())
+ data &= ~0x80;
+
+ if (BIT(c16_port7501, 1) || !state->m_iec->clk_r())
+ data &= ~0x40;
+
+// data &= ~0x20; // port bit not in pinout
+
+ if (state->m_cassette->input() > +0.0)
+ data |= 0x10;
+ else
+ data &= ~0x10;
+
+ return data;
+}
+
+static void c16_bankswitch( running_machine &machine )
+{
+ c16_state *state = machine.driver_data<c16_state>();
+ UINT8 *rom = state->memregion("maincpu")->base();
+ state->membank("bank9")->set_base(state->m_messram->pointer());
+
+ switch (state->m_lowrom)
+ {
+ case 0:
+ state->membank("bank2")->set_base(rom + 0x10000);
+ break;
+ case 1:
+ state->membank("bank2")->set_base(rom + 0x18000);
+ break;
+ case 2:
+ state->membank("bank2")->set_base(rom + 0x20000);
+ break;
+ case 3:
+ state->membank("bank2")->set_base(rom + 0x28000);
+ break;
+ }
+
+ switch (state->m_highrom)
+ {
+ case 0:
+ state->membank("bank3")->set_base(rom + 0x14000);
+ state->membank("bank8")->set_base(rom + 0x17f20);
+ break;
+ case 1:
+ state->membank("bank3")->set_base(rom + 0x1c000);
+ state->membank("bank8")->set_base(rom + 0x1ff20);
+ break;
+ case 2:
+ state->membank("bank3")->set_base(rom + 0x24000);
+ state->membank("bank8")->set_base(rom + 0x27f20);
+ break;
+ case 3:
+ state->membank("bank3")->set_base(rom + 0x2c000);
+ state->membank("bank8")->set_base(rom + 0x2ff20);
+ break;
+ }
+ state->membank("bank4")->set_base(rom + 0x17c00);
+}
+
+WRITE8_HANDLER( c16_switch_to_rom )
+{
+ c16_state *state = space->machine().driver_data<c16_state>();
+
+ ted7360_rom_switch_w(state->m_ted7360, 1);
+ c16_bankswitch(space->machine());
+}
+
+/* write access to fddX load data flipflop
+ * and selects roms
+ * a0 a1
+ * 0 0 basic
+ * 0 1 plus4 low
+ * 1 0 c1 low
+ * 1 1 c2 low
+ *
+ * a2 a3
+ * 0 0 kernal
+ * 0 1 plus4 hi
+ * 1 0 c1 high
+ * 1 1 c2 high */
+WRITE8_HANDLER( c16_select_roms )
+{
+ c16_state *state = space->machine().driver_data<c16_state>();
+
+ state->m_lowrom = offset & 0x03;
+ state->m_highrom = (offset & 0x0c) >> 2;
+ if (ted7360_rom_switch_r(state->m_ted7360))
+ c16_bankswitch(space->machine());
+}
+
+WRITE8_HANDLER( c16_switch_to_ram )
+{
+ c16_state *state = space->machine().driver_data<c16_state>();
+ UINT8 *ram = state->m_messram->pointer();
+ UINT32 ram_size = state->m_messram->size();
+
+ ted7360_rom_switch_w(state->m_ted7360, 0);
+
+ state->membank("bank2")->set_base(ram + (0x8000 % ram_size));
+ state->membank("bank3")->set_base(ram + (0xc000 % ram_size));
+ state->membank("bank4")->set_base(ram + (0xfc00 % ram_size));
+ state->membank("bank8")->set_base(ram + (0xff20 % ram_size));
+}
+
+UINT8 c16_read_keyboard( running_machine &machine, int databus )
+{
+ c16_state *state = machine.driver_data<c16_state>();
+ UINT8 value = 0xff;
+ int i;
+
+ for (i = 0; i < 8; i++)
+ {
+ if (!BIT(state->m_port6529, i))
+ value &= state->m_keyline[i];
+ }
+
+ /* looks like joy 0 needs dataline2 low
+ * and joy 1 needs dataline1 low
+ * write to 0xff08 (value on databus) reloads latches */
+ if (!BIT(databus, 2))
+ value &= state->m_keyline[8];
+
+ if (!BIT(databus, 1))
+ value &= state->m_keyline[9];
+
+ return value;
+}
+
+/*
+ * mos 6529
+ * simple 1 port 8bit input output
+ * output with pull up resistors, 0 means low
+ * input, 0 means low
+ */
+/*
+ * ic used as output,
+ * output low means keyboard line selected
+ * keyboard line is then read into the ted7360 latch
+ */
+WRITE8_HANDLER( c16_6529_port_w )
+{
+ c16_state *state = space->machine().driver_data<c16_state>();
+ state->m_port6529 = data;
+}
+
+READ8_HANDLER( c16_6529_port_r )
+{
+ c16_state *state = space->machine().driver_data<c16_state>();
+ return state->m_port6529 & (c16_read_keyboard (space->machine(), 0xff /*databus */ ) | (state->m_port6529 ^ 0xff));
+}
+
+/*
+ * p0 Userport b
+ * p1 Userport k
+ * p2 Userport 4, cassette sense
+ * p3 Userport 5
+ * p4 Userport 6
+ * p5 Userport 7
+ * p6 Userport j
+ * p7 Userport f
+ */
+WRITE8_HANDLER( plus4_6529_port_w )
+{
+}
+
+READ8_HANDLER( plus4_6529_port_r )
+{
+ c16_state *state = space->machine().driver_data<c16_state>();
+ int data = 0x00;
+
+ if ((state->m_cassette->get_state() & CASSETTE_MASK_UISTATE) != CASSETTE_STOPPED)
+ data &= ~0x04;
+ else
+ data |= 0x04;
+
+ return data;
+}
+
+READ8_HANDLER( c16_fd1x_r )
+{
+ c16_state *state = space->machine().driver_data<c16_state>();
+ int data = 0x00;
+
+ if ((state->m_cassette->get_state() & CASSETTE_MASK_UISTATE) != CASSETTE_STOPPED)
+ data &= ~0x04;
+ else
+ data |= 0x04;
+
+ return data;
+}
+
+/**
+ 0 write: transmit data
+ 0 read: receiver data
+ 1 write: programmed rest (data is dont care)
+ 1 read: status register
+ 2 command register
+ 3 control register
+ control register (offset 3)
+ cleared by hardware reset, not changed by programmed reset
+ 7: 2 stop bits (0 1 stop bit)
+ 6,5: data word length
+ 00 8 bits
+ 01 7
+ 10 6
+ 11 5
+ 4: ?? clock source
+ 0 external receiver clock
+ 1 baud rate generator
+ 3-0: baud rate generator
+ 0000 use external clock
+ 0001 60
+ 0010 75
+ 0011
+ 0100
+ 0101
+ 0110 300
+ 0111 600
+ 1000 1200
+ 1001
+ 1010 2400
+ 1011 3600
+ 1100 4800
+ 1101 7200
+ 1110 9600
+ 1111 19200
+ control register
+ */
+WRITE8_HANDLER( c16_6551_port_w )
+{
+ c16_state *state = space->machine().driver_data<c16_state>();
+
+ offset &= 0x03;
+ DBG_LOG(space->machine(), 3, "6551", ("port write %.2x %.2x\n", offset, data));
+ state->m_port6529 = data;
+}
+
+READ8_HANDLER( c16_6551_port_r )
+{
+ int data = 0x00;
+
+ offset &= 0x03;
+ DBG_LOG(space->machine(), 3, "6551", ("port read %.2x %.2x\n", offset, data));
+ return data;
+}
+
+int c16_dma_read( running_machine &machine, int offset )
+{
+ c16_state *state = machine.driver_data<c16_state>();
+ return state->m_messram->pointer()[offset % state->m_messram->size()];
+}
+
+int c16_dma_read_rom( running_machine &machine, int offset )
+{
+ c16_state *state = machine.driver_data<c16_state>();
+
+ /* should read real c16 system bus from 0xfd00 -ff1f */
+ if (offset >= 0xc000)
+ { /* rom address in rom */
+ if ((offset >= 0xfc00) && (offset < 0xfd00))
+ return state->m_mem10000[offset];
+
+ switch (state->m_highrom)
+ {
+ case 0:
+ return state->m_mem10000[offset & 0x7fff];
+ case 1:
+ return state->m_mem18000[offset & 0x7fff];
+ case 2:
+ return state->m_mem20000[offset & 0x7fff];
+ case 3:
+ return state->m_mem28000[offset & 0x7fff];
+ }
+ }
+
+ if (offset >= 0x8000)
+ { /* rom address in rom */
+ switch (state->m_lowrom)
+ {
+ case 0:
+ return state->m_mem10000[offset & 0x7fff];
+ case 1:
+ return state->m_mem18000[offset & 0x7fff];
+ case 2:
+ return state->m_mem20000[offset & 0x7fff];
+ case 3:
+ return state->m_mem28000[offset & 0x7fff];
+ }
+ }
+
+ return state->m_messram->pointer()[offset % state->m_messram->size()];
+}
+
+void c16_interrupt( running_machine &machine, int level )
+{
+ c16_state *state = machine.driver_data<c16_state>();
+
+ if (level != state->m_old_level)
+ {
+ DBG_LOG(machine, 3, "mos7501", ("irq %s\n", level ? "start" : "end"));
+ device_set_input_line(state->m_maincpu, M6510_IRQ_LINE, level);
+ state->m_old_level = level;
+ }
+}
+
+static void c16_common_driver_init( running_machine &machine )
+{
+ c16_state *state = machine.driver_data<c16_state>();
+ UINT8 *rom = state->memregion("maincpu")->base();
+
+ /* initial bankswitch (notice that TED7360 is init to ROM) */
+ state->membank("bank2")->set_base(rom + 0x10000);
+ state->membank("bank3")->set_base(rom + 0x14000);
+ state->membank("bank4")->set_base(rom + 0x17c00);
+ state->membank("bank8")->set_base(rom + 0x17f20);
+
+ state->m_mem10000 = rom + 0x10000;
+ state->m_mem14000 = rom + 0x14000;
+ state->m_mem18000 = rom + 0x18000;
+ state->m_mem1c000 = rom + 0x1c000;
+ state->m_mem20000 = rom + 0x20000;
+ state->m_mem24000 = rom + 0x24000;
+ state->m_mem28000 = rom + 0x28000;
+ state->m_mem2c000 = rom + 0x2c000;
+}
+
+DRIVER_INIT_MEMBER(c16_state,c16)
+{
+ c16_common_driver_init(machine());
+
+ m_sidcard = 0;
+ m_pal = 1;
+}
+
+DRIVER_INIT_MEMBER(c16_state,plus4)
+{
+ c16_common_driver_init(machine());
+
+ m_sidcard = 0;
+ m_pal = 0;
+}
+
+DRIVER_INIT_MEMBER(c16_state,c16sid)
+{
+ c16_common_driver_init(machine());
+
+ m_sidcard = 1;
+ m_pal = 1;
+}
+
+DRIVER_INIT_MEMBER(c16_state,plus4sid)
+{
+ c16_common_driver_init(machine());
+
+ m_sidcard = 1;
+ m_pal = 0;
+}
+
+MACHINE_RESET( c16 )
+{
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ c16_state *state = machine.driver_data<c16_state>();
+ UINT8 *ram = state->m_messram->pointer();
+ UINT32 ram_size = state->m_messram->size();
+
+ memset(state->m_keyline, 0xff, ARRAY_LENGTH(state->m_keyline));
+
+ state->m_lowrom = 0;
+ state->m_highrom = 0;
+ state->m_old_level = 0;
+ state->m_port6529 = 0;
+
+ if (state->m_pal)
+ {
+ state->membank("bank1")->set_base(ram + (0x4000 % ram_size));
+
+ state->membank("bank5")->set_base(ram + (0x4000 % ram_size));
+ state->membank("bank6")->set_base(ram + (0x8000 % ram_size));
+ state->membank("bank7")->set_base(ram + (0xc000 % ram_size));
+
+ space->install_write_bank(0xff20, 0xff3d,"bank10");
+ space->install_write_bank(0xff40, 0xffff, "bank11");
+ state->membank("bank10")->set_base(ram + (0xff20 % ram_size));
+ state->membank("bank11")->set_base(ram + (0xff40 % ram_size));
+ }
+ else
+ {
+ space->install_write_bank(0x4000, 0xfcff, "bank10");
+ state->membank("bank10")->set_base(ram + (0x4000 % ram_size));
+ }
+}
+
+#if 0
+// FIXME
+// in very old MESS versions, we had these handlers to enable SID writes to 0xd400.
+// would a real SID Card allow for this? If not, this should be removed completely
+static WRITE8_HANDLER( c16_sidcart_16k )
+{
+ c16_state *state = space->machine().driver_data<c16_state>();
+ UINT8 *ram = state->m_messram->pointer();
+
+ ram[0x1400 + offset] = data;
+ ram[0x5400 + offset] = data;
+ ram[0x9400 + offset] = data;
+ ram[0xd400 + offset] = data;
+
+ sid6581_w(state->m_sid, offset, data);
+}
+
+static WRITE8_HANDLER( c16_sidcart_64k )
+{
+ c16_state *state = space->machine().driver_data<c16_state>();
+
+ state->m_messram->pointer()[0xd400 + offset] = data;
+
+ sid6581_w(state->m_sid, offset, data);
+}
+
+static TIMER_CALLBACK( c16_sidhack_tick )
+{
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ c16_state *state = space->machine().driver_data<c16_state>();
+
+ if (machine.root_device().ioport("SID")->read_safe(0x00) & 0x02)
+ {
+ if (state->m_pal)
+ space->install_legacy_write_handler(0xd400, 0xd41f, FUNC(c16_sidcart_16k));
+ else
+ space->install_legacy_write_handler(0xd400, 0xd41f, FUNC(c16_sidcart_64k));
+ }
+ else
+ {
+ space->unmap_write(0xd400, 0xd41f);
+ }
+}
+#endif
+
+static TIMER_CALLBACK( c16_sidcard_tick )
+{
+ c16_state *state = machine.driver_data<c16_state>();
+ address_space *space = state->m_maincpu->memory().space(AS_PROGRAM);
+
+ if (machine.root_device().ioport("SID")->read_safe(0x00) & 0x01)
+ space->install_legacy_readwrite_handler(*state->m_sid, 0xfe80, 0xfe9f, FUNC(sid6581_r), FUNC(sid6581_w));
+ else
+ space->install_legacy_readwrite_handler(*state->m_sid, 0xfd40, 0xfd5f, FUNC(sid6581_r), FUNC(sid6581_w));
+}
+
+INTERRUPT_GEN( c16_frame_interrupt )
+{
+ c16_state *state = device->machine().driver_data<c16_state>();
+ int value, i;
+ static const char *const c16ports[] = { "ROW0", "ROW1", "ROW2", "ROW3", "ROW4", "ROW5", "ROW6", "ROW7" };
+
+ /* Lines 0-7 : common keyboard */
+ for (i = 0; i < 8; i++)
+ {
+ value = 0xff;
+ value &= ~device->machine().root_device().ioport(c16ports[i])->read();
+
+ /* Shift Lock is mapped on Left/Right Shift */
+ if ((i == 1) && (device->machine().root_device().ioport("SPECIAL")->read() & 0x80))
+ value &= ~0x80;
+
+ state->m_keyline[i] = value;
+ }
+
+ if (device->machine().root_device().ioport("CTRLSEL")->read() & 0x01)
+ {
+ value = 0xff;
+ if (device->machine().root_device().ioport("JOY0")->read() & 0x10) /* Joypad1_Button */
+ {
+ if (device->machine().root_device().ioport("SPECIAL")->read() & 0x40)
+ value &= ~0x80;
+ else
+ value &= ~0x40;
+ }
+
+ value &= ~(device->machine().root_device().ioport("JOY0")->read() & 0x0f); /* Other Inputs Joypad1 */
+
+ if (device->machine().root_device().ioport("SPECIAL")->read() & 0x40)
+ state->m_keyline[9] = value;
+ else
+ state->m_keyline[8] = value;
+ }
+
+ if (device->machine().root_device().ioport("CTRLSEL")->read() & 0x10)
+ {
+ value = 0xff;
+ if (device->machine().root_device().ioport("JOY1")->read() & 0x10) /* Joypad2_Button */
+ {
+ if (device->machine().root_device().ioport("SPECIAL")->read() & 0x40)
+ value &= ~0x40;
+ else
+ value &= ~0x80;
+ }
+
+ value &= ~(device->machine().root_device().ioport("JOY1")->read() & 0x0f); /* Other Inputs Joypad2 */
+
+ if (device->machine().root_device().ioport("SPECIAL")->read() & 0x40)
+ state->m_keyline[8] = value;
+ else
+ state->m_keyline[9] = value;
+ }
+
+ ted7360_frame_interrupt_gen(state->m_ted7360);
+
+ if (state->m_sidcard)
+ {
+ /* if we are emulating the SID card, check which memory area should be accessed */
+ device->machine().scheduler().timer_set(attotime::zero, FUNC(c16_sidcard_tick));
+#if 0
+ /* if we are emulating the SID card, check if writes to 0xd400 have been enabled */
+ device->machine().scheduler().timer_set(attotime::zero, FUNC(c16_sidhack_tick));
+#endif
+ }
+
+ set_led_status(device->machine(), 1, device->machine().root_device().ioport("SPECIAL")->read() & 0x80 ? 1 : 0); /* Shift Lock */
+ set_led_status(device->machine(), 0, device->machine().root_device().ioport("SPECIAL")->read() & 0x40 ? 1 : 0); /* Joystick Swap */
+}
+
+
+/***********************************************
+
+ C16 Cartridges
+
+***********************************************/
+
+static void plus4_software_list_cartridge_load(device_image_interface &image)
+{
+ UINT8 *mem = image.device().machine().root_device().memregion("maincpu")->base();
+
+ size_t size = image.get_software_region_length("c1l");
+ if (size)
+ memcpy(mem + 0x20000, image.get_software_region("c1l"), size);
+
+ size = image.get_software_region_length("c1h");
+ if (size)
+ memcpy(mem + 0x24000, image.get_software_region("c1h"), size);
+
+ size = image.get_software_region_length("c2l");
+ if (size)
+ memcpy(mem + 0x28000, image.get_software_region("c2l"), size);
+
+ size = image.get_software_region_length("c2h");
+ if (size)
+ memcpy(mem + 0x2c000, image.get_software_region("c2h"), size);
+}
+
+static int plus4_crt_load( device_image_interface &image )
+{
+ UINT8 *mem = image.device().machine().root_device().memregion("maincpu")->base();
+ int size = image.length(), test;
+ const char *filetype;
+ int address = 0;
+
+ /* magic lowrom at offset 7: $43 $42 $4d */
+ /* if at offset 6 stands 1 it will immediatly jumped to offset 0 (0x8000) */
+ static const unsigned char magic[] = {0x43, 0x42, 0x4d};
+ unsigned char buffer[sizeof (magic)];
+
+ image.fseek(7, SEEK_SET);
+ image.fread( buffer, sizeof (magic));
+ image.fseek(0, SEEK_SET);
+
+ /* Check if our cart has the magic string, and set its loading address */
+ if (!memcmp(buffer, magic, sizeof (magic)))
+ address = 0x20000;
+
+ /* Give a loading address to non .bin / non .rom carts as well */
+ filetype = image.filetype();
+
+ /* We would support .hi and .lo files, but currently I'm not sure where to load them.
+ We simply load them at 0x20000 at this stage, even if it's probably wrong!
+ It could also well be that they both need to be loaded at the same time, but this
+ is now impossible since I reduced to 1 the number of cart slots.
+ More investigations are in order if any .hi, .lo dump would surface! */
+ if (!mame_stricmp(filetype, "hi"))
+ address = 0x20000; /* FIX ME! */
+
+ else if (!mame_stricmp(filetype, "lo"))
+ address = 0x20000; /* FIX ME! */
+
+ /* As a last try, give a reasonable loading address also to .bin/.rom without the magic string */
+ else if (!address)
+ {
+ logerror("Cart %s does not contain the magic string: it may be loaded at the wrong memory address!\n", image.filename());
+ address = 0x20000;
+ }
+
+ logerror("Loading cart %s at %.5x size:%.4x\n", image.filename(), address, size);
+
+ /* Finally load the cart */
+ test = image.fread( mem + address, size);
+
+ if (test != size)
+ return IMAGE_INIT_FAIL;
+
+ return IMAGE_INIT_PASS;
+}
+
+static DEVICE_IMAGE_LOAD( c16_cart )
+{
+ int result = IMAGE_INIT_PASS;
+
+ if (image.software_entry() != NULL)
+ {
+ plus4_software_list_cartridge_load(image);
+ }
+ else
+ {
+ result = plus4_crt_load(image);
+ }
+
+ return result;
+}
+
+MACHINE_CONFIG_FRAGMENT( c16_cartslot )
+ MCFG_CARTSLOT_ADD("cart")
+ MCFG_CARTSLOT_EXTENSION_LIST("bin,rom,hi,lo")
+ MCFG_CARTSLOT_NOT_MANDATORY
+ MCFG_CARTSLOT_INTERFACE("plus4_cart")
+ MCFG_CARTSLOT_LOAD(c16_cart)
+ MCFG_SOFTWARE_LIST_ADD("cart_list", "plus4_cart")
+MACHINE_CONFIG_END
diff --git a/src/mess/machine/c2031.c b/src/mess/machine/c2031.c
new file mode 100644
index 00000000000..d733e47840d
--- /dev/null
+++ b/src/mess/machine/c2031.c
@@ -0,0 +1,502 @@
+/**********************************************************************
+
+ Commodore 2031 Single Disk Drive emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+
+#include "c1541.h"
+#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<c2031_device>;
+
+
+//-------------------------------------------------
+// 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
+
+
+//-------------------------------------------------
+// via6522_interface via0_intf
+//-------------------------------------------------
+
+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());
+}
+
+READ_LINE_MEMBER( c2031_device::via0_ca1_r )
+{
+ return !m_bus->atn_r();
+}
+
+READ_LINE_MEMBER( c2031_device::via0_ca2_r )
+{
+ return get_device_number();
+}
+
+static const via6522_interface via0_intf =
+{
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c2031_device, via0_pa_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c2031_device, via0_pb_r),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, c2031_device, via0_ca1_r),
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, c2031_device, via0_ca2_r),
+ DEVCB_NULL,
+
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c2031_device, via0_pa_w),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c2031_device, via0_pb_w),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL, // PLL SYN
+
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, c2031_device, via0_irq_w)
+};
+
+
+//-------------------------------------------------
+// via6522_interface via1_intf
+//-------------------------------------------------
+
+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 |= !floppy_wpt_r(m_image) << 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);
+}
+
+static const via6522_interface via1_intf =
+{
+ DEVCB_DEVICE_MEMBER(C64H156_TAG, c64h156_device, yb_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c2031_device, via1_pb_r),
+ DEVCB_DEVICE_LINE_MEMBER(C64H156_TAG, c64h156_device, byte_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+
+ DEVCB_DEVICE_MEMBER(C64H156_TAG, c64h156_device, yb_w),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c2031_device, via1_pb_w),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(C64H156_TAG, c64h156_device, soe_w),
+ DEVCB_DEVICE_LINE_MEMBER(C64H156_TAG, c64h156_device, oe_w),
+
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, c2031_device, via1_irq_w)
+};
+
+
+//-------------------------------------------------
+// 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);
+}
+
+static C64H156_INTERFACE( ga_intf )
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, c2031_device, byte_w)
+};
+
+
+//-------------------------------------------------
+// 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_VIA6522_ADD(M6522_0_TAG, XTAL_16MHz/16, via0_intf)
+ MCFG_VIA6522_ADD(M6522_1_TAG, XTAL_16MHz/16, via1_intf)
+
+ MCFG_LEGACY_FLOPPY_DRIVE_ADD(FLOPPY_0, c1541_floppy_interface)
+ MCFG_64H156_ADD(C64H156_TAG, XTAL_16MHz, ga_intf)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor c2031_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( c2031 );
+}
+
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// get_device_number -
+//-------------------------------------------------
+
+inline int c2031_device::get_device_number()
+{
+ int state = 1;
+
+ switch (m_address)
+ {
+ case 8: state = (m_atna && m_nrfd_out); break;
+ case 9: state = m_nrfd_out; break;
+ case 10: state = m_atna; break;
+ case 11: 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),
+ 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_image(*this, FLOPPY_0),
+ 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
+ floppy_install_unload_proc(m_image, c2031_device::on_disk_change);
+ floppy_install_load_proc(m_image, c2031_device::on_disk_change);
+
+ // 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 (!state)
+ {
+ device_reset();
+ }
+}
+
+
+//-------------------------------------------------
+// on_disk_change -
+//-------------------------------------------------
+
+void c2031_device::on_disk_change(device_image_interface &image)
+{
+ c2031_device *c2031 = static_cast<c2031_device *>(image.device().owner());
+
+ int wp = floppy_wpt_r(image);
+ c2031->m_ga->on_disk_changed(wp);
+}
diff --git a/src/mess/machine/c2031.h b/src/mess/machine/c2031.h
new file mode 100644
index 00000000000..1f2d9cb4ca2
--- /dev/null
+++ b/src/mess/machine/c2031.h
@@ -0,0 +1,93 @@
+/**********************************************************************
+
+ Commodore 2031 Single Disk Drive emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __C2031__
+#define __C2031__
+
+
+#include "emu.h"
+#include "cpu/m6502/m6502.h"
+#include "imagedev/flopdrv.h"
+#include "formats/d64_dsk.h"
+#include "formats/g64_dsk.h"
+#include "machine/64h156.h"
+#include "machine/6522via.h"
+#include "machine/ieee488.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);
+
+ // not really public
+ static void on_disk_change(device_image_interface &image);
+
+ 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_READ_LINE_MEMBER( via0_ca1_r );
+ DECLARE_READ_LINE_MEMBER( via0_ca2_r );
+ 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 );
+
+ // 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_config_complete() { m_shortname = "c2031"; }
+ 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<cpu_device> m_maincpu;
+ required_device<via6522_device> m_via0;
+ required_device<via6522_device> m_via1;
+ required_device<c64h156_device> m_ga;
+ required_device<legacy_floppy_image_device> m_image;
+
+ // IEEE-488 bus
+ int m_nrfd_out; // not ready for data
+ int m_ndac_out; // not data accepted
+ int m_atna; // attention acknowledge
+
+ // 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/mess/machine/c2040.c b/src/mess/machine/c2040.c
new file mode 100644
index 00000000000..67951e58366
--- /dev/null
+++ b/src/mess/machine/c2040.c
@@ -0,0 +1,1781 @@
+/**********************************************************************
+
+ Commodore 2040/3040/4040/8050/8250/SFD-1001 Disk Drive emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ TODO:
+
+ - 8050/8250 only work when debugger is active!?
+
+ - 2040 DOS 1 FDC rom (jumps to 104d while getting block header)
+
+ FE70: jsr $104D
+ 104D: m6502_brk#$00
+
+ - 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 "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"
+
+
+enum
+{
+ LED_POWER = 0,
+ LED_ACT0,
+ LED_ACT1,
+ LED_ERR
+};
+
+
+#define SYNC \
+ (!(((m_sr & G64_SYNC_MARK) == G64_SYNC_MARK) & m_rw))
+
+#define ERROR \
+ (!(m_ready | BIT(m_e, 3)))
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C2040 = &device_creator<c2040_device>;
+const device_type C3040 = &device_creator<c3040_device>;
+const device_type C4040 = &device_creator<c4040_device>;
+const device_type C8050 = &device_creator<c8050_device>;
+const device_type C8250 = &device_creator<c8250_device>;
+const device_type C8250LP = &device_creator<c8250lp_device>;
+const device_type SFD1001 = &device_creator<sfd1001_device>;
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void base_c2040_device::device_config_complete()
+{
+ switch (m_variant)
+ {
+ default:
+ case TYPE_2040:
+ m_shortname = "c2040";
+ break;
+
+ case TYPE_3040:
+ m_shortname = "c3040";
+ break;
+
+ case TYPE_4040:
+ m_shortname = "c4040";
+ break;
+
+ case TYPE_8050:
+ m_shortname = "c8050";
+ break;
+
+ case TYPE_8250:
+ m_shortname = "c8250";
+ break;
+
+ case TYPE_8250LP:
+ m_shortname = "c8250lp";
+ break;
+
+ case TYPE_SFD1001:
+ m_shortname = "sfd1001";
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// ROM( c2040 )
+//-------------------------------------------------
+
+ROM_START( c2040 ) // schematic 320806
+ ROM_REGION( 0x3000, M6502_TAG, 0 )
+ ROM_DEFAULT_BIOS("dos12")
+ ROM_SYSTEM_BIOS( 0, "dos10", "DOS 1.0" )
+ ROMX_LOAD( "901468-xx.ul1", 0x1000, 0x1000, NO_DUMP, ROM_BIOS(1) )
+ ROMX_LOAD( "901468-xx.uh1", 0x2000, 0x1000, NO_DUMP, ROM_BIOS(1) )
+ ROM_SYSTEM_BIOS( 1, "dos12", "DOS 1.2" )
+ ROMX_LOAD( "901468-06.ul1", 0x1000, 0x1000, CRC(25b5eed5) SHA1(4d9658f2e6ff3276e5c6e224611a66ce44b16fc7), ROM_BIOS(2) )
+ ROMX_LOAD( "901468-07.uh1", 0x2000, 0x1000, CRC(9b09ae83) SHA1(6a51c7954938439ca8342fc295bda050c06e1791), ROM_BIOS(2) )
+
+ ROM_REGION( 0x400, M6504_TAG, 0 )
+ ROMX_LOAD( "901466-01.uk3", 0x000, 0x400, NO_DUMP, ROM_BIOS(1) )
+ ROMX_LOAD( "901466-02.uk3", 0x000, 0x400, NO_DUMP, ROM_BIOS(2) ) // 6530-028 BAD_DUMP CRC(e1c86c43) SHA1(d8209c66fde3f2937688ba934ba968678a9d2ebb) ) // parsed in from disassembly
+
+ ROM_REGION( 0x800, "gcr", 0)
+ ROM_LOAD( "901467.uk6", 0x000, 0x800, CRC(a23337eb) SHA1(97df576397608455616331f8e837cb3404363fa2) )
+ROM_END
+
+
+//-------------------------------------------------
+// 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( 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, M6504_TAG, 0 )
+ ROM_LOAD_OPTIONAL( "901483-02.uk3", 0x000, 0x400, NO_DUMP ) // 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, NO_DUMP ) // 6530-039 RIOT DOS 2.5 Tandon
+ ROM_LOAD_OPTIONAL( "901884-01.uk3", 0x000, 0x400, NO_DUMP ) // 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_REGION( 0x800, "gcr", 0)
+ ROM_LOAD( "901467.uk6", 0x000, 0x800, CRC(a23337eb) SHA1(97df576397608455616331f8e837cb3404363fa2) )
+ROM_END
+
+
+//-------------------------------------------------
+// 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_REGION( 0x800, "gcr", 0)
+ ROM_LOAD( "251167-01.uc1", 0x000, 0x800, BAD_DUMP CRC(a23337eb) SHA1(97df576397608455616331f8e837cb3404363fa2) )
+ROM_END
+
+
+//-------------------------------------------------
+// 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( 0x800, M6504_TAG, 0 )
+ ROM_LOAD( "901885-04.u1", 0x000, 0x400, CRC(bab998c9) SHA1(0dc9a3b60f1b866c63eebd882403532fc59fe57f) )
+ 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 *base_c2040_device::device_rom_region() const
+{
+ switch (m_variant)
+ {
+ default:
+ case TYPE_2040:
+ case TYPE_3040:
+ return ROM_NAME( c2040 );
+
+ case TYPE_4040:
+ return ROM_NAME( c4040 );
+
+ case TYPE_8050:
+ case TYPE_8250:
+ return ROM_NAME( c8050 );
+
+ case TYPE_8250LP:
+ return ROM_NAME( c8250lp );
+
+ case TYPE_SFD1001:
+ return ROM_NAME( sfd1001 );
+ }
+}
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( c2040_main_mem )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( c2040_main_mem, AS_PROGRAM, 8, base_c2040_device )
+ ADDRESS_MAP_GLOBAL_MASK(0x7fff)
+ AM_RANGE(0x0000, 0x007f) AM_MIRROR(0x0100) AM_RAM // 6532 #1
+ AM_RANGE(0x0080, 0x00ff) AM_MIRROR(0x0100) AM_RAM // 6532 #2
+ AM_RANGE(0x0200, 0x021f) AM_MIRROR(0x0d60) AM_DEVREADWRITE_LEGACY(M6532_0_TAG, riot6532_r, riot6532_w)
+ AM_RANGE(0x0280, 0x029f) AM_MIRROR(0x0d60) AM_DEVREADWRITE_LEGACY(M6532_1_TAG, riot6532_r, riot6532_w)
+ 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, base_c2040_device )
+ ADDRESS_MAP_GLOBAL_MASK(0x1fff)
+ AM_RANGE(0x0000, 0x003f) AM_MIRROR(0x0300) AM_RAM // 6530
+ AM_RANGE(0x0040, 0x004f) AM_MIRROR(0x0330) AM_DEVREADWRITE(M6522_TAG, via6522_device, read, write)
+ AM_RANGE(0x0080, 0x008f) AM_MIRROR(0x0330) AM_DEVREADWRITE_LEGACY(M6530_TAG, mos6530_r, mos6530_w)
+ 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
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( c8050_main_mem )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( c8050_main_mem, AS_PROGRAM, 8, base_c2040_device )
+ AM_RANGE(0x0000, 0x007f) AM_MIRROR(0x0100) AM_RAM // 6532 #1
+ AM_RANGE(0x0080, 0x00ff) AM_MIRROR(0x0100) AM_RAM // 6532 #2
+ AM_RANGE(0x0200, 0x021f) AM_MIRROR(0x0d60) AM_DEVREADWRITE_LEGACY(M6532_0_TAG, riot6532_r, riot6532_w)
+ AM_RANGE(0x0280, 0x029f) AM_MIRROR(0x0d60) AM_DEVREADWRITE_LEGACY(M6532_1_TAG, riot6532_r, riot6532_w)
+ 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, base_c2040_device )
+ ADDRESS_MAP_GLOBAL_MASK(0x1fff)
+ AM_RANGE(0x0000, 0x003f) AM_MIRROR(0x0300) AM_RAM // 6530
+ AM_RANGE(0x0040, 0x004f) AM_MIRROR(0x0330) AM_DEVREADWRITE(M6522_TAG, via6522_device, read, write)
+ AM_RANGE(0x0080, 0x008f) AM_MIRROR(0x0330) AM_DEVREADWRITE_LEGACY(M6530_TAG, mos6530_r, mos6530_w)
+ 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
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( c8250lp_fdc_mem )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( c8250lp_fdc_mem, AS_PROGRAM, 8, base_c2040_device )
+ ADDRESS_MAP_GLOBAL_MASK(0x1fff)
+ AM_RANGE(0x0000, 0x003f) AM_MIRROR(0x0300) AM_RAM // 6530
+ AM_RANGE(0x0040, 0x004f) AM_MIRROR(0x0330) AM_DEVREADWRITE(M6522_TAG, via6522_device, read, write)
+ AM_RANGE(0x0080, 0x008f) AM_MIRROR(0x0330) AM_DEVREADWRITE_LEGACY(M6530_TAG, mos6530_r, mos6530_w)
+ 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, base_c2040_device )
+ ADDRESS_MAP_GLOBAL_MASK(0x1fff)
+ AM_RANGE(0x0000, 0x003f) AM_MIRROR(0x0300) AM_RAM // 6530
+ AM_RANGE(0x0040, 0x004f) AM_MIRROR(0x0330) AM_DEVREADWRITE(M6522_TAG, via6522_device, read, write)
+ AM_RANGE(0x0080, 0x008f) AM_MIRROR(0x0330) AM_DEVREADWRITE_LEGACY(M6530_TAG, mos6530_r, mos6530_w)
+ 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_interface riot0_intf uc1
+//-------------------------------------------------
+
+READ8_MEMBER( base_c2040_device::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( base_c2040_device::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);
+}
+
+
+static const riot6532_interface riot0_intf =
+{
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c2040_device, dio_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c2040_device, dio_w),
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// riot6532_interface riot1_intf ue1
+//-------------------------------------------------
+
+READ8_MEMBER( base_c2040_device::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( base_c2040_device::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( base_c2040_device::riot1_pb_r )
+{
+ /*
+
+ bit description
+
+ PB0 DEVICE NUMBER SELECTION
+ PB1 DEVICE NUMBER SELECTION
+ PB2 DEVICE NUMBER SELECTION
+ PB3 ACT LED 1
+ PB4 ACT LED 0
+ PB5 ERR LED
+ PB6 DACI
+ PB7 RFDI
+
+ */
+
+ UINT8 data = 0;
+
+ // device number selection
+ data |= m_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( base_c2040_device::riot1_pb_w )
+{
+ /*
+
+ bit description
+
+ PB0 DEVICE NUMBER SELECTION
+ PB1 DEVICE NUMBER SELECTION
+ PB2 DEVICE NUMBER SELECTION
+ PB3 ACT LED 1
+ PB4 ACT LED 0
+ PB5 ERR LED
+ PB6 DACI
+ PB7 RFDI
+
+ */
+
+ // 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 const riot6532_interface riot1_intf =
+{
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c2040_device, riot1_pa_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c2040_device, riot1_pb_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c2040_device, riot1_pa_w),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c2040_device, riot1_pb_w),
+ DEVCB_CPU_INPUT_LINE(M6502_TAG, INPUT_LINE_IRQ0)
+};
+
+
+//-------------------------------------------------
+// via6522_interface via_intf um3
+//-------------------------------------------------
+
+READ8_MEMBER( base_c2040_device::via_pa_r )
+{
+ /*
+
+ bit description
+
+ PA0 E0
+ PA1 E1
+ PA2 I2
+ PA3 E2
+ PA4 E4
+ PA5 E5
+ PA6 I7
+ PA7 E6
+
+ */
+
+ UINT16 i = m_i;
+ UINT8 e = m_e;
+ UINT8 data = (BIT(e, 6) << 7) | (BIT(i, 7) << 6) | (e & 0x33) | (BIT(e, 2) << 3) | (i & 0x04);
+
+ return data;
+}
+
+
+WRITE8_MEMBER( base_c2040_device::via_pb_w )
+{
+ /*
+
+ bit description
+
+ PB0 S1A
+ PB1 S1B
+ PB2 S0A
+ PB3 S0B
+ PB4 MTR1
+ PB5 MTR0
+ PB6
+ PB7
+
+ */
+
+ // spindle motor 1
+ int mtr1 = BIT(data, 4);
+ spindle_motor(1, mtr1);
+
+ // spindle motor 0
+ int mtr0 = BIT(data, 5);
+ spindle_motor(0, mtr0);
+
+ // stepper motor 1
+ int s1 = data & 0x03;
+ micropolis_step_motor(1, s1);
+
+ // stepper motor 0
+ int s0 = (data >> 2) & 0x03;
+ micropolis_step_motor(0, s0);
+
+ m_bit_timer->enable(!mtr1 || !mtr0);
+}
+
+
+READ_LINE_MEMBER( base_c2040_device::ready_r )
+{
+ return m_ready;
+}
+
+
+READ_LINE_MEMBER( base_c2040_device::err_r )
+{
+ return ERROR;
+}
+
+
+WRITE_LINE_MEMBER( base_c2040_device::mode_sel_w )
+{
+ // mode select
+ m_mode = state;
+
+ update_gcr_data();
+ m_via->write_cb1(ERROR);
+}
+
+WRITE_LINE_MEMBER( base_c2040_device::rw_sel_w )
+{
+ // read/write select
+ m_rw = state;
+
+ update_gcr_data();
+ m_via->write_cb1(ERROR);
+}
+
+
+static const via6522_interface via_intf =
+{
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c2040_device, via_pa_r),
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_c2040_device, ready_r),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_c2040_device, err_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c2040_device, via_pb_w),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_c2040_device, mode_sel_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_c2040_device, rw_sel_w),
+
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// via6522_interface c8050_via_intf um3
+//-------------------------------------------------
+
+READ8_MEMBER( base_c2040_device::c8050_via_pb_r )
+{
+ /*
+
+ bit description
+
+ PB0 S1A
+ PB1 S1B
+ PB2 S0A
+ PB3 S0B
+ PB4 MTR1
+ PB5 MTR0
+ PB6 PULL SYNC
+ PB7 SYNC
+
+ */
+
+ UINT8 data = 0;
+
+ // SYNC detected
+ data |= SYNC << 7;
+
+ return data;
+}
+
+
+WRITE8_MEMBER( base_c2040_device::c8050_via_pb_w )
+{
+ /*
+
+ bit description
+
+ PB0 S1A
+ PB1 S1B
+ PB2 S0A
+ PB3 S0B
+ PB4 MTR1
+ PB5 MTR0
+ PB6 PULL SYNC
+ PB7 SYNC
+
+ */
+
+ // spindle motor 1
+ int mtr1 = BIT(data, 4);
+ spindle_motor(1, mtr1);
+
+ // spindle motor 0
+ int mtr0 = BIT(data, 5);
+ spindle_motor(0, mtr0);
+
+ // stepper motor 1
+ int s1 = data & 0x03;
+ mpi_step_motor(1, s1);
+
+ // stepper motor 0
+ int s0 = (data >> 2) & 0x03;
+ mpi_step_motor(0, s0);
+
+ m_bit_timer->enable(!mtr1 || !mtr0);
+}
+
+
+static const via6522_interface c8050_via_intf =
+{
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c2040_device, via_pa_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c2040_device, c8050_via_pb_r),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_c2040_device, ready_r),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_c2040_device, err_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c2040_device, c8050_via_pb_w),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_c2040_device, mode_sel_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_c2040_device, rw_sel_w),
+
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// mos6530_interface miot_intf uk3
+//-------------------------------------------------
+
+READ8_MEMBER( base_c2040_device::pi_r )
+{
+ /*
+
+ bit description
+
+ PA0 PI0
+ PA1 PI1
+ PA2 PI2
+ PA3 PI3
+ PA4 PI4
+ PA5 PI5
+ PA6 PI6
+ PA7 PI7
+
+ */
+
+ return m_pi;
+}
+
+WRITE8_MEMBER( base_c2040_device::pi_w )
+{
+ /*
+
+ bit description
+
+ PA0 PI0
+ PA1 PI1
+ PA2 PI2
+ PA3 PI3
+ PA4 PI4
+ PA5 PI5
+ PA6 PI6
+ PA7 PI7
+
+ */
+
+ m_pi = data;
+}
+
+READ8_MEMBER( base_c2040_device::miot_pb_r )
+{
+ /*
+
+ bit description
+
+ PB0 DRV SEL
+ PB1 DS0
+ PB2 DS1
+ PB3 WPS
+ PB4
+ PB5
+ PB6 SYNC
+ PB7 M6504 IRQ
+
+ */
+
+ UINT8 data = 0;
+
+ // write protect sense
+ data |= floppy_wpt_r(m_unit[m_drive].m_image) << 3;
+
+ // SYNC detected
+ data |= SYNC << 6;
+
+ return data;
+}
+
+WRITE8_MEMBER( base_c2040_device::miot_pb_w )
+{
+ /*
+
+ bit description
+
+ PB0 DRV SEL
+ PB1 DS0
+ PB2 DS1
+ PB3 WPS
+ PB4
+ PB5
+ PB6 SYNC
+ PB7 M6504 IRQ
+
+ */
+
+ // drive select
+ m_drive = BIT(data, 0);
+
+ // density select
+ int ds = (data >> 1) & 0x03;
+
+ if (m_ds != ds)
+ {
+ m_bit_timer->adjust(attotime::zero, 0, attotime::from_hz(C2040_BITRATE[ds]/4));
+ m_ds = ds;
+ }
+
+ // interrupt
+ if (m_miot_irq != BIT(data, 7))
+ {
+ m_fdccpu->set_input_line(M6502_IRQ_LINE, BIT(data, 7) ? CLEAR_LINE : ASSERT_LINE);
+ m_miot_irq = BIT(data, 7);
+ }
+}
+
+static MOS6530_INTERFACE( miot_intf )
+{
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c2040_device, pi_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c2040_device, pi_w),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c2040_device, miot_pb_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c2040_device, miot_pb_w)
+};
+
+
+//-------------------------------------------------
+// mos6530_interface c8050_miot_intf uk3
+//-------------------------------------------------
+
+READ8_MEMBER( base_c2040_device::c8050_miot_pb_r )
+{
+ /*
+
+ bit description
+
+ PB0 DRV SEL
+ PB1 DS0
+ PB2 DS1
+ PB3 WPS
+ PB4 DRIVE TYPE (0=2A, 1=2C)
+ PB5
+ PB6 (0=DS, 1=SS)
+ PB7 M6504 IRQ
+
+ */
+
+ UINT8 data = 0;
+
+ // write protect sense
+ data |= floppy_wpt_r(m_unit[m_drive].m_image) << 3;
+
+ // drive type
+ data |= 0x10;
+
+ // single/dual sided
+ if (m_variant == base_c2040_device::TYPE_8050)
+ {
+ data |= 0x40;
+ }
+
+ return data;
+}
+
+WRITE8_MEMBER( base_c2040_device::c8050_miot_pb_w )
+{
+ /*
+
+ bit description
+
+ PB0 DRV SEL
+ PB1 DS0
+ PB2 DS1
+ PB3 WPS
+ PB4 ODD HD (0=78-154, 1=1-77)
+ PB5
+ PB6 (0=DS, 1=SS)
+ PB7 M6504 IRQ
+
+ */
+
+ // drive select
+ if ((m_variant == base_c2040_device::TYPE_8050) ||
+ (m_variant == base_c2040_device::TYPE_8250))
+ {
+ m_drive = BIT(data, 0);
+ }
+
+ // density select
+ int ds = (data >> 1) & 0x03;
+
+ if (m_ds != ds)
+ {
+ m_bit_timer->adjust(attotime::zero, 0, attotime::from_hz(C8050_BITRATE[ds]));
+ m_ds = ds;
+ }
+
+ // side select
+ if ((m_variant == base_c2040_device::TYPE_8250) ||
+ (m_variant == base_c2040_device::TYPE_SFD1001))
+ {
+ m_side = !BIT(data, 4);
+ }
+
+ // interrupt
+ if (m_miot_irq != BIT(data, 7))
+ {
+ m_fdccpu->set_input_line(M6502_IRQ_LINE, BIT(data, 7) ? CLEAR_LINE : ASSERT_LINE);
+ m_miot_irq = BIT(data, 7);
+ }
+}
+
+static MOS6530_INTERFACE( c8050_miot_intf )
+{
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c2040_device, pi_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c2040_device, pi_w),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c2040_device, c8050_miot_pb_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_c2040_device, c8050_miot_pb_w)
+};
+
+
+//-------------------------------------------------
+// LEGACY_FLOPPY_OPTIONS( c2040 )
+//-------------------------------------------------
+
+static LEGACY_FLOPPY_OPTIONS_START( c2040 )
+ LEGACY_FLOPPY_OPTION( c2040, "d67", "Commodore 2040/3040 Disk Image", d67_dsk_identify, d64_dsk_construct, NULL, NULL )
+ LEGACY_FLOPPY_OPTION( c2040, "g64", "Commodore 2040/3040 GCR Disk Image", g64_dsk_identify, g64_dsk_construct, NULL, NULL )
+LEGACY_FLOPPY_OPTIONS_END
+
+
+//-------------------------------------------------
+// LEGACY_FLOPPY_OPTIONS( c4040 )
+//-------------------------------------------------
+
+static LEGACY_FLOPPY_OPTIONS_START( c4040 )
+ LEGACY_FLOPPY_OPTION( c4040, "d64", "Commodore 4040 Disk Image", d64_dsk_identify, d64_dsk_construct, NULL, NULL )
+ LEGACY_FLOPPY_OPTION( c4040, "g64", "Commodore 4040 GCR Disk Image", g64_dsk_identify, g64_dsk_construct, NULL, NULL )
+LEGACY_FLOPPY_OPTIONS_END
+
+
+//-------------------------------------------------
+// LEGACY_FLOPPY_OPTIONS( c8050 )
+//-------------------------------------------------
+
+static LEGACY_FLOPPY_OPTIONS_START( c8050 )
+ LEGACY_FLOPPY_OPTION( c8050, "d80", "Commodore 8050 Disk Image", d80_dsk_identify, d64_dsk_construct, NULL, NULL )
+LEGACY_FLOPPY_OPTIONS_END
+
+
+//-------------------------------------------------
+// LEGACY_FLOPPY_OPTIONS( c8250 )
+//-------------------------------------------------
+
+static LEGACY_FLOPPY_OPTIONS_START( c8250 )
+ LEGACY_FLOPPY_OPTION( c8250, "d80", "Commodore 8050 Disk Image", d80_dsk_identify, d64_dsk_construct, NULL, NULL )
+ LEGACY_FLOPPY_OPTION( c8250, "d82", "Commodore 8250/SFD1001 Disk Image", d82_dsk_identify, d64_dsk_construct, NULL, NULL )
+LEGACY_FLOPPY_OPTIONS_END
+
+
+//-------------------------------------------------
+// floppy_interface c2040_floppy_interface
+//-------------------------------------------------
+
+static const floppy_interface c2040_floppy_interface =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ FLOPPY_STANDARD_5_25_SSDD,
+ LEGACY_FLOPPY_OPTIONS_NAME(c2040),
+ "floppy_5_25",
+ NULL
+};
+
+
+//-------------------------------------------------
+// floppy_interface c4040_floppy_interface
+//-------------------------------------------------
+
+static const floppy_interface c4040_floppy_interface =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ FLOPPY_STANDARD_5_25_SSDD,
+ LEGACY_FLOPPY_OPTIONS_NAME(c4040),
+ "floppy_5_25",
+ NULL
+};
+
+
+//-------------------------------------------------
+// floppy_interface c8050_floppy_interface
+//-------------------------------------------------
+
+static const floppy_interface c8050_floppy_interface =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ FLOPPY_STANDARD_5_25_SSDD,
+ LEGACY_FLOPPY_OPTIONS_NAME(c8050),
+ "floppy_5_25",
+ NULL
+};
+
+
+//-------------------------------------------------
+// floppy_interface c8250_floppy_interface
+//-------------------------------------------------
+
+static const floppy_interface c8250_floppy_interface =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ FLOPPY_STANDARD_5_25_DSQD,
+ LEGACY_FLOPPY_OPTIONS_NAME(c8250),
+ "floppy_5_25",
+ NULL
+};
+
+
+//-------------------------------------------------
+// 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_RIOT6532_ADD(M6532_0_TAG, XTAL_16MHz/16, riot0_intf)
+ MCFG_RIOT6532_ADD(M6532_1_TAG, XTAL_16MHz/16, riot1_intf)
+
+ // controller
+ MCFG_CPU_ADD(M6504_TAG, M6504, XTAL_16MHz/16)
+ MCFG_CPU_PROGRAM_MAP(c2040_fdc_mem)
+
+ MCFG_VIA6522_ADD(M6522_TAG, XTAL_16MHz/16, via_intf)
+ MCFG_MOS6530_ADD(M6530_TAG, XTAL_16MHz/16, miot_intf)
+
+ MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(c2040_floppy_interface)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// 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_RIOT6532_ADD(M6532_0_TAG, XTAL_16MHz/16, riot0_intf)
+ MCFG_RIOT6532_ADD(M6532_1_TAG, XTAL_16MHz/16, riot1_intf)
+
+ // controller
+ MCFG_CPU_ADD(M6504_TAG, M6504, XTAL_16MHz/16)
+ MCFG_CPU_PROGRAM_MAP(c2040_fdc_mem)
+
+ MCFG_VIA6522_ADD(M6522_TAG, XTAL_16MHz/16, via_intf)
+ MCFG_MOS6530_ADD(M6530_TAG, XTAL_16MHz/16, miot_intf)
+
+ MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(c4040_floppy_interface)
+MACHINE_CONFIG_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_RIOT6532_ADD(M6532_0_TAG, XTAL_12MHz/12, riot0_intf)
+ MCFG_RIOT6532_ADD(M6532_1_TAG, XTAL_12MHz/12, riot1_intf)
+
+ // controller
+ MCFG_CPU_ADD(M6504_TAG, M6504, XTAL_12MHz/12)
+ MCFG_CPU_PROGRAM_MAP(c8050_fdc_mem)
+
+ MCFG_VIA6522_ADD(M6522_TAG, XTAL_12MHz/12, c8050_via_intf)
+ MCFG_MOS6530_ADD(M6530_TAG, XTAL_12MHz/12, c8050_miot_intf)
+
+ MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(c8050_floppy_interface)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// 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_RIOT6532_ADD(M6532_0_TAG, XTAL_12MHz/12, riot0_intf)
+ MCFG_RIOT6532_ADD(M6532_1_TAG, XTAL_12MHz/12, riot1_intf)
+
+ // controller
+ MCFG_CPU_ADD(M6504_TAG, M6504, XTAL_12MHz/12)
+ MCFG_CPU_PROGRAM_MAP(c8050_fdc_mem)
+
+ MCFG_VIA6522_ADD(M6522_TAG, XTAL_12MHz/12, c8050_via_intf)
+ MCFG_MOS6530_ADD(M6530_TAG, XTAL_12MHz/12, c8050_miot_intf)
+
+ MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(c8250_floppy_interface)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// 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_RIOT6532_ADD(M6532_0_TAG, XTAL_12MHz/12, riot0_intf)
+ MCFG_RIOT6532_ADD(M6532_1_TAG, XTAL_12MHz/12, riot1_intf)
+
+ // controller
+ MCFG_CPU_ADD(M6504_TAG, M6504, XTAL_12MHz/12)
+ MCFG_CPU_PROGRAM_MAP(c8250lp_fdc_mem)
+
+ MCFG_VIA6522_ADD(M6522_TAG, XTAL_12MHz/12, c8050_via_intf)
+ MCFG_MOS6530_ADD(M6530_TAG, XTAL_12MHz/12, c8050_miot_intf)
+
+ MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(c8250_floppy_interface)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// 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_RIOT6532_ADD(M6532_0_TAG, XTAL_12MHz/12, riot0_intf)
+ MCFG_RIOT6532_ADD(M6532_1_TAG, XTAL_12MHz/12, riot1_intf)
+
+ // controller
+ MCFG_CPU_ADD(M6504_TAG, M6504, XTAL_12MHz/12)
+ MCFG_CPU_PROGRAM_MAP(sfd1001_fdc_mem)
+
+ MCFG_VIA6522_ADD(M6522_TAG, XTAL_12MHz/12, c8050_via_intf)
+ MCFG_MOS6530_ADD(M6530_TAG, XTAL_12MHz/12, c8050_miot_intf)
+
+ MCFG_LEGACY_FLOPPY_DRIVE_ADD(FLOPPY_0, c8250_floppy_interface)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor base_c2040_device::device_mconfig_additions() const
+{
+ switch (m_variant)
+ {
+ default:
+ case TYPE_2040:
+ case TYPE_3040:
+ return MACHINE_CONFIG_NAME( c2040 );
+
+ case TYPE_4040:
+ return MACHINE_CONFIG_NAME( c4040 );
+
+ case TYPE_8050:
+ return MACHINE_CONFIG_NAME( c8050 );
+
+ case TYPE_8250:
+ return MACHINE_CONFIG_NAME( c8250 );
+
+ case TYPE_8250LP:
+ return MACHINE_CONFIG_NAME( c8250lp );
+
+ case TYPE_SFD1001:
+ return MACHINE_CONFIG_NAME( sfd1001 );
+ }
+}
+
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// update_ieee_signals -
+//-------------------------------------------------
+
+inline void base_c2040_device::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);
+}
+
+
+//-------------------------------------------------
+// update_gcr_data -
+//-------------------------------------------------
+
+inline void base_c2040_device::update_gcr_data()
+{
+ if (m_rw)
+ {
+ /*
+
+ bit description
+
+ I0 SR0
+ I1 SR1
+ I2 SR2
+ I3 SR3
+ I4 SR4
+ I5 SR5
+ I6 SR6
+ I7 SR7
+ I8 SR8
+ I9 SR9
+ I10 R/_W SEL
+
+ */
+
+ m_i = (m_rw << 10) | (m_sr & 0x3ff);
+ }
+ else
+ {
+ /*
+
+ bit description
+
+ I0 PI0
+ I1 PI1
+ I2 PI2
+ I3 PI3
+ I4 MODE SEL
+ I5 PI4
+ I6 PI5
+ I7 PI6
+ I8 PI7
+ I9 0
+ I10 R/_W SEL
+
+ */
+
+ m_i = (m_rw << 10) | ((m_pi & 0xf0) << 1) | (m_mode << 4) | (m_pi & 0x0f);
+ }
+
+ m_e = m_gcr[m_i];
+}
+
+
+//-------------------------------------------------
+// update_ieee_signals -
+//-------------------------------------------------
+
+inline void base_c2040_device::read_current_track(int unit)
+{
+ m_unit[unit].m_track_len = G64_BUFFER_SIZE;
+ m_unit[unit].m_buffer_pos = 0;
+ m_unit[unit].m_bit_pos = 7;
+ m_bit_count = 0;
+
+ // read track data
+ floppy_drive_read_track_data_info_buffer(m_unit[unit].m_image, m_side, m_unit[unit].m_track_buffer, &m_unit[unit].m_track_len);
+
+ // extract track length
+ m_unit[unit].m_track_len = floppy_drive_get_current_track_size(m_unit[unit].m_image, m_side);
+}
+
+
+//-------------------------------------------------
+// spindle_motor -
+//-------------------------------------------------
+
+inline void base_c2040_device::spindle_motor(int unit, int mtr)
+{
+ if (m_unit[unit].m_mtr != mtr)
+ {
+ if (!mtr)
+ {
+ // read track data
+ read_current_track(unit);
+ }
+
+ floppy_mon_w(m_unit[unit].m_image, mtr);
+
+ m_unit[unit].m_mtr = mtr;
+ }
+}
+
+
+//-------------------------------------------------
+// micropolis_step_motor -
+//-------------------------------------------------
+
+inline void base_c2040_device::micropolis_step_motor(int unit, int stp)
+{
+ if (!m_unit[unit].m_mtr && (m_unit[unit].m_stp != stp))
+ {
+ int tracks = 0;
+
+ switch (m_unit[unit].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 != 0)
+ {
+ // step read/write head
+ floppy_drive_seek(m_unit[unit].m_image, tracks);
+
+ // read new track data
+ read_current_track(unit);
+ }
+
+ m_unit[unit].m_stp = stp;
+ }
+}
+
+
+//-------------------------------------------------
+// mpi_step_motor -
+//-------------------------------------------------
+
+inline void base_c2040_device::mpi_step_motor(int unit, int stp)
+{
+ if (!m_unit[unit].m_mtr && (m_unit[unit].m_stp != stp))
+ {
+ int tracks = 0;
+
+ switch (m_unit[unit].m_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 != 0)
+ {
+ // step read/write head
+ floppy_drive_seek(m_unit[unit].m_image, tracks);
+
+ // read new track data
+ read_current_track(unit);
+ }
+
+ m_unit[unit].m_stp = stp;
+ }
+}
+
+
+//-------------------------------------------------
+// initialize -
+//-------------------------------------------------
+
+inline void base_c2040_device::initialize(int drives)
+{
+ // find GCR ROM
+ m_gcr = memregion("gcr")->base();
+
+ // install image callbacks
+ m_unit[0].m_image = m_image0;
+
+ floppy_install_unload_proc(m_image0, base_c2040_device::on_disk0_change);
+ floppy_install_load_proc(m_image0, base_c2040_device::on_disk0_change);
+
+ if (drives == 2)
+ {
+ m_unit[1].m_image = m_image1;
+
+ floppy_install_unload_proc(m_image1, base_c2040_device::on_disk1_change);
+ floppy_install_load_proc(m_image1, base_c2040_device::on_disk1_change);
+ }
+
+ // register for state saving
+ save_item(NAME(m_drive));
+ save_item(NAME(m_side));
+ save_item(NAME(m_rfdo));
+ save_item(NAME(m_daco));
+ save_item(NAME(m_atna));
+ save_item(NAME(m_ds));
+ save_item(NAME(m_bit_count));
+ save_item(NAME(m_sr));
+ save_item(NAME(m_pi));
+ save_item(NAME(m_i));
+ save_item(NAME(m_e));
+ save_item(NAME(m_ready));
+ save_item(NAME(m_mode));
+ save_item(NAME(m_rw));
+ save_item(NAME(m_miot_irq));
+ save_item(NAME(m_unit[0].m_stp));
+ save_item(NAME(m_unit[0].m_mtr));
+ save_item(NAME(m_unit[0].m_track_len));
+ save_item(NAME(m_unit[0].m_buffer_pos));
+ save_item(NAME(m_unit[0].m_bit_pos));
+
+ if (drives == 2)
+ {
+ save_item(NAME(m_unit[1].m_stp));
+ save_item(NAME(m_unit[1].m_mtr));
+ save_item(NAME(m_unit[1].m_track_len));
+ save_item(NAME(m_unit[1].m_buffer_pos));
+ save_item(NAME(m_unit[1].m_bit_pos));
+ }
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// base_c2040_device - constructor
+//-------------------------------------------------
+
+base_c2040_device::base_c2040_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant)
+ : device_t(mconfig, type, name, tag, owner, clock),
+ 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_image0(*this, FLOPPY_0),
+ m_image1(*this, FLOPPY_1),
+ m_drive(0),
+ m_side(0),
+ m_rfdo(1),
+ m_daco(1),
+ m_atna(1),
+ m_ds(-1),
+ m_bit_count(0),
+ m_ready(0),
+ m_mode(0),
+ m_rw(0),
+ m_miot_irq(CLEAR_LINE),
+ m_variant(variant)
+{
+ for (int i = 0; i < 2; i++)
+ {
+ m_unit[i].m_stp = 0;
+ m_unit[i].m_mtr = 1;
+ m_unit[i].m_track_len = 0;
+ m_unit[i].m_buffer_pos = 0;
+ m_unit[i].m_bit_pos = 0;
+ }
+}
+
+
+//-------------------------------------------------
+// base_c2040_device - constructor
+//-------------------------------------------------
+
+c2040_device::c2040_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : base_c2040_device(mconfig, C2040, "C2040", tag, owner, clock, TYPE_2040) { }
+
+
+//-------------------------------------------------
+// c3040_device - constructor
+//-------------------------------------------------
+
+c3040_device::c3040_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : base_c2040_device(mconfig, C3040, "C3040", tag, owner, clock, TYPE_3040) { }
+
+
+//-------------------------------------------------
+// c4040_device - constructor
+//-------------------------------------------------
+
+c4040_device::c4040_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : base_c2040_device(mconfig, C4040, "C4040", tag, owner, clock, TYPE_4040) { }
+
+
+//-------------------------------------------------
+// c8050_device - constructor
+//-------------------------------------------------
+
+c8050_device::c8050_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : base_c2040_device(mconfig, C8050, "C8050", tag, owner, clock, TYPE_8050) { }
+
+
+//-------------------------------------------------
+// c8250_device - constructor
+//-------------------------------------------------
+
+c8250_device::c8250_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : base_c2040_device(mconfig, C8250, "C8250", tag, owner, clock, TYPE_8250) { }
+
+
+//-------------------------------------------------
+// c8250lp_device - constructor
+//-------------------------------------------------
+
+c8250lp_device::c8250lp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : base_c2040_device(mconfig, C8250LP, "C8250LP", tag, owner, clock, TYPE_8250LP) { }
+
+
+//-------------------------------------------------
+// sfd1001_device - constructor
+//-------------------------------------------------
+
+sfd1001_device::sfd1001_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : base_c2040_device(mconfig, SFD1001, "SFD1001", tag, owner, clock, TYPE_SFD1001) { }
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void base_c2040_device::device_start()
+{
+ m_bit_timer = timer_alloc();
+
+ switch (m_variant)
+ {
+ default:
+ initialize(2);
+ break;
+
+ case base_c2040_device::TYPE_SFD1001:
+ initialize(1);
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void base_c2040_device::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();
+
+ // turn off spindle motors
+ m_unit[0].m_mtr = m_unit[1].m_mtr = 1;
+}
+
+
+//-------------------------------------------------
+// device_timer - handler timer events
+//-------------------------------------------------
+
+void base_c2040_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ int ready = 1;
+
+ // shift in data from the read head
+ m_sr <<= 1;
+ m_sr |= BIT(m_unit[m_drive].m_track_buffer[m_unit[m_drive].m_buffer_pos], m_unit[m_drive].m_bit_pos);
+
+ // update GCR data
+ update_gcr_data();
+
+ // update bit counters
+ m_unit[m_drive].m_bit_pos--;
+ m_bit_count++;
+
+ if (m_unit[m_drive].m_bit_pos < 0)
+ {
+ m_unit[m_drive].m_bit_pos = 7;
+ m_unit[m_drive].m_buffer_pos++;
+
+ if (m_unit[m_drive].m_buffer_pos >= m_unit[m_drive].m_track_len)
+ {
+ // loop to the start of the track
+ m_unit[m_drive].m_buffer_pos = 0;
+ }
+ }
+
+ if (!SYNC)
+ {
+ // SYNC detected
+ m_bit_count = 0;
+ }
+
+ if (m_bit_count == 10)
+ {
+ // byte ready
+ m_bit_count = 0;
+ ready = 0;
+ }
+
+ if (m_ready != ready)
+ {
+ // set byte ready flag
+ m_ready = ready;
+
+ m_via->write_ca1(ready);
+ m_via->write_cb1(ERROR);
+
+ if ((m_variant == base_c2040_device::TYPE_8050) ||
+ (m_variant == base_c2040_device::TYPE_8250) ||
+ (m_variant == base_c2040_device::TYPE_SFD1001))
+ {
+ m_fdccpu->set_input_line(M6502_SET_OVERFLOW, ready ? CLEAR_LINE : ASSERT_LINE);
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// ieee488_atn -
+//-------------------------------------------------
+
+void base_c2040_device::ieee488_atn(int state)
+{
+ update_ieee_signals();
+
+ // set RIOT PA7
+ riot6532_porta_in_set(m_riot1, !state << 7, 0x80);
+}
+
+
+//-------------------------------------------------
+// ieee488_ifc -
+//-------------------------------------------------
+
+void base_c2040_device::ieee488_ifc(int state)
+{
+ if (!state)
+ {
+ device_reset();
+ }
+}
+
+
+//-------------------------------------------------
+// on_disk0_change -
+//-------------------------------------------------
+
+void base_c2040_device::on_disk0_change(device_image_interface &image)
+{
+ base_c2040_device *c2040 = static_cast<base_c2040_device *>(image.device().owner());
+
+ c2040->read_current_track(0);
+}
+
+
+//-------------------------------------------------
+// on_disk_change -
+//-------------------------------------------------
+
+void base_c2040_device::on_disk1_change(device_image_interface &image)
+{
+ base_c2040_device *c2040 = static_cast<base_c2040_device *>(image.device().owner());
+
+ c2040->read_current_track(1);
+}
diff --git a/src/mess/machine/c2040.h b/src/mess/machine/c2040.h
new file mode 100644
index 00000000000..ed09107a62f
--- /dev/null
+++ b/src/mess/machine/c2040.h
@@ -0,0 +1,235 @@
+/**********************************************************************
+
+ Commodore 2040/3040/4040/8050/8250/SFD-1001 Disk Drive emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __C2040__
+#define __C2040__
+
+
+#include "emu.h"
+#include "cpu/m6502/m6502.h"
+#include "imagedev/flopdrv.h"
+#include "formats/d64_dsk.h"
+#include "formats/g64_dsk.h"
+#include "machine/6522via.h"
+#include "machine/6532riot.h"
+#include "machine/mos6530.h"
+#include "machine/ieee488.h"
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> base_c2040_device
+
+class base_c2040_device : public device_t,
+ public device_ieee488_interface
+{
+public:
+ enum
+ {
+ TYPE_2040,
+ TYPE_3040,
+ TYPE_4040,
+ TYPE_8050,
+ TYPE_8250,
+ TYPE_8250LP,
+ TYPE_SFD1001
+ };
+
+ // construction/destruction
+ base_c2040_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant);
+
+ // not really public
+ static void on_disk0_change(device_image_interface &image);
+ static void on_disk1_change(device_image_interface &image);
+
+ 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_pa_r );
+ DECLARE_WRITE8_MEMBER( via_pb_w );
+ DECLARE_READ_LINE_MEMBER( ready_r );
+ DECLARE_READ_LINE_MEMBER( err_r );
+ DECLARE_WRITE_LINE_MEMBER( mode_sel_w );
+ DECLARE_WRITE_LINE_MEMBER( rw_sel_w );
+ DECLARE_READ8_MEMBER( pi_r );
+ DECLARE_WRITE8_MEMBER( pi_w );
+ DECLARE_READ8_MEMBER( miot_pb_r );
+ DECLARE_WRITE8_MEMBER( miot_pb_w );
+ DECLARE_READ8_MEMBER( c8050_via_pb_r );
+ DECLARE_WRITE8_MEMBER( c8050_via_pb_w );
+ DECLARE_READ8_MEMBER( c8050_miot_pb_r );
+ DECLARE_WRITE8_MEMBER( c8050_miot_pb_w );
+
+ // 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_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);
+
+ // device_ieee488_interface overrides
+ virtual void ieee488_atn(int state);
+ virtual void ieee488_ifc(int state);
+
+ inline void update_ieee_signals();
+ inline void update_gcr_data();
+ inline void read_current_track(int unit);
+ inline void spindle_motor(int unit, int mtr);
+ inline void micropolis_step_motor(int unit, int stp);
+ inline void mpi_step_motor(int unit, int stp);
+ inline void initialize(int drives);
+
+ required_device<cpu_device> m_maincpu;
+ required_device<cpu_device> m_fdccpu;
+ required_device<riot6532_device> m_riot0;
+ required_device<riot6532_device> m_riot1;
+ required_device<device_t> m_miot;
+ required_device<via6522_device> m_via;
+ required_device<legacy_floppy_image_device> m_image0;
+ optional_device<legacy_floppy_image_device> m_image1;
+
+ struct {
+ // motors
+ int m_stp; // stepper motor phase
+ int m_mtr; // spindle motor on
+
+ // track
+ UINT8 m_track_buffer[G64_BUFFER_SIZE]; // track data buffer
+ int m_track_len; // track length
+ int m_buffer_pos; // byte position within track buffer
+ int m_bit_pos; // bit position within track buffer byte
+
+ // devices
+ device_t *m_image;
+ } m_unit[2];
+
+ int m_drive; // selected drive
+ int m_side; // selected side
+
+ // IEEE-488 bus
+ int m_rfdo; // not ready for data output
+ int m_daco; // not data accepted output
+ int m_atna; // attention acknowledge
+
+ // track
+ int m_ds; // density select
+ int m_bit_count; // GCR bit counter
+ UINT16 m_sr; // GCR data shift register
+ UINT8 m_pi; // parallel data input
+ UINT8* m_gcr; // GCR encoder/decoder ROM
+ UINT16 m_i; // GCR encoder/decoded ROM address
+ UINT8 m_e; // GCR encoder/decoded ROM data
+
+ // signals
+ int m_ready; // byte ready
+ int m_mode; // mode select
+ int m_rw; // read/write select
+ int m_miot_irq; // MIOT interrupt
+
+ // timers
+ emu_timer *m_bit_timer;
+
+ int m_variant;
+};
+
+
+// ======================> c2040_device
+
+class c2040_device : public base_c2040_device
+{
+public:
+ // construction/destruction
+ c2040_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+// ======================> c3040_device
+
+class c3040_device : public base_c2040_device
+{
+public:
+ // construction/destruction
+ c3040_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+// ======================> c4040_device
+
+class c4040_device : public base_c2040_device
+{
+public:
+ // construction/destruction
+ c4040_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+// ======================> c8050_device
+
+class c8050_device : public base_c2040_device
+{
+public:
+ // construction/destruction
+ c8050_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+// ======================> c8250_device
+
+class c8250_device : public base_c2040_device
+{
+public:
+ // construction/destruction
+ c8250_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+// ======================> c8250lp_device
+
+class c8250lp_device : public base_c2040_device
+{
+public:
+ // construction/destruction
+ c8250lp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+// ======================> sfd1001_device
+
+class sfd1001_device : public base_c2040_device
+{
+public:
+ // construction/destruction
+ sfd1001_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+// device type definition
+extern const device_type C2040;
+extern const device_type C3040;
+extern const device_type C4040;
+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/mess/machine/c64.c b/src/mess/machine/c64.c
new file mode 100644
index 00000000000..7774db8c4f6
--- /dev/null
+++ b/src/mess/machine/c64.c
@@ -0,0 +1,2064 @@
+/***************************************************************************
+ commodore c64 home computer
+
+ peter.trauner@jk.uni-linz.ac.at
+ documentation
+ www.funet.fi
+***************************************************************************/
+
+/*
+ 2008-09-06: Tape status for C64 & C128 [FP & RZ]
+ - tape loading works
+ - tap files are supported
+ - tape writing works
+*/
+
+#include "emu.h"
+
+#include "cpu/m6502/m6502.h"
+#include "cpu/z80/z80.h"
+#include "sound/sid6581.h"
+#include "machine/6526cia.h"
+#include "machine/cbmiec.h"
+#include "video/vic6567.h"
+
+#include "includes/cbm.h"
+#include "includes/c64_legacy.h"
+
+#include "imagedev/cassette.h"
+#include "imagedev/cartslot.h"
+
+#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 log_cart 0
+
+/* expansion port lines input */
+
+/* cpu port */
+
+
+
+static void c64_nmi( running_machine &machine )
+{
+ legacy_c64_state *state = machine.driver_data<legacy_c64_state>();
+ device_t *cia_1 = machine.device("cia_1");
+ int cia1irq = mos6526_irq_r(cia_1);
+
+ if (state->m_nmilevel != (machine.root_device().ioport("SPECIAL")->read() & 0x80) || cia1irq) /* KEY_RESTORE */
+ {
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_NMI, (machine.root_device().ioport("SPECIAL")->read() & 0x80) || cia1irq);
+
+ state->m_nmilevel = (machine.root_device().ioport("SPECIAL")->read() & 0x80) || cia1irq;
+ }
+}
+
+
+/***********************************************
+
+ CIA Interfaces
+
+***********************************************/
+
+/*
+ * CIA 0 - Port A keyboard line select
+ * CIA 0 - Port B keyboard line read
+ *
+ * flag cassette read input, serial request in
+ * irq to irq connected
+ *
+ * see machine/cbm.c
+ */
+
+static READ8_DEVICE_HANDLER( c64_cia0_port_a_r )
+{
+ UINT8 cia0portb = mos6526_pb_r(device->machine().device("cia_0"), 0);
+
+ return cbm_common_cia0_port_a_r(device, cia0portb);
+}
+
+static READ8_DEVICE_HANDLER( c64_cia0_port_b_r )
+{
+ UINT8 cia0porta = mos6526_pa_r(device->machine().device("cia_0"), 0);
+
+ return cbm_common_cia0_port_b_r(device, cia0porta);
+}
+
+static WRITE8_DEVICE_HANDLER( c64_cia0_port_b_w )
+{
+ device_t *vic2 = device->machine().device("vic2");
+ vic2_lightpen_write(vic2, data & 0x10);
+}
+
+static void c64_irq( running_machine &machine, int level )
+{
+ legacy_c64_state *state = machine.driver_data<legacy_c64_state>();
+ if (level != state->m_old_level)
+ {
+ DBG_LOG(machine, 3, "mos6510", ("irq %s\n", level ? "start" : "end"));
+ cputag_set_input_line(machine, "maincpu", M6510_IRQ_LINE, level);
+ state->m_old_level = level;
+ }
+}
+
+static void c64_cia0_interrupt( device_t *device, int level )
+{
+ legacy_c64_state *state = device->machine().driver_data<legacy_c64_state>();
+ c64_irq (device->machine(), level || state->m_vicirq);
+}
+
+WRITE_LINE_MEMBER( legacy_c64_state::c64_vic_interrupt )
+{
+ device_t *cia_0 = machine().device("cia_0");
+#if 1
+ if (state != m_vicirq)
+ {
+ c64_irq(machine(), state || mos6526_irq_r(cia_0));
+ m_vicirq = state;
+ }
+#endif
+}
+
+const mos6526_interface c64_ntsc_cia0 =
+{
+ 10, /* 1/10 second */
+ DEVCB_LINE(c64_cia0_interrupt),
+ DEVCB_NULL, /* pc_func */
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(c64_cia0_port_a_r),
+ DEVCB_NULL,
+ DEVCB_HANDLER(c64_cia0_port_b_r),
+ DEVCB_HANDLER(c64_cia0_port_b_w)
+};
+
+const mos6526_interface c64_pal_cia0 =
+{
+ 10, /* 1/10 second */
+ DEVCB_LINE(c64_cia0_interrupt),
+ DEVCB_NULL, /* pc_func */
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(c64_cia0_port_a_r),
+ DEVCB_NULL,
+ DEVCB_HANDLER(c64_cia0_port_b_r),
+ DEVCB_HANDLER(c64_cia0_port_b_w)
+};
+
+
+/*
+ * CIA 1 - Port A
+ * bit 7 serial bus data input
+ * bit 6 serial bus clock input
+ * bit 5 serial bus data output
+ * bit 4 serial bus clock output
+ * bit 3 serial bus atn output
+ * bit 2 rs232 data output
+ * bits 1-0 vic-chip system memory bank select
+ *
+ * CIA 1 - Port B
+ * bit 7 user rs232 data set ready
+ * bit 6 user rs232 clear to send
+ * bit 5 user
+ * bit 4 user rs232 carrier detect
+ * bit 3 user rs232 ring indicator
+ * bit 2 user rs232 data terminal ready
+ * bit 1 user rs232 request to send
+ * bit 0 user rs232 received data
+ *
+ * flag restore key or rs232 received data input
+ * irq to nmi connected ?
+ */
+static READ8_DEVICE_HANDLER( c64_cia1_port_a_r )
+{
+ legacy_c64_state *state = device->machine().driver_data<legacy_c64_state>();
+
+ UINT8 value = 0xff;
+
+ if (!state->m_iec->clk_r())
+ value &= ~0x40;
+
+ if (!state->m_iec->data_r())
+ value &= ~0x80;
+
+ return value;
+}
+
+static WRITE8_DEVICE_HANDLER( c64_cia1_port_a_w )
+{
+ legacy_c64_state *state = device->machine().driver_data<legacy_c64_state>();
+ static const int helper[4] = {0xc000, 0x8000, 0x4000, 0x0000};
+
+ state->m_iec->clk_w(!(data & 0x10));
+ state->m_iec->data_w(!(data & 0x20));
+ state->m_iec->atn_w(!(data & 0x08));
+ state->m_vicaddr = state->m_memory + helper[data & 0x03];
+}
+
+static void c64_cia1_interrupt( device_t *device, int level )
+{
+ c64_nmi(device->machine());
+}
+
+const mos6526_interface c64_ntsc_cia1 =
+{
+ 10, /* 1/10 second */
+ DEVCB_LINE(c64_cia1_interrupt),
+ DEVCB_NULL, /* pc_func */
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(c64_cia1_port_a_r),
+ DEVCB_HANDLER(c64_cia1_port_a_w),
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+const mos6526_interface c64_pal_cia1 =
+{
+ 10, /* 1/10 second */
+ DEVCB_LINE(c64_cia1_interrupt),
+ DEVCB_NULL, /* pc_func */
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(c64_cia1_port_a_r),
+ DEVCB_HANDLER(c64_cia1_port_a_w),
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+/***********************************************
+
+ Memory Handlers
+
+***********************************************/
+
+WRITE8_HANDLER( c64_roml_w )
+{
+ legacy_c64_state *state = space->machine().driver_data<legacy_c64_state>();
+
+ state->m_memory[offset + 0x8000] = data;
+
+ if (state->m_roml_writable)
+ state->m_roml[offset] = data;
+}
+
+WRITE8_HANDLER( c64_write_io )
+{
+ legacy_c64_state *state = space->machine().driver_data<legacy_c64_state>();
+ device_t *cia_0 = space->machine().device("cia_0");
+ device_t *cia_1 = space->machine().device("cia_1");
+ device_t *sid = space->machine().device("sid6581");
+ device_t *vic2 = space->machine().device("vic2");
+
+ state->m_io_mirror[offset] = data;
+ if (offset < 0x400)
+ vic2_port_w(vic2, offset & 0x3ff, data);
+ else if (offset < 0x800)
+ sid6581_w(sid, offset & 0x3ff, data);
+ else if (offset < 0xc00)
+ state->m_colorram[offset & 0x3ff] = data | 0xf0;
+ else if (offset < 0xd00)
+ mos6526_w(cia_0, offset, data);
+ else if (offset < 0xe00)
+ {
+ if (state->m_cia1_on)
+ mos6526_w(cia_1, offset, data);
+ else
+ DBG_LOG(space->machine(), 1, "io write", ("%.3x %.2x\n", offset, data));
+ }
+ else if (offset < 0xf00)
+ DBG_LOG(space->machine(), 1, "io write", ("%.3x %.2x\n", offset, data)); /* i/o 1 */
+ else
+ DBG_LOG(space->machine(), 1, "io write", ("%.3x %.2x\n", offset, data)); /* i/o 2 */
+}
+
+WRITE8_HANDLER( c64_ioarea_w )
+{
+ legacy_c64_state *state = space->machine().driver_data<legacy_c64_state>();
+ if (state->m_io_enabled)
+ c64_write_io(space, offset, data);
+ else
+ state->m_io_ram_w_ptr[offset] = data;
+}
+
+READ8_HANDLER( c64_read_io )
+{
+ legacy_c64_state *state = space->machine().driver_data<legacy_c64_state>();
+ device_t *cia_0 = space->machine().device("cia_0");
+ device_t *cia_1 = space->machine().device("cia_1");
+ device_t *sid = space->machine().device("sid6581");
+ device_t *vic2 = space->machine().device("vic2");
+
+ if (offset < 0x400)
+ return vic2_port_r(vic2, offset & 0x3ff);
+
+ else if (offset < 0x800)
+ return sid6581_r(sid, offset & 0x3ff);
+
+ else if (offset < 0xc00)
+ return state->m_colorram[offset & 0x3ff];
+
+ else if (offset < 0xd00)
+ {
+ if (offset & 1)
+ cia_set_port_mask_value(cia_0, 1, space->machine().root_device().ioport("CTRLSEL")->read() & 0x80 ? c64_keyline[9] : c64_keyline[8] );
+ else
+ cia_set_port_mask_value(cia_0, 0, state->ioport("CTRLSEL")->read() & 0x80 ? c64_keyline[8] : c64_keyline[9] );
+
+ return mos6526_r(cia_0, offset);
+ }
+
+ else if (state->m_cia1_on && (offset < 0xe00))
+ return mos6526_r(cia_1, offset);
+
+ DBG_LOG(space->machine(), 1, "io read", ("%.3x\n", offset));
+
+ return 0xff;
+}
+
+READ8_HANDLER( c64_ioarea_r )
+{
+ legacy_c64_state *state = space->machine().driver_data<legacy_c64_state>();
+ return state->m_io_enabled ? c64_read_io(space, offset) : state->m_io_ram_r_ptr[offset];
+}
+
+
+/* Info from http://unusedino.de/ec64/technical/misc/c64/64doc.html */
+/*
+
+ The leftmost column of the table contains addresses in hexadecimal
+notation. The columns aside it introduce all possible memory
+configurations. The default mode is on the left, and the absolutely
+most rarely used Ultimax game console configuration is on the right.
+(Has anybody ever seen any Ultimax games?) Each memory configuration
+column has one or more four-digit binary numbers as a title. The bits,
+from left to right, represent the state of the -LORAM, -HIRAM, -GAME
+and -EXROM lines, respectively. The bits whose state does not matter
+are marked with "x". For instance, when the Ultimax video game
+configuration is active (the -GAME line is shorted to ground), the
+-LORAM and -HIRAM lines have no effect.
+
+ default 001x Ultimax
+ 1111 101x 1000 011x 00x0 1110 0100 1100 xx01
+10000
+----------------------------------------------------------------------
+ F000
+ Kernal RAM RAM Kernal RAM Kernal Kernal Kernal ROMH(*
+ E000
+----------------------------------------------------------------------
+ D000 IO/C IO/C IO/RAM IO/C RAM IO/C IO/C IO/C I/O
+----------------------------------------------------------------------
+ C000 RAM RAM RAM RAM RAM RAM RAM RAM -
+----------------------------------------------------------------------
+ B000
+ BASIC RAM RAM RAM RAM BASIC ROMH ROMH -
+ A000
+----------------------------------------------------------------------
+ 9000
+ RAM RAM RAM RAM RAM ROML RAM ROML ROML(*
+ 8000
+----------------------------------------------------------------------
+ 7000
+
+ 6000
+ RAM RAM RAM RAM RAM RAM RAM RAM -
+ 5000
+
+ 4000
+----------------------------------------------------------------------
+ 3000
+
+ 2000 RAM RAM RAM RAM RAM RAM RAM RAM -
+
+ 1000
+----------------------------------------------------------------------
+ 0000 RAM RAM RAM RAM RAM RAM RAM RAM RAM
+----------------------------------------------------------------------
+
+ *) Internal memory does not respond to write accesses to these
+ areas.
+
+
+ Legend: Kernal E000-FFFF Kernal ROM.
+
+ IO/C D000-DFFF I/O address space or Character
+ generator ROM, selected by
+ -CHAREN. If the CHAREN bit is
+ clear, the character generator
+ ROM will be selected. If it is
+ set, the I/O chips are
+ accessible.
+
+ IO/RAM D000-DFFF I/O address space or RAM,
+ selected by -CHAREN. If the
+ CHAREN bit is clear, the
+ character generator ROM will
+ be selected. If it is set, the
+ internal RAM is accessible.
+
+ I/O D000-DFFF I/O address space.
+ The -CHAREN line has no effect.
+
+ BASIC A000-BFFF BASIC ROM.
+
+ ROMH A000-BFFF or External ROM with the -ROMH line
+ E000-FFFF connected to its -CS line.
+
+ ROML 8000-9FFF External ROM with the -ROML line
+ connected to its -CS line.
+
+ RAM various ranges Commodore 64's internal RAM.
+
+ - 1000-7FFF and Open address space.
+ A000-CFFF The Commodore 64's memory chips
+ do not detect any memory accesses
+ to this area except the VIC-II's
+ DMA and memory refreshes.
+
+ NOTE: Whenever the processor tries to write to any ROM area
+ (Kernal, BASIC, CHAROM, ROML, ROMH), the data will get
+ "through the ROM" to the C64's internal RAM.
+
+ For this reason, you can easily copy data from ROM to RAM,
+ without any bank switching. But implementing external
+ memory expansions without DMA is very hard, as you have to
+ use a 256 byte window on the I/O1 or I/O2 area, like
+ GEORAM, or the Ultimax memory configuration, if you do not
+ want the data to be written both to internal and external
+ RAM.
+
+ However, this is not true for the Ultimax video game
+ configuration. In that mode, the internal RAM ignores all
+ memory accesses outside the area $0000-$0FFF, unless they
+ are performed by the VIC, and you can write to external
+ memory at $1000-$CFFF and $E000-$FFFF, if any, without
+ changing the contents of the internal RAM.
+
+*/
+
+static void c64_bankswitch( running_machine &machine, int reset )
+{
+ legacy_c64_state *state = machine.driver_data<legacy_c64_state>();
+ int loram, hiram, charen;
+ int ultimax_mode = 0;
+ int data = m6510_get_port(machine.device<legacy_cpu_device>("maincpu")) & 0x07;
+
+ /* Are we in Ultimax mode? */
+ if (!state->m_game && state->m_exrom)
+ ultimax_mode = 1;
+
+ DBG_LOG(machine, 1, "bankswitch", ("%d\n", data & 7));
+ loram = (data & 1) ? 1 : 0;
+ hiram = (data & 2) ? 1 : 0;
+ charen = (data & 4) ? 1 : 0;
+ //logerror("Bankswitch mode || charen, state->m_ultimax\n");
+ //logerror("%d, %d, %d, %d || %d, %d \n", loram, hiram, state->m_game, state->m_exrom, charen, ultimax_mode);
+
+ if (ultimax_mode)
+ {
+ state->m_io_enabled = 1; // charen has no effect in ultimax_mode
+
+ state->membank("bank1")->set_base(state->m_roml);
+ state->membank("bank3")->set_base(state->m_memory + 0xa000);
+ state->membank("bank4")->set_base(state->m_romh);
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->nop_write(0xe000, 0xffff);
+ }
+ else
+ {
+ /* 0x8000-0x9000 */
+ if (loram && hiram && !state->m_exrom)
+ {
+ state->membank("bank1")->set_base(state->m_roml);
+ }
+ else
+ {
+ state->membank("bank1")->set_base(state->m_memory + 0x8000);
+ }
+
+ /* 0xa000 */
+ if (hiram && !state->m_game && !state->m_exrom)
+ state->membank("bank3")->set_base(state->m_romh);
+
+ else if (loram && hiram && state->m_game)
+ state->membank("bank3")->set_base(state->m_basic);
+
+ else
+ state->membank("bank3")->set_base(state->m_memory + 0xa000);
+
+ /* 0xd000 */
+ // RAM
+ if (!loram && !hiram && (state->m_game || !state->m_exrom))
+ {
+ state->m_io_enabled = 0;
+ state->m_io_ram_r_ptr = state->m_memory + 0xd000;
+ state->m_io_ram_w_ptr = state->m_memory + 0xd000;
+ }
+ // IO/RAM
+ else if (loram && !hiram && !state->m_game) // remember we cannot be in ultimax_mode, no need of !state->m_exrom
+ {
+ state->m_io_enabled = 1;
+ state->m_io_ram_r_ptr = (!charen) ? state->m_chargen : state->m_memory + 0xd000;
+ state->m_io_ram_w_ptr = state->m_memory + 0xd000;
+ }
+ // IO/C
+ else
+ {
+ state->m_io_enabled = charen ? 1 : 0;
+
+ if (!charen)
+ {
+ state->m_io_ram_r_ptr = state->m_chargen;
+ state->m_io_ram_w_ptr = state->m_memory + 0xd000;
+ }
+ }
+
+ /* 0xe000-0xf000 */
+ state->membank("bank4")->set_base(hiram ? state->m_kernal : state->m_memory + 0xe000);
+ state->membank("bank5")->set_base(state->m_memory + 0xe000);
+ }
+
+ /* make sure the opbase function gets called each time */
+ /* NPW 15-May-2008 - Another hack in the C64 drivers broken! */
+ /* opbase->mem_max = 0xcfff; */
+
+ state->m_old_game = state->m_game;
+ state->m_old_exrom = state->m_exrom;
+ state->m_old_data = data;
+}
+
+/**
+ ddr bit 1 port line is output
+ port bit 1 port line is high
+
+ p0 output loram
+ p1 output hiram
+ p2 output charen
+ p3 output cassette data
+ p4 input cassette switch
+ p5 output cassette motor
+ p6,7 not available on M6510
+ */
+
+WRITE8_DEVICE_HANDLER(c64_m6510_port_write)
+{
+ legacy_c64_state *state = device->machine().driver_data<legacy_c64_state>();
+
+ UINT8 direction = offset; // HACK ALERT!
+
+ /* if line is marked as input then keep current value */
+ data = (state->m_port_data & ~direction) | (data & direction);
+
+ /* resistors make P0,P1,P2 go high when respective line is changed to input */
+ if (!(direction & 0x04))
+ data |= 0x04;
+
+ if (!(direction & 0x02))
+ data |= 0x02;
+
+ if (!(direction & 0x01))
+ data |= 0x01;
+
+ state->m_port_data = data;
+
+ if (state->m_tape_on)
+ {
+ if (direction & 0x08)
+ {
+ device->machine().device<cassette_image_device>(CASSETTE_TAG)->output((data & 0x08) ? -(0x5a9e >> 1) : +(0x5a9e >> 1));
+ }
+
+ if (direction & 0x20)
+ {
+ if(!(data & 0x20))
+ {
+ device->machine().device<cassette_image_device>(CASSETTE_TAG)->change_state(CASSETTE_MOTOR_ENABLED, CASSETTE_MASK_MOTOR);
+ state->m_datasette_timer->adjust(attotime::zero, 0, attotime::from_hz(44100));
+ }
+ else
+ {
+ device->machine().device<cassette_image_device>(CASSETTE_TAG)->change_state(CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR);
+ state->m_datasette_timer->reset();
+ }
+ }
+ }
+
+ if (!state->m_ultimax)
+ c64_bankswitch(device->machine(), 0);
+
+ state->m_memory[0x000] = device->memory().space(AS_PROGRAM)->read_byte(0);
+ state->m_memory[0x001] = device->memory().space(AS_PROGRAM)->read_byte(1);
+
+}
+
+READ8_DEVICE_HANDLER(c64_m6510_port_read)
+{
+ legacy_c64_state *state = device->machine().driver_data<legacy_c64_state>();
+ UINT8 data = state->m_port_data;
+
+ if (state->m_tape_on)
+ {
+ if ((device->machine().device<cassette_image_device>(CASSETTE_TAG)->get_state() & CASSETTE_MASK_UISTATE) != CASSETTE_STOPPED)
+ data &= ~0x10;
+ else
+ data |= 0x10;
+ }
+
+ return data;
+}
+
+
+int c64_paddle_read( device_t *device, int which )
+{
+ running_machine &machine = device->machine();
+ int pot1 = 0xff, pot2 = 0xff, pot3 = 0xff, pot4 = 0xff, temp;
+ UINT8 cia0porta = mos6526_pa_r(machine.device("cia_0"), 0);
+ int controller1 = machine.root_device().ioport("CTRLSEL")->read() & 0x07;
+ int controller2 = machine.root_device().ioport("CTRLSEL")->read() & 0x70;
+ /* Notice that only a single input is defined for Mouse & Lightpen in both ports */
+ switch (controller1)
+ {
+ case 0x01:
+ if (which)
+ pot2 = machine.root_device().ioport("PADDLE2")->read();
+ else
+ pot1 = machine.root_device().ioport("PADDLE1")->read();
+ break;
+
+ case 0x02:
+ if (which)
+ pot2 = machine.root_device().ioport("TRACKY")->read();
+ else
+ pot1 = machine.root_device().ioport("TRACKX")->read();
+ break;
+
+ case 0x03:
+ if (which && (machine.root_device().ioport("JOY1_2B")->read() & 0x20)) /* Joy1 Button 2 */
+ pot1 = 0x00;
+ break;
+
+ case 0x04:
+ if (which)
+ pot2 = machine.root_device().ioport("LIGHTY")->read();
+ else
+ pot1 = machine.root_device().ioport("LIGHTX")->read();
+ break;
+
+ case 0x06:
+ if (which && (machine.root_device().ioport("OTHER")->read() & 0x04)) /* Lightpen Signal */
+ pot2 = 0x00;
+ break;
+
+ case 0x00:
+ case 0x07:
+ break;
+
+ default:
+ logerror("Invalid Controller Setting %d\n", controller1);
+ break;
+ }
+
+ switch (controller2)
+ {
+ case 0x10:
+ if (which)
+ pot4 = machine.root_device().ioport("PADDLE4")->read();
+ else
+ pot3 = machine.root_device().ioport("PADDLE3")->read();
+ break;
+
+ case 0x20:
+ if (which)
+ pot4 = machine.root_device().ioport("TRACKY")->read();
+ else
+ pot3 = machine.root_device().ioport("TRACKX")->read();
+ break;
+
+ case 0x30:
+ if (which && (machine.root_device().ioport("JOY2_2B")->read() & 0x20)) /* Joy2 Button 2 */
+ pot4 = 0x00;
+ break;
+
+ case 0x40:
+ if (which)
+ pot4 = machine.root_device().ioport("LIGHTY")->read();
+ else
+ pot3 = machine.root_device().ioport("LIGHTX")->read();
+ break;
+
+ case 0x60:
+ if (which && (machine.root_device().ioport("OTHER")->read() & 0x04)) /* Lightpen Signal */
+ pot4 = 0x00;
+ break;
+
+ case 0x00:
+ case 0x70:
+ break;
+
+ default:
+ logerror("Invalid Controller Setting %d\n", controller1);
+ break;
+ }
+
+ if (machine.root_device().ioport("CTRLSEL")->read() & 0x80) /* Swap */
+ {
+ temp = pot1; pot1 = pot3; pot3 = temp;
+ temp = pot2; pot2 = pot4; pot4 = temp;
+ }
+
+ switch (cia0porta & 0xc0)
+ {
+ case 0x40:
+ return which ? pot2 : pot1;
+
+ case 0x80:
+ return which ? pot4 : pot3;
+
+ case 0xc0:
+ return which ? pot2 : pot1;
+
+ default:
+ return 0;
+ }
+}
+
+READ8_HANDLER( c64_colorram_read )
+{
+ legacy_c64_state *state = space->machine().driver_data<legacy_c64_state>();
+ return state->m_colorram[offset & 0x3ff];
+}
+
+WRITE8_HANDLER( c64_colorram_write )
+{
+ legacy_c64_state *state = space->machine().driver_data<legacy_c64_state>();
+ state->m_colorram[offset & 0x3ff] = data | 0xf0;
+}
+
+TIMER_CALLBACK( c64_tape_timer )
+{
+ double tmp = machine.device<cassette_image_device>(CASSETTE_TAG)->input();
+ device_t *cia_0 = machine.device("cia_0");
+
+ mos6526_flag_w(cia_0, tmp > +0.0);
+}
+
+static void c64_common_driver_init( running_machine &machine )
+{
+ legacy_c64_state *state = machine.driver_data<legacy_c64_state>();
+ cbm_common_init();
+ state->m_game = 1;
+ state->m_exrom = 1;
+ state->m_old_data = -1;
+
+ if (!state->m_ultimax)
+ {
+ UINT8 *mem = state->memregion("maincpu")->base();
+ state->m_basic = mem + 0x10000;
+ state->m_kernal = mem + 0x12000;
+ state->m_chargen = mem + 0x14000;
+ state->m_colorram = mem + 0x15000;
+ state->m_c64_roml = mem + 0x15400;
+ state->m_c64_romh = mem + 0x17400;
+ }
+
+ if (state->m_tape_on)
+ state->m_datasette_timer = machine.scheduler().timer_alloc(FUNC(c64_tape_timer));
+
+ // "cyberload" tape loader check the e000-ffff ram; the init ram need to return different value
+ {
+ int i;
+ for (i = 0; i < 0x2000; i += 0x40)
+ memset(state->m_memory + (0xe000 + i), ((i & 0x40) >> 6) * 0xff, 0x40);
+ }
+}
+
+DRIVER_INIT_MEMBER(legacy_c64_state,c64)
+{
+ m_ultimax = 0;
+ m_is_sx64 = 0;
+ m_pal = 0;
+ m_cia1_on = 1;
+ m_tape_on = 1;
+ c64_common_driver_init(machine());
+}
+
+DRIVER_INIT_MEMBER(legacy_c64_state,c64pal)
+{
+ m_ultimax = 0;
+ m_is_sx64 = 0;
+ m_pal = 1;
+ m_cia1_on = 1;
+ m_tape_on = 1;
+ c64_common_driver_init(machine());
+}
+
+DRIVER_INIT_MEMBER(legacy_c64_state,ultimax)
+{
+ m_ultimax = 1;
+ m_is_sx64 = 0;
+ m_pal = 0;
+ m_cia1_on = 0;
+ m_tape_on = 1;
+ c64_common_driver_init(machine());
+}
+
+DRIVER_INIT_MEMBER(legacy_c64_state,c64gs)
+{
+ m_ultimax = 0;
+ m_is_sx64 = 0;
+ m_pal = 1;
+ m_cia1_on = 1;
+ m_tape_on = 0;
+ c64_common_driver_init(machine());
+}
+
+DRIVER_INIT_MEMBER(legacy_c64_state,sx64)
+{
+ m_ultimax = 0;
+ m_is_sx64 = 1;
+ m_pal = 1;
+ m_cia1_on = 1;
+ m_tape_on = 0;
+ c64_common_driver_init(machine());
+}
+
+MACHINE_START( c64 )
+{
+ legacy_c64_state *state = machine.driver_data<legacy_c64_state>();
+ state->m_port_data = 0x17;
+
+ state->m_io_mirror = auto_alloc_array(machine, UINT8, 0x1000);
+ state->m_io_enabled = 0;
+
+ state->m_vicaddr = state->m_memory;
+ state->m_vicirq = 0;
+
+ if (!state->m_ultimax)
+ c64_bankswitch(machine, 1);
+}
+
+INTERRUPT_GEN( c64_frame_interrupt )
+{
+ c64_nmi(device->machine());
+ cbm_common_interrupt(device);
+}
+
+
+/***********************************************
+
+ C64 Cartridges
+
+***********************************************/
+
+/* Info based on http://ist.uwaterloo.ca/~schepers/formats/CRT.TXT */
+/* Please refer to the webpage for the latest version and for a very
+ complete listing of various cart types and their bankswitch tricks */
+/*
+ Cartridge files were introduced in the CCS64 emulator, written by Per
+Hakan Sundell, and use the ".CRT" file extension. This format was created
+to handle the various ROM cartridges that exist, such as Action Replay, the
+Power cartridge, and the Final Cartridge.
+
+ Normal game cartridges can load into several different memory ranges
+($8000-9FFF, $A000-BFFF or $E000-FFFF). Newer utility and freezer
+cartridges were less intrusive, hiding themselves until called upon, and
+still others used bank-switching techniques to allow much larger ROM's than
+normal. Because of these "stealthing" and bank-switching methods, a special
+cartridge format was necessary, to let the emulator know where the
+cartridge should reside, the control line states to enable it and any
+special hardware features it uses.
+
+(...)
+
+[ A .CRT file consists of
+
+ $0000-0040 : Header of the whole .crt files
+ $0040-EOF : Blocks of data
+
+ Each block of data, called 'CHIP', can be of variable size. The first
+0x10 bytes of each CHIP block is the block header, and it contains various
+informations on the block itself, as its size (both with and without the
+header), the loading address and an index to identify which memory bank
+the data must be loaded to. FP ]
+
+.CRT header description
+-----------------------
+
+ Bytes: $0000-000F - 16-byte cartridge signature "C64 CARTRIDGE" (padded
+ with space characters)
+ 0010-0013 - File header length ($00000040, in high/low format,
+ calculated from offset $0000). The default (also the
+ minimum) value is $40. Some cartridges exist which
+ show a value of $00000020 which is wrong.
+ 0014-0015 - Cartridge version (high/low, presently 01.00)
+ 0016-0017 - Cartridge hardware type ($0000, high/low)
+ 0018 - Cartridge port EXROM line status
+ 0 - inactive
+ 1 - active
+ 0019 - Cartridge port GAME line status
+ 0 - inactive
+ 1 - active
+ 001A-001F - Reserved for future use
+ 0020-003F - 32-byte cartridge name "CCSMON" (uppercase, padded
+ with null characters)
+ 0040-xxxx - Cartridge contents (called CHIP PACKETS, as there can
+ be more than one per CRT file). See below for a
+ breakdown of the CHIP format.
+
+CHIP content description
+------------------------
+
+[ Addresses shifted back to $0000. FP ]
+
+ Bytes: $0000-0003 - Contained ROM signature "CHIP" (note there can be more
+ than one image in a .CRT file)
+ 0004-0007 - Total packet length (ROM image size and
+ header combined) (high/low format)
+ 0008-0009 - Chip type
+ 0 - ROM
+ 1 - RAM, no ROM data
+ 2 - Flash ROM
+ 000A-000B - Bank number
+ 000C-000D - Starting load address (high/low format)
+ 000E-000F - ROM image size in bytes (high/low format, typically
+ $2000 or $4000)
+ 0010-xxxx - ROM data
+
+
+*/
+
+
+/* Hardware Types for C64 carts */
+enum {
+ GENERIC_CRT = 0, /* 00 - Normal cartridge */
+ ACTION_REPLAY, /* 01 - Action Replay */
+ KCS_PC, /* 02 - KCS Power Cartridge */
+ FINAL_CART_III, /* 03 - Final Cartridge III */
+ SIMONS_BASIC, /* 04 - Simons Basic */
+ OCEAN_1, /* 05 - Ocean type 1 (1) */
+ EXPERT, /* 06 - Expert Cartridge */
+ FUN_PLAY, /* 07 - Fun Play, Power Play */
+ SUPER_GAMES, /* 08 - Super Games */
+ ATOMIC_POWER, /* 09 - Atomic Power */
+ EPYX_FASTLOAD, /* 10 - Epyx Fastload */
+ WESTERMANN, /* 11 - Westermann Learning */
+ REX, /* 12 - Rex Utility */
+ FINAL_CART_I, /* 13 - Final Cartridge I */
+ MAGIC_FORMEL, /* 14 - Magic Formel */
+ C64GS, /* 15 - C64 Game System, System 3 */
+ WARPSPEED, /* 16 - WarpSpeed */
+ DINAMIC, /* 17 - Dinamic (2) */
+ ZAXXON, /* 18 - Zaxxon, Super Zaxxon (SEGA) */
+ DOMARK, /* 19 - Magic Desk, Domark, HES Australia */
+ SUPER_SNAP_5, /* 20 - Super Snapshot 5 */
+ COMAL_80, /* 21 - Comal-80 */
+ STRUCT_BASIC, /* 22 - Structured Basic */
+ ROSS, /* 23 - Ross */
+ DELA_EP64, /* 24 - Dela EP64 */
+ DELA_EP7X8, /* 25 - Dela EP7x8 */
+ DELA_EP256, /* 26 - Dela EP256 */
+ REX_EP256, /* 27 - Rex EP256 */
+ MIKRO_ASSMBLR, /* 28 - Mikro Assembler */
+ REAL_FC_I, /* 29 - (3) */
+ ACTION_REPLAY_4, /* 30 - Action Replay 4 */
+ STARDOS, /* 31 - StarDOS */
+ /*
+ (1) Ocean type 1 includes Navy Seals, Robocop 2 & 3, Shadow of
+ the Beast, Toki, Terminator 2 and more. Both 256 and 128 Kb images.
+ (2) Dinamic includes Narco Police and more.
+ (3) Type 29 is reserved for the real Final Cartridge I, the one
+ above (Type 13) will become Final Cartridge II. */
+ /****************************************
+ Vice also defines the following types:
+ #define CARTRIDGE_ACTION_REPLAY3 -29
+ #define CARTRIDGE_IEEE488 -11
+ #define CARTRIDGE_IDE64 -7
+ #define CARTRIDGE_RETRO_REPLAY -5
+ #define CARTRIDGE_SUPER_SNAPSHOT -4
+
+ Can we support these as well?
+ *****************************************/
+};
+
+static DEVICE_IMAGE_UNLOAD( c64_cart )
+{
+ legacy_c64_state *state = image.device().machine().driver_data<legacy_c64_state>();
+ int i;
+
+ for (i = 0; i < C64_MAX_ROMBANK; i++)
+ {
+ state->m_cart.bank[i].size = 0;
+ state->m_cart.bank[i].addr = 0;
+ state->m_cart.bank[i].index = 0;
+ state->m_cart.bank[i].start = 0;
+ }
+}
+
+
+static DEVICE_START( c64_cart )
+{
+ legacy_c64_state *state = device->machine().driver_data<legacy_c64_state>();
+ /* In the first slot we can load a .crt file. In this case we want
+ to use game & exrom values from the header, not the default ones. */
+ state->m_cart.game = -1;
+ state->m_cart.exrom = -1;
+ state->m_cart.mapper = GENERIC_CRT;
+ state->m_cart.n_banks = 0;
+}
+
+static int c64_crt_load( device_image_interface &image )
+{
+ legacy_c64_state *state = image.device().machine().driver_data<legacy_c64_state>();
+ int size = image.length(), test, i = 0, ii;
+ int _80_loaded = 0, _90_loaded = 0, a0_loaded = 0, b0_loaded = 0, e0_loaded = 0, f0_loaded = 0;
+ const char *filetype = image.filetype();
+ int address = 0, new_start = 0;
+ // int lbank_end_addr = 0, hbank_end_addr = 0;
+ UINT8 *cart_cpy = state->memregion("user1")->base();
+
+ /* We support .crt files */
+ if (!mame_stricmp(filetype, "crt"))
+ {
+ int j;
+ unsigned short c64_cart_type;
+
+ if (i >= C64_MAX_ROMBANK)
+ return IMAGE_INIT_FAIL;
+
+ /* Start to parse the .crt header */
+ /* 0x16-0x17 is Hardware type */
+ image.fseek(0x16, SEEK_SET);
+ image.fread(&c64_cart_type, 2);
+ state->m_cart.mapper = BIG_ENDIANIZE_INT16(c64_cart_type);
+
+ /* If it is unsupported cart type, warn the user */
+ switch (state->m_cart.mapper)
+ {
+ case SIMONS_BASIC: /* Type # 4 */
+ case OCEAN_1: /* Type # 5 */
+ case FUN_PLAY: /* Type # 7 */
+ case SUPER_GAMES: /* Type # 8 */
+ case EPYX_FASTLOAD: /* Type # 10 */
+ case REX: /* Type # 12 */
+ case C64GS: /* Type # 15 */
+ case DINAMIC: /* Type # 17 */
+ case ZAXXON: /* Type # 18 */
+ case DOMARK: /* Type # 19 */
+ case COMAL_80: /* Type # 21 */
+ case GENERIC_CRT: /* Type # 0 */
+ printf("Currently supported cart type (Type %d)\n", state->m_cart.mapper);
+ break;
+
+ default:
+ case ACTION_REPLAY: /* Type # 1 */
+ case KCS_PC: /* Type # 2 */
+ case FINAL_CART_III: /* Type # 3 */
+ case EXPERT: /* Type # 6 */
+ case ATOMIC_POWER: /* Type # 9 */
+ case WESTERMANN: /* Type # 11 */
+ case FINAL_CART_I: /* Type # 13 */
+ case MAGIC_FORMEL: /* Type # 14 */
+ case SUPER_SNAP_5: /* Type # 20 */
+ printf("Currently unsupported cart type (Type %d)\n", state->m_cart.mapper);
+ break;
+ }
+
+ /* 0x18 is EXROM */
+ image.fseek(0x18, SEEK_SET);
+ image.fread(&state->m_cart.exrom, 1);
+
+ /* 0x19 is GAME */
+ image.fread(&state->m_cart.game, 1);
+
+ /* We can pass to the data: it starts from 0x40 */
+ image.fseek(0x40, SEEK_SET);
+ j = 0x40;
+
+ logerror("Loading cart %s size:%.4x\n", image.filename(), size);
+ logerror("Header info: EXROM %d, GAME %d, Cart Type %d \n", state->m_cart.exrom, state->m_cart.game, c64_cart_type);
+
+
+ /* Data in a .crt image are organized in blocks called 'CHIP':
+ each 'CHIP' consists of a 0x10 header, which contains the
+ actual size of the block, the loading address and info on
+ the bankswitch, followed by the actual data */
+ while (j < size)
+ {
+ unsigned short chip_size, chip_bank_index, chip_data_size;
+ unsigned char buffer[10];
+
+ /* Start to parse the CHIP header */
+ /* First 4 bytes are the string 'CHIP' */
+ image.fread(buffer, 6);
+
+ /* 0x06-0x07 is the size of the CHIP block (header + data) */
+ image.fread(&chip_size, 2);
+ chip_size = BIG_ENDIANIZE_INT16(chip_size);
+
+ /* 0x08-0x09 chip type (ROM, RAM + no ROM, Flash ROM) */
+ image.fread(buffer + 6, 2);
+
+ /* 0x0a-0x0b is the bank number of the CHIP block */
+ image.fread(&chip_bank_index, 2);
+ chip_bank_index = BIG_ENDIANIZE_INT16(chip_bank_index);
+
+ /* 0x0c-0x0d is the loading address of the CHIP block */
+ image.fread(&address, 2);
+ address = BIG_ENDIANIZE_INT16(address);
+
+ /* 0x0e-0x0f is the data size of the CHIP block (without header) */
+ image.fread(&chip_data_size, 2);
+ chip_data_size = BIG_ENDIANIZE_INT16(chip_data_size);
+
+ /* Print out the CHIP header! */
+ logerror("%.4s %.2x %.2x %.4x %.2x %.2x %.4x %.4x:%.4x\n",
+ buffer, buffer[4], buffer[5], chip_size,
+ buffer[6], buffer[7], chip_bank_index,
+ address, chip_data_size);
+ logerror("Loading CHIP data at %.4x size:%.4x\n", address, chip_data_size);
+
+ /* Store data, address & size of the CHIP block */
+ state->m_cart.bank[i].addr = address;
+ state->m_cart.bank[i].index = chip_bank_index;
+ state->m_cart.bank[i].size = chip_data_size;
+ state->m_cart.bank[i].start = new_start;
+
+ test = image.fread(cart_cpy + new_start, state->m_cart.bank[i].size);
+ new_start += state->m_cart.bank[i].size;
+
+ /* Does CHIP contain any data? */
+ if (test != state->m_cart.bank[i].size)
+ return IMAGE_INIT_FAIL;
+
+ /* Advance to the next CHIP block */
+ i++;
+ j += chip_size;
+ }
+ }
+ else /* We also support .80 files for c64 & .e0/.f0 for max */
+ {
+ /* Assign loading address according to extension */
+ if (!mame_stricmp(filetype, "80"))
+ address = 0x8000;
+
+ if (!mame_stricmp(filetype, "e0"))
+ address = 0xe000;
+
+ if (!mame_stricmp(filetype, "f0"))
+ address = 0xf000;
+
+ logerror("loading %s rom at %.4x size:%.4x\n", image.filename(), address, size);
+
+ /* Store data, address & size */
+ state->m_cart.bank[0].addr = address;
+ state->m_cart.bank[0].size = size;
+ state->m_cart.bank[0].start = new_start;
+
+ test = image.fread(cart_cpy + new_start, state->m_cart.bank[0].size);
+ new_start += state->m_cart.bank[0].size;
+
+ /* Does cart contain any data? */
+ if (test != state->m_cart.bank[0].size)
+ return IMAGE_INIT_FAIL;
+ }
+
+ state->m_cart.n_banks = i; // this is also needed so that we only set mappers if a cart is present!
+
+ /* If we load a .crt file, use EXROM & GAME from the header! */
+ if ((state->m_cart.exrom != -1) && (state->m_cart.game != -1))
+ {
+ state->m_exrom = state->m_cart.exrom;
+ state->m_game = state->m_cart.game;
+ }
+
+ /* Finally load the cart */
+ state->m_roml = state->m_c64_roml;
+ state->m_romh = state->m_c64_romh;
+
+ memset(state->m_roml, 0, 0x2000);
+ memset(state->m_romh, 0, 0x2000);
+
+ switch (state->m_cart.mapper)
+ {
+ default:
+ if (!state->m_game && state->m_exrom && (state->m_cart.n_banks == 1))
+ {
+ memcpy(state->m_romh, cart_cpy, 0x2000);
+ }
+ else
+ {
+ // we first attempt to load the first 'CHIPs' with address 0x8000-0xb000 and 0xe000-0xf000, otherwise we load the first (or first two) 'CHIPs' of the image
+ for (ii = 0; ii < state->m_cart.n_banks; ii++)
+ {
+ if (state->m_cart.bank[ii].addr == 0x8000 && !_80_loaded)
+ {
+ memcpy(state->m_roml, cart_cpy + state->m_cart.bank[ii].start, state->m_cart.bank[ii].size);
+ _80_loaded = 1;
+ if (state->m_cart.bank[ii].size > 0x1000)
+ _90_loaded = 1;
+ if (state->m_cart.bank[ii].size > 0x2000)
+ a0_loaded = 1;
+ if (state->m_cart.bank[ii].size > 0x3000)
+ b0_loaded = 1;
+// printf("addr 0x8000: 80 %d, 90 %d, a0 %d, b0 %d\n", _80_loaded, _90_loaded, a0_loaded, b0_loaded);
+ }
+
+ if (state->m_cart.bank[ii].addr == 0x9000 && !_90_loaded)
+ {
+ memcpy(state->m_roml + 0x1000, cart_cpy + state->m_cart.bank[ii].start, state->m_cart.bank[ii].size);
+ _90_loaded = 1;
+ if (state->m_cart.bank[ii].size > 0x1000)
+ a0_loaded = 1;
+ if (state->m_cart.bank[ii].size > 0x2000)
+ b0_loaded = 1;
+// printf("addr 0x9000: 80 %d, 90 %d, a0 %d, b0 %d\n", _80_loaded, _90_loaded, a0_loaded, b0_loaded);
+ }
+
+ if (state->m_cart.bank[ii].addr == 0xa000 && !a0_loaded)
+ {
+ memcpy(state->m_roml + 0x2000, cart_cpy + state->m_cart.bank[ii].start, state->m_cart.bank[ii].size);
+ a0_loaded = 1;
+ if (state->m_cart.bank[ii].size > 0x1000)
+ b0_loaded = 1;
+// printf("addr 0xa000: 80 %d, 90 %d, a0 %d, b0 %d\n", _80_loaded, _90_loaded, a0_loaded, b0_loaded);
+ }
+
+ if (state->m_cart.bank[ii].addr == 0xb000 && !b0_loaded)
+ {
+ memcpy(state->m_roml + 0x3000, cart_cpy + state->m_cart.bank[ii].start, state->m_cart.bank[ii].size);
+ b0_loaded = 1;
+// printf("addr 0xb000: 80 %d, 90 %d, a0 %d, b0 %d\n", _80_loaded, _90_loaded, a0_loaded, b0_loaded);
+ }
+
+ if (state->m_cart.bank[ii].addr == 0xe000 && !e0_loaded)
+ {
+ memcpy(state->m_romh, cart_cpy + state->m_cart.bank[ii].start, state->m_cart.bank[ii].size);
+ e0_loaded = 1;
+ if (state->m_cart.bank[ii].size > 0x1000)
+ f0_loaded = 1;
+// printf("addr 0xe000: e0 %d, f0 %d\n", e0_loaded, f0_loaded);
+ }
+
+ if (state->m_cart.bank[ii].addr == 0xf000 && !f0_loaded)
+ {
+ memcpy(state->m_romh + 0x1000, cart_cpy + state->m_cart.bank[ii].start, state->m_cart.bank[ii].size);
+ f0_loaded = 1;
+// printf("addr 0xe000: e0 %d, f0 %d\n", e0_loaded, f0_loaded);
+ }
+ }
+ }
+ }
+
+ return IMAGE_INIT_PASS;
+}
+
+/***************************************************************************
+ SOFTWARE LIST CARTRIDGE HANDLING
+***************************************************************************/
+
+#define install_write_handler(_start, _end, _handler) \
+ image.device().machine().firstcpu->memory().space(AS_PROGRAM)->install_legacy_write_handler(_start, _end, FUNC(_handler));
+
+#define install_io1_handler(_handler) \
+ image.device().machine().firstcpu->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xde00, 0xde00, 0, 0xff, FUNC(_handler));
+
+#define install_io2_handler(_handler) \
+ image.device().machine().firstcpu->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xdf00, 0xdf00, 0, 0xff, FUNC(_handler));
+
+#define allocate_cartridge_timer(_period, _func) \
+ legacy_c64_state *state = image.device().machine().driver_data<legacy_c64_state>(); \
+ state->m_cartridge_timer = image.device().machine().scheduler().timer_alloc(FUNC(_func)); \
+ state->m_cartridge_timer->adjust(_period, 0);
+
+#define set_game_line(_machine, _state) \
+ _machine.driver_data<legacy_c64_state>()->m_game = _state; \
+ c64_bankswitch(_machine, 0);
+
+INLINE void load_cartridge_region(device_image_interface &image, const char *name, offs_t offset, size_t size)
+{
+ UINT8 *cart = image.device().machine().root_device().memregion("user1")->base();
+ UINT8 *rom = image.get_software_region(name);
+ memcpy(cart + offset, rom, size);
+}
+
+INLINE void map_cartridge_roml(running_machine &machine, offs_t offset)
+{
+ legacy_c64_state *state = machine.driver_data<legacy_c64_state>();
+ UINT8 *cart = state->memregion("user1")->base();
+ memcpy(state->m_roml, cart + offset, 0x2000);
+}
+
+INLINE void map_cartridge_romh(running_machine &machine, offs_t offset)
+{
+ legacy_c64_state *state = machine.driver_data<legacy_c64_state>();
+ UINT8 *cart = state->memregion("user1")->base();
+ memcpy(state->m_romh, cart + offset, 0x2000);
+}
+
+static void load_standard_c64_cartridge(device_image_interface &image)
+{
+ legacy_c64_state *state = image.device().machine().driver_data<legacy_c64_state>();
+ UINT32 size;
+
+ // is there anything to load at 0x8000?
+ size = image.get_software_region_length("roml");
+
+ if (size)
+ {
+ memcpy(state->m_roml, image.get_software_region("roml"), MIN(0x2000, size));
+
+ if (size == 0x4000)
+ {
+ // continue loading to ROMH region
+ memcpy(state->m_romh, image.get_software_region("roml") + 0x2000, 0x2000);
+ }
+ }
+
+ // is there anything to load at 0xa000?
+ size = image.get_software_region_length("romh");
+ if (size)
+ memcpy(state->m_romh, image.get_software_region("romh"), size);
+}
+
+static TIMER_CALLBACK( vizawrite_timer )
+{
+ map_cartridge_roml(machine, 0x2000);
+ set_game_line(machine, 1);
+}
+
+static void load_vizawrite_cartridge(device_image_interface &image)
+{
+ #define VW64_DECRYPT_ADDRESS(_offset) \
+ BITSWAP16(_offset,15,14,13,12,7,8,6,9,5,11,4,3,2,10,1,0)
+
+ #define VW64_DECRYPT_DATA(_data) \
+ BITSWAP8(_data,7,6,0,5,1,4,2,3)
+
+ UINT8 *roml = image.get_software_region("roml");
+ UINT8 *romh = image.get_software_region("romh");
+ UINT8 *decrypted = image.device().machine().root_device().memregion("user1")->base();
+
+ // decrypt ROMs
+ for (offs_t offset = 0; offset < 0x2000; offset++)
+ {
+ offs_t address = VW64_DECRYPT_ADDRESS(offset);
+ decrypted[address] = VW64_DECRYPT_DATA(roml[offset]);
+ decrypted[address + 0x2000] = VW64_DECRYPT_DATA(roml[offset + 0x2000]);
+ decrypted[address + 0x4000] = VW64_DECRYPT_DATA(romh[offset]);
+ }
+
+ // map cartridge ROMs
+ map_cartridge_roml(image.device().machine(), 0x0000);
+ map_cartridge_romh(image.device().machine(), 0x4000);
+
+ // allocate GAME changing timer
+ allocate_cartridge_timer(attotime::from_msec(1184), vizawrite_timer);
+}
+
+static WRITE8_HANDLER( hugo_bank_w )
+{
+ /*
+
+ bit description
+
+ 0
+ 1
+ 2
+ 3
+ 4 A14
+ 5 A15
+ 6 A16
+ 7 A13
+
+ */
+
+ int bank = ((data >> 3) & 0x0e) | BIT(data, 7);
+
+ map_cartridge_roml(space->machine(), bank * 0x2000);
+}
+
+static void load_hugo_cartridge(device_image_interface &image)
+{
+ #define HUGO_DECRYPT_ADDRESS(_offset) \
+ BITSWAP16(_offset,15,14,13,12,7,6,5,4,3,2,1,0,8,9,11,10)
+
+ #define HUGO_DECRYPT_DATA(_data) \
+ BITSWAP8(_data,7,6,5,4,0,1,2,3)
+
+ UINT8 *roml = image.get_software_region("roml");
+ UINT8 *decrypted = image.device().machine().root_device().memregion("user1")->base();
+
+ // decrypt ROMs
+ for (offs_t offset = 0; offset < 0x20000; offset++)
+ {
+ offs_t address = (offset & 0x10000) | HUGO_DECRYPT_ADDRESS(offset);
+ decrypted[address] = HUGO_DECRYPT_DATA(roml[offset]);
+ }
+
+ // map cartridge ROMs
+ map_cartridge_roml(image.device().machine(), 0x0000);
+
+ // install bankswitch handler
+ install_io1_handler(hugo_bank_w);
+}
+
+static WRITE8_HANDLER( easy_calc_result_bank_w )
+{
+ map_cartridge_romh(space->machine(), 0x2000 + (!offset * 0x2000));
+}
+
+static void load_easy_calc_result_cartridge(device_image_interface &image)
+{
+ load_cartridge_region(image, "roml", 0x0000, 0x2000);
+ load_cartridge_region(image, "romh", 0x2000, 0x4000);
+
+ map_cartridge_roml(image.device().machine(), 0x0000);
+ map_cartridge_romh(image.device().machine(), 0x2000);
+
+ install_write_handler(0xde00, 0xde01, easy_calc_result_bank_w);
+}
+
+static WRITE8_HANDLER( pagefox_bank_w )
+{
+ /*
+
+ Die 96KB des Moduls belegen in 6 16K-Banken den Modulbereich von $8000- $c000.
+ Die Umschaltung erfolgt mit einem Register in $DE80 (-$DEFF, nicht voll decodiert),
+ welches nur beschrieben und nicht gelesen werden kann. Durch Schreiben der Werte
+ $08 oder $0A selektiert man eine der beiden RAM-Banke, $FF deselektiert das Modul.
+
+ Zusatzlich muss Adresse 1 entsprechend belegt werden :$37 fur Lesezugriffe auf das
+ Modul, $35 oder $34 fur Lesezugriffe auf das Ram des C64. Schreibzugriffe lenkt
+ der C64 grundsatzlich ins eigene RAM, weshalb zum Beschreiben des Modulrams ein
+ Trick notwendig ist: Man schaltet das Ram-Modul parallel zum C64-Ram, rettet vor
+ dem Schreiben den C64-Ram-Inhalt und stellt ihn nachher wieder her...
+
+ Ldy#0
+ Lda#$35
+ Sta 1
+ Loop Lda (Ptr),y
+ Pha
+ Lda#$08
+ Sta $DE80
+ Lda (Quell),y
+ Sta (Ptr),y
+ Lda#$FF
+ Sta $DE80
+ Pla
+ Sta (Ptr),y
+ Iny
+ Bne Loop
+
+ */
+
+ legacy_c64_state *state = space->machine().driver_data<legacy_c64_state>();
+ UINT8 *cart = state->memregion("user1")->base();
+
+ if (data == 0xff)
+ {
+ // hide cartridge
+ state->m_game = 1;
+ state->m_exrom = 1;
+ }
+ else
+ {
+ if (state->m_game)
+ {
+ // enable cartridge
+ state->m_game = 0;
+ state->m_exrom = 0;
+ }
+
+ int bank = (data >> 1) & 0x07;
+ int ram = BIT(data, 3);
+ offs_t address = bank * 0x4000;
+
+ state->m_roml_writable = ram;
+
+ if (ram)
+ {
+ state->m_roml = cart + address;
+ }
+ else
+ {
+ state->m_roml = state->m_c64_roml;
+
+ map_cartridge_roml(space->machine(), address);
+ map_cartridge_romh(space->machine(), address + 0x2000);
+ }
+ }
+
+ c64_bankswitch(space->machine(), 0);
+}
+
+static void load_pagefox_cartridge(device_image_interface &image)
+{
+ load_cartridge_region(image, "rom", 0x0000, 0x10000);
+
+ map_cartridge_roml(image.device().machine(), 0x0000);
+ map_cartridge_romh(image.device().machine(), 0x2000);
+
+ install_write_handler(0xde80, 0xdeff, pagefox_bank_w);
+}
+
+static WRITE8_HANDLER( multiscreen_bank_w )
+{
+ legacy_c64_state *state = space->machine().driver_data<legacy_c64_state>();
+ UINT8 *cart = state->memregion("user1")->base();
+ int bank = data & 0x0f;
+ offs_t address = bank * 0x4000;
+
+ if (bank == 0x0d)
+ {
+ // RAM
+ state->m_roml = cart + address;
+ state->m_roml_writable = 1;
+
+ map_cartridge_romh(space->machine(), 0x2000);
+ }
+ else
+ {
+ // ROM
+ state->m_roml = state->m_c64_roml;
+ state->m_roml_writable = 0;
+
+ map_cartridge_roml(space->machine(), address);
+ map_cartridge_romh(space->machine(), address + 0x2000);
+ }
+
+ c64_bankswitch(space->machine(), 0);
+}
+
+static void load_multiscreen_cartridge(device_image_interface &image)
+{
+ load_cartridge_region(image, "roml", 0x0000, 0x4000);
+ load_cartridge_region(image, "rom", 0x4000, 0x30000);
+
+ map_cartridge_roml(image.device().machine(), 0x0000);
+ map_cartridge_romh(image.device().machine(), 0x2000);
+
+ install_write_handler(0xdfff, 0xdfff, multiscreen_bank_w);
+}
+
+static WRITE8_HANDLER( simons_basic_bank_w )
+{
+ set_game_line(space->machine(), !BIT(data, 0));
+}
+
+static void load_simons_basic_cartridge(device_image_interface &image)
+{
+ load_cartridge_region(image, "roml", 0x0000, 0x2000);
+ load_cartridge_region(image, "romh", 0x2000, 0x2000);
+
+ map_cartridge_roml(image.device().machine(), 0x0000);
+ map_cartridge_romh(image.device().machine(), 0x2000);
+
+ install_io1_handler(simons_basic_bank_w);
+}
+
+static READ8_HANDLER( super_explode_r )
+{
+ legacy_c64_state *state = space->machine().driver_data<legacy_c64_state>();
+
+ return state->m_roml[0x1f00 | offset];
+}
+
+static WRITE8_HANDLER( super_explode_bank_w )
+{
+ map_cartridge_roml(space->machine(), BIT(data, 7) * 0x2000);
+}
+
+static void load_super_explode_cartridge(device_image_interface &image)
+{
+ load_cartridge_region(image, "roml", 0x0000, 0x4000);
+
+ map_cartridge_roml(image.device().machine(), 0x0000);
+
+ address_space *space = image.device().machine().firstcpu->memory().space(AS_PROGRAM);
+ space->install_legacy_read_handler(0xdf00, 0xdfff, FUNC(super_explode_r));
+
+ install_io2_handler(super_explode_bank_w);
+}
+
+static void c64_software_list_cartridge_load(device_image_interface &image)
+{
+ legacy_c64_state *state = image.device().machine().driver_data<legacy_c64_state>();
+
+ // initialize ROML and ROMH pointers
+ state->m_roml = state->m_c64_roml;
+ state->m_romh = state->m_c64_romh;
+
+ // clear ROML and ROMH areas
+ memset(state->m_roml, 0, 0x2000);
+ memset(state->m_romh, 0, 0x2000);
+
+ // set GAME and EXROM
+ state->m_game = atol(image.get_feature("game"));
+ state->m_exrom = atol(image.get_feature("exrom"));
+
+ // determine cartridge type
+ const char *cart_type = image.get_feature("cart_type");
+
+ if (cart_type == NULL)
+ {
+ load_standard_c64_cartridge(image);
+ }
+ else
+ {
+ if (!strcmp(cart_type, "vizawrite"))
+ load_vizawrite_cartridge(image);
+
+ else if (!strcmp(cart_type, "hugo"))
+ load_hugo_cartridge(image);
+
+ else if (!strcmp(cart_type, "easy_calc_result"))
+ load_easy_calc_result_cartridge(image);
+
+ else if (!strcmp(cart_type, "pagefox"))
+ load_pagefox_cartridge(image);
+
+ else if (!strcmp(cart_type, "multiscreen"))
+ /*
+
+ TODO: crashes on protection check after cartridge RAM test
+
+ 805A: lda $01
+ 805C: and #$FE
+ 805E: sta $01
+ 8060: m6502_brk#$00 <-- BOOM!
+
+ */
+ load_multiscreen_cartridge(image);
+
+ else if (!strcmp(cart_type, "simons_basic"))
+ load_simons_basic_cartridge(image);
+
+ else if (!strcmp(cart_type, "super_explode"))
+ load_super_explode_cartridge(image);
+
+ else
+ load_standard_c64_cartridge(image);
+ }
+}
+
+static DEVICE_IMAGE_LOAD( c64_cart )
+{
+ int result = IMAGE_INIT_PASS;
+
+ if (image.software_entry() != NULL)
+ {
+ c64_software_list_cartridge_load(image);
+ }
+ else
+ result = c64_crt_load(image);
+
+ return result;
+}
+
+static DEVICE_IMAGE_LOAD( max_cart )
+{
+ legacy_c64_state *state = image.device().machine().driver_data<legacy_c64_state>();
+ int result = IMAGE_INIT_PASS;
+
+ if (image.software_entry() != NULL)
+ {
+ UINT32 size;
+
+ // setup Ultimax mode
+ state->m_exrom = 1;
+ state->m_game = 0;
+
+ state->m_roml = state->m_c64_roml;
+ state->m_romh = state->m_c64_romh;
+
+ memset(state->m_roml, 0, 0x2000);
+ memset(state->m_romh, 0, 0x2000);
+
+ // is there anything to load at 0x8000?
+ size = image.get_software_region_length("roml");
+ if (size)
+ memcpy(state->m_roml, image.get_software_region("roml"), size);
+
+ // is there anything to load at 0xe000?
+ size = image.get_software_region_length("romh");
+ if (size)
+ memcpy(state->m_romh, image.get_software_region("romh"), size);
+ }
+ else
+ result = c64_crt_load(image);
+
+ return result;
+}
+
+
+/***************************************************************************
+ *.CRT CARTRIDGE HANDLING
+***************************************************************************/
+
+static WRITE8_HANDLER( fc3_bank_w )
+{
+ legacy_c64_state *state = space->machine().driver_data<legacy_c64_state>();
+ // Type # 3
+ // working:
+ // not working:
+
+ UINT8 bank = data & 0x3f;
+ UINT8 *cart = state->memregion("user1")->base();
+
+ if (data & 0x40)
+ {
+ if (bank > 3)
+ logerror("Warning: This cart type should have at most 4 banks and the cart looked for bank %d... Something strange is going on!\n", bank);
+ else
+ {
+ memcpy(state->m_roml, cart + bank * 0x4000, 0x2000);
+ memcpy(state->m_romh, cart + bank * 0x4000 + 0x2000, 0x2000);
+/*
+ if (log_cart)
+ {
+ logerror("bank %d of size %d successfully loaded at %d!\n", bank, state->m_cart.bank[bank].size, state->m_cart.bank[bank].addr);
+ if (state->m_cart.bank[bank].index != bank)
+ logerror("Warning: According to the CHIP info this should be bank %d, but we are loading it as bank %d!\n", state->m_cart.bank[bank].index, bank);
+ }
+*/
+ }
+ }
+}
+
+static WRITE8_HANDLER( ocean1_bank_w )
+{
+ legacy_c64_state *state = space->machine().driver_data<legacy_c64_state>();
+ // Type # 5
+ // working: Double Dragon, Ghostbusters, Terminator 2
+ // not working: Pang, Robocop 2, Toki
+
+ UINT8 bank = data & 0x3f;
+ UINT8 *cart = state->memregion("user1")->base();
+
+ switch (state->m_cart.bank[bank].addr)
+ {
+ case 0x8000:
+ memcpy(state->m_roml, cart + bank * 0x2000, state->m_cart.bank[bank].size);
+ break;
+ case 0xa000:
+ memcpy(state->m_roml + 0x2000, cart + bank * 0x2000, state->m_cart.bank[bank].size);
+ break;
+ case 0xe000:
+ memcpy(state->m_romh, cart + bank * 0x2000, state->m_cart.bank[bank].size);
+ break;
+ default:
+ logerror("Unexpected loading address (%x) for bank %x\n", state->m_cart.bank[bank].addr, bank);
+ break;
+ }
+/*
+ if (log_cart)
+ {
+ logerror("bank %d of size %d successfully loaded at %d!\n", bank, state->m_cart.bank[bank].size, state->m_cart.bank[bank].addr);
+ if (state->m_cart.bank[bank].index != bank)
+ logerror("Warning: According to the CHIP info this should be bank %d, but we are loading it as bank %d!\n", state->m_cart.bank[bank].index, bank);
+ }
+*/
+}
+
+static WRITE8_HANDLER( funplay_bank_w )
+{
+ legacy_c64_state *state = space->machine().driver_data<legacy_c64_state>();
+ // Type # 7
+ // working:
+ // not working:
+
+ UINT8 bank = data & 0x39, real_bank = 0;
+ UINT8 *cart = state->memregion("user1")->base();
+
+ /* This should be written after the bankswitch has happened. We log it to see if it is really working */
+ if (data == 0x86)
+ logerror("Reserved value written\n");
+ else
+ {
+ /* bank number is not the value written, but state->m_cart.bank[bank].index IS the value written! */
+ real_bank = ((bank & 0x01) << 3) + ((bank & 0x38) >> 3);
+
+ memcpy(state->m_roml, cart + real_bank * 0x2000, 0x2000);
+/*
+ if (log_cart)
+ {
+ logerror("bank %d of size %d successfully loaded at %d!\n", bank, state->m_cart.bank[bank].size, state->m_cart.bank[bank].addr);
+ if (state->m_cart.bank[bank].index != bank)
+ logerror("Warning: According to the CHIP info this should be bank %d, but we are loading it as bank %d!\n", state->m_cart.bank[bank].index, bank);
+ }
+*/
+ }
+}
+
+static WRITE8_HANDLER( supergames_bank_w )
+{
+ legacy_c64_state *state = space->machine().driver_data<legacy_c64_state>();
+ // Type # 8
+ // working:
+ // not working:
+
+ UINT8 bank = data & 0x03, bit2 = data & 0x04;
+ UINT8 *cart = state->memregion("user1")->base();
+
+ if (data & 0x04)
+ {
+ state->m_game = 0;
+ state->m_exrom = 0;
+ }
+ else
+ {
+ state->m_game = 0;
+ state->m_exrom = 0;
+ }
+
+ if (data == 0xc)
+ {
+ state->m_game = 1;
+ state->m_exrom = 1;
+ }
+
+ if (bit2)
+ {
+ memcpy(state->m_roml, cart + bank * 0x4000, 0x2000);
+ memcpy(state->m_romh, cart + bank * 0x4000 + 0x2000, 0x2000);
+ }
+ else
+ {
+ memcpy(state->m_roml, cart + bank * 0x4000, 0x2000);
+ memcpy(state->m_romh, cart + bank * 0x4000 + 0x2000, 0x2000);
+ }
+}
+
+static WRITE8_HANDLER( c64gs_bank_w )
+{
+ legacy_c64_state *state = space->machine().driver_data<legacy_c64_state>();
+ // Type # 15
+ // working:
+ // not working: The Last Ninja Remix
+
+ UINT8 bank = offset & 0xff;
+ UINT8 *cart = state->memregion("user1")->base();
+
+ if (bank > 0x3f)
+ logerror("Warning: This cart type should have at most 64 banks and the cart looked for bank %d... Something strange is going on!\n", bank);
+
+ memcpy(state->m_roml, cart + bank * 0x2000, 0x2000);
+/*
+ if (log_cart)
+ {
+ logerror("bank %d of size %d successfully loaded at %d!\n", bank, state->m_cart.bank[bank].size, state->m_cart.bank[bank].addr);
+ if (state->m_cart.bank[bank].index != bank)
+ logerror("Warning: According to the CHIP info this should be bank %d, but we are loading it as bank %d!\n", state->m_cart.bank[bank].index, bank);
+ }
+*/
+}
+
+static READ8_HANDLER( dinamic_bank_r )
+{
+ legacy_c64_state *state = space->machine().driver_data<legacy_c64_state>();
+ // Type # 17
+ // working: Satan
+ // not working:
+
+ UINT8 bank = offset & 0xff;
+ UINT8 *cart = state->memregion("user1")->base();
+
+ if (bank > 0xf)
+ logerror("Warning: This cart type should have 16 banks and the cart looked for bank %d... Something strange is going on!\n", bank);
+
+ memcpy(state->m_roml, cart + bank * 0x2000, 0x2000);
+/*
+ if (log_cart)
+ {
+ logerror("bank %d of size %d successfully loaded at %d!\n", bank, state->m_cart.bank[bank].size, state->m_cart.bank[bank].addr);
+ if (state->m_cart.bank[bank].index != bank)
+ logerror("Warning: According to the CHIP info this should be bank %d, but we are loading it as bank %d!\n", state->m_cart.bank[bank].index, bank);
+ }
+*/
+ return 0;
+}
+
+static READ8_HANDLER( zaxxon_bank_r )
+{
+ legacy_c64_state *state = space->machine().driver_data<legacy_c64_state>();
+ // Type # 18
+ // working:
+ // not working:
+
+ UINT8 bank;
+ UINT8 *cart = state->memregion("user1")->base();
+
+ if (offset < 0x1000)
+ bank = 0;
+ else
+ bank = 1;
+
+ // state->m_game = 0;
+ // state->m_exrom = 0;
+
+ memcpy(state->m_romh, cart + bank * 0x2000 + 0x1000, 0x2000);
+
+ return cart[offset & 0x0fff];
+}
+
+static WRITE8_HANDLER( domark_bank_w )
+{
+ legacy_c64_state *state = space->machine().driver_data<legacy_c64_state>();
+ // Type # 19
+ // working:
+ // not working:
+
+ UINT8 bank = data & 0x7f;
+ UINT8 *cart = state->memregion("user1")->base();
+
+ if (data & 0x80)
+ {
+ state->m_game = 1;
+ state->m_exrom = 1;
+ }
+ else
+ {
+ state->m_game = 1;
+ state->m_exrom = 0;
+ memcpy(state->m_roml, cart + bank * 0x2000, 0x2000);
+ }
+}
+
+static WRITE8_HANDLER( comal80_bank_w )
+{
+ legacy_c64_state *state = space->machine().driver_data<legacy_c64_state>();
+ // Type # 21
+ // working: Comal 80
+ // not working:
+
+ UINT8 bank = data & 0x83;
+ UINT8 *cart = state->memregion("user1")->base();
+
+ /* only valid values 0x80, 0x81, 0x82, 0x83 */
+ if (!(bank & 0x80))
+ logerror("Warning: we are writing an invalid bank value %d\n", bank);
+ else
+ {
+ bank &= 0x03;
+
+ memcpy(state->m_roml, cart + bank * 0x4000, 0x4000);
+/*
+ if (log_cart)
+ {
+ logerror("bank %d of size %d successfully loaded at %d!\n", bank, state->m_cart.bank[bank].size, state->m_cart.bank[bank].addr);
+ if (state->m_cart.bank[bank].index != bank)
+ logerror("Warning: According to the CHIP info this should be bank %d, but we are loading it as bank %d!\n", state->m_cart.bank[bank].index, bank);
+ }
+*/
+ }
+}
+
+static void setup_c64_custom_mappers(running_machine &machine)
+{
+ legacy_c64_state *state = machine.driver_data<legacy_c64_state>();
+ address_space *space = machine.device( "maincpu")->memory().space( AS_PROGRAM );
+
+ switch (state->m_cart.mapper)
+ {
+ case ACTION_REPLAY: /* Type # 1 not working */
+ break;
+ case KCS_PC: /* Type # 2 not working */
+ break;
+ case FINAL_CART_III: /* Type # 3 not working - 4 16k banks, loaded at 0x8000, banks chosen by writing to 0xdfff */
+ space->install_legacy_write_handler( 0xdfff, 0xdfff, FUNC(fc3_bank_w) );
+ break;
+ case SIMONS_BASIC: /* Type # 4 not working */
+ break;
+ case OCEAN_1: /* Type # 5 - up to 64 8k banks, loaded at 0x8000 or 0xa000, banks chosen by writing to 0xde00 */
+ space->install_legacy_write_handler( 0xde00, 0xde00, FUNC(ocean1_bank_w) );
+ break;
+ case EXPERT: /* Type # 6 not working */
+ break;
+ case FUN_PLAY: /* Type # 7 - 16 8k banks, loaded at 0x8000, banks chosen by writing to 0xde00 */
+ space->install_legacy_write_handler( 0xde00, 0xde00, FUNC(funplay_bank_w) );
+ break;
+ case SUPER_GAMES: /* Type # 8 not working */
+ space->install_legacy_write_handler( 0xdf00, 0xdf00, FUNC(supergames_bank_w) );
+ break;
+ case ATOMIC_POWER: /* Type # 9 not working */
+ break;
+ case EPYX_FASTLOAD: /* Type # 10 not working */
+ break;
+ case WESTERMANN: /* Type # 11 not working */
+ break;
+ case REX: /* Type # 12 working */
+ break;
+ case FINAL_CART_I: /* Type # 13 not working */
+ break;
+ case MAGIC_FORMEL: /* Type # 14 not working */
+ break;
+ case C64GS: /* Type # 15 - up to 64 8k banks, loaded at 0x8000, banks chosen by writing to 0xde00 + bank */
+ space->install_legacy_write_handler( 0xde00, 0xdeff, FUNC(c64gs_bank_w) );
+ break;
+ case DINAMIC: /* Type # 17 - 16 8k banks, loaded at 0x8000, banks chosen by reading to 0xde00 + bank */
+ space->install_legacy_read_handler( 0xde00, 0xdeff, FUNC(dinamic_bank_r) );
+ break;
+ case ZAXXON: /* Type # 18 */
+ space->install_legacy_read_handler( 0x8000, 0x9fff, FUNC(zaxxon_bank_r) );
+ break;
+ case DOMARK: /* Type # 19 */
+ space->install_legacy_write_handler( 0xde00, 0xde00, FUNC(domark_bank_w) );
+ break;
+ case SUPER_SNAP_5: /* Type # 20 not working */
+ break;
+ case COMAL_80: /* Type # 21 - 4 16k banks, loaded at 0x8000, banks chosen by writing to 0xde00 */
+ space->install_legacy_write_handler( 0xde00, 0xde00, FUNC(comal80_bank_w) );
+ break;
+ case GENERIC_CRT: /* Type # 0 - single bank, no bankswitch, loaded at start with correct size and place */
+ default:
+ break;
+ }
+}
+
+
+MACHINE_RESET( c64 )
+{
+ legacy_c64_state *state = machine.driver_data<legacy_c64_state>();
+ if (state->m_cart.n_banks)
+ setup_c64_custom_mappers(machine);
+}
+
+
+MACHINE_CONFIG_FRAGMENT( c64_cartslot )
+ MCFG_CARTSLOT_ADD("cart1")
+ MCFG_CARTSLOT_EXTENSION_LIST("crt,80")
+ MCFG_CARTSLOT_NOT_MANDATORY
+ MCFG_CARTSLOT_INTERFACE("c64_cart")
+ MCFG_CARTSLOT_START(c64_cart)
+ MCFG_CARTSLOT_LOAD(c64_cart)
+ MCFG_CARTSLOT_UNLOAD(c64_cart)
+
+ MCFG_CARTSLOT_ADD("cart2")
+ MCFG_CARTSLOT_EXTENSION_LIST("crt,80")
+ MCFG_CARTSLOT_NOT_MANDATORY
+ MCFG_CARTSLOT_START(c64_cart)
+ MCFG_CARTSLOT_LOAD(c64_cart)
+ MCFG_CARTSLOT_UNLOAD(c64_cart)
+
+ MCFG_SOFTWARE_LIST_ADD("cart_list_c64", "c64_cart")
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_FRAGMENT( ultimax_cartslot )
+ MCFG_CARTSLOT_ADD("cart")
+ MCFG_CARTSLOT_EXTENSION_LIST("crt,e0,f0")
+ MCFG_CARTSLOT_MANDATORY
+ MCFG_CARTSLOT_INTERFACE("ultimax_cart")
+ MCFG_CARTSLOT_START(c64_cart)
+ MCFG_CARTSLOT_LOAD(max_cart)
+ MCFG_CARTSLOT_UNLOAD(c64_cart)
+
+ /* software lists */
+ MCFG_SOFTWARE_LIST_ADD("cart_list","max")
+MACHINE_CONFIG_END
diff --git a/src/mess/machine/c64_16kb.c b/src/mess/machine/c64_16kb.c
new file mode 100644
index 00000000000..b8945ef8b25
--- /dev/null
+++ b/src/mess/machine/c64_16kb.c
@@ -0,0 +1,149 @@
+/**********************************************************************
+
+ Commodore 64 16KB EPROM cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_16kb.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_16KB = &device_creator<c64_16kb_cartridge_device>;
+
+
+//-------------------------------------------------
+// ROM( c64_16kb )
+//-------------------------------------------------
+
+ROM_START( c64_16kb )
+ ROM_REGION( 0x2000, "roml", 0 )
+ ROM_CART_LOAD( "roml", 0x0000, 0x2000, ROM_MIRROR )
+
+ ROM_REGION( 0x2000, "romh", 0 )
+ ROM_CART_LOAD( "romh", 0x0000, 0x2000, ROM_MIRROR )
+ROM_END
+
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *c64_16kb_cartridge_device::device_rom_region() const
+{
+ return ROM_NAME( c64_16kb );
+}
+
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( c64_16kb )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( c64_16kb )
+ MCFG_CARTSLOT_ADD("roml")
+ MCFG_CARTSLOT_EXTENSION_LIST("rom,bin,80")
+
+ MCFG_CARTSLOT_ADD("romh")
+ MCFG_CARTSLOT_EXTENSION_LIST("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),
+ device_c64_expansion_card_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void c64_16kb_cartridge_device::device_start()
+{
+ m_roml = memregion("roml")->base();
+ m_romh = memregion("romh")->base();
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void c64_16kb_cartridge_device::device_reset()
+{
+ UINT8 mode = device().ioport("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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ if (!roml)
+ {
+ data = m_roml[offset & 0x1fff];
+ }
+ else if (!romh)
+ {
+ data = m_romh[offset & 0x1fff];
+ }
+
+ return data;
+}
diff --git a/src/mess/machine/c64_16kb.h b/src/mess/machine/c64_16kb.h
new file mode 100644
index 00000000000..7b68a740bac
--- /dev/null
+++ b/src/mess/machine/c64_16kb.h
@@ -0,0 +1,56 @@
+/**********************************************************************
+
+ Commodore 64 16KB EPROM cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __C64_16KB__
+#define __C64_16KB__
+
+
+#include "emu.h"
+#include "imagedev/cartslot.h"
+#include "machine/c64exp.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 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_config_complete() { m_shortname = "c64_16kb"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+};
+
+
+// device type definition
+extern const device_type C64_16KB;
+
+
+
+#endif
diff --git a/src/mess/machine/c64_4cga.c b/src/mess/machine/c64_4cga.c
new file mode 100644
index 00000000000..f43ae513aa9
--- /dev/null
+++ b/src/mess/machine/c64_4cga.c
@@ -0,0 +1,112 @@
+/**********************************************************************
+
+ Classical Games/Protovision 4 Player Interface emulation
+
+ http://www.protovision-online.com/hardw/4_player.htm
+ http://hitmen.c02.at/html/hardware.html
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_4cga.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_4CGA = &device_creator<c64_4cga_device>;
+
+
+static INPUT_PORTS_START( c64_4player )
+ PORT_START("JOY3")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(1)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(1)
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(1)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(1)
+ PORT_BIT( 0xf0, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("JOY4")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(2)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(2)
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(2)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(2)
+ PORT_BIT( 0xf0, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("FIRE")
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2)
+ PORT_BIT( 0xcf, 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),
+ device_c64_user_port_interface(mconfig, *this),
+ m_port(0)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void c64_4cga_device::device_start()
+{
+ // state saving
+ save_item(NAME(m_port));
+}
+
+
+//-------------------------------------------------
+// c64_pb_r - port B read
+//-------------------------------------------------
+
+UINT8 c64_4cga_device::c64_pb_r(address_space &space, offs_t offset)
+{
+ UINT8 data = ioport("FIRE")->read();
+
+ if (m_port)
+ {
+ data &= ioport("JOY3")->read();
+ }
+ else
+ {
+ data &= ioport("JOY4")->read();
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// c64_pb_w - port B write
+//-------------------------------------------------
+
+void c64_4cga_device::c64_pb_w(address_space &space, offs_t offset, UINT8 data)
+{
+ m_port = BIT(data, 7);
+}
diff --git a/src/mess/machine/c64_4cga.h b/src/mess/machine/c64_4cga.h
new file mode 100644
index 00000000000..6732ac44ff8
--- /dev/null
+++ b/src/mess/machine/c64_4cga.h
@@ -0,0 +1,55 @@
+/**********************************************************************
+
+ Classical Games/Protovision 4 Player Interface emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __C64_4CGA__
+#define __C64_4CGA__
+
+
+#include "emu.h"
+#include "machine/c64user.h"
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> c64_4cga_device
+
+class c64_4cga_device : public device_t,
+ public device_c64_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;
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "c64_4cga"; }
+ virtual void device_start();
+
+ // device_c64_user_port_interface overrides
+ virtual UINT8 c64_pb_r(address_space &space, offs_t offset);
+ virtual void c64_pb_w(address_space &space, offs_t offset, UINT8 data);
+
+private:
+ int m_port;
+};
+
+
+// device type definition
+extern const device_type C64_4CGA;
+
+
+#endif
diff --git a/src/mess/machine/c64_4dxh.c b/src/mess/machine/c64_4dxh.c
new file mode 100644
index 00000000000..0c8900d3a08
--- /dev/null
+++ b/src/mess/machine/c64_4dxh.c
@@ -0,0 +1,109 @@
+/**********************************************************************
+
+ The Digital Excess & Hitmen 4-Player Joystick adapter emulation
+
+ http://hitmen.c02.at/html/hardware.html
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_4dxh.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_4DXH = &device_creator<c64_4dxh_device>;
+
+
+INPUT_CHANGED_MEMBER( c64_4dxh_device::fire4 )
+{
+ m_slot->sp2_w(newval);
+}
+
+static INPUT_PORTS_START( c64_4player )
+ PORT_START("SP2")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_CHANGED_MEMBER(DEVICE_SELF, c64_4dxh_device, fire4, 0)
+
+ PORT_START("PB")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(1)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(1)
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(1)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(1)
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(2)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(2)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(2)
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(2)
+
+ PORT_START("PA2")
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1)
+INPUT_PORTS_END
+
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+ioport_constructor c64_4dxh_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( c64_4player );
+}
+
+
+
+//**************************************************************************
+// 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),
+ device_c64_user_port_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void c64_4dxh_device::device_start()
+{
+}
+
+
+//-------------------------------------------------
+// c64_pb_r - port B read
+//-------------------------------------------------
+
+UINT8 c64_4dxh_device::c64_pb_r(address_space &space, offs_t offset)
+{
+ return ioport("PB")->read();
+}
+
+
+//-------------------------------------------------
+// c64_pb_w - port B write
+//-------------------------------------------------
+
+int c64_4dxh_device::c64_pa2_r()
+{
+ return BIT(ioport("PA2")->read(), 0);
+}
+
+
+//-------------------------------------------------
+// c64_cnt1_w - CNT 1 write
+//-------------------------------------------------
+
+void c64_4dxh_device::c64_cnt1_w(int level)
+{
+ m_slot->cnt2_w(level);
+}
diff --git a/src/mess/machine/c64_4dxh.h b/src/mess/machine/c64_4dxh.h
new file mode 100644
index 00000000000..4cb35313229
--- /dev/null
+++ b/src/mess/machine/c64_4dxh.h
@@ -0,0 +1,55 @@
+/**********************************************************************
+
+ The Digital Excess & Hitmen 4-Player Joystick adapter emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __C64_4DXH__
+#define __C64_4DXH__
+
+
+#include "emu.h"
+#include "machine/c64user.h"
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> c64_4dxh_device
+
+class c64_4dxh_device : public device_t,
+ public device_c64_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;
+
+ DECLARE_INPUT_CHANGED_MEMBER( fire4 );
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "c64_4dxh"; }
+ virtual void device_start();
+
+ // device_c64_user_port_interface overrides
+ virtual UINT8 c64_pb_r(address_space &space, offs_t offset);
+ virtual int c64_pa2_r();
+ virtual void c64_cnt1_w(int level);
+};
+
+
+// device type definition
+extern const device_type C64_4DXH;
+
+
+#endif
diff --git a/src/mess/machine/c64_4ksa.c b/src/mess/machine/c64_4ksa.c
new file mode 100644
index 00000000000..437ffb9c45a
--- /dev/null
+++ b/src/mess/machine/c64_4ksa.c
@@ -0,0 +1,109 @@
+/**********************************************************************
+
+ Kingsoft 4-Player Adapter emulation
+
+ http://hitmen.c02.at/html/hardware.html
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_4ksa.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_4KSA = &device_creator<c64_4ksa_device>;
+
+
+INPUT_CHANGED_MEMBER( c64_4ksa_device::fire4 )
+{
+ m_slot->sp2_w(newval);
+}
+
+static INPUT_PORTS_START( c64_4player )
+ PORT_START("SP2")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_CHANGED_MEMBER(DEVICE_SELF, c64_4ksa_device, fire4, 0)
+
+ PORT_START("PB")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(2)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(2)
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(2)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(2)
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(1)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(1)
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(1)
+
+ PORT_START("PA2")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(1)
+INPUT_PORTS_END
+
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+ioport_constructor c64_4ksa_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( c64_4player );
+}
+
+
+
+//**************************************************************************
+// 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),
+ device_c64_user_port_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void c64_4ksa_device::device_start()
+{
+}
+
+
+//-------------------------------------------------
+// c64_pb_r - port B read
+//-------------------------------------------------
+
+UINT8 c64_4ksa_device::c64_pb_r(address_space &space, offs_t offset)
+{
+ return ioport("PB")->read();
+}
+
+
+//-------------------------------------------------
+// c64_pb_w - port B write
+//-------------------------------------------------
+
+int c64_4ksa_device::c64_pa2_r()
+{
+ return BIT(ioport("PA2")->read(), 0);
+}
+
+
+//-------------------------------------------------
+// c64_cnt1_w - CNT 1 write
+//-------------------------------------------------
+
+void c64_4ksa_device::c64_cnt1_w(int level)
+{
+ m_slot->cnt2_w(level);
+}
diff --git a/src/mess/machine/c64_4ksa.h b/src/mess/machine/c64_4ksa.h
new file mode 100644
index 00000000000..443e0057ca9
--- /dev/null
+++ b/src/mess/machine/c64_4ksa.h
@@ -0,0 +1,55 @@
+/**********************************************************************
+
+ Kingsoft 4-Player Adapter emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __C64_4KSA__
+#define __C64_4KSA__
+
+
+#include "emu.h"
+#include "machine/c64user.h"
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> c64_4ksa_device
+
+class c64_4ksa_device : public device_t,
+ public device_c64_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;
+
+ DECLARE_INPUT_CHANGED_MEMBER( fire4 );
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "c64_4ksa"; }
+ virtual void device_start();
+
+ // device_c64_user_port_interface overrides
+ virtual UINT8 c64_pb_r(address_space &space, offs_t offset);
+ virtual int c64_pa2_r();
+ virtual void c64_cnt1_w(int level);
+};
+
+
+// device type definition
+extern const device_type C64_4KSA;
+
+
+#endif
diff --git a/src/mess/machine/c64_4tba.c b/src/mess/machine/c64_4tba.c
new file mode 100644
index 00000000000..3e65c272bbd
--- /dev/null
+++ b/src/mess/machine/c64_4tba.c
@@ -0,0 +1,109 @@
+/**********************************************************************
+
+ Starbyte Software Tie Break Adaptor emulation
+
+ http://hitmen.c02.at/html/hardware.html
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_4tba.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_4TBA = &device_creator<c64_4tba_device>;
+
+
+INPUT_CHANGED_MEMBER( c64_4tba_device::fire3 )
+{
+ m_slot->sp2_w(newval);
+}
+
+static INPUT_PORTS_START( c64_4player )
+ PORT_START("SP2")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_CHANGED_MEMBER(DEVICE_SELF, c64_4tba_device, fire3, 0)
+
+ PORT_START("PB")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(1)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(1)
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(1)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(1)
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(2)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(2)
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(2)
+
+ PORT_START("PA2")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(2)
+INPUT_PORTS_END
+
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+ioport_constructor c64_4tba_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( c64_4player );
+}
+
+
+
+//**************************************************************************
+// 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),
+ device_c64_user_port_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void c64_4tba_device::device_start()
+{
+}
+
+
+//-------------------------------------------------
+// c64_pb_r - port B read
+//-------------------------------------------------
+
+UINT8 c64_4tba_device::c64_pb_r(address_space &space, offs_t offset)
+{
+ return ioport("PB")->read();
+}
+
+
+//-------------------------------------------------
+// c64_pb_w - port B write
+//-------------------------------------------------
+
+int c64_4tba_device::c64_pa2_r()
+{
+ return BIT(ioport("PA2")->read(), 0);
+}
+
+
+//-------------------------------------------------
+// c64_cnt1_w - CNT 1 write
+//-------------------------------------------------
+
+void c64_4tba_device::c64_cnt1_w(int level)
+{
+ m_slot->cnt2_w(level);
+}
diff --git a/src/mess/machine/c64_4tba.h b/src/mess/machine/c64_4tba.h
new file mode 100644
index 00000000000..6de5a8f4053
--- /dev/null
+++ b/src/mess/machine/c64_4tba.h
@@ -0,0 +1,55 @@
+/**********************************************************************
+
+ Starbyte Software Tie Break Adaptor emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __C64_4TBA__
+#define __C64_4TBA__
+
+
+#include "emu.h"
+#include "machine/c64user.h"
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> c64_4tba_device
+
+class c64_4tba_device : public device_t,
+ public device_c64_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;
+
+ DECLARE_INPUT_CHANGED_MEMBER( fire3 );
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "c64_4tba"; }
+ virtual void device_start();
+
+ // device_c64_user_port_interface overrides
+ virtual UINT8 c64_pb_r(address_space &space, offs_t offset);
+ virtual int c64_pa2_r();
+ virtual void c64_cnt1_w(int level);
+};
+
+
+// device type definition
+extern const device_type C64_4TBA;
+
+
+#endif
diff --git a/src/mess/machine/c64_bn1541.c b/src/mess/machine/c64_bn1541.c
new file mode 100644
index 00000000000..cfbba72d027
--- /dev/null
+++ b/src/mess/machine/c64_bn1541.c
@@ -0,0 +1,160 @@
+/**********************************************************************
+
+ SpeedDOS / Burst Nibbler 1541/1571 Parallel Cable emulation
+
+ http://sta.c64.org/cbmparc2.html
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_bn1541.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LOG 0
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_BN1541 = &device_creator<c64_bn1541_device>;
+
+
+
+//**************************************************************************
+// 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),
+ device_c64_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);
+
+ m_parallel_data = data;
+}
+
+
+//-------------------------------------------------
+// parallel_strobe_w -
+//-------------------------------------------------
+
+void c64_bn1541_device::parallel_strobe_w(int state)
+{
+ if (LOG) logerror("1541 parallel strobe %u\n", state);
+
+ m_slot->flag2_w(state);
+}
+
+
+//-------------------------------------------------
+// c64_pb_r - port B read
+//-------------------------------------------------
+
+UINT8 c64_bn1541_device::c64_pb_r(address_space &space, offs_t offset)
+{
+ return m_parallel_data;
+}
+
+
+//-------------------------------------------------
+// c64_pb_w - port B write
+//-------------------------------------------------
+
+void c64_bn1541_device::c64_pb_w(address_space &space, offs_t offset, UINT8 data)
+{
+ if (LOG) logerror("C64 parallel data %02x\n", data);
+
+ if (m_other != NULL)
+ {
+ m_other->parallel_data_w(data);
+ }
+}
+
+
+//-------------------------------------------------
+// c64_pc2_w - CIA2 PC write
+//-------------------------------------------------
+
+void c64_bn1541_device::c64_pc2_w(int state)
+{
+ if (LOG) logerror("C64 parallel strobe %u\n", state);
+
+ if (m_other != NULL)
+ {
+ m_other->parallel_strobe_w(state);
+ }
+}
diff --git a/src/mess/machine/c64_bn1541.h b/src/mess/machine/c64_bn1541.h
new file mode 100644
index 00000000000..bceaa6122ca
--- /dev/null
+++ b/src/mess/machine/c64_bn1541.h
@@ -0,0 +1,74 @@
+/**********************************************************************
+
+ SpeedDOS / Burst Nibbler 1541/1571 Parallel Cable emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __C64_BN1541__
+#define __C64_BN1541__
+
+
+#include "emu.h"
+#include "machine/c64user.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_c64_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_config_complete() { m_shortname = "c64_bn1541"; }
+ virtual void device_start();
+
+ // device_c64_user_port_interface overrides
+ virtual UINT8 c64_pb_r(address_space &space, offs_t offset);
+ virtual void c64_pb_w(address_space &space, offs_t offset, UINT8 data);
+ virtual void c64_pc2_w(int level);
+
+ // device_c64_floppy_parallel_interface overrides
+ virtual void parallel_data_w(UINT8 data);
+ virtual void parallel_strobe_w(int state);
+};
+
+
+// device type definition
+extern const device_type C64_BN1541;
+
+
+#endif
diff --git a/src/mess/machine/c64_comal80.c b/src/mess/machine/c64_comal80.c
new file mode 100644
index 00000000000..74c1f3b437e
--- /dev/null
+++ b/src/mess/machine/c64_comal80.c
@@ -0,0 +1,89 @@
+/**********************************************************************
+
+ COMAL 80 cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_comal80.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_COMAL80 = &device_creator<c64_comal80_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ 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 ba, int roml, int romh, int io1, int io2)
+{
+ if (!io1)
+ {
+ if (BIT(data, 7))
+ {
+ m_bank = data & 0x03;
+ }
+ }
+}
diff --git a/src/mess/machine/c64_comal80.h b/src/mess/machine/c64_comal80.h
new file mode 100644
index 00000000000..c61bfce950e
--- /dev/null
+++ b/src/mess/machine/c64_comal80.h
@@ -0,0 +1,53 @@
+/**********************************************************************
+
+ COMAL 80 cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __COMAL80__
+#define __COMAL80__
+
+
+#include "emu.h"
+#include "machine/c64exp.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();
+ virtual void device_config_complete() { m_shortname = "c64_comal80"; }
+
+ // device_c64_expansion_card_interface overrides
+ virtual UINT8 c64_cd_r(address_space &space, offs_t offset, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, 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/mess/machine/c64_cpm.c b/src/mess/machine/c64_cpm.c
new file mode 100644
index 00000000000..4885893ebb6
--- /dev/null
+++ b/src/mess/machine/c64_cpm.c
@@ -0,0 +1,231 @@
+/**********************************************************************
+
+ Commodore 64 CP/M cartridge emulation
+
+ http://www.baltissen.org/newhtm/c64_cpm.htm
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ TODO:
+
+ - Z80 clock speed
+
+*/
+
+#include "c64_cpm.h"
+
+
+
+//**************************************************************************
+// MACROS/CONSTANTS
+//**************************************************************************
+
+#define Z80_TAG "z80"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_CPM = &device_creator<c64_cpm_cartridge_device>;
+
+
+//-------------------------------------------------
+// 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)
+ {
+ device_set_input_line(m_maincpu, INPUT_LINE_HALT, CLEAR_LINE);
+ device_set_input_line(machine().firstcpu, INPUT_LINE_HALT, ASSERT_LINE);
+
+ if (m_reset)
+ {
+ m_maincpu->reset();
+ m_maincpu->set_state(Z80_PC, 0);
+ m_reset = 0;
+ }
+ }
+ else
+ {
+ device_set_input_line(m_maincpu, INPUT_LINE_HALT, ASSERT_LINE);
+ device_set_input_line(machine().firstcpu, INPUT_LINE_HALT, 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),
+ 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 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 ba, int rw, int hiram)
+{
+ 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(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(addr, data);
+ }
+}
diff --git a/src/mess/machine/c64_cpm.h b/src/mess/machine/c64_cpm.h
new file mode 100644
index 00000000000..923bc434c59
--- /dev/null
+++ b/src/mess/machine/c64_cpm.h
@@ -0,0 +1,69 @@
+/**********************************************************************
+
+ Commodore 64 CP/M cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __CPM__
+#define __CPM__
+
+#define ADDRESS_MAP_MODERN
+
+#include "emu.h"
+#include "cpu/z80/z80.h"
+#include "machine/c64exp.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();
+ virtual void device_config_complete() { m_shortname = "c64_cpm"; }
+
+ // device_c64_expansion_card_interface overrides
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int ba, int roml, int romh, int io1, int io2);
+ virtual int c64_game_r(offs_t offset, int ba, int rw, int hiram);
+
+private:
+ inline void update_signals();
+
+ required_device<cpu_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/mess/machine/c64_currah_speech.c b/src/mess/machine/c64_currah_speech.c
new file mode 100644
index 00000000000..ef3a9ed883f
--- /dev/null
+++ b/src/mess/machine/c64_currah_speech.c
@@ -0,0 +1,271 @@
+/**********************************************************************
+
+ Currah Speech 64 cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+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 "c64_currah_speech.h"
+
+
+
+//**************************************************************************
+// MACROS/CONSTANTS
+//**************************************************************************
+
+#define SP0256_TAG "sp0256"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_CURRAH_SPEECH = &device_creator<c64_currah_speech_cartridge_device>;
+
+
+//-------------------------------------------------
+// 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 );
+}
+
+
+//-------------------------------------------------
+// sp0256_interface sp0256_intf
+//-------------------------------------------------
+
+static sp0256_interface sp0256_intf =
+{
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// 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_CONFIG(sp0256_intf)
+ 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
+ sp0256_set_clock(m_nsp, 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),
+ 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ if (!romh)
+ {
+ data = m_romh[offset & 0x1fff];
+ }
+ else if (!io1)
+ {
+ /*
+
+ bit description
+
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7 SBY
+
+ */
+
+ data = sp0256_sby_r(m_nsp) << 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 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);
+
+ sp0256_ALD_w(m_nsp, 0, data & 0x3f);
+ }
+}
diff --git a/src/mess/machine/c64_currah_speech.h b/src/mess/machine/c64_currah_speech.h
new file mode 100644
index 00000000000..2be0299b624
--- /dev/null
+++ b/src/mess/machine/c64_currah_speech.h
@@ -0,0 +1,60 @@
+/**********************************************************************
+
+ Currah Speech 64 cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __CURRAH_SPEECH_64__
+#define __CURRAH_SPEECH_64__
+
+
+#include "emu.h"
+#include "machine/c64exp.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_config_complete() { m_shortname = "c64_cs"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int ba, int roml, int romh, int io1, int io2);
+
+private:
+ inline void set_osc1(int voice, int intonation);
+
+ required_device<device_t> m_nsp;
+};
+
+
+// device type definition
+extern const device_type C64_CURRAH_SPEECH;
+
+
+#endif
diff --git a/src/mess/machine/c64_dela_ep256.c b/src/mess/machine/c64_dela_ep256.c
new file mode 100644
index 00000000000..76966889aa4
--- /dev/null
+++ b/src/mess/machine/c64_dela_ep256.c
@@ -0,0 +1,179 @@
+/**********************************************************************
+
+ Dela 256KB EPROM cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_dela_ep256.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_DELA_EP256 = &device_creator<c64_dela_ep256_cartridge_device>;
+
+
+//-------------------------------------------------
+// ROM( c64_dela_ep256 )
+//-------------------------------------------------
+
+ROM_START( c64_dela_ep256 )
+ ROM_REGION( 0x40000, "rom", 0 )
+ ROM_CART_LOAD( "rom1", 0x00000, 0x08000, ROM_MIRROR )
+ ROM_CART_LOAD( "rom2", 0x08000, 0x08000, ROM_MIRROR )
+ ROM_CART_LOAD( "rom3", 0x10000, 0x08000, ROM_MIRROR )
+ ROM_CART_LOAD( "rom4", 0x18000, 0x08000, ROM_MIRROR )
+ ROM_CART_LOAD( "rom5", 0x20000, 0x08000, ROM_MIRROR )
+ ROM_CART_LOAD( "rom6", 0x28000, 0x08000, ROM_MIRROR )
+ ROM_CART_LOAD( "rom7", 0x30000, 0x08000, ROM_MIRROR )
+ ROM_CART_LOAD( "rom8", 0x38000, 0x08000, ROM_MIRROR )
+ROM_END
+
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *c64_dela_ep256_cartridge_device::device_rom_region() const
+{
+ return ROM_NAME( c64_dela_ep256 );
+}
+
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( c64_dela_ep256 )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( c64_dela_ep256 )
+ MCFG_CARTSLOT_ADD("rom1")
+ MCFG_CARTSLOT_EXTENSION_LIST("rom,bin")
+ MCFG_CARTSLOT_ADD("rom2")
+ MCFG_CARTSLOT_EXTENSION_LIST("rom,bin")
+ MCFG_CARTSLOT_ADD("rom3")
+ MCFG_CARTSLOT_EXTENSION_LIST("rom,bin")
+ MCFG_CARTSLOT_ADD("rom4")
+ MCFG_CARTSLOT_EXTENSION_LIST("rom,bin")
+ MCFG_CARTSLOT_ADD("rom5")
+ MCFG_CARTSLOT_EXTENSION_LIST("rom,bin")
+ MCFG_CARTSLOT_ADD("rom6")
+ MCFG_CARTSLOT_EXTENSION_LIST("rom,bin")
+ MCFG_CARTSLOT_ADD("rom7")
+ MCFG_CARTSLOT_EXTENSION_LIST("rom,bin")
+ MCFG_CARTSLOT_ADD("rom8")
+ MCFG_CARTSLOT_EXTENSION_LIST("rom,bin")
+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),
+ device_c64_expansion_card_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void c64_dela_ep256_cartridge_device::device_start()
+{
+ m_rom = memregion("rom")->base();
+
+ // state saving
+ save_item(NAME(m_bank));
+ save_item(NAME(m_reset));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void c64_dela_ep256_cartridge_device::device_reset()
+{
+ m_reset = 1;
+ m_bank = 0;
+ m_exrom = 0;
+}
+
+
+//-------------------------------------------------
+// c64_cd_r - cartridge data read
+//-------------------------------------------------
+
+UINT8 c64_dela_ep256_cartridge_device::c64_cd_r(address_space &space, offs_t offset, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ if (!roml)
+ {
+ if (m_reset)
+ {
+ data = m_roml[offset & 0x1fff];
+ }
+ else
+ {
+ offs_t addr = (m_bank << 13) | (offset & 0x1fff);
+ data = m_rom[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 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_bank = ((data & 0x07) << 2) | ((data >> 4) & 0x03);
+
+ m_exrom = BIT(data, 7);
+ }
+}
diff --git a/src/mess/machine/c64_dela_ep256.h b/src/mess/machine/c64_dela_ep256.h
new file mode 100644
index 00000000000..878162278f8
--- /dev/null
+++ b/src/mess/machine/c64_dela_ep256.h
@@ -0,0 +1,62 @@
+/**********************************************************************
+
+ Dela 256KB EPROM cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __DELA_EP256__
+#define __DELA_EP256__
+
+
+#include "emu.h"
+#include "imagedev/cartslot.h"
+#include "machine/c64exp.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 const rom_entry *device_rom_region() const;
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "delep256"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int ba, int roml, int romh, int io1, int io2);
+
+private:
+ UINT8 *m_rom;
+
+ UINT8 m_bank;
+ int m_reset;
+};
+
+
+// device type definition
+extern const device_type C64_DELA_EP256;
+
+
+
+#endif
diff --git a/src/mess/machine/c64_dela_ep64.c b/src/mess/machine/c64_dela_ep64.c
new file mode 100644
index 00000000000..61202d6eb92
--- /dev/null
+++ b/src/mess/machine/c64_dela_ep64.c
@@ -0,0 +1,170 @@
+/**********************************************************************
+
+ Dela 64KB EPROM cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_dela_ep64.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_DELA_EP64 = &device_creator<c64_dela_ep64_cartridge_device>;
+
+
+//-------------------------------------------------
+// ROM( c64_dela_ep64 )
+//-------------------------------------------------
+
+ROM_START( c64_dela_ep64 )
+ ROM_REGION( 0x10000, "rom", 0 )
+ ROM_CART_LOAD( "rom1", 0x0000, 0x08000, ROM_MIRROR )
+ ROM_CART_LOAD( "rom2", 0x8000, 0x08000, ROM_MIRROR )
+ROM_END
+
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *c64_dela_ep64_cartridge_device::device_rom_region() const
+{
+ return ROM_NAME( c64_dela_ep64 );
+}
+
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( c64_dela_ep64 )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( c64_dela_ep64 )
+ MCFG_CARTSLOT_ADD("rom1")
+ MCFG_CARTSLOT_EXTENSION_LIST("rom,bin")
+ MCFG_CARTSLOT_ADD("rom2")
+ MCFG_CARTSLOT_EXTENSION_LIST("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),
+ device_c64_expansion_card_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void c64_dela_ep64_cartridge_device::device_start()
+{
+ m_rom = memregion("rom")->base();
+
+ // 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ 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_rom[0x0000 + addr];
+ if (!m_rom2_ce) data |= m_rom[0x8000 + 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 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/mess/machine/c64_dela_ep64.h b/src/mess/machine/c64_dela_ep64.h
new file mode 100644
index 00000000000..a1b5f806c22
--- /dev/null
+++ b/src/mess/machine/c64_dela_ep64.h
@@ -0,0 +1,65 @@
+/**********************************************************************
+
+ Dela 64KB EPROM cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __DELA_EP64__
+#define __DELA_EP64__
+
+
+#include "emu.h"
+#include "imagedev/cartslot.h"
+#include "machine/c64exp.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 const rom_entry *device_rom_region() const;
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "c64_dela_ep64"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int ba, int roml, int romh, int io1, int io2);
+
+private:
+ UINT8 *m_rom;
+
+ 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/mess/machine/c64_dela_ep7x8.c b/src/mess/machine/c64_dela_ep7x8.c
new file mode 100644
index 00000000000..30e6c10fa32
--- /dev/null
+++ b/src/mess/machine/c64_dela_ep7x8.c
@@ -0,0 +1,157 @@
+/**********************************************************************
+
+ Dela 7x8K EPROM cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_dela_ep7x8.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_DELA_EP7X8 = &device_creator<c64_dela_ep7x8_cartridge_device>;
+
+
+//-------------------------------------------------
+// ROM( c64_dela_ep7x8 )
+//-------------------------------------------------
+
+ROM_START( c64_dela_ep7x8 )
+ ROM_REGION( 0x10000, "rom", 0 )
+ ROM_CART_LOAD( "rom1", 0x2000, 0x2000, ROM_MIRROR )
+ ROM_CART_LOAD( "rom2", 0x4000, 0x2000, ROM_MIRROR )
+ ROM_CART_LOAD( "rom3", 0x6000, 0x2000, ROM_MIRROR )
+ ROM_CART_LOAD( "rom4", 0x8000, 0x2000, ROM_MIRROR )
+ ROM_CART_LOAD( "rom5", 0xa000, 0x2000, ROM_MIRROR )
+ ROM_CART_LOAD( "rom6", 0xc000, 0x2000, ROM_MIRROR )
+ ROM_CART_LOAD( "rom7", 0xe000, 0x2000, ROM_MIRROR )
+ROM_END
+
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *c64_dela_ep7x8_cartridge_device::device_rom_region() const
+{
+ return ROM_NAME( c64_dela_ep7x8 );
+}
+
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( c64_dela_ep7x8 )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( c64_dela_ep7x8 )
+ MCFG_CARTSLOT_ADD("rom1")
+ MCFG_CARTSLOT_EXTENSION_LIST("rom,bin")
+ MCFG_CARTSLOT_ADD("rom2")
+ MCFG_CARTSLOT_EXTENSION_LIST("rom,bin")
+ MCFG_CARTSLOT_ADD("rom3")
+ MCFG_CARTSLOT_EXTENSION_LIST("rom,bin")
+ MCFG_CARTSLOT_ADD("rom4")
+ MCFG_CARTSLOT_EXTENSION_LIST("rom,bin")
+ MCFG_CARTSLOT_ADD("rom5")
+ MCFG_CARTSLOT_EXTENSION_LIST("rom,bin")
+ MCFG_CARTSLOT_ADD("rom6")
+ MCFG_CARTSLOT_EXTENSION_LIST("rom,bin")
+ MCFG_CARTSLOT_ADD("rom7")
+ MCFG_CARTSLOT_EXTENSION_LIST("rom,bin")
+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),
+ device_c64_expansion_card_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void c64_dela_ep7x8_cartridge_device::device_start()
+{
+ m_rom = memregion("rom")->base();
+
+ // 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ if (!roml)
+ {
+ offs_t addr = offset & 0x1fff;
+
+ if (!BIT(m_bank, 0)) data |= m_roml[addr];
+ if (!BIT(m_bank, 1)) data |= m_rom[0x2000 + addr];
+ if (!BIT(m_bank, 2)) data |= m_rom[0x4000 + addr];
+ if (!BIT(m_bank, 3)) data |= m_rom[0x6000 + addr];
+ if (!BIT(m_bank, 4)) data |= m_rom[0x8000 + addr];
+ if (!BIT(m_bank, 5)) data |= m_rom[0xa000 + addr];
+ if (!BIT(m_bank, 6)) data |= m_rom[0xc000 + addr];
+ if (!BIT(m_bank, 7)) data |= m_rom[0xe000 + 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 ba, int roml, int romh, int io1, int io2)
+{
+ if (!io1)
+ {
+ m_bank = data;
+
+ m_exrom = (data == 0xff);
+ }
+}
diff --git a/src/mess/machine/c64_dela_ep7x8.h b/src/mess/machine/c64_dela_ep7x8.h
new file mode 100644
index 00000000000..0799d630a2a
--- /dev/null
+++ b/src/mess/machine/c64_dela_ep7x8.h
@@ -0,0 +1,61 @@
+/**********************************************************************
+
+ Dela 7x8K EPROM cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __DELA_EP7X8__
+#define __DELA_EP7X8__
+
+
+#include "emu.h"
+#include "imagedev/cartslot.h"
+#include "machine/c64exp.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 const rom_entry *device_rom_region() const;
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "ep7x8"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int ba, int roml, int romh, int io1, int io2);
+
+private:
+ UINT8 *m_rom;
+
+ UINT8 m_bank;
+};
+
+
+// device type definition
+extern const device_type C64_DELA_EP7X8;
+
+
+
+#endif
diff --git a/src/mess/machine/c64_dinamic.c b/src/mess/machine/c64_dinamic.c
new file mode 100644
index 00000000000..3da700c5ffc
--- /dev/null
+++ b/src/mess/machine/c64_dinamic.c
@@ -0,0 +1,77 @@
+/**********************************************************************
+
+ Dinamic Software cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_dinamic.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_DINAMIC = &device_creator<c64_dinamic_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ 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/mess/machine/c64_dinamic.h b/src/mess/machine/c64_dinamic.h
new file mode 100644
index 00000000000..d35fdb3ee12
--- /dev/null
+++ b/src/mess/machine/c64_dinamic.h
@@ -0,0 +1,52 @@
+/**********************************************************************
+
+ Dinamic Software cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __DINAMIC__
+#define __DINAMIC__
+
+
+#include "emu.h"
+#include "machine/c64exp.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();
+ virtual void device_config_complete() { m_shortname = "c64_dinamic"; }
+
+ // device_c64_expansion_card_interface overrides
+ virtual UINT8 c64_cd_r(address_space &space, offs_t offset, 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/mess/machine/c64_dqbb.c b/src/mess/machine/c64_dqbb.c
new file mode 100644
index 00000000000..caa59fb425f
--- /dev/null
+++ b/src/mess/machine/c64_dqbb.c
@@ -0,0 +1,124 @@
+/**********************************************************************
+
+ Brown Boxes Double Quick Brown Box emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ TODO:
+
+ - 64/128 mode switch
+ - dump of the initial NVRAM contents
+
+*/
+
+#include "c64_dqbb.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_DQBB = &device_creator<c64_dqbb_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ 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
+ c64_nvram_pointer(machine(), 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ 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 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/mess/machine/c64_dqbb.h b/src/mess/machine/c64_dqbb.h
new file mode 100644
index 00000000000..fdaea3e82dd
--- /dev/null
+++ b/src/mess/machine/c64_dqbb.h
@@ -0,0 +1,61 @@
+/**********************************************************************
+
+ Brown Boxes Double Quick Brown Box emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __DQBB__
+#define __DQBB__
+
+
+#include "emu.h"
+#include "machine/c64exp.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();
+ virtual void device_config_complete() { m_shortname = "c64_dqbb"; }
+
+ // 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_size); } }
+ virtual void nvram_write(emu_file &file) { if (m_nvram != NULL) { file.write(m_nvram, m_nvram_size); } }
+
+ // device_c64_expansion_card_interface overrides
+ virtual UINT8 c64_cd_r(address_space &space, offs_t offset, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, 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/mess/machine/c64_easy_calc_result.c b/src/mess/machine/c64_easy_calc_result.c
new file mode 100644
index 00000000000..d5856a4ca90
--- /dev/null
+++ b/src/mess/machine/c64_easy_calc_result.c
@@ -0,0 +1,110 @@
+/**********************************************************************
+
+ Easy Calc Result cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ PCB Layout
+ ----------
+
+ |===========================|
+ |=| |
+ |=| ROM0 LS73 |
+ |=| |
+ |=| |
+ |=| |
+ |=| |
+ |=| ROM1 LS00 |
+ |=| |
+ |===========================|
+
+ ROM0 - Hitachi HN61364P 8Kx8 EPROM "CR2001"
+ ROM1 - Hitachi HN613128P 16Kx8 EPROM "CR3001"
+
+*/
+
+#include "c64_easy_calc_result.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_EASY_CALC_RESULT = &device_creator<c64_easy_calc_result_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ 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 ba, int roml, int romh, int io1, int io2)
+{
+ if (!io1)
+ {
+ m_bank = !BIT(offset, 0);
+ }
+}
diff --git a/src/mess/machine/c64_easy_calc_result.h b/src/mess/machine/c64_easy_calc_result.h
new file mode 100644
index 00000000000..93b6631da9d
--- /dev/null
+++ b/src/mess/machine/c64_easy_calc_result.h
@@ -0,0 +1,53 @@
+/**********************************************************************
+
+ Easy Calc Result cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __EASY_CALC_RESULT__
+#define __EASY_CALC_RESULT__
+
+
+#include "emu.h"
+#include "machine/c64exp.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();
+ virtual void device_config_complete() { m_shortname = "c64_easy_calc_result"; }
+
+ // device_c64_expansion_card_interface overrides
+ virtual UINT8 c64_cd_r(address_space &space, offs_t offset, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, 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/mess/machine/c64_easyflash.c b/src/mess/machine/c64_easyflash.c
new file mode 100644
index 00000000000..b73d6e0c864
--- /dev/null
+++ b/src/mess/machine/c64_easyflash.c
@@ -0,0 +1,239 @@
+/**********************************************************************
+
+ EasyFlash cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_easyflash.h"
+
+
+//**************************************************************************
+// MACROS/CONSTANTS
+//**************************************************************************
+
+#define AM29F040_0_TAG "u3"
+#define AM29F040_1_TAG "u4"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_EASYFLASH = &device_creator<c64_easyflash_cartridge_device>;
+
+
+//-------------------------------------------------
+// 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 )
+//-------------------------------------------------
+
+INPUT_CHANGED_MEMBER( c64_easyflash_cartridge_device::reset )
+{
+ if (!newval)
+ {
+ device_reset();
+ }
+
+ m_slot->reset_w(newval ? CLEAR_LINE : ASSERT_LINE);
+}
+
+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_LOW, IPT_SPECIAL ) PORT_NAME("Reset") PORT_CHANGED_MEMBER(DEVICE_SELF, c64_easyflash_cartridge_device, reset, 0)
+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),
+ device_c64_expansion_card_interface(mconfig, *this),
+ m_flash_roml(*this, AM29F040_0_TAG),
+ m_flash_romh(*this, AM29F040_1_TAG),
+ m_bank(0),
+ m_mode(0)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void c64_easyflash_cartridge_device::device_start()
+{
+ // allocate memory
+ c64_ram_pointer(machine(), 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ 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 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 ba, int rw, int hiram)
+{
+ return !BIT(m_mode, 1);
+}
+
+
+//-------------------------------------------------
+// c64_game_r - GAME read
+//-------------------------------------------------
+
+int c64_easyflash_cartridge_device::c64_game_r(offs_t offset, int ba, int rw, int hiram)
+{
+ return !(BIT(m_mode, 0) | !(BIT(m_mode, 2) | device().ioport("JP1")->read()));
+}
diff --git a/src/mess/machine/c64_easyflash.h b/src/mess/machine/c64_easyflash.h
new file mode 100644
index 00000000000..7ec6958a35a
--- /dev/null
+++ b/src/mess/machine/c64_easyflash.h
@@ -0,0 +1,66 @@
+/**********************************************************************
+
+ EasyFlash cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __EASYFLASH__
+#define __EASYFLASH__
+
+
+#include "emu.h"
+#include "machine/c64exp.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;
+
+ DECLARE_INPUT_CHANGED_MEMBER( reset );
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "c64_easyflash"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int ba, int roml, int romh, int io1, int io2);
+ virtual int c64_exrom_r(offs_t offset, int ba, int rw, int hiram);
+ virtual int c64_game_r(offs_t offset, int ba, int rw, int hiram);
+
+private:
+ required_device<amd_29f040_device> m_flash_roml;
+ required_device<amd_29f040_device> m_flash_romh;
+
+ UINT8 m_bank;
+ UINT8 m_mode;
+};
+
+
+// device type definition
+extern const device_type C64_EASYFLASH;
+
+
+#endif
diff --git a/src/mess/machine/c64_epyx_fast_load.c b/src/mess/machine/c64_epyx_fast_load.c
new file mode 100644
index 00000000000..b27126536f6
--- /dev/null
+++ b/src/mess/machine/c64_epyx_fast_load.c
@@ -0,0 +1,119 @@
+/**********************************************************************
+
+ Epyx Fast Load cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_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<c64_epyx_fast_load_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ 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 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/mess/machine/c64_epyx_fast_load.h b/src/mess/machine/c64_epyx_fast_load.h
new file mode 100644
index 00000000000..7818481432b
--- /dev/null
+++ b/src/mess/machine/c64_epyx_fast_load.h
@@ -0,0 +1,54 @@
+/**********************************************************************
+
+ Epyx Fast Load cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __EPYX_FAST_LOAD__
+#define __EPYX_FAST_LOAD__
+
+
+#include "emu.h"
+#include "machine/c64exp.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_config_complete() { m_shortname = "c64_epyx_fast_load"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, 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/mess/machine/c64_exos.c b/src/mess/machine/c64_exos.c
new file mode 100644
index 00000000000..c287f235752
--- /dev/null
+++ b/src/mess/machine/c64_exos.c
@@ -0,0 +1,70 @@
+/**********************************************************************
+
+ Rex ExOS cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_exos.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_EXOS = &device_creator<c64_exos_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ 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 ba, int rw, int hiram)
+{
+ return !(ba & rw & ((offset & 0xe000) == 0xe000) & hiram);
+}
diff --git a/src/mess/machine/c64_exos.h b/src/mess/machine/c64_exos.h
new file mode 100644
index 00000000000..eaaa46be427
--- /dev/null
+++ b/src/mess/machine/c64_exos.h
@@ -0,0 +1,49 @@
+/**********************************************************************
+
+ Rex ExOS cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __EXOS__
+#define __EXOS__
+
+
+#include "emu.h"
+#include "machine/c64exp.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_config_complete() { m_shortname = "c64_exos"; }
+ virtual void device_start();
+
+ // device_c64_expansion_card_interface overrides
+ virtual UINT8 c64_cd_r(address_space &space, offs_t offset, int ba, int roml, int romh, int io1, int io2);
+ virtual int c64_game_r(offs_t offset, int ba, int rw, int hiram);
+};
+
+
+// device type definition
+extern const device_type C64_EXOS;
+
+
+#endif
diff --git a/src/mess/machine/c64_final.c b/src/mess/machine/c64_final.c
new file mode 100644
index 00000000000..26d104576d6
--- /dev/null
+++ b/src/mess/machine/c64_final.c
@@ -0,0 +1,138 @@
+/**********************************************************************
+
+ Final Cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_final.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_FINAL = &device_creator<c64_final_cartridge_device>;
+
+
+INPUT_CHANGED_MEMBER( c64_final_cartridge_device::reset )
+{
+ if (!newval)
+ {
+ device_reset();
+ }
+
+ m_slot->reset_w(newval ? CLEAR_LINE : ASSERT_LINE);
+}
+
+INPUT_CHANGED_MEMBER( c64_final_cartridge_device::freeze )
+{
+ if (!newval)
+ {
+ m_game = 0;
+ }
+
+ m_slot->nmi_w(newval ? CLEAR_LINE : ASSERT_LINE);
+}
+
+static INPUT_PORTS_START( c64_final )
+ PORT_START("SW")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Reset") PORT_CODE(KEYCODE_F11) PORT_CHANGED_MEMBER(DEVICE_SELF, c64_final_cartridge_device, reset, 0)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) 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),
+ 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ 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 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/mess/machine/c64_final.h b/src/mess/machine/c64_final.h
new file mode 100644
index 00000000000..e419bfabfd4
--- /dev/null
+++ b/src/mess/machine/c64_final.h
@@ -0,0 +1,56 @@
+/**********************************************************************
+
+ Final Cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __FINAL__
+#define __FINAL__
+
+
+#include "emu.h"
+#include "machine/c64exp.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( reset );
+ DECLARE_INPUT_CHANGED_MEMBER( freeze );
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "c64_final"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int ba, int roml, int romh, int io1, int io2);
+};
+
+
+// device type definition
+extern const device_type C64_FINAL;
+
+
+#endif
diff --git a/src/mess/machine/c64_final3.c b/src/mess/machine/c64_final3.c
new file mode 100644
index 00000000000..5a0398d1358
--- /dev/null
+++ b/src/mess/machine/c64_final3.c
@@ -0,0 +1,154 @@
+/**********************************************************************
+
+ Final Cartridge III emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_final3.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_FINAL3 = &device_creator<c64_final3_cartridge_device>;
+
+
+INPUT_CHANGED_MEMBER( c64_final3_cartridge_device::reset )
+{
+ if (!newval)
+ {
+ device_reset();
+ }
+
+ m_slot->reset_w(newval ? CLEAR_LINE : ASSERT_LINE);
+}
+
+INPUT_CHANGED_MEMBER( c64_final3_cartridge_device::freeze )
+{
+ if (!newval)
+ {
+ m_game = 0;
+ m_hidden = 0;
+ }
+
+ m_slot->nmi_w(newval ? CLEAR_LINE : ASSERT_LINE);
+}
+
+static INPUT_PORTS_START( c64_final3 )
+ PORT_START("SW")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Reset") PORT_CODE(KEYCODE_F11) PORT_CHANGED_MEMBER(DEVICE_SELF, c64_final3_cartridge_device, reset, 0)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) 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),
+ 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ 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 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/mess/machine/c64_final3.h b/src/mess/machine/c64_final3.h
new file mode 100644
index 00000000000..9cb3bedd487
--- /dev/null
+++ b/src/mess/machine/c64_final3.h
@@ -0,0 +1,60 @@
+/**********************************************************************
+
+ Final Cartridge III emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __FINAL3__
+#define __FINAL3__
+
+
+#include "emu.h"
+#include "machine/c64exp.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( reset );
+ DECLARE_INPUT_CHANGED_MEMBER( freeze );
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "c64_final3"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, 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/mess/machine/c64_fun_play.c b/src/mess/machine/c64_fun_play.c
new file mode 100644
index 00000000000..1adf36f7252
--- /dev/null
+++ b/src/mess/machine/c64_fun_play.c
@@ -0,0 +1,101 @@
+/**********************************************************************
+
+ Fun Play / Power Play cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_fun_play.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_FUN_PLAY = &device_creator<c64_fun_play_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ 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 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/mess/machine/c64_fun_play.h b/src/mess/machine/c64_fun_play.h
new file mode 100644
index 00000000000..5a2701bbcf6
--- /dev/null
+++ b/src/mess/machine/c64_fun_play.h
@@ -0,0 +1,53 @@
+/**********************************************************************
+
+ Fun Play / Power Play cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __FUN_PLAY__
+#define __FUN_PLAY__
+
+
+#include "emu.h"
+#include "machine/c64exp.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_config_complete() { m_shortname = "c64_fun_play"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, 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/mess/machine/c64_geocable.c b/src/mess/machine/c64_geocable.c
new file mode 100644
index 00000000000..ba7e1e3f643
--- /dev/null
+++ b/src/mess/machine/c64_geocable.c
@@ -0,0 +1,109 @@
+/**********************************************************************
+
+ geoCable Centronics Cable emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_geocable.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define CENTRONICS_TAG "centronics"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_GEOCABLE = &device_creator<c64_geocable_device>;
+
+
+//-------------------------------------------------
+// centronics_interface centronics_intf
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( c64_geocable_device::busy_w )
+{
+ m_slot->flag2_w(state);
+}
+
+static const centronics_interface centronics_intf =
+{
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF, c64_geocable_device, busy_w),
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( c64_geocable )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( c64_geocable )
+ MCFG_CENTRONICS_PRINTER_ADD(CENTRONICS_TAG, centronics_intf)
+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),
+ device_c64_user_port_interface(mconfig, *this),
+ m_centronics(*this, CENTRONICS_TAG)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void c64_geocable_device::device_start()
+{
+}
+
+
+//-------------------------------------------------
+// c64_pb_w - port B write
+//-------------------------------------------------
+
+void c64_geocable_device::c64_pb_w(address_space &space, offs_t offset, UINT8 data)
+{
+ m_centronics->write(space, 0, data);
+}
+
+
+//-------------------------------------------------
+// c64_pb_w - port B write
+//-------------------------------------------------
+
+void c64_geocable_device::c64_pa2_w(int level)
+{
+ m_centronics->strobe_w(level);
+}
diff --git a/src/mess/machine/c64_geocable.h b/src/mess/machine/c64_geocable.h
new file mode 100644
index 00000000000..675de868690
--- /dev/null
+++ b/src/mess/machine/c64_geocable.h
@@ -0,0 +1,59 @@
+/**********************************************************************
+
+ geoCable Centronics Cable emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __C64_GEOCABLE__
+#define __C64_GEOCABLE__
+
+
+#include "emu.h"
+#include "machine/c64user.h"
+#include "machine/ctronics.h"
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> c64_geocable_device
+
+class c64_geocable_device : public device_t,
+ public device_c64_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;
+
+ // not really public
+ DECLARE_WRITE_LINE_MEMBER( busy_w );
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "c64_geocable"; }
+ virtual void device_start();
+
+ // device_c64_user_port_interface overrides
+ virtual void c64_pb_w(address_space &space, offs_t offset, UINT8 data);
+ virtual void c64_pa2_w(int level);
+
+private:
+ required_device<centronics_device> m_centronics;
+};
+
+
+// device type definition
+extern const device_type C64_GEOCABLE;
+
+
+#endif
diff --git a/src/mess/machine/c64_georam.c b/src/mess/machine/c64_georam.c
new file mode 100644
index 00000000000..34d7bd016b7
--- /dev/null
+++ b/src/mess/machine/c64_georam.c
@@ -0,0 +1,101 @@
+/**********************************************************************
+
+ Berkeley Softworks GeoRAM emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_georam.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_GEORAM = &device_creator<c64_georam_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ device_c64_expansion_card_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void c64_georam_cartridge_device::device_start()
+{
+ // allocate memory
+ c64_ram_pointer(machine(), 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ 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 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/mess/machine/c64_georam.h b/src/mess/machine/c64_georam.h
new file mode 100644
index 00000000000..0a758e3acf1
--- /dev/null
+++ b/src/mess/machine/c64_georam.h
@@ -0,0 +1,53 @@
+/**********************************************************************
+
+ Berkeley Softworks GeoRAM emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __GEORAM__
+#define __GEORAM__
+
+
+#include "emu.h"
+#include "machine/c64exp.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_config_complete() { m_shortname = "c64_georam"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int ba, int roml, int romh, int io1, int io2);
+
+private:
+ UINT16 m_bank;
+};
+
+
+// device type definition
+extern const device_type C64_GEORAM;
+
+
+#endif
diff --git a/src/mess/machine/c64_ide64.c b/src/mess/machine/c64_ide64.c
new file mode 100644
index 00000000000..81d53642fc2
--- /dev/null
+++ b/src/mess/machine/c64_ide64.c
@@ -0,0 +1,325 @@
+/**********************************************************************
+
+ IDE64 v4.1 cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ TODO:
+
+ - fast loader does not work with 1541
+ - graphics corruption during Ultimax mode (VIC issue?)
+ - IDE unknown command (E8)
+ - FT245 USB
+ - CompactFlash slot
+ - ShortBus (ETH64, DUART, DigiMAX, ETFE)
+ - clock port (ETH64 II, RR-Net, SilverSurfer, MP3@64)
+
+*/
+
+#include "c64_ide64.h"
+
+
+
+//**************************************************************************
+// MACROS/CONSTANTS
+//**************************************************************************
+
+#define AT29C010A_TAG "u3"
+#define DS1302_TAG "u4"
+#define FT245R_TAG "u21"
+#define IDE_TAG "ide"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_IDE64 = &device_creator<c64_ide64_cartridge_device>;
+
+
+//-------------------------------------------------
+// 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_IDE_CONTROLLER_ADD(IDE_TAG, NULL, ide_image_devices, "hdd", "hdd", 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),
+ device_c64_expansion_card_interface(mconfig, *this),
+ m_flash_rom(*this, AT29C010A_TAG),
+ m_rtc(*this, DS1302_TAG),
+ m_ide(*this, IDE_TAG)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void c64_ide64_cartridge_device::device_start()
+{
+ // allocate memory
+ c64_ram_pointer(machine(), 0x8000);
+
+ // state saving
+ save_item(NAME(m_bank));
+ save_item(NAME(m_ide_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 = ioport("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, int ba, int roml, int romh, int io1, int io2)
+{
+ if (!m_enable) return 0;
+
+ UINT8 data = 0;
+ int rom_oe = 1, ram_oe = 1;
+
+ if (!m_game && m_exrom && 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)
+ {
+ // 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 < 0x30)
+ {
+ m_ide_data = ide_bus_r(m_ide, BIT(offset, 3), offset & 0x07);
+
+ data = m_ide_data & 0xff;
+ }
+ else if (io1_offset == 0x31)
+ {
+ data = m_ide_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 = 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 ba, int roml, int romh, int io1, int io2)
+{
+ if (!m_enable) return;
+
+ if (!m_game && m_exrom && ba)
+ {
+ 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 < 0x30)
+ {
+ m_ide_data = (m_ide_data & 0xff00) | data;
+
+ ide_bus_w(m_ide, BIT(offset, 3), offset & 0x07, m_ide_data);
+ }
+ else if (io1_offset == 0x31)
+ {
+ m_ide_data = (data << 8) | (m_ide_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);
+ }
+ }
+}
diff --git a/src/mess/machine/c64_ide64.h b/src/mess/machine/c64_ide64.h
new file mode 100644
index 00000000000..9fd4b052c16
--- /dev/null
+++ b/src/mess/machine/c64_ide64.h
@@ -0,0 +1,68 @@
+/**********************************************************************
+
+ IDE64 v4.1 cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __IDE64__
+#define __IDE64__
+
+
+#include "emu.h"
+#include "machine/c64exp.h"
+#include "machine/ds1302.h"
+#include "machine/idectrl.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_config_complete() { m_shortname = "c64_ide64"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int ba, int roml, int romh, int io1, int io2);
+
+private:
+ required_device<atmel_29c010_device> m_flash_rom;
+ required_device<ds1302_device> m_rtc;
+ required_device<device_t> m_ide;
+
+ UINT8 m_bank;
+ UINT16 m_ide_data;
+ int m_wp;
+ int m_enable;
+};
+
+
+// device type definition
+extern const device_type C64_IDE64;
+
+
+#endif
diff --git a/src/mess/machine/c64_ieee488.c b/src/mess/machine/c64_ieee488.c
new file mode 100644
index 00000000000..9013c44a040
--- /dev/null
+++ b/src/mess/machine/c64_ieee488.c
@@ -0,0 +1,322 @@
+/**********************************************************************
+
+ Commodore IEEE-488 cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_ieee488.h"
+
+
+
+//**************************************************************************
+// MACROS/CONSTANTS
+//**************************************************************************
+
+#define MOS6525_TAG "u3"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_IEEE488 = &device_creator<c64_ieee488_device>;
+
+
+//-------------------------------------------------
+// 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, 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);
+}
+
+static const tpi6525_interface tpi_intf =
+{
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c64_ieee488_device, tpi_pa_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c64_ieee488_device, tpi_pa_w),
+ DEVCB_DEVICE_MEMBER(IEEE488_TAG, ieee488_device, dio_r),
+ DEVCB_DEVICE_MEMBER(IEEE488_TAG, ieee488_device, dio_w),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c64_ieee488_device, tpi_pc_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c64_ieee488_device, tpi_pc_w),
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// IEEE488_INTERFACE( ieee488_intf )
+//-------------------------------------------------
+
+static IEEE488_INTERFACE( ieee488_intf )
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// C64_EXPANSION_INTERFACE( expansion_intf )
+//-------------------------------------------------
+
+READ8_MEMBER( c64_ieee488_device::dma_cd_r )
+{
+ return m_slot->dma_cd_r(offset);
+}
+
+WRITE8_MEMBER( c64_ieee488_device::dma_cd_w )
+{
+ m_slot->dma_cd_w(offset, data);
+}
+
+WRITE_LINE_MEMBER( c64_ieee488_device::irq_w )
+{
+ m_slot->irq_w(state);
+}
+
+WRITE_LINE_MEMBER( c64_ieee488_device::nmi_w )
+{
+ m_slot->nmi_w(state);
+}
+
+WRITE_LINE_MEMBER( c64_ieee488_device::dma_w )
+{
+ m_slot->dma_w(state);
+}
+
+WRITE_LINE_MEMBER( c64_ieee488_device::reset_w )
+{
+ m_slot->reset_w(state);
+}
+
+static C64_EXPANSION_INTERFACE( expansion_intf )
+{
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c64_ieee488_device, dma_cd_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c64_ieee488_device, dma_cd_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, c64_ieee488_device, irq_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, c64_ieee488_device, nmi_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, c64_ieee488_device, dma_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, c64_ieee488_device, reset_w)
+};
+
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( c64_ieee488 )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( c64_ieee488 )
+ MCFG_TPI6525_ADD(MOS6525_TAG, tpi_intf)
+ MCFG_CBM_IEEE488_ADD(ieee488_intf, NULL)
+ MCFG_C64_EXPANSION_SLOT_ADD(C64_EXPANSION_SLOT_TAG, 0, expansion_intf, c64_expansion_cards, NULL, NULL)
+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),
+ 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = m_exp->cd_r(space, offset, ba, roml, romh, io1, io2);
+
+ if (!roml)
+ {
+ if (m_roml_sel)
+ {
+ data = m_roml[offset & 0xfff];
+ }
+ }
+ else if (!io2)
+ {
+ data |= tpi6525_r(m_tpi, 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 ba, int roml, int romh, int io1, int io2)
+{
+ if (!io2)
+ {
+ tpi6525_w(m_tpi, offset & 0x07, data);
+ }
+
+ m_exp->cd_w(space, offset, data, ba, roml, romh, io1, io2);
+}
+
+
+//-------------------------------------------------
+// c64_game_r - GAME read
+//-------------------------------------------------
+
+int c64_ieee488_device::c64_game_r(offs_t offset, int ba, int rw, int hiram)
+{
+ return m_exp->game_r(offset, ba, rw, hiram);
+}
diff --git a/src/mess/machine/c64_ieee488.h b/src/mess/machine/c64_ieee488.h
new file mode 100644
index 00000000000..386d918e2c3
--- /dev/null
+++ b/src/mess/machine/c64_ieee488.h
@@ -0,0 +1,78 @@
+/**********************************************************************
+
+ Commodore IEEE-488 cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __C64_IEEE488__
+#define __C64_IEEE488__
+
+
+#include "emu.h"
+#include "machine/6525tpi.h"
+#include "machine/c64exp.h"
+#include "machine/cbmipt.h"
+#include "machine/ieee488.h"
+#include "video/mc6845.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 );
+ DECLARE_READ8_MEMBER( dma_cd_r );
+ DECLARE_WRITE8_MEMBER( dma_cd_w );
+ DECLARE_WRITE_LINE_MEMBER( irq_w );
+ DECLARE_WRITE_LINE_MEMBER( nmi_w );
+ DECLARE_WRITE_LINE_MEMBER( dma_w );
+ DECLARE_WRITE_LINE_MEMBER( reset_w );
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "c64_ieee488"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int ba, int roml, int romh, int io1, int io2);
+ virtual int c64_game_r(offs_t offset, int ba, int rw, int hiram);
+
+private:
+ required_device<device_t> m_tpi;
+ required_device<ieee488_device> m_bus;
+ required_device<c64_expansion_slot_device> m_exp;
+
+ int m_roml_sel;
+};
+
+
+
+// device type definition
+extern const device_type C64_IEEE488;
+
+
+#endif
diff --git a/src/mess/machine/c64_kingsoft.c b/src/mess/machine/c64_kingsoft.c
new file mode 100644
index 00000000000..4c17578e38e
--- /dev/null
+++ b/src/mess/machine/c64_kingsoft.c
@@ -0,0 +1,101 @@
+/**********************************************************************
+
+ Kingsoft cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_kingsoft.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_KINGSOFT = &device_creator<c64_kingsoft_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ 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 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 ba, int rw, int hiram)
+{
+ return m_exrom & !(ba & rw & ((offset >= 0x8000 && offset < 0xc000) || (offset >= 0xe000)));
+}
diff --git a/src/mess/machine/c64_kingsoft.h b/src/mess/machine/c64_kingsoft.h
new file mode 100644
index 00000000000..9bc86380803
--- /dev/null
+++ b/src/mess/machine/c64_kingsoft.h
@@ -0,0 +1,51 @@
+/**********************************************************************
+
+ Kingsoft cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __KINGSOFT__
+#define __KINGSOFT__
+
+
+#include "emu.h"
+#include "machine/c64exp.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_config_complete() { m_shortname = "c64_kingsoft"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int ba, int roml, int romh, int io1, int io2);
+ virtual int c64_game_r(offs_t offset, int ba, int rw, int hiram);
+};
+
+
+// device type definition
+extern const device_type C64_KINGSOFT;
+
+
+#endif
diff --git a/src/mess/machine/c64_mach5.c b/src/mess/machine/c64_mach5.c
new file mode 100644
index 00000000000..df3601b8258
--- /dev/null
+++ b/src/mess/machine/c64_mach5.c
@@ -0,0 +1,87 @@
+/**********************************************************************
+
+ Access Software MACH 5 cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_mach5.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_MACH5 = &device_creator<c64_mach5_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ device_c64_expansion_card_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// 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_exrom = 0;
+}
+
+
+//-------------------------------------------------
+// c64_cd_r - cartridge data read
+//-------------------------------------------------
+
+UINT8 c64_mach5_cartridge_device::c64_cd_r(address_space &space, offs_t offset, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ if (!roml || !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 ba, int roml, int romh, int io1, int io2)
+{
+ if (!io1)
+ {
+ m_exrom = 0;
+ }
+ else if (!io2)
+ {
+ m_exrom = 1;
+ }
+}
diff --git a/src/mess/machine/c64_mach5.h b/src/mess/machine/c64_mach5.h
new file mode 100644
index 00000000000..1339d40977b
--- /dev/null
+++ b/src/mess/machine/c64_mach5.h
@@ -0,0 +1,50 @@
+/**********************************************************************
+
+ Cinemaware Warp Speed cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __MACH5__
+#define __MACH5__
+
+
+#include "emu.h"
+#include "machine/c64exp.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);
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "c64_mach5"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int ba, int roml, int romh, int io1, int io2);
+};
+
+
+// device type definition
+extern const device_type C64_MACH5;
+
+
+#endif
diff --git a/src/mess/machine/c64_magic_desk.c b/src/mess/machine/c64_magic_desk.c
new file mode 100644
index 00000000000..e7cbad1e052
--- /dev/null
+++ b/src/mess/machine/c64_magic_desk.c
@@ -0,0 +1,88 @@
+/**********************************************************************
+
+ Magic Desk cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_magic_desk.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_MAGIC_DESK = &device_creator<c64_magic_desk_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ 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 ba, int roml, int romh, int io1, int io2)
+{
+ if (!io1)
+ {
+ m_exrom = BIT(data, 7);
+
+ m_bank = data & 0x3f;
+ }
+}
diff --git a/src/mess/machine/c64_magic_desk.h b/src/mess/machine/c64_magic_desk.h
new file mode 100644
index 00000000000..1ba1754e8ef
--- /dev/null
+++ b/src/mess/machine/c64_magic_desk.h
@@ -0,0 +1,53 @@
+/**********************************************************************
+
+ Magic Desk cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __MAGIC_DESK__
+#define __MAGIC_DESK__
+
+
+#include "emu.h"
+#include "machine/c64exp.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_config_complete() { m_shortname = "c64_magic_desk"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, 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/mess/machine/c64_magic_formel.c b/src/mess/machine/c64_magic_formel.c
new file mode 100644
index 00000000000..cb6c78ed5b8
--- /dev/null
+++ b/src/mess/machine/c64_magic_formel.c
@@ -0,0 +1,277 @@
+/**********************************************************************
+
+ Magic Formel cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_magic_formel.h"
+
+
+
+//**************************************************************************
+// MACROS/CONSTANTS
+//**************************************************************************
+
+#define MC6821_TAG "mc6821"
+
+#define PA4 (m_pb7_ff ? m_ram_oe : 0)
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_MAGIC_FORMEL = &device_creator<c64_magic_formel_cartridge_device>;
+
+
+//-------------------------------------------------
+// pia6821_interface pia_intf
+//-------------------------------------------------
+
+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
+
+ */
+
+ logerror("PA %02x\n",data);
+ m_rom_bank = data & 0x0f;
+
+ m_rom_oe = BIT(data, 3);
+
+ 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
+ PB6
+ PB7 ROMH enable
+
+ */
+ logerror("PB %02x\n",data);
+ m_ram_bank = data & 0x1f;
+
+ m_pb7 = BIT(data, 7);
+
+ if (!m_pb7)
+ {
+ m_pb7_ff = 1;
+ }
+}
+
+WRITE_LINE_MEMBER( c64_magic_formel_cartridge_device::pia_cb2_w )
+{
+ if (!state)
+ {
+ m_cb2_ff = 1;
+ }
+}
+
+static const pia6821_interface pia_intf =
+{
+ DEVCB_NULL, // input A
+ DEVCB_NULL, // input B
+ DEVCB_NULL, // input CA1
+ DEVCB_NULL, // input CB1
+ DEVCB_NULL, // input CA2
+ DEVCB_NULL, // input CB2
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c64_magic_formel_cartridge_device, pia_pa_w), // output A
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c64_magic_formel_cartridge_device, pia_pb_w), // output B
+ DEVCB_NULL, // output CA2
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, c64_magic_formel_cartridge_device, pia_cb2_w), // output CB2
+ DEVCB_NULL, // irq A
+ DEVCB_NULL // irq B
+};
+
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( c64_magic_formel )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( c64_magic_formel )
+ MCFG_PIA6821_ADD(MC6821_TAG, pia_intf)
+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_PORTS( c64_magic_formel )
+//-------------------------------------------------
+
+INPUT_CHANGED_MEMBER( c64_magic_formel_cartridge_device::freeze )
+{
+ if (!newval && (m_pb7_ff & m_cb2_ff))
+ {
+ m_cb2_ff = 0;
+
+ m_slot->nmi_w(ASSERT_LINE);
+ }
+ else
+ {
+ m_slot->nmi_w(CLEAR_LINE);
+ }
+}
+
+static INPUT_PORTS_START( c64_magic_formel )
+ PORT_START("FREEZE")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_NAME("Freeze") 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),
+ device_c64_expansion_card_interface(mconfig, *this),
+ m_pia(*this, MC6821_TAG),
+ m_rom_bank(0),
+ m_ram_bank(0),
+ m_pb7_ff(0),
+ m_cb2_ff(0),
+ m_rom_oe(0),
+ m_ram_oe(0),
+ m_pb7(1)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void c64_magic_formel_cartridge_device::device_start()
+{
+ // state saving
+ save_item(NAME(m_rom_bank));
+ save_item(NAME(m_ram_bank));
+ save_item(NAME(m_pb7_ff));
+ save_item(NAME(m_cb2_ff));
+ save_item(NAME(m_rom_oe));
+ save_item(NAME(m_ram_oe));
+ save_item(NAME(m_pb7));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void c64_magic_formel_cartridge_device::device_reset()
+{
+ m_rom_bank = 0;
+ m_ram_bank = 0;
+ m_pb7_ff = 0;
+ m_cb2_ff = 0;
+ m_rom_oe = 0;
+ m_ram_oe = 0;
+ m_pb7 = 1;
+}
+
+
+//-------------------------------------------------
+// c64_cd_r - cartridge data read
+//-------------------------------------------------
+
+UINT8 c64_magic_formel_cartridge_device::c64_cd_r(address_space &space, offs_t offset, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ if (!romh && !m_rom_oe)
+ {
+ UINT8 bank = m_pb7_ff ? m_rom_bank : 0;
+ offs_t addr = (bank << 13) | (offset & 0x1fff);
+ data = m_romh[addr];
+ }
+ else if (!io1 && !PA4)
+ {
+ 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 ba, int roml, int romh, int io1, int io2)
+{
+ if (!io1)
+ {
+ offs_t addr = (m_ram_bank << 8) | (offset & 0xff);
+ m_ram[addr] = data;
+ }
+ else if (!io2 && !(m_cb2_ff & PA4))
+ {
+ 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_pb7_ff = 0;
+ }
+}
+
+
+//-------------------------------------------------
+// c64_game_r - GAME read
+//-------------------------------------------------
+
+int c64_magic_formel_cartridge_device::c64_game_r(offs_t offset, int ba, int rw, int hiram)
+{
+ return !(ba & rw & ((offset & 0xe000) == 0xe000) & !(m_pb7 & m_cb2_ff));
+}
diff --git a/src/mess/machine/c64_magic_formel.h b/src/mess/machine/c64_magic_formel.h
new file mode 100644
index 00000000000..643b31a6702
--- /dev/null
+++ b/src/mess/machine/c64_magic_formel.h
@@ -0,0 +1,74 @@
+/**********************************************************************
+
+ Magic Formel cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __MAGIC_FORMEL__
+#define __MAGIC_FORMEL__
+
+
+#include "emu.h"
+#include "machine/c64exp.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_config_complete() { m_shortname = "c64_magic_formel"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int ba, int roml, int romh, int io1, int io2);
+ virtual int c64_game_r(offs_t offset, int ba, int rw, int hiram);
+
+private:
+ required_device<pia6821_device> m_pia;
+
+ UINT8 m_rom_bank;
+ UINT8 m_ram_bank;
+ int m_pb7_ff;
+ int m_cb2_ff;
+ int m_rom_oe;
+ int m_ram_oe;
+ int m_pb7;
+};
+
+
+// device type definition
+extern const device_type C64_MAGIC_FORMEL;
+
+
+#endif
diff --git a/src/mess/machine/c64_mikro_assembler.c b/src/mess/machine/c64_mikro_assembler.c
new file mode 100644
index 00000000000..b1a0dfab01e
--- /dev/null
+++ b/src/mess/machine/c64_mikro_assembler.c
@@ -0,0 +1,60 @@
+/**********************************************************************
+
+ Mikro Assembler cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_mikro_assembler.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_MIKRO_ASSEMBLER = &device_creator<c64_mikro_assembler_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ if (!roml || !romh || !io1 || !io2)
+ {
+ data = m_roml[offset & 0x1fff];
+ }
+
+ return data;
+}
diff --git a/src/mess/machine/c64_mikro_assembler.h b/src/mess/machine/c64_mikro_assembler.h
new file mode 100644
index 00000000000..0477fc0eca0
--- /dev/null
+++ b/src/mess/machine/c64_mikro_assembler.h
@@ -0,0 +1,48 @@
+/**********************************************************************
+
+ Mikro Assembler cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __MIKRO_ASSEMBLER__
+#define __MIKRO_ASSEMBLER__
+
+
+#include "emu.h"
+#include "machine/c64exp.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_config_complete() { m_shortname = "c64_mikro_assembler"; }
+ virtual void device_start();
+
+ // device_c64_expansion_card_interface overrides
+ virtual UINT8 c64_cd_r(address_space &space, offs_t offset, 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/mess/machine/c64_multiscreen.c b/src/mess/machine/c64_multiscreen.c
new file mode 100644
index 00000000000..c14e88de127
--- /dev/null
+++ b/src/mess/machine/c64_multiscreen.c
@@ -0,0 +1,265 @@
+/**********************************************************************
+
+ Multiscreen cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ 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
+
+*/
+
+#include "c64_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<c64_multiscreen_cartridge_device>;
+
+
+//-------------------------------------------------
+// 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
+
+
+//-------------------------------------------------
+// pia6821_interface pia0_intf -
+//-------------------------------------------------
+
+static const pia6821_interface pia0_intf =
+{
+ DEVCB_NULL, // input A
+ DEVCB_NULL, // input B
+ DEVCB_NULL, // input CA1
+ DEVCB_NULL, // input CB1
+ DEVCB_NULL, // input CA2
+ DEVCB_NULL, // input CB2
+ DEVCB_NULL, // output A
+ DEVCB_NULL, // output B
+ DEVCB_NULL, // output CA2
+ DEVCB_NULL, // output CB2
+ DEVCB_NULL, // irq A
+ DEVCB_NULL // irq B
+};
+
+
+//-------------------------------------------------
+// pia6821_interface pia1_intf -
+//-------------------------------------------------
+
+static const pia6821_interface pia1_intf =
+{
+ DEVCB_NULL, // input A
+ DEVCB_NULL, // input B
+ DEVCB_NULL, // input CA1
+ DEVCB_NULL, // input CB1
+ DEVCB_NULL, // input CA2
+ DEVCB_NULL, // input CB2
+ DEVCB_NULL, // output A
+ DEVCB_NULL, // output B
+ DEVCB_NULL, // output CA2
+ DEVCB_NULL, // output CB2
+ DEVCB_NULL, // irq A
+ DEVCB_NULL // irq B
+};
+
+
+//-------------------------------------------------
+// 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_PIA6821_ADD(MC6821P_0_TAG, pia0_intf)
+ MCFG_PIA6821_ADD(MC6821P_1_TAG, pia1_intf)
+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),
+ 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ 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 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/mess/machine/c64_multiscreen.h b/src/mess/machine/c64_multiscreen.h
new file mode 100644
index 00000000000..dacc6b829e7
--- /dev/null
+++ b/src/mess/machine/c64_multiscreen.h
@@ -0,0 +1,59 @@
+/**********************************************************************
+
+ Multiscreen cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __MULTISCREEN__
+#define __MULTISCREEN__
+
+
+#include "emu.h"
+#include "cpu/m6800/m6800.h"
+#include "machine/6821pia.h"
+#include "machine/c64exp.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_config_complete() { m_shortname = "c64_mscr"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, 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/mess/machine/c64_neoram.c b/src/mess/machine/c64_neoram.c
new file mode 100644
index 00000000000..07433551707
--- /dev/null
+++ b/src/mess/machine/c64_neoram.c
@@ -0,0 +1,102 @@
+/**********************************************************************
+
+ NeoRAM cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_neoram.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_NEORAM = &device_creator<c64_neoram_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ 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
+ c64_nvram_pointer(machine(), 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ 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 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/mess/machine/c64_neoram.h b/src/mess/machine/c64_neoram.h
new file mode 100644
index 00000000000..d22a73d9d9b
--- /dev/null
+++ b/src/mess/machine/c64_neoram.h
@@ -0,0 +1,59 @@
+/**********************************************************************
+
+ NeoRAM cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __NEORAM__
+#define __NEORAM__
+
+
+#include "emu.h"
+#include "machine/c64exp.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_config_complete() { m_shortname = "c64_neoram"; }
+ 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_size); } }
+ virtual void nvram_write(emu_file &file) { if (m_nvram != NULL) { file.write(m_nvram, m_nvram_size); } }
+
+ // device_c64_expansion_card_interface overrides
+ virtual UINT8 c64_cd_r(address_space &space, offs_t offset, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, 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/mess/machine/c64_ocean.c b/src/mess/machine/c64_ocean.c
new file mode 100644
index 00000000000..ffe7ddd8471
--- /dev/null
+++ b/src/mess/machine/c64_ocean.c
@@ -0,0 +1,117 @@
+/**********************************************************************
+
+ Ocean Software cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ 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 "c64_ocean.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_OCEAN = &device_creator<c64_ocean_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ device_c64_expansion_card_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ if (!roml)
+ {
+ offs_t addr = (m_bank << 13) | (offset & 0x1fff);
+ data = m_roml[addr & m_roml_mask];
+ }
+ else if (!romh)
+ {
+ 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 ba, int roml, int romh, int io1, int io2)
+{
+ if (!io1)
+ {
+ m_bank = data & 0x3f;
+ }
+}
diff --git a/src/mess/machine/c64_ocean.h b/src/mess/machine/c64_ocean.h
new file mode 100644
index 00000000000..a8d6969faae
--- /dev/null
+++ b/src/mess/machine/c64_ocean.h
@@ -0,0 +1,53 @@
+/**********************************************************************
+
+ Ocean Software cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __OCEAN__
+#define __OCEAN__
+
+
+#include "emu.h"
+#include "machine/c64exp.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_config_complete() { m_shortname = "c64_ocean"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, 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/mess/machine/c64_pagefox.c b/src/mess/machine/c64_pagefox.c
new file mode 100644
index 00000000000..19b4fcc1fa0
--- /dev/null
+++ b/src/mess/machine/c64_pagefox.c
@@ -0,0 +1,136 @@
+/**********************************************************************
+
+ Scanntronik Pagefox cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ 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 "c64_pagefox.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_PAGEFOX = &device_creator<c64_pagefox_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ device_c64_expansion_card_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void c64_pagefox_cartridge_device::device_start()
+{
+ // 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ 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 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/mess/machine/c64_pagefox.h b/src/mess/machine/c64_pagefox.h
new file mode 100644
index 00000000000..8c9546e2385
--- /dev/null
+++ b/src/mess/machine/c64_pagefox.h
@@ -0,0 +1,53 @@
+/**********************************************************************
+
+ Scanntronik Pagefox cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __PAGEFOX__
+#define __PAGEFOX__
+
+
+#include "emu.h"
+#include "machine/c64exp.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_config_complete() { m_shortname = "c64_pagefox"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int ba, int roml, int romh, int io1, int io2);
+
+private:
+ UINT8 m_bank;
+};
+
+
+// device type definition
+extern const device_type C64_PAGEFOX;
+
+
+#endif
diff --git a/src/mess/machine/c64_prophet64.c b/src/mess/machine/c64_prophet64.c
new file mode 100644
index 00000000000..4fc0e7fb8ea
--- /dev/null
+++ b/src/mess/machine/c64_prophet64.c
@@ -0,0 +1,87 @@
+/**********************************************************************
+
+ Prophet-64 emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_prophet64.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_PROPHET64 = &device_creator<c64_prophet64_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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, "C64 Prophet-64 cartridge", tag, owner, clock),
+ device_c64_expansion_card_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// 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_exrom = 0;
+}
+
+
+//-------------------------------------------------
+// c64_cd_r - cartridge data read
+//-------------------------------------------------
+
+UINT8 c64_prophet64_cartridge_device::c64_cd_r(address_space &space, offs_t offset, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ 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 ba, int roml, int romh, int io1, int io2)
+{
+ if (!io2)
+ {
+ m_bank = data & 0x1f;
+ m_exrom = BIT(data, 5);
+ }
+}
diff --git a/src/mess/machine/c64_prophet64.h b/src/mess/machine/c64_prophet64.h
new file mode 100644
index 00000000000..b9c15570c87
--- /dev/null
+++ b/src/mess/machine/c64_prophet64.h
@@ -0,0 +1,53 @@
+/**********************************************************************
+
+ Prophet-64 emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __PROPHET64__
+#define __PROPHET64__
+
+
+#include "emu.h"
+#include "machine/c64exp.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_config_complete() { m_shortname = "c64_prophet64"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, 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/mess/machine/c64_ps64.c b/src/mess/machine/c64_ps64.c
new file mode 100644
index 00000000000..fc1e70d4eb4
--- /dev/null
+++ b/src/mess/machine/c64_ps64.c
@@ -0,0 +1,160 @@
+/**********************************************************************
+
+ PS-64 speech cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ 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 "c64_ps64.h"
+
+
+
+//**************************************************************************
+// MACROS/CONSTANTS
+//**************************************************************************
+
+#define SSI263_TAG "ssi263"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_PS64 = &device_creator<c64_ps64_cartridge_device>;
+
+
+//-------------------------------------------------
+// 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),
+ 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ 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 ba, int roml, int romh, int io1, int io2)
+{
+ if (!io1)
+ {
+ // sc02->write(offset & 0x07, data);
+ }
+}
diff --git a/src/mess/machine/c64_ps64.h b/src/mess/machine/c64_ps64.h
new file mode 100644
index 00000000000..4bc03de3d33
--- /dev/null
+++ b/src/mess/machine/c64_ps64.h
@@ -0,0 +1,54 @@
+/**********************************************************************
+
+ PS-64 speech cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __PS64__
+#define __PS64__
+
+
+#include "emu.h"
+#include "machine/c64exp.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_config_complete() { m_shortname = "c64_ps64"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int ba, int roml, int romh, int io1, int io2);
+};
+
+
+// device type definition
+extern const device_type C64_PS64;
+
+
+#endif
diff --git a/src/mess/machine/c64_rex.c b/src/mess/machine/c64_rex.c
new file mode 100644
index 00000000000..011a6404ed9
--- /dev/null
+++ b/src/mess/machine/c64_rex.c
@@ -0,0 +1,81 @@
+/**********************************************************************
+
+ REX Datentechnik cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_rex.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_REX = &device_creator<c64_rex_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ 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/mess/machine/c64_rex.h b/src/mess/machine/c64_rex.h
new file mode 100644
index 00000000000..b5b5619509f
--- /dev/null
+++ b/src/mess/machine/c64_rex.h
@@ -0,0 +1,49 @@
+/**********************************************************************
+
+ REX Datentechnik cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __REX__
+#define __REX__
+
+
+#include "emu.h"
+#include "machine/c64exp.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_config_complete() { m_shortname = "c64_rex"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+};
+
+
+// device type definition
+extern const device_type C64_REX;
+
+
+#endif
diff --git a/src/mess/machine/c64_rex_ep256.c b/src/mess/machine/c64_rex_ep256.c
new file mode 100644
index 00000000000..26bc354a959
--- /dev/null
+++ b/src/mess/machine/c64_rex_ep256.c
@@ -0,0 +1,188 @@
+/**********************************************************************
+
+ Rex Datentechnik 256KB EPROM cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_rex_ep256.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_REX_EP256 = &device_creator<c64_rex_ep256_cartridge_device>;
+
+
+//-------------------------------------------------
+// ROM( c64_rex_ep256 )
+//-------------------------------------------------
+
+ROM_START( c64_rex_ep256 )
+ ROM_REGION( 0x40000, "rom", 0 )
+ ROM_CART_LOAD( "rom1", 0x00000, 0x08000, ROM_MIRROR )
+ ROM_CART_LOAD( "rom2", 0x08000, 0x08000, ROM_MIRROR )
+ ROM_CART_LOAD( "rom3", 0x10000, 0x08000, ROM_MIRROR )
+ ROM_CART_LOAD( "rom4", 0x18000, 0x08000, ROM_MIRROR )
+ ROM_CART_LOAD( "rom5", 0x20000, 0x08000, ROM_MIRROR )
+ ROM_CART_LOAD( "rom6", 0x28000, 0x08000, ROM_MIRROR )
+ ROM_CART_LOAD( "rom7", 0x30000, 0x08000, ROM_MIRROR )
+ ROM_CART_LOAD( "rom8", 0x38000, 0x08000, ROM_MIRROR )
+ROM_END
+
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *c64_rex_ep256_cartridge_device::device_rom_region() const
+{
+ return ROM_NAME( c64_rex_ep256 );
+}
+
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( c64_rex_ep256 )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( c64_rex_ep256 )
+ MCFG_CARTSLOT_ADD("rom1")
+ MCFG_CARTSLOT_EXTENSION_LIST("rom,bin")
+ MCFG_CARTSLOT_ADD("rom2")
+ MCFG_CARTSLOT_EXTENSION_LIST("rom,bin")
+ MCFG_CARTSLOT_ADD("rom3")
+ MCFG_CARTSLOT_EXTENSION_LIST("rom,bin")
+ MCFG_CARTSLOT_ADD("rom4")
+ MCFG_CARTSLOT_EXTENSION_LIST("rom,bin")
+ MCFG_CARTSLOT_ADD("rom5")
+ MCFG_CARTSLOT_EXTENSION_LIST("rom,bin")
+ MCFG_CARTSLOT_ADD("rom6")
+ MCFG_CARTSLOT_EXTENSION_LIST("rom,bin")
+ MCFG_CARTSLOT_ADD("rom7")
+ MCFG_CARTSLOT_EXTENSION_LIST("rom,bin")
+ MCFG_CARTSLOT_ADD("rom8")
+ MCFG_CARTSLOT_EXTENSION_LIST("rom,bin")
+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),
+ device_c64_expansion_card_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void c64_rex_ep256_cartridge_device::device_start()
+{
+ m_rom = memregion("rom")->base();
+
+ // state saving
+ save_item(NAME(m_bank));
+ save_item(NAME(m_reset));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void c64_rex_ep256_cartridge_device::device_reset()
+{
+ m_exrom = 0;
+ m_reset = 1;
+ m_bank = 0;
+}
+
+
+//-------------------------------------------------
+// c64_cd_r - cartridge data read
+//-------------------------------------------------
+
+UINT8 c64_rex_ep256_cartridge_device::c64_cd_r(address_space &space, offs_t offset, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ if (!roml)
+ {
+ if (m_reset)
+ {
+ data = m_roml[offset & 0x1fff];
+ }
+ else
+ {
+ offs_t addr = (m_bank << 13) | (offset & 0x1fff);
+ data = m_rom[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 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_bank = ((data & 0x07) << 2) | ((data >> 5) & 0x03);
+ }
+}
diff --git a/src/mess/machine/c64_rex_ep256.h b/src/mess/machine/c64_rex_ep256.h
new file mode 100644
index 00000000000..49b99d6f487
--- /dev/null
+++ b/src/mess/machine/c64_rex_ep256.h
@@ -0,0 +1,62 @@
+/**********************************************************************
+
+ Rex Datentechnik 256KB EPROM cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __REX_EP256__
+#define __REX_EP256__
+
+
+#include "emu.h"
+#include "imagedev/cartslot.h"
+#include "machine/c64exp.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 const rom_entry *device_rom_region() const;
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "rexep256"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int ba, int roml, int romh, int io1, int io2);
+
+private:
+ UINT8 *m_rom;
+
+ UINT8 m_bank;
+ int m_reset;
+};
+
+
+// device type definition
+extern const device_type C64_REX_EP256;
+
+
+
+#endif
diff --git a/src/mess/machine/c64_ross.c b/src/mess/machine/c64_ross.c
new file mode 100644
index 00000000000..7fda625761f
--- /dev/null
+++ b/src/mess/machine/c64_ross.c
@@ -0,0 +1,95 @@
+/**********************************************************************
+
+ Ross cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_ross.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_ROSS = &device_creator<c64_ross_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ 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 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/mess/machine/c64_ross.h b/src/mess/machine/c64_ross.h
new file mode 100644
index 00000000000..c1d5afb03ed
--- /dev/null
+++ b/src/mess/machine/c64_ross.h
@@ -0,0 +1,55 @@
+/**********************************************************************
+
+ Ross cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __ROSS__
+#define __ROSS__
+
+
+#include "emu.h"
+#include "imagedev/cartslot.h"
+#include "machine/c64exp.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_config_complete() { m_shortname = "c64_ross"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, 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/mess/machine/c64_sfx_sound_expander.c b/src/mess/machine/c64_sfx_sound_expander.c
new file mode 100644
index 00000000000..1439d72d865
--- /dev/null
+++ b/src/mess/machine/c64_sfx_sound_expander.c
@@ -0,0 +1,300 @@
+/**********************************************************************
+
+ Commodore SFX Sound Expander cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_sfx_sound_expander.h"
+
+#define YM3526_TAG "ic3"
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_SFX_SOUND_EXPANDER = &device_creator<c64_sfx_sound_expander_cartridge_device>;
+
+
+//-------------------------------------------------
+// ym3526_interface ym3526_config
+//-------------------------------------------------
+
+static const ym3526_interface ym3526_config =
+{
+ DEVCB_LINE_MEMBER(c64_sfx_sound_expander_cartridge_device, irq_w)
+};
+
+
+//-------------------------------------------------
+// C64_EXPANSION_INTERFACE( expansion_intf )
+//-------------------------------------------------
+
+READ8_MEMBER( c64_sfx_sound_expander_cartridge_device::dma_cd_r )
+{
+ return m_slot->dma_cd_r(offset);
+}
+
+WRITE8_MEMBER( c64_sfx_sound_expander_cartridge_device::dma_cd_w )
+{
+ m_slot->dma_cd_w(offset, data);
+}
+
+WRITE_LINE_MEMBER( c64_sfx_sound_expander_cartridge_device::irq_w )
+{
+ m_slot->irq_w(state);
+}
+
+WRITE_LINE_MEMBER( c64_sfx_sound_expander_cartridge_device::nmi_w )
+{
+ m_slot->nmi_w(state);
+}
+
+WRITE_LINE_MEMBER( c64_sfx_sound_expander_cartridge_device::dma_w )
+{
+ m_slot->dma_w(state);
+}
+
+WRITE_LINE_MEMBER( c64_sfx_sound_expander_cartridge_device::reset_w )
+{
+ m_slot->reset_w(state);
+}
+
+static C64_EXPANSION_INTERFACE( expansion_intf )
+{
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c64_sfx_sound_expander_cartridge_device, dma_cd_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c64_sfx_sound_expander_cartridge_device, dma_cd_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, c64_sfx_sound_expander_cartridge_device, irq_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, c64_sfx_sound_expander_cartridge_device, nmi_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, c64_sfx_sound_expander_cartridge_device, dma_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, c64_sfx_sound_expander_cartridge_device, reset_w)
+};
+
+
+//-------------------------------------------------
+// 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_SOUND_CONFIG(ym3526_config)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.70)
+
+ MCFG_C64_EXPANSION_SLOT_ADD(C64_EXPANSION_SLOT_TAG, 0, expansion_intf, c64_expansion_cards, NULL, NULL)
+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( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("KB1")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("KB2")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("KB3")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("KB4")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("KB5")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("KB6")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("KB7")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD )
+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 );
+}
+
+
+
+//**************************************************************************
+// 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),
+ device_c64_expansion_card_interface(mconfig, *this),
+ m_opl(*this, YM3526_TAG),
+ m_exp(*this, C64_EXPANSION_SLOT_TAG)
+{
+}
+
+
+//-------------------------------------------------
+// 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()
+{
+}
+
+
+//-------------------------------------------------
+// c64_cd_r - cartridge data read
+//-------------------------------------------------
+
+UINT8 c64_sfx_sound_expander_cartridge_device::c64_cd_r(address_space &space, offs_t offset, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = m_exp->cd_r(space, offset, ba, roml, romh, io1, io2);
+
+ if (!io2)
+ {
+ if (BIT(offset, 3))
+ {
+ switch (offset & 0x07)
+ {
+ case 0: data |= ioport("KB0")->read(); break;
+ case 1: data |= ioport("KB1")->read(); break;
+ case 2: data |= ioport("KB2")->read(); break;
+ case 3: data |= ioport("KB3")->read(); break;
+ case 4: data |= ioport("KB4")->read(); break;
+ case 5: data |= ioport("KB5")->read(); break;
+ case 6: data |= ioport("KB6")->read(); break;
+ case 7: data |= ioport("KB7")->read(); break;
+ }
+ }
+ else if (BIT(offset, 5))
+ {
+ data |= ym3526_r(m_opl, 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 ba, int roml, int romh, int io1, int io2)
+{
+ if (!io2 && BIT(offset, 5))
+ {
+ ym3526_w(m_opl, BIT(offset, 4), data);
+ }
+
+ m_exp->cd_w(space, offset, data, ba, roml, romh, io1, io2);
+}
+
+
+//-------------------------------------------------
+// c64_game_r - GAME read
+//-------------------------------------------------
+
+int c64_sfx_sound_expander_cartridge_device::c64_game_r(offs_t offset, int ba, int rw, int hiram)
+{
+ return m_exp->game_r(offset, ba, rw, hiram);
+}
+
+
+//-------------------------------------------------
+// c64_exrom_r - EXROM read
+//-------------------------------------------------
+
+int c64_sfx_sound_expander_cartridge_device::c64_exrom_r(offs_t offset, int ba, int rw, int hiram)
+{
+ return m_exp->exrom_r(offset, ba, rw, hiram);
+}
diff --git a/src/mess/machine/c64_sfx_sound_expander.h b/src/mess/machine/c64_sfx_sound_expander.h
new file mode 100644
index 00000000000..94184853121
--- /dev/null
+++ b/src/mess/machine/c64_sfx_sound_expander.h
@@ -0,0 +1,70 @@
+/**********************************************************************
+
+ Commodore SFX Sound Expander cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __SFX_SOUND_EXPANDER__
+#define __SFX_SOUND_EXPANDER__
+
+
+#include "emu.h"
+#include "machine/c64exp.h"
+#include "machine/cbmipt.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;
+
+ // not really public
+ DECLARE_READ8_MEMBER( dma_cd_r );
+ DECLARE_WRITE8_MEMBER( dma_cd_w );
+ DECLARE_WRITE_LINE_MEMBER( irq_w );
+ DECLARE_WRITE_LINE_MEMBER( nmi_w );
+ DECLARE_WRITE_LINE_MEMBER( dma_w );
+ DECLARE_WRITE_LINE_MEMBER( reset_w );
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "c64_sfx_sound_expander"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int ba, int roml, int romh, int io1, int io2);
+ virtual int c64_game_r(offs_t offset, int ba, int rw, int hiram);
+ virtual int c64_exrom_r(offs_t offset, int ba, int rw, int hiram);
+
+private:
+ required_device<device_t> m_opl;
+ required_device<c64_expansion_slot_device> m_exp;
+};
+
+
+// device type definition
+extern const device_type C64_SFX_SOUND_EXPANDER;
+
+
+#endif
diff --git a/src/mess/machine/c64_silverrock.c b/src/mess/machine/c64_silverrock.c
new file mode 100644
index 00000000000..3138e4bebcb
--- /dev/null
+++ b/src/mess/machine/c64_silverrock.c
@@ -0,0 +1,135 @@
+/**********************************************************************
+
+ SilverRock Productions cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ PCB Layout
+ ----------
+
+ e9048
+ |=============|
+ |=| LS00 |
+ |=| LS273|
+ |=| |
+ |=| |
+ |=| ROM |
+ |=| |
+ |=| |
+ |=| |
+ |=============|
+
+ ROM - Atmel AT27C010-25PC 128Kx8 OTP EPROM "HUGO 2012"
+
+*/
+
+#include "c64_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<c64_silverrock_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ 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 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/mess/machine/c64_silverrock.h b/src/mess/machine/c64_silverrock.h
new file mode 100644
index 00000000000..ef5677613a3
--- /dev/null
+++ b/src/mess/machine/c64_silverrock.h
@@ -0,0 +1,53 @@
+/**********************************************************************
+
+ SilverRock Productions cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __SILVERROCK__
+#define __SILVERROCK__
+
+
+#include "emu.h"
+#include "machine/c64exp.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_config_complete() { m_shortname = "c64_silverrock"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, 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/mess/machine/c64_simons_basic.c b/src/mess/machine/c64_simons_basic.c
new file mode 100644
index 00000000000..c71b9cf141d
--- /dev/null
+++ b/src/mess/machine/c64_simons_basic.c
@@ -0,0 +1,87 @@
+/**********************************************************************
+
+ VizaWrite 64 cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_simons_basic.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_SIMONS_BASIC = &device_creator<c64_simons_basic_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ 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 ba, int roml, int romh, int io1, int io2)
+{
+ if (!io1)
+ {
+ m_game = !BIT(data, 0);
+ }
+}
diff --git a/src/mess/machine/c64_simons_basic.h b/src/mess/machine/c64_simons_basic.h
new file mode 100644
index 00000000000..20e87141fd0
--- /dev/null
+++ b/src/mess/machine/c64_simons_basic.h
@@ -0,0 +1,50 @@
+/**********************************************************************
+
+ Simons' BASIC cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __SIMONS_BASIC__
+#define __SIMONS_BASIC__
+
+
+#include "emu.h"
+#include "machine/c64exp.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_config_complete() { m_shortname = "c64_simons_basic"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, 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/mess/machine/c64_stardos.c b/src/mess/machine/c64_stardos.c
new file mode 100644
index 00000000000..c02fbe71295
--- /dev/null
+++ b/src/mess/machine/c64_stardos.c
@@ -0,0 +1,197 @@
+/**********************************************************************
+
+ StarPoint Software StarDOS cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ PCB Layout
+ ----------
+
+ |===========================|
+ |=| |
+ |=| LS30 |
+ |=| LS157 |
+ |=| LS00 |
+ |=| ROM |
+ |=| 7407 |
+ |=| |
+ |=| SW1|
+ |===========================|
+
+ ROM - Toshiba TMM271128D-25 16Kx8 EPROM
+
+*/
+
+#include "c64_stardos.h"
+
+
+
+//**************************************************************************
+// MACROS/CONSTANTS
+//**************************************************************************
+
+#define IO1_FULL_CHARGE 27
+#define IO2_FULL_CHARGE 42
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_STARDOS = &device_creator<c64_stardos_cartridge_device>;
+
+
+//-------------------------------------------------
+// INPUT_PORTS( c64_stardos )
+//-------------------------------------------------
+
+INPUT_CHANGED_MEMBER( c64_stardos_cartridge_device::reset )
+{
+ if (!newval)
+ {
+ device_reset();
+ }
+
+ m_slot->reset_w(newval ? CLEAR_LINE : ASSERT_LINE);
+}
+
+static INPUT_PORTS_START( c64_stardos )
+ PORT_START("RESET")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Reset") PORT_CODE(KEYCODE_F11) PORT_CHANGED_MEMBER(DEVICE_SELF, c64_stardos_cartridge_device, reset, 0)
+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),
+ 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ 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 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 ba, int rw, int hiram)
+{
+ return !(ba & rw & ((offset & 0xe000) == 0xe000) & hiram);
+}
diff --git a/src/mess/machine/c64_stardos.h b/src/mess/machine/c64_stardos.h
new file mode 100644
index 00000000000..236d4c11203
--- /dev/null
+++ b/src/mess/machine/c64_stardos.h
@@ -0,0 +1,63 @@
+/**********************************************************************
+
+ StarPoint Software StarDOS cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __STARDOS__
+#define __STARDOS__
+
+
+#include "emu.h"
+#include "machine/c64exp.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;
+
+ DECLARE_INPUT_CHANGED_MEMBER( reset );
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "c64_stardos"; }
+ virtual void device_start();
+
+ // device_c64_expansion_card_interface overrides
+ virtual UINT8 c64_cd_r(address_space &space, offs_t offset, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int ba, int roml, int romh, int io1, int io2);
+ virtual int c64_game_r(offs_t offset, int ba, int rw, int hiram);
+
+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/mess/machine/c64_std.c b/src/mess/machine/c64_std.c
new file mode 100644
index 00000000000..2ee85a9bfc5
--- /dev/null
+++ b/src/mess/machine/c64_std.c
@@ -0,0 +1,71 @@
+/**********************************************************************
+
+ Commodore 64 Standard 8K/16K cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_std.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_STD = &device_creator<c64_standard_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ if (!roml && m_roml_mask)
+ {
+ data = m_roml[offset & 0x1fff];
+ }
+ else if (!romh)
+ {
+ if (m_romh_mask)
+ {
+ data = m_romh[offset & 0x1fff];
+ }
+ else if (m_roml_mask == 0x3fff)
+ {
+ data = m_roml[offset & 0x3fff];
+ }
+ }
+
+ return data;
+}
diff --git a/src/mess/machine/c64_std.h b/src/mess/machine/c64_std.h
new file mode 100644
index 00000000000..74343ec5c86
--- /dev/null
+++ b/src/mess/machine/c64_std.h
@@ -0,0 +1,49 @@
+/**********************************************************************
+
+ Commodore 64 Standard 8K/16K cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __C64_STANDARD_CARTRIDGE__
+#define __C64_STANDARD_CARTRIDGE__
+
+
+#include "emu.h"
+#include "imagedev/cartslot.h"
+#include "machine/c64exp.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_config_complete() { m_shortname = "c64_standard"; }
+ virtual void device_start();
+
+ // device_c64_expansion_card_interface overrides
+ virtual UINT8 c64_cd_r(address_space &space, offs_t offset, int ba, int roml, int romh, int io1, int io2);
+};
+
+
+// device type definition
+extern const device_type C64_STD;
+
+
+#endif
diff --git a/src/mess/machine/c64_structured_basic.c b/src/mess/machine/c64_structured_basic.c
new file mode 100644
index 00000000000..75b102c231d
--- /dev/null
+++ b/src/mess/machine/c64_structured_basic.c
@@ -0,0 +1,106 @@
+/**********************************************************************
+
+ Structured Basic cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_structured_basic.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_STRUCTURED_BASIC = &device_creator<c64_structured_basic_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ 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 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/mess/machine/c64_structured_basic.h b/src/mess/machine/c64_structured_basic.h
new file mode 100644
index 00000000000..46451bff063
--- /dev/null
+++ b/src/mess/machine/c64_structured_basic.h
@@ -0,0 +1,55 @@
+/**********************************************************************
+
+ Structured Basic cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __STRUCTURED_BASIC__
+#define __STRUCTURED_BASIC__
+
+
+#include "emu.h"
+#include "imagedev/cartslot.h"
+#include "machine/c64exp.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_config_complete() { m_shortname = "c64_structured_basic"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, 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/mess/machine/c64_super_explode.c b/src/mess/machine/c64_super_explode.c
new file mode 100644
index 00000000000..11706e4f4f7
--- /dev/null
+++ b/src/mess/machine/c64_super_explode.c
@@ -0,0 +1,128 @@
+/**********************************************************************
+
+ Super Explode! cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_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<c64_super_explode_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ 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 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/mess/machine/c64_super_explode.h b/src/mess/machine/c64_super_explode.h
new file mode 100644
index 00000000000..499673fccd0
--- /dev/null
+++ b/src/mess/machine/c64_super_explode.h
@@ -0,0 +1,56 @@
+/**********************************************************************
+
+ Super Explode! cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __SUPER_EXPLODE__
+#define __SUPER_EXPLODE__
+
+
+#include "emu.h"
+#include "machine/c64exp.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_config_complete() { m_shortname = "c64_super_explode"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, 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/mess/machine/c64_super_games.c b/src/mess/machine/c64_super_games.c
new file mode 100644
index 00000000000..3b8d99a9f3a
--- /dev/null
+++ b/src/mess/machine/c64_super_games.c
@@ -0,0 +1,105 @@
+/**********************************************************************
+
+ Commodore Super Games cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_super_games.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_SUPER_GAMES = &device_creator<c64_super_games_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ 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 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/mess/machine/c64_super_games.h b/src/mess/machine/c64_super_games.h
new file mode 100644
index 00000000000..49a63f4bfe4
--- /dev/null
+++ b/src/mess/machine/c64_super_games.h
@@ -0,0 +1,53 @@
+/**********************************************************************
+
+ Commodore Super Games cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __SUPER_GAMES__
+#define __SUPER_GAMES__
+
+
+#include "emu.h"
+#include "machine/c64exp.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_config_complete() { m_shortname = "c64_super_games"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, 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/mess/machine/c64_sw8k.c b/src/mess/machine/c64_sw8k.c
new file mode 100644
index 00000000000..848a78d229e
--- /dev/null
+++ b/src/mess/machine/c64_sw8k.c
@@ -0,0 +1,116 @@
+/**********************************************************************
+
+ C64 switchable 8K cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ 4040 + Fast Hack'em
+
+ PCB Layout
+ ----------
+
+ |===========================|
+ |=| |
+ |=| SW1 |
+ |=| ROM0 |
+ |=| |
+ |=| |
+ |=| ROM1 |
+ |=| |
+ |=| |
+ |===========================|
+
+ ROM0,1 - National Semiconductor NMC27C64Q 8Kx8 EPROM
+ SW1 - ROM selection switch
+
+*/
+
+#include "c64_sw8k.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_SW8K = &device_creator<c64_switchable_8k_cartridge_device>;
+
+
+//-------------------------------------------------
+// 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),
+ device_c64_expansion_card_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// 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 = ioport("SW")->read();
+}
+
+
+//-------------------------------------------------
+// c64_cd_r - cartridge data read
+//-------------------------------------------------
+
+UINT8 c64_switchable_8k_cartridge_device::c64_cd_r(address_space &space, offs_t offset, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ if (!roml)
+ {
+ offs_t addr = (m_bank << 13) | (offset & 0x1fff);
+ data = m_roml[addr];
+ }
+
+ return data;
+}
diff --git a/src/mess/machine/c64_sw8k.h b/src/mess/machine/c64_sw8k.h
new file mode 100644
index 00000000000..24cb8019431
--- /dev/null
+++ b/src/mess/machine/c64_sw8k.h
@@ -0,0 +1,55 @@
+/**********************************************************************
+
+ C64 switchable 8K cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __C64_SW8K__
+#define __C64_SW8K__
+
+
+#include "emu.h"
+#include "machine/c64exp.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_config_complete() { m_shortname = "c64_sw8k"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+
+private:
+ int m_bank;
+};
+
+
+// device type definition
+extern const device_type C64_SW8K;
+
+
+#endif
diff --git a/src/mess/machine/c64_system3.c b/src/mess/machine/c64_system3.c
new file mode 100644
index 00000000000..7d419a96f7d
--- /dev/null
+++ b/src/mess/machine/c64_system3.c
@@ -0,0 +1,86 @@
+/**********************************************************************
+
+ System 3 cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_system3.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_SYSTEM3 = &device_creator<c64_system3_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ if (!roml)
+ {
+ offs_t addr = (m_bank << 13) | (offset & 0x1fff);
+ data = m_roml[addr];
+ }
+
+ 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 ba, int roml, int romh, int io1, int io2)
+{
+ if (!io1)
+ {
+ m_bank = offset & 0x3f;
+ }
+}
diff --git a/src/mess/machine/c64_system3.h b/src/mess/machine/c64_system3.h
new file mode 100644
index 00000000000..3c56d2a5249
--- /dev/null
+++ b/src/mess/machine/c64_system3.h
@@ -0,0 +1,53 @@
+/**********************************************************************
+
+ Dinamic Software cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __SYSTEM3__
+#define __SYSTEM3__
+
+
+#include "emu.h"
+#include "machine/c64exp.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_config_complete() { m_shortname = "c64_system3"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, 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/mess/machine/c64_tdos.c b/src/mess/machine/c64_tdos.c
new file mode 100644
index 00000000000..00f9bf9b849
--- /dev/null
+++ b/src/mess/machine/c64_tdos.c
@@ -0,0 +1,256 @@
+/**********************************************************************
+
+ Triton QD TDOS cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ 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 custom (?)
+ SSDA - Motorola MC68A52P SSDA
+ CN1 - C64 expansion connector (pass-thru)
+ CN2,3 - 19x1 flat ribbon cable to other PCB
+ CN4 - 9 wires to 3" drive
+ SW1 - cartridge on/off switch
+
+*/
+
+#include "c64_tdos.h"
+
+
+
+//**************************************************************************
+// MACROS/CONSTANTS
+//**************************************************************************
+
+#define MC68A52P_TAG "mc6852"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_TDOS = &device_creator<c64_tdos_cartridge_device>;
+
+
+//-------------------------------------------------
+// MC6852_INTERFACE( ssda_intf )
+//-------------------------------------------------
+
+static MC6852_INTERFACE( ssda_intf )
+{
+ 0,
+ 0,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// floppy_interface tdos_floppy_interface
+//-------------------------------------------------
+
+static const floppy_interface tdos_floppy_interface =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ FLOPPY_STANDARD_5_25_DSHD,
+ LEGACY_FLOPPY_OPTIONS_NAME(default),
+ "floppy_2_8",
+ NULL
+};
+
+
+//-------------------------------------------------
+// C64_EXPANSION_INTERFACE( expansion_intf )
+//-------------------------------------------------
+
+READ8_MEMBER( c64_tdos_cartridge_device::dma_cd_r )
+{
+ return m_slot->dma_cd_r(offset);
+}
+
+WRITE8_MEMBER( c64_tdos_cartridge_device::dma_cd_w )
+{
+ m_slot->dma_cd_w(offset, data);
+}
+
+WRITE_LINE_MEMBER( c64_tdos_cartridge_device::irq_w )
+{
+ m_slot->irq_w(state);
+}
+
+WRITE_LINE_MEMBER( c64_tdos_cartridge_device::nmi_w )
+{
+ m_slot->nmi_w(state);
+}
+
+WRITE_LINE_MEMBER( c64_tdos_cartridge_device::dma_w )
+{
+ m_slot->dma_w(state);
+}
+
+WRITE_LINE_MEMBER( c64_tdos_cartridge_device::reset_w )
+{
+ m_slot->reset_w(state);
+}
+
+static C64_EXPANSION_INTERFACE( expansion_intf )
+{
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c64_tdos_cartridge_device, dma_cd_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c64_tdos_cartridge_device, dma_cd_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, c64_tdos_cartridge_device, irq_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, c64_tdos_cartridge_device, nmi_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, c64_tdos_cartridge_device, dma_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, c64_tdos_cartridge_device, reset_w)
+};
+
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( c64_multiscreen )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( c64_tdos )
+ MCFG_MC6852_ADD(MC68A52P_TAG, XTAL_6_5MHz, ssda_intf)
+ MCFG_LEGACY_FLOPPY_DRIVE_ADD(FLOPPY_0, tdos_floppy_interface)
+
+ MCFG_C64_EXPANSION_SLOT_ADD(C64_EXPANSION_SLOT_TAG, 0, expansion_intf, c64_expansion_cards, NULL, NULL)
+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 );
+}
+
+
+
+//**************************************************************************
+// 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),
+ device_c64_expansion_card_interface(mconfig, *this),
+ m_ssda(*this, MC68A52P_TAG),
+ m_exp(*this, C64_EXPANSION_SLOT_TAG)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void c64_tdos_cartridge_device::device_start()
+{
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void c64_tdos_cartridge_device::device_reset()
+{
+}
+
+
+//-------------------------------------------------
+// c64_cd_r - cartridge data read
+//-------------------------------------------------
+
+UINT8 c64_tdos_cartridge_device::c64_cd_r(address_space &space, offs_t offset, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = m_exp->cd_r(space, offset, ba, roml, romh, io1, io2);
+
+ // TODO
+
+ 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 ba, int roml, int romh, int io1, int io2)
+{
+ // TODO
+ m_exp->cd_w(space, offset, data, ba, roml, romh, io1, io2);
+}
+
+
+//-------------------------------------------------
+// c64_game_r - GAME read
+//-------------------------------------------------
+
+int c64_tdos_cartridge_device::c64_game_r(offs_t offset, int ba, int rw, int hiram)
+{
+ return m_exp->game_r(offset, ba, rw, hiram);
+}
+
+
+//-------------------------------------------------
+// c64_exrom_r - EXROM read
+//-------------------------------------------------
+
+int c64_tdos_cartridge_device::c64_exrom_r(offs_t offset, int ba, int rw, int hiram)
+{
+ return m_exp->exrom_r(offset, ba, rw, hiram);
+}
diff --git a/src/mess/machine/c64_tdos.h b/src/mess/machine/c64_tdos.h
new file mode 100644
index 00000000000..64b5ea3e0ce
--- /dev/null
+++ b/src/mess/machine/c64_tdos.h
@@ -0,0 +1,70 @@
+/**********************************************************************
+
+ Triton QD TDOS cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __TDOS__
+#define __TDOS__
+
+
+#include "emu.h"
+#include "imagedev/flopdrv.h"
+#include "machine/c64exp.h"
+#include "machine/cbmipt.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;
+
+ // not really public
+ DECLARE_READ8_MEMBER( dma_cd_r );
+ DECLARE_WRITE8_MEMBER( dma_cd_w );
+ DECLARE_WRITE_LINE_MEMBER( irq_w );
+ DECLARE_WRITE_LINE_MEMBER( nmi_w );
+ DECLARE_WRITE_LINE_MEMBER( dma_w );
+ DECLARE_WRITE_LINE_MEMBER( reset_w );
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "c64_tdos"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int ba, int roml, int romh, int io1, int io2);
+ virtual int c64_game_r(offs_t offset, int ba, int rw, int hiram);
+ virtual int c64_exrom_r(offs_t offset, int ba, int rw, int hiram);
+
+private:
+ required_device<mc6852_device> m_ssda;
+ required_device<c64_expansion_slot_device> m_exp;
+};
+
+
+// device type definition
+extern const device_type C64_TDOS;
+
+
+#endif
diff --git a/src/mess/machine/c64_vw64.c b/src/mess/machine/c64_vw64.c
new file mode 100644
index 00000000000..a96f2924d1a
--- /dev/null
+++ b/src/mess/machine/c64_vw64.c
@@ -0,0 +1,130 @@
+/**********************************************************************
+
+ VizaWrite 64 cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ 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 "c64_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<c64_vizawrite_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ 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/mess/machine/c64_vw64.h b/src/mess/machine/c64_vw64.h
new file mode 100644
index 00000000000..c4de74cf11c
--- /dev/null
+++ b/src/mess/machine/c64_vw64.h
@@ -0,0 +1,54 @@
+/**********************************************************************
+
+ VizaWrite 64 cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __VW64__
+#define __VW64__
+
+
+#include "emu.h"
+#include "machine/c64exp.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_config_complete() { m_shortname = "c64_vizawrite"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual int c64_exrom_r(offs_t offset, int ba, int rw, int hiram) { return 0; }
+
+private:
+ emu_timer *m_game_timer;
+};
+
+
+// device type definition
+extern const device_type C64_VW64;
+
+
+#endif
diff --git a/src/mess/machine/c64_warp_speed.c b/src/mess/machine/c64_warp_speed.c
new file mode 100644
index 00000000000..cf04586b413
--- /dev/null
+++ b/src/mess/machine/c64_warp_speed.c
@@ -0,0 +1,160 @@
+/**********************************************************************
+
+ Cinemaware Warp Speed cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ 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 "c64_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<c64_warp_speed_cartridge_device>;
+
+
+//-------------------------------------------------
+// INPUT_PORTS( c64_warp_speed )
+//-------------------------------------------------
+
+INPUT_CHANGED_MEMBER( c64_warp_speed_cartridge_device::reset )
+{
+ if (!newval)
+ {
+ device_reset();
+ }
+
+ m_slot->reset_w(newval ? CLEAR_LINE : ASSERT_LINE);
+}
+
+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_KEYBOARD ) PORT_NAME("Reset") PORT_CODE(KEYCODE_F11) PORT_CHANGED_MEMBER(DEVICE_SELF, c64_warp_speed_cartridge_device, reset, 0)
+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),
+ 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ 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 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/mess/machine/c64_warp_speed.h b/src/mess/machine/c64_warp_speed.h
new file mode 100644
index 00000000000..c69e4db996d
--- /dev/null
+++ b/src/mess/machine/c64_warp_speed.h
@@ -0,0 +1,58 @@
+/**********************************************************************
+
+ Cinemaware Warp Speed cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __WARP_SPEED__
+#define __WARP_SPEED__
+
+
+#include "emu.h"
+#include "machine/c64exp.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;
+
+ DECLARE_INPUT_CHANGED_MEMBER( reset );
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "c64_warp_speed"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, 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/mess/machine/c64_westermann.c b/src/mess/machine/c64_westermann.c
new file mode 100644
index 00000000000..1f5658717fb
--- /dev/null
+++ b/src/mess/machine/c64_westermann.c
@@ -0,0 +1,85 @@
+/**********************************************************************
+
+ Westermann Learning cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_westermann.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_WESTERMANN = &device_creator<c64_westermann_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ if (!roml)
+ {
+ data = m_roml[offset & 0x1fff];
+ }
+ else if (!romh)
+ {
+ if (m_romh_mask)
+ {
+ data = m_romh[offset & 0x1fff];
+ }
+ else
+ {
+ data = m_roml[offset & 0x3fff];
+ }
+ }
+ else if (!io2)
+ {
+ m_game = 1;
+ }
+
+ return data;
+}
diff --git a/src/mess/machine/c64_westermann.h b/src/mess/machine/c64_westermann.h
new file mode 100644
index 00000000000..eb69bb5ad3a
--- /dev/null
+++ b/src/mess/machine/c64_westermann.h
@@ -0,0 +1,49 @@
+/**********************************************************************
+
+ Westermann Learning cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __WESTERMANN__
+#define __WESTERMANN__
+
+
+#include "emu.h"
+#include "machine/c64exp.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_config_complete() { m_shortname = "c64_westermann"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+};
+
+
+// device type definition
+extern const device_type C64_WESTERMANN;
+
+
+#endif
diff --git a/src/mess/machine/c64_xl80.c b/src/mess/machine/c64_xl80.c
new file mode 100644
index 00000000000..83e782cfd2a
--- /dev/null
+++ b/src/mess/machine/c64_xl80.c
@@ -0,0 +1,257 @@
+/*
+
+XL 80 cartridge
+(c) 1984 20 Data 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 "c64_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<c64_xl80_device>;
+
+
+//-------------------------------------------------
+// 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_interface crtc_intf
+//-------------------------------------------------
+
+void c64_xl80_device::crtc_update_row(mc6845_device *device, bitmap_rgb32 &bitmap, const rectangle &cliprect, UINT16 ma, UINT8 ra, UINT16 y, UINT8 x_count, INT8 cursor_x, void *param)
+{
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ 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[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) ? 7 : 0;
+
+ bitmap.pix32(y, x) = palette[color];
+
+ data <<= 1;
+ }
+ }
+}
+
+static MC6845_UPDATE_ROW( c64_xl80_update_row )
+{
+ c64_xl80_device *xl80 = downcast<c64_xl80_device *>(device->owner());
+ xl80->crtc_update_row(device,bitmap,cliprect,ma,ra,y,x_count,cursor_x,param);
+}
+
+static const mc6845_interface crtc_intf =
+{
+ MC6845_SCREEN_TAG,
+ 8,
+ NULL,
+ c64_xl80_update_row,
+ NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ NULL
+};
+
+
+//-------------------------------------------------
+// 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_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500))
+ MCFG_SCREEN_REFRESH_RATE(50)
+
+ //MCFG_GFXDECODE(c64_xl80)
+
+ MCFG_MC6845_ADD(HD46505SP_TAG, H46505, XTAL_14_31818MHz, crtc_intf)
+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),
+ device_c64_expansion_card_interface(mconfig, *this),
+ m_crtc(*this, HD46505SP_TAG)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void c64_xl80_device::device_start()
+{
+ // find memory regions
+ m_char_rom = memregion(HD46505SP_TAG)->base();
+ c64_ram_pointer(machine(), RAM_SIZE);
+
+ // state saving
+ save_pointer(NAME(m_ram), 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ 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 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/mess/machine/c64_xl80.h b/src/mess/machine/c64_xl80.h
new file mode 100644
index 00000000000..1ce855c725f
--- /dev/null
+++ b/src/mess/machine/c64_xl80.h
@@ -0,0 +1,65 @@
+/**********************************************************************
+
+ XL 80 cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __XL80__
+#define __XL80__
+
+
+#include "emu.h"
+#include "machine/c64exp.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
+ void crtc_update_row(mc6845_device *device, bitmap_rgb32 &bitmap, const rectangle &cliprect, UINT16 ma, UINT8 ra, UINT16 y, UINT8 x_count, INT8 cursor_x, void *param);
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "c64_xl80"; }
+ 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, int ba, int roml, int romh, int io1, int io2);
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int ba, int roml, int romh, int io1, int io2);
+ virtual int c64_game_r(offs_t offset, int ba, int rw, int hiram) { return 1; }
+ virtual int c64_exrom_r(offs_t offset, int ba, int rw, int hiram) { return 0; }
+
+private:
+ required_device<h46505_device> m_crtc;
+
+ UINT8 *m_char_rom;
+};
+
+
+// device type definition
+extern const device_type C64_XL80;
+
+
+#endif
diff --git a/src/mess/machine/c64_zaxxon.c b/src/mess/machine/c64_zaxxon.c
new file mode 100644
index 00000000000..e1ed4add9fa
--- /dev/null
+++ b/src/mess/machine/c64_zaxxon.c
@@ -0,0 +1,69 @@
+/**********************************************************************
+
+ Zaxxon/Super Zaxxon cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "c64_zaxxon.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_ZAXXON = &device_creator<c64_zaxxon_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ 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, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ 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/mess/machine/c64_zaxxon.h b/src/mess/machine/c64_zaxxon.h
new file mode 100644
index 00000000000..b87fca6f41c
--- /dev/null
+++ b/src/mess/machine/c64_zaxxon.h
@@ -0,0 +1,51 @@
+/**********************************************************************
+
+ Zaxxon/Super Zaxxon cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __ZAXXON__
+#define __ZAXXON__
+
+
+#include "emu.h"
+#include "machine/c64exp.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_config_complete() { m_shortname = "c64_zaxxon"; }
+ virtual void device_start();
+
+ // device_c64_expansion_card_interface overrides
+ virtual UINT8 c64_cd_r(address_space &space, offs_t offset, 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/mess/machine/c64exp.c b/src/mess/machine/c64exp.c
new file mode 100644
index 00000000000..37123f377be
--- /dev/null
+++ b/src/mess/machine/c64exp.c
@@ -0,0 +1,476 @@
+/**********************************************************************
+
+ Commodore 64 Expansion Port emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "machine/c64exp.h"
+
+
+
+//**************************************************************************
+// MACROS/CONSTANTS
+//**************************************************************************
+
+#define LOG 0
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C64_EXPANSION_SLOT = &device_creator<c64_expansion_slot_device>;
+
+
+
+//**************************************************************************
+// 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(NULL),
+ m_romh(NULL),
+ m_ram(NULL),
+ m_nvram(NULL),
+ m_nvram_size(0),
+ m_roml_mask(0),
+ m_romh_mask(0),
+ m_ram_mask(0),
+ m_game(1),
+ m_exrom(1)
+{
+ m_slot = dynamic_cast<c64_expansion_slot_device *>(device.owner());
+}
+
+
+//-------------------------------------------------
+// ~device_c64_expansion_card_interface - destructor
+//-------------------------------------------------
+
+device_c64_expansion_card_interface::~device_c64_expansion_card_interface()
+{
+}
+
+
+//-------------------------------------------------
+// c64_roml_pointer - get low ROM pointer
+//-------------------------------------------------
+
+UINT8* device_c64_expansion_card_interface::c64_roml_pointer(running_machine &machine, size_t size)
+{
+ if (m_roml == NULL)
+ {
+ m_roml = auto_alloc_array(machine, UINT8, size);
+
+ m_roml_mask = size - 1;
+ }
+
+ return m_roml;
+}
+
+
+//-------------------------------------------------
+// c64_romh_pointer - get high ROM pointer
+//-------------------------------------------------
+
+UINT8* device_c64_expansion_card_interface::c64_romh_pointer(running_machine &machine, size_t size)
+{
+ if (m_romh == NULL)
+ {
+ m_romh = auto_alloc_array(machine, UINT8, size);
+
+ m_romh_mask = size - 1;
+ }
+
+ return m_romh;
+}
+
+
+//-------------------------------------------------
+// c64_ram_pointer - get RAM pointer
+//-------------------------------------------------
+
+UINT8* device_c64_expansion_card_interface::c64_ram_pointer(running_machine &machine, size_t size)
+{
+ if (m_ram == NULL)
+ {
+ m_ram = auto_alloc_array(machine, UINT8, size);
+
+ m_ram_mask = size - 1;
+ }
+
+ return m_ram;
+}
+
+
+//-------------------------------------------------
+// c64_ram_pointer - get NVRAM pointer
+//-------------------------------------------------
+
+UINT8* device_c64_expansion_card_interface::c64_nvram_pointer(running_machine &machine, size_t size)
+{
+ if (m_nvram == NULL)
+ {
+ m_nvram = auto_alloc_array(machine, UINT8, size);
+
+ m_nvram_mask = size - 1;
+ m_nvram_size = size;
+ }
+
+ return m_nvram;
+}
+
+
+
+//**************************************************************************
+// 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),
+ device_slot_interface(mconfig, *this),
+ device_image_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// c64_expansion_slot_device - destructor
+//-------------------------------------------------
+
+c64_expansion_slot_device::~c64_expansion_slot_device()
+{
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void c64_expansion_slot_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const c64_expansion_slot_interface *intf = reinterpret_cast<const c64_expansion_slot_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<c64_expansion_slot_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_in_dma_cd_cb, 0, sizeof(m_in_dma_cd_cb));
+ memset(&m_out_dma_cd_cb, 0, sizeof(m_out_dma_cd_cb));
+ memset(&m_out_irq_cb, 0, sizeof(m_out_irq_cb));
+ memset(&m_out_nmi_cb, 0, sizeof(m_out_nmi_cb));
+ memset(&m_out_dma_cb, 0, sizeof(m_out_dma_cb));
+ memset(&m_out_reset_cb, 0, sizeof(m_out_reset_cb));
+ }
+
+ // set brief and instance name
+ update_names();
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void c64_expansion_slot_device::device_start()
+{
+ m_cart = dynamic_cast<device_c64_expansion_card_interface *>(get_card_device());
+
+ // resolve callbacks
+ m_in_dma_cd_func.resolve(m_in_dma_cd_cb, *this);
+ m_out_dma_cd_func.resolve(m_out_dma_cd_cb, *this);
+ m_out_irq_func.resolve(m_out_irq_cb, *this);
+ m_out_nmi_func.resolve(m_out_nmi_cb, *this);
+ m_out_dma_func.resolve(m_out_dma_cb, *this);
+ m_out_reset_func.resolve(m_out_reset_cb, *this);
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void c64_expansion_slot_device::device_reset()
+{
+ port_reset_w(ASSERT_LINE);
+ port_reset_w(CLEAR_LINE);
+}
+
+
+//-------------------------------------------------
+// call_load -
+//-------------------------------------------------
+
+bool c64_expansion_slot_device::call_load()
+{
+ if (m_cart)
+ {
+ size_t size = 0;
+
+ if (software_entry() == NULL)
+ {
+ size = length();
+
+ if (!mame_stricmp(filetype(), "80"))
+ {
+ fread(m_cart->c64_roml_pointer(machine(), size), size);
+ m_cart->m_exrom = (0);
+
+ if (size == 0x4000)
+ {
+ m_cart->m_game = 0;
+ }
+ }
+ else if (!mame_stricmp(filetype(), "a0"))
+ {
+ fread(m_cart->c64_romh_pointer(machine(), 0x2000), 0x2000);
+
+ m_cart->m_exrom = 0;
+ m_cart->m_game = 0;
+ }
+ else if (!mame_stricmp(filetype(), "e0"))
+ {
+ fread(m_cart->c64_romh_pointer(machine(), 0x2000), 0x2000);
+
+ m_cart->m_game = 0;
+ }
+ else if (!mame_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;
+
+ if (roml_size) roml = m_cart->c64_roml_pointer(machine(), roml_size);
+ if (romh_size) romh = m_cart->c64_romh_pointer(machine(), romh_size);
+
+ cbm_crt_read_data(m_file, roml, romh);
+ }
+
+ m_cart->m_exrom = exrom;
+ m_cart->m_game = game;
+ }
+ }
+ else
+ {
+ size = get_software_region_length("uprom");
+
+ if (size)
+ {
+ // Ultimax (VIC-10) cartridge
+ memcpy(m_cart->c64_romh_pointer(machine(), size), get_software_region("uprom"), size);
+
+ size = get_software_region_length("lorom");
+ if (size) memcpy(m_cart->c64_roml_pointer(machine(), size), get_software_region("lorom"), size);
+
+ m_cart->m_exrom = 1;
+ m_cart->m_game = 0;
+ }
+ else
+ {
+ // Commodore 64/128 cartridge
+ size = get_software_region_length("roml");
+ if (size) memcpy(m_cart->c64_roml_pointer(machine(), size), get_software_region("roml"), size);
+
+ size = get_software_region_length("romh");
+ if (size) memcpy(m_cart->c64_romh_pointer(machine(), size), get_software_region("romh"), size);
+
+ size = get_software_region_length("ram");
+ if (size) memset(m_cart->c64_ram_pointer(machine(), size), 0, size);
+
+ size = get_software_region_length("nvram");
+ if (size) memset(m_cart->c64_nvram_pointer(machine(), size), 0, size);
+
+ m_cart->m_exrom = atol(get_feature("exrom"));
+ m_cart->m_game = atol(get_feature("game"));
+ }
+ }
+ }
+
+ return IMAGE_INIT_PASS;
+}
+
+
+//-------------------------------------------------
+// call_softlist_load -
+//-------------------------------------------------
+
+bool c64_expansion_slot_device::call_softlist_load(char *swlist, char *swname, rom_entry *start_entry)
+{
+ load_software_part_region(this, swlist, swname, start_entry);
+
+ return true;
+}
+
+
+//-------------------------------------------------
+// get_default_card_software -
+//-------------------------------------------------
+
+const char * c64_expansion_slot_device::get_default_card_software(const machine_config &config, emu_options &options)
+{
+ if (open_image_file(options))
+ {
+ if (!mame_stricmp(filetype(), "crt"))
+ {
+ return cbm_crt_get_card(m_file);
+ }
+
+ clear();
+ }
+
+ return software_get_default_slot(config, options, this, "standard");
+}
+
+
+//-------------------------------------------------
+// cd_r - cartridge data read
+//-------------------------------------------------
+
+UINT8 c64_expansion_slot_device::cd_r(address_space &space, offs_t offset, int ba, int roml, int romh, int io1, int io2)
+{
+ UINT8 data = 0;
+
+ if (m_cart != NULL)
+ {
+ data = m_cart->c64_cd_r(space, offset, 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 ba, int roml, int romh, int io1, int io2)
+{
+ if (m_cart != NULL)
+ {
+ m_cart->c64_cd_w(space, offset, data, ba, roml, romh, io1, io2);
+ }
+}
+
+
+//-------------------------------------------------
+// game_r - GAME read
+//-------------------------------------------------
+
+int c64_expansion_slot_device::game_r(offs_t offset, int ba, int rw, int hiram)
+{
+ int state = 1;
+
+ if (m_cart != NULL)
+ {
+ state = m_cart->c64_game_r(offset, ba, rw, hiram);
+ }
+
+ return state;
+}
+
+
+//-------------------------------------------------
+// exrom_r - EXROM read
+//-------------------------------------------------
+
+int c64_expansion_slot_device::exrom_r(offs_t offset, int ba, int rw, int hiram)
+{
+ int state = 1;
+
+ if (m_cart != NULL)
+ {
+ state = m_cart->c64_exrom_r(offset, ba, rw, hiram);
+ }
+
+ return state;
+}
+
+
+//-------------------------------------------------
+// screen_update -
+//-------------------------------------------------
+
+UINT32 c64_expansion_slot_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ bool value = false;
+
+ if (m_cart != NULL)
+ {
+ value = m_cart->c64_screen_update(screen, bitmap, cliprect);
+ }
+
+ return value;
+}
+
+WRITE_LINE_MEMBER( c64_expansion_slot_device::port_reset_w ) { if (m_cart != NULL) m_cart->c64_reset_w(state); }
+
+
+//-------------------------------------------------
+// dma_cd_r - DMA read
+//-------------------------------------------------
+
+UINT8 c64_expansion_slot_device::dma_cd_r(offs_t offset)
+{
+ return m_in_dma_cd_func(offset);
+}
+
+
+//-------------------------------------------------
+// dma_cd_w - DMA write
+//-------------------------------------------------
+
+void c64_expansion_slot_device::dma_cd_w(offs_t offset, UINT8 data)
+{
+ m_out_dma_cd_func(offset, data);
+}
+
+
+WRITE_LINE_MEMBER( c64_expansion_slot_device::irq_w ) { m_out_irq_func(state); }
+WRITE_LINE_MEMBER( c64_expansion_slot_device::nmi_w ) { m_out_nmi_func(state); }
+WRITE_LINE_MEMBER( c64_expansion_slot_device::dma_w ) { m_out_dma_func(state); }
+WRITE_LINE_MEMBER( c64_expansion_slot_device::reset_w ) { m_out_reset_func(state); }
+
+
+//-------------------------------------------------
+// phi2 - system clock frequency
+//-------------------------------------------------
+
+int c64_expansion_slot_device::phi2()
+{
+ return clock();
+}
+
+
+//-------------------------------------------------
+// dotclock - dot clock frequency
+//-------------------------------------------------
+
+int c64_expansion_slot_device::dotclock()
+{
+ return phi2() * 8;
+}
diff --git a/src/mess/machine/c64exp.h b/src/mess/machine/c64exp.h
new file mode 100644
index 00000000000..32937a81daa
--- /dev/null
+++ b/src/mess/machine/c64exp.h
@@ -0,0 +1,202 @@
+/**********************************************************************
+
+ Commodore 64 Expansion Port emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+
+ 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 C64_EXPANSION_INTERFACE(_name) \
+ const c64_expansion_slot_interface (_name) =
+
+
+#define MCFG_C64_EXPANSION_SLOT_ADD(_tag, _clock, _config, _slot_intf, _def_slot, _def_inp) \
+ MCFG_DEVICE_ADD(_tag, C64_EXPANSION_SLOT, _clock) \
+ MCFG_DEVICE_CONFIG(_config) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false)
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> c64_expansion_slot_interface
+
+struct c64_expansion_slot_interface
+{
+ devcb_read8 m_in_dma_cd_cb;
+ devcb_write8 m_out_dma_cd_cb;
+ devcb_write_line m_out_irq_cb;
+ devcb_write_line m_out_nmi_cb;
+ devcb_write_line m_out_dma_cb;
+ devcb_write_line m_out_reset_cb;
+};
+
+
+// ======================> c64_expansion_slot_device
+
+class device_c64_expansion_card_interface;
+
+class c64_expansion_slot_device : public device_t,
+ public c64_expansion_slot_interface,
+ 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);
+ virtual ~c64_expansion_slot_device();
+
+ // computer interface
+ UINT8 cd_r(address_space &space, offs_t offset, int ba, int roml, int romh, int io1, int io2);
+ void cd_w(address_space &space, offs_t offset, UINT8 data, int ba, int roml, int romh, int io1, int io2);
+ int game_r(offs_t offset, int ba, int rw, int hiram);
+ int exrom_r(offs_t offset, int ba, int rw, int hiram);
+ UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+ DECLARE_WRITE_LINE_MEMBER( port_reset_w );
+
+ // cartridge interface
+ UINT8 dma_cd_r(offs_t offset);
+ void dma_cd_w(offs_t offset, UINT8 data);
+ DECLARE_WRITE_LINE_MEMBER( irq_w );
+ DECLARE_WRITE_LINE_MEMBER( nmi_w );
+ DECLARE_WRITE_LINE_MEMBER( dma_w );
+ DECLARE_WRITE_LINE_MEMBER( reset_w );
+ int phi2();
+ int dotclock();
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+ virtual void device_start();
+ virtual void device_reset();
+
+ // image-level overrides
+ virtual bool call_load();
+ virtual bool call_softlist_load(char *swlist, char *swname, 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 const char * get_default_card_software(const machine_config &config, emu_options &options);
+
+ devcb_resolved_read8 m_in_dma_cd_func;
+ devcb_resolved_write8 m_out_dma_cd_func;
+ devcb_resolved_write_line m_out_irq_func;
+ devcb_resolved_write_line m_out_nmi_func;
+ devcb_resolved_write_line m_out_dma_func;
+ devcb_resolved_write_line m_out_reset_func;
+
+ device_c64_expansion_card_interface *m_cart;
+};
+
+
+// ======================> 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();
+
+protected:
+ // initialization
+ virtual UINT8* c64_roml_pointer(running_machine &machine, size_t size);
+ virtual UINT8* c64_romh_pointer(running_machine &machine, size_t size);
+ virtual UINT8* c64_ram_pointer(running_machine &machine, size_t size);
+ virtual UINT8* c64_nvram_pointer(running_machine &machine, size_t size);
+
+ // runtime
+ virtual UINT8 c64_cd_r(address_space &space, offs_t offset, int ba, int roml, int romh, int io1, int io2) { return 0; };
+ virtual void c64_cd_w(address_space &space, offs_t offset, UINT8 data, int ba, int roml, int romh, int io1, int io2) { };
+ virtual int c64_game_r(offs_t offset, int ba, int rw, int hiram) { return m_game; }
+ virtual int c64_exrom_r(offs_t offset, int ba, int rw, int hiram) { return m_exrom; }
+ virtual void c64_reset_w(int state) { };
+ virtual UINT32 c64_screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { return 0; }
+
+ c64_expansion_slot_device *m_slot;
+
+ UINT8 *m_roml;
+ UINT8 *m_romh;
+ UINT8 *m_ram;
+ UINT8 *m_nvram;
+
+ size_t m_nvram_size;
+
+ size_t m_roml_mask;
+ size_t m_romh_mask;
+ size_t m_ram_mask;
+ size_t m_nvram_mask;
+
+ int m_game;
+ int m_exrom;
+};
+
+
+// device type definition
+extern const device_type C64_EXPANSION_SLOT;
+
+
+
+#endif
diff --git a/src/mess/machine/c64user.c b/src/mess/machine/c64user.c
new file mode 100644
index 00000000000..018fcd564c3
--- /dev/null
+++ b/src/mess/machine/c64user.c
@@ -0,0 +1,141 @@
+/**********************************************************************
+
+ Commodore 64 User Port emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "machine/c64user.h"
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type C64_USER_PORT = &device_creator<c64_user_port_device>;
+
+
+
+//**************************************************************************
+// CARD INTERFACE
+//**************************************************************************
+
+//-------------------------------------------------
+// device_c64_user_port_interface - constructor
+//-------------------------------------------------
+
+device_c64_user_port_interface::device_c64_user_port_interface(const machine_config &mconfig, device_t &device)
+ : device_slot_card_interface(mconfig,device)
+{
+ m_slot = dynamic_cast<c64_user_port_device *>(device.owner());
+}
+
+
+//-------------------------------------------------
+// ~device_c64_user_port_interface - destructor
+//-------------------------------------------------
+
+device_c64_user_port_interface::~device_c64_user_port_interface()
+{
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// c64_user_port_device - constructor
+//-------------------------------------------------
+
+c64_user_port_device::c64_user_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, C64_USER_PORT, "C64 user port", tag, owner, clock),
+ device_slot_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// c64_user_port_device - destructor
+//-------------------------------------------------
+
+c64_user_port_device::~c64_user_port_device()
+{
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void c64_user_port_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const c64_user_port_interface *intf = reinterpret_cast<const c64_user_port_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<c64_user_port_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_cnt1_cb, 0, sizeof(m_out_cnt1_cb));
+ memset(&m_out_sp1_cb, 0, sizeof(m_out_sp1_cb));
+ memset(&m_out_cnt2_cb, 0, sizeof(m_out_cnt2_cb));
+ memset(&m_out_sp2_cb, 0, sizeof(m_out_sp2_cb));
+ memset(&m_out_flag2_cb, 0, sizeof(m_out_flag2_cb));
+ memset(&m_out_reset_cb, 0, sizeof(m_out_reset_cb));
+ }
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void c64_user_port_device::device_start()
+{
+ m_cart = dynamic_cast<device_c64_user_port_interface *>(get_card_device());
+
+ // resolve callbacks
+ m_out_cnt1_func.resolve(m_out_cnt1_cb, *this);
+ m_out_sp1_func.resolve(m_out_sp1_cb, *this);
+ m_out_cnt2_func.resolve(m_out_cnt2_cb, *this);
+ m_out_sp2_func.resolve(m_out_sp2_cb, *this);
+ m_out_flag2_func.resolve(m_out_flag2_cb, *this);
+ m_out_reset_func.resolve(m_out_reset_cb, *this);
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void c64_user_port_device::device_reset()
+{
+ port_reset_w(ASSERT_LINE);
+ port_reset_w(CLEAR_LINE);
+}
+
+
+READ8_MEMBER( c64_user_port_device::pb_r ) { UINT8 data = 0xff; if (m_cart != NULL) data = m_cart->c64_pb_r(space, offset); return data; }
+WRITE8_MEMBER( c64_user_port_device::pb_w ) { if (m_cart != NULL) m_cart->c64_pb_w(space, offset, data); }
+READ_LINE_MEMBER( c64_user_port_device::pa2_r ) { int state = 1; if (m_cart != NULL) state = m_cart->c64_pa2_r(); return state; }
+WRITE_LINE_MEMBER( c64_user_port_device::pa2_w ) { if (m_cart != NULL) m_cart->c64_pa2_w(state); }
+WRITE_LINE_MEMBER( c64_user_port_device::pc2_w ) { if (m_cart != NULL) m_cart->c64_pc2_w(state); }
+WRITE_LINE_MEMBER( c64_user_port_device::atn_w ) { if (m_cart != NULL) m_cart->c64_atn_w(state); }
+WRITE_LINE_MEMBER( c64_user_port_device::port_reset_w ) { if (m_cart != NULL) m_cart->c64_reset_w(state); }
+
+WRITE_LINE_MEMBER( c64_user_port_device::cnt1_w ) { m_out_cnt1_func(state); }
+WRITE_LINE_MEMBER( c64_user_port_device::sp1_w ) { m_out_sp1_func(state); }
+WRITE_LINE_MEMBER( c64_user_port_device::cnt2_w ) { m_out_cnt2_func(state); }
+WRITE_LINE_MEMBER( c64_user_port_device::sp2_w ) { m_out_sp2_func(state); }
+WRITE_LINE_MEMBER( c64_user_port_device::flag2_w ) { m_out_flag2_func(state); }
+WRITE_LINE_MEMBER( c64_user_port_device::reset_w ) { m_out_reset_func(state); }
diff --git a/src/mess/machine/c64user.h b/src/mess/machine/c64user.h
new file mode 100644
index 00000000000..761bc5ff3a8
--- /dev/null
+++ b/src/mess/machine/c64user.h
@@ -0,0 +1,156 @@
+/**********************************************************************
+
+ Commodore 64 User Port emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+
+ 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 "emu.h"
+
+
+
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
+
+#define C64_USER_PORT_TAG "user"
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define C64_USER_PORT_INTERFACE(_name) \
+ const c64_user_port_interface (_name) =
+
+
+#define MCFG_C64_USER_PORT_ADD(_tag, _config, _slot_intf, _def_slot, _def_inp) \
+ MCFG_DEVICE_ADD(_tag, C64_USER_PORT, 0) \
+ MCFG_DEVICE_CONFIG(_config) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false)
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> c64_user_port_interface
+
+struct c64_user_port_interface
+{
+ devcb_write_line m_out_cnt1_cb;
+ devcb_write_line m_out_sp1_cb;
+ devcb_write_line m_out_cnt2_cb;
+ devcb_write_line m_out_sp2_cb;
+ devcb_write_line m_out_flag2_cb;
+ devcb_write_line m_out_reset_cb;
+};
+
+
+// ======================> c64_user_port_device
+
+class device_c64_user_port_interface;
+
+class c64_user_port_device : public device_t,
+ public c64_user_port_interface,
+ public device_slot_interface
+{
+public:
+ // construction/destruction
+ c64_user_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ virtual ~c64_user_port_device();
+
+ // computer interface
+ DECLARE_READ8_MEMBER( pb_r );
+ DECLARE_WRITE8_MEMBER( pb_w );
+ DECLARE_READ_LINE_MEMBER( pa2_r );
+ DECLARE_WRITE_LINE_MEMBER( pa2_w );
+ DECLARE_WRITE_LINE_MEMBER( pc2_w );
+ DECLARE_WRITE_LINE_MEMBER( port_reset_w );
+
+ // cartridge interface
+ DECLARE_WRITE_LINE_MEMBER( sp1_w );
+ DECLARE_WRITE_LINE_MEMBER( cnt1_w );
+ DECLARE_WRITE_LINE_MEMBER( sp2_w );
+ DECLARE_WRITE_LINE_MEMBER( cnt2_w );
+ DECLARE_WRITE_LINE_MEMBER( flag2_w );
+ DECLARE_WRITE_LINE_MEMBER( atn_w );
+ DECLARE_WRITE_LINE_MEMBER( reset_w );
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+ virtual void device_start();
+ virtual void device_reset();
+
+ devcb_resolved_write_line m_out_cnt1_func;
+ devcb_resolved_write_line m_out_sp1_func;
+ devcb_resolved_write_line m_out_cnt2_func;
+ devcb_resolved_write_line m_out_sp2_func;
+ devcb_resolved_write_line m_out_flag2_func;
+ devcb_resolved_write_line m_out_reset_func;
+
+ device_c64_user_port_interface *m_cart;
+};
+
+
+// ======================> device_c64_user_port_interface
+
+// class representing interface-specific live c64_expansion card
+class device_c64_user_port_interface : public device_slot_card_interface
+{
+public:
+ // construction/destruction
+ device_c64_user_port_interface(const machine_config &mconfig, device_t &device);
+ virtual ~device_c64_user_port_interface();
+
+ virtual UINT8 c64_pb_r(address_space &space, offs_t offset) { return 0xff; };
+ virtual void c64_pb_w(address_space &space, offs_t offset, UINT8 data) { };
+
+ virtual int c64_pa2_r() { return 1; };
+ virtual void c64_pa2_w(int state) { };
+ virtual void c64_cnt1_w(int state) { };
+ virtual void c64_sp1_w(int state) { };
+ virtual void c64_pc2_w(int state) { };
+ virtual void c64_cnt2_w(int state) { };
+ virtual void c64_sp2_w(int state) { };
+ virtual void c64_atn_w(int state) { };
+
+ // reset
+ virtual void c64_reset_w(int state) { };
+
+protected:
+ c64_user_port_device *m_slot;
+};
+
+
+// device type definition
+extern const device_type C64_USER_PORT;
+
+
+
+#endif
diff --git a/src/mess/machine/c65.c b/src/mess/machine/c65.c
new file mode 100644
index 00000000000..e5b908b4300
--- /dev/null
+++ b/src/mess/machine/c65.c
@@ -0,0 +1,1068 @@
+/***************************************************************************
+ commodore c65 home computer
+ peter.trauner@jk.uni-linz.ac.at
+ documention
+ www.funet.fi
+ ***************************************************************************/
+
+#include "emu.h"
+
+#include "includes/cbm.h"
+#include "includes/c65.h"
+#include "includes/c64_legacy.h"
+#include "cpu/m6502/m4510.h"
+#include "sound/sid6581.h"
+#include "machine/6526cia.h"
+#include "machine/cbmiec.h"
+#include "machine/ram.h"
+#include "video/vic4567.h"
+
+#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)
+
+
+
+
+
+/*UINT8 *c65_basic; */
+/*UINT8 *c65_kernal; */
+/*UINT8 *c65_dos; */
+/*UINT8 *c65_monitor; */
+/*UINT8 *c65_graphics; */
+
+
+static void c65_nmi( running_machine &machine )
+{
+ c65_state *state = machine.driver_data<c65_state>();
+ device_t *cia_1 = machine.device("cia_1");
+ int cia1irq = mos6526_irq_r(cia_1);
+
+ if (state->m_nmilevel != (machine.root_device().ioport("SPECIAL")->read() & 0x80) || cia1irq) /* KEY_RESTORE */
+ {
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_NMI, (machine.root_device().ioport("SPECIAL")->read() & 0x80) || cia1irq);
+
+ state->m_nmilevel = (machine.root_device().ioport("SPECIAL")->read() & 0x80) || cia1irq;
+ }
+}
+
+
+/***********************************************
+
+ CIA Interfaces
+
+***********************************************/
+
+/*
+ * CIA 0 - Port A keyboard line select
+ * CIA 0 - Port B keyboard line read
+ *
+ * flag cassette read input, serial request in
+ * irq to irq connected
+ *
+ * see machine/cbm.c
+ */
+
+static READ8_DEVICE_HANDLER( c65_cia0_port_a_r )
+{
+ UINT8 cia0portb = mos6526_pb_r(device->machine().device("cia_0"), 0);
+
+ return cbm_common_cia0_port_a_r(device, cia0portb);
+}
+
+static READ8_DEVICE_HANDLER( c65_cia0_port_b_r )
+{
+ c65_state *state = device->machine().driver_data<c65_state>();
+ UINT8 value = 0xff;
+ UINT8 cia0porta = mos6526_pa_r(device->machine().device("cia_0"), 0);
+
+ value &= cbm_common_cia0_port_b_r(device, cia0porta);
+
+ if (!(state->m_6511_port & 0x02))
+ value &= state->m_keyline;
+
+ return value;
+}
+
+static WRITE8_DEVICE_HANDLER( c65_cia0_port_b_w )
+{
+// was there lightpen support in c65 video chip?
+// device_t *vic3 = device->machine().device("vic3");
+// vic3_lightpen_write(vic3, data & 0x10);
+}
+
+static void c65_irq( running_machine &machine, int level )
+{
+ c65_state *state = machine.driver_data<c65_state>();
+ if (level != state->m_old_level)
+ {
+ DBG_LOG(machine, 3, "mos6510", ("irq %s\n", level ? "start" : "end"));
+ cputag_set_input_line(machine, "maincpu", M6510_IRQ_LINE, level);
+ state->m_old_level = level;
+ }
+}
+
+/* is this correct for c65 as well as c64? */
+static void c65_cia0_interrupt( device_t *device, int level )
+{
+ c65_state *state = device->machine().driver_data<c65_state>();
+ c65_irq (device->machine(), level || state->m_vicirq);
+}
+
+/* is this correct for c65 as well as c64? */
+void c65_vic_interrupt( running_machine &machine, int level )
+{
+ c65_state *state = machine.driver_data<c65_state>();
+ device_t *cia_0 = machine.device("cia_0");
+#if 1
+ if (level != state->m_vicirq)
+ {
+ c65_irq (machine, level || mos6526_irq_r(cia_0));
+ state->m_vicirq = level;
+ }
+#endif
+}
+
+const mos6526_interface c65_ntsc_cia0 =
+{
+ 60,
+ DEVCB_LINE(c65_cia0_interrupt),
+ DEVCB_NULL, /* pc_func */
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(c65_cia0_port_a_r),
+ DEVCB_NULL,
+ DEVCB_HANDLER(c65_cia0_port_b_r),
+ DEVCB_HANDLER(c65_cia0_port_b_w)
+};
+
+const mos6526_interface c65_pal_cia0 =
+{
+ 50,
+ DEVCB_LINE(c65_cia0_interrupt),
+ DEVCB_NULL, /* pc_func */
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(c65_cia0_port_a_r),
+ DEVCB_NULL,
+ DEVCB_HANDLER(c65_cia0_port_b_r),
+ DEVCB_HANDLER(c65_cia0_port_b_w)
+};
+
+/*
+ * CIA 1 - Port A
+ * bit 7 serial bus data input
+ * bit 6 serial bus clock input
+ * bit 5 serial bus data output
+ * bit 4 serial bus clock output
+ * bit 3 serial bus atn output
+ * bit 2 rs232 data output
+ * bits 1-0 vic-chip system memory bank select
+ *
+ * CIA 1 - Port B
+ * bit 7 user rs232 data set ready
+ * bit 6 user rs232 clear to send
+ * bit 5 user
+ * bit 4 user rs232 carrier detect
+ * bit 3 user rs232 ring indicator
+ * bit 2 user rs232 data terminal ready
+ * bit 1 user rs232 request to send
+ * bit 0 user rs232 received data
+ *
+ * flag restore key or rs232 received data input
+ * irq to nmi connected ?
+ */
+static READ8_DEVICE_HANDLER( c65_cia1_port_a_r )
+{
+ c65_state *state = device->machine().driver_data<c65_state>();
+ UINT8 value = 0xff;
+
+ if (!state->m_iec->clk_r())
+ value &= ~0x40;
+
+ if (!state->m_iec->data_r())
+ value &= ~0x80;
+
+ return value;
+}
+
+static WRITE8_DEVICE_HANDLER( c65_cia1_port_a_w )
+{
+ c65_state *state = device->machine().driver_data<c65_state>();
+ static const int helper[4] = {0xc000, 0x8000, 0x4000, 0x0000};
+
+ state->m_iec->atn_w(!BIT(data, 3));
+ state->m_iec->clk_w(!BIT(data, 4));
+ state->m_iec->data_w(!BIT(data, 5));
+
+ state->m_vicaddr = state->m_memory + helper[data & 0x03];
+}
+
+static WRITE_LINE_DEVICE_HANDLER( c65_cia1_interrupt )
+{
+ c65_nmi(device->machine());
+}
+
+const mos6526_interface c65_ntsc_cia1 =
+{
+ 60,
+ DEVCB_LINE(c65_cia1_interrupt),
+ DEVCB_NULL, /* pc_func */
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(c65_cia1_port_a_r),
+ DEVCB_HANDLER(c65_cia1_port_a_w),
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+const mos6526_interface c65_pal_cia1 =
+{
+ 50,
+ DEVCB_LINE(c65_cia1_interrupt),
+ DEVCB_NULL, /* pc_func */
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(c65_cia1_port_a_r),
+ DEVCB_HANDLER(c65_cia1_port_a_w),
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+/***********************************************
+
+ Memory Handlers
+
+***********************************************/
+
+/* processor has only 1 mega address space !? */
+/* and system 8 megabyte */
+/* dma controller and bankswitch hardware ?*/
+static READ8_HANDLER( c65_read_mem )
+{
+ c65_state *state = space->machine().driver_data<c65_state>();
+ UINT8 result;
+ if (offset <= 0x0ffff)
+ result = state->m_memory[offset];
+ else
+ result = space->read_byte(offset);
+ return result;
+}
+
+static WRITE8_HANDLER( c65_write_mem )
+{
+ c65_state *state = space->machine().driver_data<c65_state>();
+ if (offset <= 0x0ffff)
+ state->m_memory[offset] = data;
+ else
+ space->write_byte(offset, data);
+}
+
+/* dma chip at 0xd700
+ used:
+ writing banknumber to offset 2
+ writing hibyte to offset 1
+ writing lobyte to offset 0
+ cpu holded, dma transfer(data at address) executed, cpu activated
+
+ command data:
+ 0 command (0 copy, 3 fill)
+ 1,2 length
+ 3,4,5 source
+ 6,7,8 dest
+ 9 subcommand
+ 10 mod
+
+ version 1:
+ seldom copy (overlapping) from 0x402002 to 0x402008
+ (making place for new line in basic area)
+ for whats this bit 0x400000, or is this really the address?
+ maybe means add counter to address for access,
+ so allowing up or down copies, and reordering copies
+
+ version 2:
+ cmd 0x30 used for this
+*/
+static void c65_dma_port_w( running_machine &machine, int offset, int value )
+{
+ c65_state *state = machine.driver_data<c65_state>();
+ PAIR pair, src, dst, len;
+ UINT8 cmd, fill;
+ int i;
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ switch (offset & 3)
+ {
+ case 2:
+ case 1:
+ state->m_dma.data[offset & 3] = value;
+ break;
+ case 0:
+ pair.b.h3 = 0;
+ pair.b.h2 = state->m_dma.data[2];
+ pair.b.h = state->m_dma.data[1];
+ pair.b.l = state->m_dma.data[0]=value;
+ cmd = c65_read_mem(space, pair.d++);
+ len.w.h = 0;
+ len.b.l = c65_read_mem(space, pair.d++);
+ len.b.h = c65_read_mem(space, pair.d++);
+ src.b.h3 = 0;
+ fill = src.b.l = c65_read_mem(space, pair.d++);
+ src.b.h = c65_read_mem(space, pair.d++);
+ src.b.h2 = c65_read_mem(space, pair.d++);
+ dst.b.h3 = 0;
+ dst.b.l = c65_read_mem(space, pair.d++);
+ dst.b.h = c65_read_mem(space, pair.d++);
+ dst.b.h2 = c65_read_mem(space, pair.d++);
+
+ switch (cmd)
+ {
+ case 0:
+ if (src.d == 0x3ffff) state->m_dump_dma = 1;
+ if (state->m_dump_dma)
+ DBG_LOG(space->machine(), 1,"dma copy job",
+ ("len:%.4x src:%.6x dst:%.6x sub:%.2x modrm:%.2x\n",
+ len.w.l, src.d, dst.d, c65_read_mem(space, pair.d),
+ c65_read_mem(space, pair.d + 1) ) );
+ if ((state->m_dma.version == 1)
+ && ( (src.d&0x400000) || (dst.d & 0x400000)))
+ {
+ if (!(src.d & 0x400000))
+ {
+ dst.d &= ~0x400000;
+ for (i = 0; i < len.w.l; i++)
+ c65_write_mem(space, dst.d--, c65_read_mem(space, src.d++));
+ }
+ else if (!(dst.d & 0x400000))
+ {
+ src.d &= ~0x400000;
+ for (i = 0; i < len.w.l; i++)
+ c65_write_mem(space, dst.d++, c65_read_mem(space, src.d--));
+ }
+ else
+ {
+ src.d &= ~0x400000;
+ dst.d &= ~0x400000;
+ for (i = 0; i < len.w.l; i++)
+ c65_write_mem(space, --dst.d, c65_read_mem(space, --src.d));
+ }
+ }
+ else
+ {
+ for (i = 0; i < len.w.l; i++)
+ c65_write_mem(space, dst.d++, c65_read_mem(space, src.d++));
+ }
+ break;
+ case 3:
+ DBG_LOG(space->machine(), 3,"dma fill job",
+ ("len:%.4x value:%.2x dst:%.6x sub:%.2x modrm:%.2x\n",
+ len.w.l, fill, dst.d, c65_read_mem(space, pair.d),
+ c65_read_mem(space, pair.d + 1)));
+ for (i = 0; i < len.w.l; i++)
+ c65_write_mem(space, dst.d++, fill);
+ break;
+ case 0x30:
+ DBG_LOG(space->machine(), 1,"dma copy down",
+ ("len:%.4x src:%.6x dst:%.6x sub:%.2x modrm:%.2x\n",
+ len.w.l, src.d, dst.d, c65_read_mem(space, pair.d),
+ c65_read_mem(space, pair.d + 1) ) );
+ for (i = 0; i < len.w.l; i++)
+ c65_write_mem(space, dst.d--,c65_read_mem(space, src.d--));
+ break;
+ default:
+ DBG_LOG(space->machine(), 1,"dma job",
+ ("cmd:%.2x len:%.4x src:%.6x dst:%.6x sub:%.2x modrm:%.2x\n",
+ cmd,len.w.l, src.d, dst.d, c65_read_mem(space, pair.d),
+ c65_read_mem(space, pair.d + 1)));
+ }
+ break;
+ default:
+ DBG_LOG(space->machine(), 1, "dma chip write", ("%.3x %.2x\n", offset, value));
+ break;
+ }
+}
+
+static int c65_dma_port_r( running_machine &machine, int offset )
+{
+ /* offset 3 bit 7 in progress ? */
+ DBG_LOG(machine, 2, "dma chip read", ("%.3x\n", offset));
+ return 0x7f;
+}
+
+static void c65_6511_port_w( running_machine &machine, int offset, int value )
+{
+ c65_state *state = machine.driver_data<c65_state>();
+ if (offset == 7)
+ {
+ state->m_6511_port = value;
+ }
+ DBG_LOG(machine, 2, "r6511 write", ("%.2x %.2x\n", offset, value));
+}
+
+static int c65_6511_port_r( running_machine &machine, int offset )
+{
+ int data = 0xff;
+
+ if (offset == 7)
+ {
+ if (machine.root_device().ioport("SPECIAL")->read() & 0x20)
+ data &= ~1;
+ }
+ DBG_LOG(machine, 2, "r6511 read", ("%.2x\n", offset));
+
+ return data;
+}
+
+/* one docu states custom 4191 disk controller
+ (for 2 1MB MFM disk drives, 1 internal, the other extern (optional) 1565
+ with integrated 512 byte buffer
+
+ 0->0 reset ?
+
+ 0->1, 0->0, wait until 2 positiv, 1->0 ???
+
+ 0->0, 0 not 0 means no drive ???, other system entries
+
+
+ reg 0 write/read
+ 0,1 written
+ bit 1 set
+ bit 2 set
+ bit 3 set
+ bit 4 set
+
+
+ reg 0 read
+ bit 0
+ bit 1
+ bit 2
+ 0..2 ->$1d4
+
+ reg 1 write
+ $01 written
+ $18 written
+ $46 written
+ $80 written
+ $a1 written
+ $01 written, dec
+ $10 written
+
+ reg 2 read/write?(lsr)
+ bit 2
+ bit 4
+ bit 5 busy waiting until zero, then reading reg 7
+ bit 6 operation not activ flag!? or set overflow pin used
+ bit 7 busy flag?
+
+ reg 3 read/write?(rcr)
+ bit 1
+ bit 3
+ bit 7 busy flag?
+
+ reg 4
+ track??
+ 0 written
+ read -> $1d2
+ cmp #$50
+ bcs
+
+
+ reg 5
+ sector ??
+ 1 written
+ read -> $1d3
+ cmp #$b bcc
+
+
+ reg 6
+ head ??
+ 0 written
+ read -> $1d1
+ cmp #2 bcc
+
+ reg 7 read
+ #4e written
+ 12 times 0, a1 a1 a1 fe written
+
+ reg 8 read
+ #ff written
+ 16 times #ff written
+
+ reg 9
+ #60 written
+
+might use the set overflow input
+
+$21a6c 9a6c format
+$21c97 9c97 write operation
+$21ca0 9ca0 get byte?
+$21cab 9cab read reg 7
+$21caf 9caf write reg 7
+$21cb3
+*/
+
+#define FDC_LOST 4
+#define FDC_CRC 8
+#define FDC_RNF 0x10
+#define FDC_BUSY 0x80
+#define FDC_IRQ 0x200
+
+#define FDC_CMD_MOTOR_SPIN_UP 0x10
+
+#if 0
+static void c65_fdc_state(void)
+{
+ c65_state *state = machine.driver_data<c65_state>();
+ switch (state->m_fdc.state)
+ {
+ case FDC_CMD_MOTOR_SPIN_UP:
+ if (machine.time() - state->m_fdc.time)
+ {
+ state->m_fdc.state = 0;
+ state->m_fdc.status &= ~FDC_BUSY;
+ }
+ break;
+ }
+}
+#endif
+
+static void c65_fdc_w( running_machine &machine, int offset, int data )
+{
+ c65_state *state = machine.driver_data<c65_state>();
+ DBG_LOG(machine, 1, "fdc write", ("%.5x %.2x %.2x\n", cpu_get_pc(machine.device("maincpu")), offset, data));
+ switch (offset & 0xf)
+ {
+ case 0:
+ state->m_fdc.reg[0] = data;
+ break;
+ case 1:
+ state->m_fdc.reg[1] = data;
+ switch (data & 0xf9)
+ {
+ case 0x20: // wait for motor spin up
+ state->m_fdc.status &= ~(FDC_IRQ|FDC_LOST|FDC_CRC|FDC_RNF);
+ state->m_fdc.status |= FDC_BUSY;
+ state->m_fdc.time = machine.time();
+ state->m_fdc.state = FDC_CMD_MOTOR_SPIN_UP;
+ break;
+ case 0: // cancel
+ state->m_fdc.status &= ~(FDC_BUSY);
+ state->m_fdc.state = 0;
+ break;
+ case 0x80: // buffered write
+ case 0x40: // buffered read
+ case 0x81: // unbuffered write
+ case 0x41: // unbuffered read
+ case 0x30:case 0x31: // step
+ break;
+ }
+ break;
+ case 2: case 3: // read only
+ break;
+ case 4:
+ state->m_fdc.reg[offset & 0xf] = data;
+ state->m_fdc.track = data;
+ break;
+ case 5:
+ state->m_fdc.reg[offset & 0xf] = data;
+ state->m_fdc.sector = data;
+ break;
+ case 6:
+ state->m_fdc.reg[offset & 0xf] = data;
+ state->m_fdc.head = data;
+ break;
+ case 7:
+ state->m_fdc.buffer[state->m_fdc.cpu_pos++] = data;
+ break;
+ default:
+ state->m_fdc.reg[offset & 0xf] = data;
+ break;
+ }
+}
+
+static int c65_fdc_r( running_machine &machine, int offset )
+{
+ c65_state *state = machine.driver_data<c65_state>();
+ UINT8 data = 0;
+ switch (offset & 0xf)
+ {
+ case 0:
+ data = state->m_fdc.reg[0];
+ break;
+ case 1:
+ data = state->m_fdc.reg[1];
+ break;
+ case 2:
+ data = state->m_fdc.status;
+ break;
+ case 3:
+ data = state->m_fdc.status >> 8;
+ break;
+ case 4:
+ data = state->m_fdc.track;
+ break;
+ case 5:
+ data = state->m_fdc.sector;
+ break;
+ case 6:
+ data = state->m_fdc.head;
+ break;
+ case 7:
+ data = state->m_fdc.buffer[state->m_fdc.cpu_pos++];
+ break;
+ default:
+ data = state->m_fdc.reg[offset & 0xf];
+ break;
+ }
+ DBG_LOG(machine, 1, "fdc read", ("%.5x %.2x %.2x\n", cpu_get_pc(machine.device("maincpu")), offset, data));
+ return data;
+}
+
+/* version 1 ramcheck
+ write 0:0
+ read write read write 80000,90000,f0000
+ write 0:8
+ read write read write 80000,90000,f0000
+
+ version 2 ramcheck???
+ read 0:
+ write 0:0
+ read 0:
+ first read and second read bit 0x80 set --> nothing
+ write 0:0
+ read 0
+ write 0:ff
+*/
+
+static READ8_HANDLER( c65_ram_expansion_r )
+{
+ c65_state *state = space->machine().driver_data<c65_state>();
+ UINT8 data = 0xff;
+ if (space->machine().device<ram_device>(RAM_TAG)->size() > (128 * 1024))
+ data = state->m_expansion_ram.reg;
+ return data;
+}
+
+static WRITE8_HANDLER( c65_ram_expansion_w )
+{
+ c65_state *state = space->machine().driver_data<c65_state>();
+ offs_t expansion_ram_begin;
+ offs_t expansion_ram_end;
+
+ if (space->machine().device<ram_device>(RAM_TAG)->size() > (128 * 1024))
+ {
+ state->m_expansion_ram.reg = data;
+
+ expansion_ram_begin = 0x80000;
+ expansion_ram_end = 0x80000 + (space->machine().device<ram_device>(RAM_TAG)->size() - 128*1024) - 1;
+
+ if (data == 0x00) {
+ space->install_readwrite_bank(expansion_ram_begin, expansion_ram_end,"bank16");
+ state->membank("bank16")->set_base(space->machine().device<ram_device>(RAM_TAG)->pointer() + 128*1024);
+ } else {
+ space->nop_readwrite(expansion_ram_begin, expansion_ram_end);
+ }
+ }
+}
+
+static WRITE8_HANDLER( c65_write_io )
+{
+ device_t *sid_0 = space->machine().device("sid_r");
+ device_t *sid_1 = space->machine().device("sid_l");
+ device_t *vic3 = space->machine().device("vic3");
+
+ switch (offset & 0xf00)
+ {
+ case 0x000:
+ if (offset < 0x80)
+ vic3_port_w(vic3, offset & 0x7f, data);
+ else if (offset < 0xa0)
+ c65_fdc_w(space->machine(), offset&0x1f,data);
+ else
+ {
+ c65_ram_expansion_w(space, offset&0x1f, data);
+ /*ram expansion crtl optional */
+ }
+ break;
+ case 0x100:
+ case 0x200:
+ case 0x300:
+ vic3_palette_w(vic3, offset - 0x100, data);
+ break;
+ case 0x400:
+ if (offset<0x420) /* maybe 0x20 */
+ sid6581_w(sid_0, offset & 0x3f, data);
+ else if (offset<0x440)
+ sid6581_w(sid_1, offset & 0x3f, data);
+ else
+ DBG_LOG(space->machine(), 1, "io write", ("%.3x %.2x\n", offset, data));
+ break;
+ case 0x500:
+ DBG_LOG(space->machine(), 1, "io write", ("%.3x %.2x\n", offset, data));
+ break;
+ case 0x600:
+ c65_6511_port_w(space->machine(), offset&0xff,data);
+ break;
+ case 0x700:
+ c65_dma_port_w(space->machine(), offset&0xff, data);
+ break;
+ }
+}
+
+static WRITE8_HANDLER( c65_write_io_dc00 )
+{
+ device_t *cia_0 = space->machine().device("cia_0");
+ device_t *cia_1 = space->machine().device("cia_1");
+
+ switch (offset & 0xf00)
+ {
+ case 0x000:
+ mos6526_w(cia_0, offset, data);
+ break;
+ case 0x100:
+ mos6526_w(cia_1, offset, data);
+ break;
+ case 0x200:
+ case 0x300:
+ DBG_LOG(space->machine(), 1, "io write", ("%.3x %.2x\n", offset+0xc00, data));
+ break;
+ }
+}
+
+static READ8_HANDLER( c65_read_io )
+{
+ device_t *sid_0 = space->machine().device("sid_r");
+ device_t *sid_1 = space->machine().device("sid_l");
+ device_t *vic3 = space->machine().device("vic3");
+
+ switch (offset & 0xf00)
+ {
+ case 0x000:
+ if (offset < 0x80)
+ return vic3_port_r(vic3, offset & 0x7f);
+ if (offset < 0xa0)
+ return c65_fdc_r(space->machine(), offset&0x1f);
+ else
+ {
+ return c65_ram_expansion_r(space, offset&0x1f);
+ /*return; ram expansion crtl optional */
+ }
+ break;
+ case 0x100:
+ case 0x200:
+ case 0x300:
+ /* read only !? */
+ DBG_LOG(space->machine(), 1, "io read", ("%.3x\n", offset));
+ break;
+ case 0x400:
+ if (offset < 0x420)
+ return sid6581_r(sid_0, offset & 0x3f);
+ if (offset < 0x440)
+ return sid6581_r(sid_1, offset & 0x3f);
+ DBG_LOG(space->machine(), 1, "io read", ("%.3x\n", offset));
+ break;
+ case 0x500:
+ DBG_LOG(space->machine(), 1, "io read", ("%.3x\n", offset));
+ break;
+ case 0x600:
+ return c65_6511_port_r(space->machine(), offset&0xff);
+ case 0x700:
+ return c65_dma_port_r(space->machine(), offset&0xff);
+ }
+ return 0xff;
+}
+
+static READ8_HANDLER( c65_read_io_dc00 )
+{
+ device_t *cia_0 = space->machine().device("cia_0");
+ device_t *cia_1 = space->machine().device("cia_1");
+
+ switch (offset & 0x300)
+ {
+ case 0x000:
+ return mos6526_r(cia_0, offset);
+ case 0x100:
+ return mos6526_r(cia_1, offset);
+ case 0x200:
+ case 0x300:
+ DBG_LOG(space->machine(), 1, "io read", ("%.3x\n", offset+0xc00));
+ break;
+ }
+ return 0xff;
+}
+
+
+/*
+d02f:
+ init a5 96 written (seems to be switch to c65 or vic3 mode)
+ go64 0 written
+*/
+
+/* bit 1 external sync enable (genlock)
+ bit 2 palette enable
+ bit 6 vic3 c65 character set */
+void c65_bankswitch_interface( running_machine &machine, int value )
+{
+ c65_state *state = machine.driver_data<c65_state>();
+ DBG_LOG(machine, 2, "c65 bankswitch", ("%.2x\n",value));
+
+ if (state->m_io_on)
+ {
+ if (value & 1)
+ {
+ state->membank("bank8")->set_base(state->m_colorram + 0x400);
+ state->membank("bank9")->set_base(state->m_colorram + 0x400);
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0x0dc00, 0x0dfff, "bank8");
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_write_bank(0x0dc00, 0x0dfff, "bank9");
+ }
+ else
+ {
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x0dc00, 0x0dfff, FUNC(c65_read_io_dc00));
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x0dc00, 0x0dfff, FUNC(c65_write_io_dc00));
+ }
+ }
+
+ state->m_io_dc00_on = !(value & 1);
+#if 0
+ /* cartridge roms !?*/
+ if (value & 0x08)
+ state->membank("bank1")->set_base(state->m_roml);
+ else
+ state->membank("bank1")->set_base(state->m_memory + 0x8000);
+
+ if (value & 0x10)
+ state->membank("bank2")->set_base(state->m_basic);
+ else
+ state->membank("bank2")->set_base(state->m_memory + 0xa000);
+#endif
+ if ((state->m_old_value^value) & 0x20)
+ {
+ /* bankswitching faulty when doing actual page */
+ if (value & 0x20)
+ state->membank("bank3")->set_base(state->m_basic);
+ else
+ state->membank("bank3")->set_base(state->m_memory + 0xc000);
+ }
+ state->m_charset_select = value & 0x40;
+#if 0
+ /* cartridge roms !?*/
+ if (value & 0x80)
+ state->membank("bank8")->set_base(state->m_kernal);
+ else
+ state->membank("bank6")->set_base(state->m_memory + 0xe000);
+#endif
+ state->m_old_value = value;
+}
+
+void c65_bankswitch( running_machine &machine )
+{
+ c65_state *state = machine.driver_data<c65_state>();
+ int data, loram, hiram, charen;
+
+ data = m4510_get_port(machine.device<legacy_cpu_device>("maincpu"));
+ if (data == state->m_old_data)
+ return;
+
+ DBG_LOG(machine, 1, "bankswitch", ("%d\n", data & 7));
+ loram = (data & 1) ? 1 : 0;
+ hiram = (data & 2) ? 1 : 0;
+ charen = (data & 4) ? 1 : 0;
+
+ if ((!state->m_game && state->m_exrom) || (loram && hiram && !state->m_exrom))
+ state->membank("bank1")->set_base(state->m_roml);
+ else
+ state->membank("bank1")->set_base(state->m_memory + 0x8000);
+
+ if ((!state->m_game && state->m_exrom && hiram) || (!state->m_exrom))
+ state->membank("bank2")->set_base(state->m_romh);
+ else if (loram && hiram)
+ state->membank("bank2")->set_base(state->m_basic);
+ else
+ state->membank("bank2")->set_base(state->m_memory + 0xa000);
+
+ if ((!state->m_game && state->m_exrom) || (charen && (loram || hiram)))
+ {
+ state->m_io_on = 1;
+ state->membank("bank6")->set_base(state->m_colorram);
+ state->membank("bank7")->set_base(state->m_colorram);
+
+ if (state->m_io_dc00_on)
+ {
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x0dc00, 0x0dfff, FUNC(c65_read_io_dc00));
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x0dc00, 0x0dfff, FUNC(c65_write_io_dc00));
+ }
+ else
+ {
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0x0dc00, 0x0dfff, "bank8");
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_write_bank(0x0dc00, 0x0dfff, "bank9");
+ state->membank("bank8")->set_base(state->m_colorram + 0x400);
+ state->membank("bank9")->set_base(state->m_colorram + 0x400);
+ }
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x0d000, 0x0d7ff, FUNC(c65_read_io));
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x0d000, 0x0d7ff, FUNC(c65_write_io));
+ }
+ else
+ {
+ state->m_io_on = 0;
+ state->membank("bank5")->set_base(state->m_memory + 0xd000);
+ state->membank("bank7")->set_base(state->m_memory + 0xd800);
+ state->membank("bank9")->set_base(state->m_memory + 0xdc00);
+ if (!charen && (loram || hiram))
+ {
+ state->membank("bank4")->set_base(state->m_chargen);
+ state->membank("bank6")->set_base(state->m_chargen + 0x800);
+ state->membank("bank8")->set_base(state->m_chargen + 0xc00);
+ }
+ else
+ {
+ state->membank("bank4")->set_base(state->m_memory + 0xd000);
+ state->membank("bank6")->set_base(state->m_memory + 0xd800);
+ state->membank("bank8")->set_base(state->m_memory + 0xdc00);
+ }
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0x0d000, 0x0d7ff, "bank4");
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_write_bank(0x0d000, 0x0d7ff, "bank5");
+ }
+
+ if (!state->m_game && state->m_exrom)
+ {
+ state->membank("bank10")->set_base(state->m_romh);
+ }
+ else
+ {
+ if (hiram)
+ {
+ state->membank("bank10")->set_base(state->m_kernal);
+ }
+ else
+ {
+ state->membank("bank10")->set_base(state->m_memory + 0xe000);
+ }
+ }
+ state->m_old_data = data;
+}
+
+#ifdef UNUSED_FUNCTION
+void c65_colorram_write( running_machine &machine, int offset, int value )
+{
+ c65_state *state = machine.driver_data<c65_state>();
+ state->m_colorram[offset & 0x7ff] = value | 0xf0;
+}
+#endif
+
+/*
+ * only 14 address lines
+ * a15 and a14 portlines
+ * 0x1000-0x1fff, 0x9000-0x9fff char rom
+ */
+int c65_dma_read( running_machine &machine, int offset )
+{
+ c65_state *state = machine.driver_data<c65_state>();
+ if (!state->m_game && state->m_exrom)
+ {
+ if (offset < 0x3000)
+ return state->m_memory[offset];
+ return state->m_romh[offset & 0x1fff];
+ }
+ if ((state->m_vicaddr == state->m_memory) || (state->m_vicaddr == state->m_memory + 0x8000))
+ {
+ if (offset < 0x1000)
+ return state->m_vicaddr[offset & 0x3fff];
+ if (offset < 0x2000) {
+ if (state->m_charset_select)
+ return state->m_chargen[offset & 0xfff];
+ else
+ return state->m_chargen[offset & 0xfff];
+ }
+ return state->m_vicaddr[offset & 0x3fff];
+ }
+ return state->m_vicaddr[offset & 0x3fff];
+}
+
+int c65_dma_read_color( running_machine &machine, int offset )
+{
+ c65_state *state = machine.driver_data<c65_state>();
+ if (state->m_c64mode)
+ return state->m_colorram[offset & 0x3ff] & 0xf;
+ return state->m_colorram[offset & 0x7ff];
+}
+
+static void c65_common_driver_init( running_machine &machine )
+{
+ c65_state *state = machine.driver_data<c65_state>();
+ state->m_memory = auto_alloc_array_clear(machine, UINT8, 0x10000);
+ state->membank("bank11")->set_base(state->m_memory + 0x00000);
+ state->membank("bank12")->set_base(state->m_memory + 0x08000);
+ state->membank("bank13")->set_base(state->m_memory + 0x0a000);
+ state->membank("bank14")->set_base(state->m_memory + 0x0c000);
+ state->membank("bank15")->set_base(state->m_memory + 0x0e000);
+
+ cbm_common_init();
+ state->m_keyline = 0xff;
+
+ state->m_pal = 0;
+ state->m_charset_select = 0;
+ state->m_6511_port = 0xff;
+ state->m_vicirq = 0;
+ state->m_old_data = -1;
+
+ /* C65 had no datasette port */
+ state->m_tape_on = 0;
+ state->m_game = 1;
+ state->m_exrom = 1;
+
+ /*memset(state->m_memory + 0x40000, 0, 0x800000 - 0x40000); */
+}
+
+DRIVER_INIT_MEMBER(c65_state,c65)
+{
+ m_dma.version = 2;
+ c65_common_driver_init(machine());
+}
+
+DRIVER_INIT_MEMBER(c65_state,c65pal)
+{
+ m_dma.version = 1;
+ c65_common_driver_init(machine());
+ m_pal = 1;
+}
+
+MACHINE_START( c65 )
+{
+ c65_state *state = machine.driver_data<c65_state>();
+ /* clear upper memory */
+ memset(machine.device<ram_device>(RAM_TAG)->pointer() + 128*1024, 0xff, machine.device<ram_device>(RAM_TAG)->size() - 128*1024);
+
+//removed cbm_drive_0_config (SERIAL, 10);
+//removed cbm_drive_1_config (SERIAL, 11);
+ state->m_vicaddr = state->m_memory;
+
+ state->m_c64mode = 0;
+
+ c65_bankswitch_interface(machine, 0xff);
+ c65_bankswitch (machine);
+}
+
+
+INTERRUPT_GEN( c65_frame_interrupt )
+{
+ c65_state *state = device->machine().driver_data<c65_state>();
+ int value;
+
+ c65_nmi(device->machine());
+
+ /* common keys input ports */
+ cbm_common_interrupt(device);
+
+ /* c65 specific: function keys input ports */
+ value = 0xff;
+
+ value &= ~state->ioport("FUNCT")->read();
+ state->m_keyline = value;
+}
diff --git a/src/mess/machine/c8280.c b/src/mess/machine/c8280.c
new file mode 100644
index 00000000000..9a658b88b49
--- /dev/null
+++ b/src/mess/machine/c8280.c
@@ -0,0 +1,451 @@
+/**********************************************************************
+
+ Commodore 8280 Dual 8" Disk Drive emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#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"
+
+
+enum
+{
+ LED_POWER = 0,
+ LED_ACT0,
+ LED_ACT1,
+ LED_ERR
+};
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type C8280 = &device_creator<c8280_device>;
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void c8280_device::device_config_complete()
+{
+ m_shortname = "c8280";
+}
+
+
+//-------------------------------------------------
+// ROM( c8280 )
+//-------------------------------------------------
+
+ROM_START( c8280 )
+ ROM_REGION( 0x4000, M6502_DOS_TAG, 0 )
+ ROM_LOAD( "300542-001.10c", 0x0000, 0x2000, CRC(3c6eee1e) SHA1(0726f6ab4de4fc9c18707fe87780ffd9f5ed72ab) )
+ ROM_LOAD( "300543-001.10d", 0x2000, 0x2000, CRC(f58e665e) SHA1(9e58b47c686c91efc6ef1a27f72dbb5e26c485ec) )
+
+ ROM_REGION( 0x800, M6502_FDC_TAG, 0 )
+ ROM_LOAD( "300541-001.3c", 0x000, 0x800, CRC(cb07b2db) SHA1(a1f9c5a7bd3798f5a97dc0b465c3bf5e3513e148) )
+ROM_END
+
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *c8280_device::device_rom_region() const
+{
+ return ROM_NAME( c8280 );
+}
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( c8280_main_mem )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( c8280_main_mem, AS_PROGRAM, 8, c8280_device )
+ AM_RANGE(0x0000, 0x007f) AM_MIRROR(0x0100) AM_RAM // 6532 #1
+ AM_RANGE(0x0080, 0x00ff) AM_MIRROR(0x0100) AM_RAM // 6532 #2
+ AM_RANGE(0x0200, 0x021f) AM_MIRROR(0x0d60) AM_DEVREADWRITE_LEGACY(M6532_0_TAG, riot6532_r, riot6532_w)
+ AM_RANGE(0x0280, 0x029f) AM_MIRROR(0x0d60) AM_DEVREADWRITE_LEGACY(M6532_1_TAG, riot6532_r, riot6532_w)
+ 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( c8280_fdc_mem )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( c8280_fdc_mem, AS_PROGRAM, 8, c8280_device )
+ ADDRESS_MAP_GLOBAL_MASK(0x1fff)
+ AM_RANGE(0x0000, 0x007f) AM_MIRROR(0x380) AM_RAM
+ 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_FDC_TAG, 0)
+ADDRESS_MAP_END
+
+
+//-------------------------------------------------
+// riot6532_interface riot0_intf
+//-------------------------------------------------
+
+READ8_MEMBER( c8280_device::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_device::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);
+}
+
+static const riot6532_interface riot0_intf =
+{
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c8280_device, dio_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c8280_device, dio_w),
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// riot6532_interface riot1_intf
+//-------------------------------------------------
+
+READ8_MEMBER( c8280_device::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_device::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_device::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_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_device::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 const riot6532_interface riot1_intf =
+{
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c8280_device, riot1_pa_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c8280_device, riot1_pb_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c8280_device, riot1_pa_w),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, c8280_device, riot1_pb_w),
+ DEVCB_CPU_INPUT_LINE(M6502_DOS_TAG, INPUT_LINE_IRQ0)
+};
+
+
+//-------------------------------------------------
+// LEGACY_FLOPPY_OPTIONS( c8280 )
+//-------------------------------------------------
+
+static LEGACY_FLOPPY_OPTIONS_START( c8280 )
+LEGACY_FLOPPY_OPTIONS_END
+
+
+//-------------------------------------------------
+// floppy_interface c8280_floppy_interface
+//-------------------------------------------------
+
+static const floppy_interface c8280_floppy_interface =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ FLOPPY_STANDARD_8_DSDD,
+ LEGACY_FLOPPY_OPTIONS_NAME(c8280),
+ "floppy_8",
+ NULL
+};
+
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( c8280 )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( c8280 )
+ MCFG_CPU_ADD(M6502_DOS_TAG, M6502, 1000000)
+ MCFG_CPU_PROGRAM_MAP(c8280_main_mem)
+
+ MCFG_RIOT6532_ADD(M6532_0_TAG, 1000000, riot0_intf)
+ MCFG_RIOT6532_ADD(M6532_1_TAG, 1000000, riot1_intf)
+
+ MCFG_CPU_ADD(M6502_FDC_TAG, M6502, 1000000)
+ MCFG_CPU_PROGRAM_MAP(c8280_fdc_mem)
+
+ MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(c8280_floppy_interface)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor c8280_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( c8280 );
+}
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// update_ieee_signals -
+//-------------------------------------------------
+
+inline void c8280_device::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_device - constructor
+//-------------------------------------------------
+
+c8280_device::c8280_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, C8280, "C8280", tag, owner, clock),
+ 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_image0(*this, FLOPPY_0),
+ m_image1(*this, FLOPPY_1),
+ m_rfdo(1),
+ m_daco(1),
+ m_atna(1)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void c8280_device::device_start()
+{
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void c8280_device::device_reset()
+{
+}
+
+
+//-------------------------------------------------
+// device_timer - handler timer events
+//-------------------------------------------------
+
+void c8280_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+}
+
+
+//-------------------------------------------------
+// ieee488_atn -
+//-------------------------------------------------
+
+void c8280_device::ieee488_atn(int state)
+{
+ update_ieee_signals();
+
+ // set RIOT PA7
+ riot6532_porta_in_set(m_riot1, !state << 7, 0x80);
+}
+
+
+//-------------------------------------------------
+// ieee488_ifc -
+//-------------------------------------------------
+
+void c8280_device::ieee488_ifc(int state)
+{
+ if (!state)
+ {
+ device_reset();
+ }
+}
diff --git a/src/mess/machine/c8280.h b/src/mess/machine/c8280.h
new file mode 100644
index 00000000000..37587d1505a
--- /dev/null
+++ b/src/mess/machine/c8280.h
@@ -0,0 +1,82 @@
+/**********************************************************************
+
+ Commodore 8280 Dual 8" Disk Drive emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __C8280__
+#define __C8280__
+
+
+#include "emu.h"
+#include "cpu/m6502/m6502.h"
+#include "imagedev/flopdrv.h"
+#include "machine/6532riot.h"
+#include "machine/ieee488.h"
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> c8280_device
+
+class c8280_device : public device_t,
+ public device_ieee488_interface
+{
+public:
+ // construction/destruction
+ c8280_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( 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 );
+
+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();
+
+ // device_ieee488_interface overrides
+ void ieee488_atn(int state);
+ void ieee488_ifc(int state);
+
+private:
+ inline void update_ieee_signals();
+
+ required_device<cpu_device> m_maincpu;
+ required_device<cpu_device> m_fdccpu;
+ required_device<riot6532_device> m_riot0;
+ required_device<riot6532_device> m_riot1;
+ required_device<device_t> m_image0;
+ required_device<device_t> m_image1;
+
+ // IEEE-488 bus
+ int m_rfdo; // not ready for data output
+ int m_daco; // not data accepted output
+ int m_atna; // attention acknowledge
+};
+
+
+// device type definition
+extern const device_type C8280;
+
+
+
+#endif
diff --git a/src/mess/machine/cbm.c b/src/mess/machine/cbm.c
new file mode 100644
index 00000000000..a5f85443c2b
--- /dev/null
+++ b/src/mess/machine/cbm.c
@@ -0,0 +1,359 @@
+#include "emu.h"
+#include "imagedev/cassette.h"
+#include "crsshair.h"
+#include "includes/cbm.h"
+#include "formats/cbm_tap.h"
+
+
+/***********************************************
+
+ Input Reading - Common Components
+
+***********************************************/
+
+/* These are needed by c64, c65 and c128, each machine has also additional specific
+components in its INTERRUPT_GEN */
+
+/* keyboard lines */
+UINT8 c64_keyline[10];
+
+void cbm_common_init(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_LENGTH(c64_keyline); i++)
+ c64_keyline[i] = 0xff;
+}
+
+static TIMER_CALLBACK( lightpen_tick )
+{
+ if (((machine.root_device().ioport("CTRLSEL")->read() & 0x07) == 0x04) || ((machine.root_device().ioport("CTRLSEL")->read() & 0x07) == 0x06))
+ {
+ /* enable lightpen crosshair */
+ crosshair_set_screen(machine, 0, CROSSHAIR_SCREEN_ALL);
+ }
+ else
+ {
+ /* disable lightpen crosshair */
+ crosshair_set_screen(machine, 0, CROSSHAIR_SCREEN_NONE);
+ }
+}
+
+void cbm_common_interrupt( device_t *device )
+{
+ int value, i;
+ int controller1 = device->machine().root_device().ioport("CTRLSEL")->read() & 0x07;
+ int controller2 = device->machine().root_device().ioport("CTRLSEL")->read() & 0x70;
+ static const char *const c64ports[] = { "ROW0", "ROW1", "ROW2", "ROW3", "ROW4", "ROW5", "ROW6", "ROW7" };
+
+ /* Lines 0-7 : common keyboard */
+ for (i = 0; i < 8; i++)
+ {
+ value = 0xff;
+ value &= ~device->machine().root_device().ioport(c64ports[i])->read();
+
+ /* Shift Lock is mapped on Left Shift */
+ if ((i == 1) && (device->machine().root_device().ioport("SPECIAL")->read() & 0x40))
+ value &= ~0x80;
+
+ c64_keyline[i] = value;
+ }
+
+
+ value = 0xff;
+ switch(controller1)
+ {
+ case 0x00:
+ value &= ~device->machine().root_device().ioport("JOY1_1B")->read(); /* Joy1 Directions + Button 1 */
+ break;
+
+ case 0x01:
+ if (device->machine().root_device().ioport("OTHER")->read() & 0x40) /* Paddle2 Button */
+ value &= ~0x08;
+ if (device->machine().root_device().ioport("OTHER")->read() & 0x80) /* Paddle1 Button */
+ value &= ~0x04;
+ break;
+
+ case 0x02:
+ if (device->machine().root_device().ioport("OTHER")->read() & 0x02) /* Mouse Button Left */
+ value &= ~0x10;
+ if (device->machine().root_device().ioport("OTHER")->read() & 0x01) /* Mouse Button Right */
+ value &= ~0x01;
+ break;
+
+ case 0x03:
+ value &= ~(device->machine().root_device().ioport("JOY1_2B")->read() & 0x1f); /* Joy1 Directions + Button 1 */
+ break;
+
+ case 0x04:
+/* was there any input on the lightpen? where is it mapped? */
+// if (device->machine().root_device().ioport("OTHER")->read() & 0x04) /* Lightpen Signal */
+// value &= ?? ;
+ break;
+
+ case 0x07:
+ break;
+
+ default:
+ logerror("Invalid Controller 1 Setting %d\n", controller1);
+ break;
+ }
+
+ c64_keyline[8] = value;
+
+
+ value = 0xff;
+ switch(controller2)
+ {
+ case 0x00:
+ value &= ~device->machine().root_device().ioport("JOY2_1B")->read(); /* Joy2 Directions + Button 1 */
+ break;
+
+ case 0x10:
+ if (device->machine().root_device().ioport("OTHER")->read() & 0x10) /* Paddle4 Button */
+ value &= ~0x08;
+ if (device->machine().root_device().ioport("OTHER")->read() & 0x20) /* Paddle3 Button */
+ value &= ~0x04;
+ break;
+
+ case 0x20:
+ if (device->machine().root_device().ioport("OTHER")->read() & 0x02) /* Mouse Button Left */
+ value &= ~0x10;
+ if (device->machine().root_device().ioport("OTHER")->read() & 0x01) /* Mouse Button Right */
+ value &= ~0x01;
+ break;
+
+ case 0x30:
+ value &= ~(device->machine().root_device().ioport("JOY2_2B")->read() & 0x1f); /* Joy2 Directions + Button 1 */
+ break;
+
+ case 0x40:
+/* was there any input on the lightpen? where is it mapped? */
+// if (device->machine().root_device().ioport("OTHER")->read() & 0x04) /* Lightpen Signal */
+// value &= ?? ;
+ break;
+
+ case 0x70:
+ break;
+
+ default:
+ logerror("Invalid Controller 2 Setting %d\n", controller2);
+ break;
+ }
+
+ c64_keyline[9] = value;
+
+// vic2_frame_interrupt does nothing so this is not necessary
+// vic2_frame_interrupt (device);
+
+ /* check if lightpen has been chosen as input: if so, enable crosshair */
+ device->machine().scheduler().timer_set(attotime::zero, FUNC(lightpen_tick));
+
+ set_led_status (device->machine(), 1, device->machine().root_device().ioport("SPECIAL")->read() & 0x40 ? 1 : 0); /* Shift Lock */
+ set_led_status (device->machine(), 0, device->machine().root_device().ioport("CTRLSEL")->read() & 0x80 ? 1 : 0); /* Joystick Swap */
+}
+
+
+/***********************************************
+
+ CIA Common Handlers
+
+***********************************************/
+
+/* These are shared by c64, c65 and c128. c65 and c128 also have additional specific
+components (to select/read additional keyboard lines) */
+
+/*
+ * CIA 0 - Port A
+ * bits 7-0 keyboard line select
+ * bits 7,6: paddle select( 01 port a, 10 port b)
+ * bit 4: joystick a fire button
+ * bits 3,2: Paddles port a fire button
+ * bits 3-0: joystick a direction
+ *
+ * CIA 0 - Port B
+ * bits 7-0: keyboard raw values
+ * bit 4: joystick b fire button, lightpen select
+ * bits 3,2: paddle b fire buttons (left,right)
+ * bits 3-0: joystick b direction
+ *
+ * flag cassette read input, serial request in
+ * irq to irq connected
+ */
+
+UINT8 cbm_common_cia0_port_a_r( device_t *device, UINT8 output_b )
+{
+ UINT8 value = 0xff;
+
+ if (!(output_b & 0x80))
+ {
+ UINT8 t = 0xff;
+ if (!(c64_keyline[7] & 0x80)) t &= ~0x80;
+ if (!(c64_keyline[6] & 0x80)) t &= ~0x40;
+ if (!(c64_keyline[5] & 0x80)) t &= ~0x20;
+ if (!(c64_keyline[4] & 0x80)) t &= ~0x10;
+ if (!(c64_keyline[3] & 0x80)) t &= ~0x08;
+ if (!(c64_keyline[2] & 0x80)) t &= ~0x04;
+ if (!(c64_keyline[1] & 0x80)) t &= ~0x02;
+ if (!(c64_keyline[0] & 0x80)) t &= ~0x01;
+ value &= t;
+ }
+
+ if (!(output_b & 0x40))
+ {
+ UINT8 t = 0xff;
+ if (!(c64_keyline[7] & 0x40)) t &= ~0x80;
+ if (!(c64_keyline[6] & 0x40)) t &= ~0x40;
+ if (!(c64_keyline[5] & 0x40)) t &= ~0x20;
+ if (!(c64_keyline[4] & 0x40)) t &= ~0x10;
+ if (!(c64_keyline[3] & 0x40)) t &= ~0x08;
+ if (!(c64_keyline[2] & 0x40)) t &= ~0x04;
+ if (!(c64_keyline[1] & 0x40)) t &= ~0x02;
+ if (!(c64_keyline[0] & 0x40)) t &= ~0x01;
+ value &= t;
+ }
+
+ if (!(output_b & 0x20))
+ {
+ UINT8 t = 0xff;
+ if (!(c64_keyline[7] & 0x20)) t &= ~0x80;
+ if (!(c64_keyline[6] & 0x20)) t &= ~0x40;
+ if (!(c64_keyline[5] & 0x20)) t &= ~0x20;
+ if (!(c64_keyline[4] & 0x20)) t &= ~0x10;
+ if (!(c64_keyline[3] & 0x20)) t &= ~0x08;
+ if (!(c64_keyline[2] & 0x20)) t &= ~0x04;
+ if (!(c64_keyline[1] & 0x20)) t &= ~0x02;
+ if (!(c64_keyline[0] & 0x20)) t &= ~0x01;
+ value &= t;
+ }
+
+ if (!(output_b & 0x10))
+ {
+ UINT8 t = 0xff;
+ if (!(c64_keyline[7] & 0x10)) t &= ~0x80;
+ if (!(c64_keyline[6] & 0x10)) t &= ~0x40;
+ if (!(c64_keyline[5] & 0x10)) t &= ~0x20;
+ if (!(c64_keyline[4] & 0x10)) t &= ~0x10;
+ if (!(c64_keyline[3] & 0x10)) t &= ~0x08;
+ if (!(c64_keyline[2] & 0x10)) t &= ~0x04;
+ if (!(c64_keyline[1] & 0x10)) t &= ~0x02;
+ if (!(c64_keyline[0] & 0x10)) t &= ~0x01;
+ value &= t;
+ }
+
+ if (!(output_b & 0x08))
+ {
+ UINT8 t = 0xff;
+ if (!(c64_keyline[7] & 0x08)) t &= ~0x80;
+ if (!(c64_keyline[6] & 0x08)) t &= ~0x40;
+ if (!(c64_keyline[5] & 0x08)) t &= ~0x20;
+ if (!(c64_keyline[4] & 0x08)) t &= ~0x10;
+ if (!(c64_keyline[3] & 0x08)) t &= ~0x08;
+ if (!(c64_keyline[2] & 0x08)) t &= ~0x04;
+ if (!(c64_keyline[1] & 0x08)) t &= ~0x02;
+ if (!(c64_keyline[0] & 0x08)) t &= ~0x01;
+ value &= t;
+ }
+
+ if (!(output_b & 0x04))
+ {
+ UINT8 t = 0xff;
+ if (!(c64_keyline[7] & 0x04)) t &= ~0x80;
+ if (!(c64_keyline[6] & 0x04)) t &= ~0x40;
+ if (!(c64_keyline[5] & 0x04)) t &= ~0x20;
+ if (!(c64_keyline[4] & 0x04)) t &= ~0x10;
+ if (!(c64_keyline[3] & 0x04)) t &= ~0x08;
+ if (!(c64_keyline[2] & 0x04)) t &= ~0x04;
+ if (!(c64_keyline[1] & 0x04)) t &= ~0x02;
+ if (!(c64_keyline[0] & 0x04)) t &= ~0x01;
+ value &= t;
+ }
+
+ if (!(output_b & 0x02))
+ {
+ UINT8 t = 0xff;
+ if (!(c64_keyline[7] & 0x02)) t &= ~0x80;
+ if (!(c64_keyline[6] & 0x02)) t &= ~0x40;
+ if (!(c64_keyline[5] & 0x02)) t &= ~0x20;
+ if (!(c64_keyline[4] & 0x02)) t &= ~0x10;
+ if (!(c64_keyline[3] & 0x02)) t &= ~0x08;
+ if (!(c64_keyline[2] & 0x02)) t &= ~0x04;
+ if (!(c64_keyline[1] & 0x02)) t &= ~0x02;
+ if (!(c64_keyline[0] & 0x02)) t &= ~0x01;
+ value &= t;
+ }
+
+ if (!(output_b & 0x01))
+ {
+ UINT8 t = 0xff;
+ if (!(c64_keyline[7] & 0x01)) t &= ~0x80;
+ if (!(c64_keyline[6] & 0x01)) t &= ~0x40;
+ if (!(c64_keyline[5] & 0x01)) t &= ~0x20;
+ if (!(c64_keyline[4] & 0x01)) t &= ~0x10;
+ if (!(c64_keyline[3] & 0x01)) t &= ~0x08;
+ if (!(c64_keyline[2] & 0x01)) t &= ~0x04;
+ if (!(c64_keyline[1] & 0x01)) t &= ~0x02;
+ if (!(c64_keyline[0] & 0x01)) t &= ~0x01;
+ value &= t;
+ }
+
+ if ( device->machine().root_device().ioport("CTRLSEL")->read() & 0x80 )
+ value &= c64_keyline[8];
+ else
+ value &= c64_keyline[9];
+
+ return value;
+}
+
+UINT8 cbm_common_cia0_port_b_r( device_t *device, UINT8 output_a )
+{
+ UINT8 value = 0xff;
+
+ if (!(output_a & 0x80)) value &= c64_keyline[7];
+ if (!(output_a & 0x40)) value &= c64_keyline[6];
+ if (!(output_a & 0x20)) value &= c64_keyline[5];
+ if (!(output_a & 0x10)) value &= c64_keyline[4];
+ if (!(output_a & 0x08)) value &= c64_keyline[3];
+ if (!(output_a & 0x04)) value &= c64_keyline[2];
+ if (!(output_a & 0x02)) value &= c64_keyline[1];
+ if (!(output_a & 0x01)) value &= c64_keyline[0];
+
+ if ( device->machine().root_device().ioport("CTRLSEL")->read() & 0x80 )
+ value &= c64_keyline[9];
+ else
+ value &= c64_keyline[8];
+
+ return value;
+}
+
+
+/***********************************************
+
+ CBM Cartridges
+
+***********************************************/
+
+
+/* All the cartridge specific code has been moved
+ to machine/ drivers. Once more informations
+ surface about the cart expansions for systems
+ in c65.c, c128.c, cbmb.c and pet.c, the shared
+ code could be refactored to have here the
+ common functions */
+
+
+
+/***********************************************
+
+ CBM Datasette Tapes
+
+***********************************************/
+
+const cassette_interface cbm_cassette_interface =
+{
+ cbm_cassette_formats,
+ NULL,
+ (cassette_state) (CASSETTE_STOPPED | CASSETTE_MOTOR_DISABLED | CASSETTE_SPEAKER_ENABLED),
+ NULL,
+ NULL
+};
diff --git a/src/mess/machine/cbmb.c b/src/mess/machine/cbmb.c
new file mode 100644
index 00000000000..028e884ffa0
--- /dev/null
+++ b/src/mess/machine/cbmb.c
@@ -0,0 +1,504 @@
+/***************************************************************************
+ commodore b series computer
+
+ peter.trauner@jk.uni-linz.ac.at
+***************************************************************************/
+
+#include "emu.h"
+#include "cpu/m6502/m6509.h"
+#include "sound/sid6581.h"
+#include "machine/6525tpi.h"
+#include "machine/6526cia.h"
+#include "machine/ieee488.h"
+
+#include "includes/cbmb.h"
+#include "crsshair.h"
+
+#include "imagedev/cartslot.h"
+
+/* 2008-05 FP: Were these added as a reminder to add configs of
+drivers 8 & 9 as in pet.c ? */
+#define IEEE8ON 0
+#define IEEE9ON 0
+
+#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)
+
+static TIMER_CALLBACK( cbmb_frame_interrupt );
+/* keyboard lines */
+
+
+/* tpi at 0xfde00
+ in interrupt mode
+ irq to m6509 irq
+ pa7 ieee nrfd
+ pa6 ieee ndac
+ pa5 ieee eoi
+ pa4 ieee dav
+ pa3 ieee atn
+ pa2 ieee ren
+ pa1 ieee io chips te
+ pa0 ieee io chip dc
+ pb1 ieee seq
+ pb0 ieee ifc
+ cb ?
+ ca chargen rom address line 12
+ i4 acia irq
+ i3 ?
+ i2 cia6526 irq
+ i1 self pb0
+ i0 tod (50 or 60 hertz frequency)
+ */
+READ8_DEVICE_HANDLER( cbmb_tpi0_port_a_r )
+{
+ cbmb_state *state = device->machine().driver_data<cbmb_state>();
+ UINT8 data = 0;
+
+ if (state->m_ieee->nrfd_r())
+ data |= 0x80;
+
+ if (state->m_ieee->ndac_r())
+ data |= 0x40;
+
+ if (state->m_ieee->eoi_r())
+ data |= 0x20;
+
+ if (state->m_ieee->dav_r())
+ data |= 0x10;
+
+ if (state->m_ieee->atn_r())
+ data |= 0x08;
+
+ if (state->m_ieee->ren_r())
+ data |= 0x04;
+
+ return data;
+}
+
+WRITE8_DEVICE_HANDLER( cbmb_tpi0_port_a_w )
+{
+ cbmb_state *state = device->machine().driver_data<cbmb_state>();
+
+ state->m_ieee->nrfd_w(BIT(data, 7));
+ state->m_ieee->ndac_w(BIT(data, 6));
+ state->m_ieee->eoi_w(BIT(data, 5));
+ state->m_ieee->dav_w(BIT(data, 4));
+ state->m_ieee->atn_w(BIT(data, 3));
+ state->m_ieee->ren_w(BIT(data, 2));
+}
+
+READ8_DEVICE_HANDLER( cbmb_tpi0_port_b_r )
+{
+ cbmb_state *state = device->machine().driver_data<cbmb_state>();
+ UINT8 data = 0;
+
+ if (state->m_ieee->srq_r())
+ data |= 0x02;
+
+ if (state->m_ieee->ifc_r())
+ data |= 0x01;
+
+ return data;
+}
+
+WRITE8_DEVICE_HANDLER( cbmb_tpi0_port_b_w )
+{
+ cbmb_state *state = device->machine().driver_data<cbmb_state>();
+
+ state->m_ieee->srq_w(BIT(data, 1));
+ state->m_ieee->ifc_w(BIT(data, 0));
+}
+
+/* tpi at 0xfdf00
+ cbm 500
+ port c7 video address lines?
+ port c6 ?
+ cbm 600
+ port c7 low
+ port c6 ntsc 1, 0 pal
+ cbm 700
+ port c7 high
+ port c6 ?
+ port c5 .. c0 keyboard line select
+ port a7..a0 b7..b0 keyboard input */
+WRITE8_DEVICE_HANDLER( cbmb_keyboard_line_select_a )
+{
+ cbmb_state *state = device->machine().driver_data<cbmb_state>();
+ state->m_keyline_a = data;
+}
+
+WRITE8_DEVICE_HANDLER( cbmb_keyboard_line_select_b )
+{
+ cbmb_state *state = device->machine().driver_data<cbmb_state>();
+ state->m_keyline_b = data;
+}
+
+WRITE8_DEVICE_HANDLER( cbmb_keyboard_line_select_c )
+{
+ cbmb_state *state = device->machine().driver_data<cbmb_state>();
+ state->m_keyline_c = data;
+}
+
+READ8_DEVICE_HANDLER( cbmb_keyboard_line_a )
+{
+ cbmb_state *state = device->machine().driver_data<cbmb_state>();
+ int data = 0;
+ if (!(state->m_keyline_c & 0x01))
+ data |= device->machine().root_device().ioport("ROW0")->read();
+
+ if (!(state->m_keyline_c & 0x02))
+ data |= device->machine().root_device().ioport("ROW2")->read();
+
+ if (!(state->m_keyline_c & 0x04))
+ data |= device->machine().root_device().ioport("ROW4")->read();
+
+ if (!(state->m_keyline_c & 0x08))
+ data |= device->machine().root_device().ioport("ROW6")->read();
+
+ if (!(state->m_keyline_c & 0x10))
+ data |= device->machine().root_device().ioport("ROW8")->read();
+
+ if (!(state->m_keyline_c & 0x20))
+ data |= state->ioport("ROW10")->read();
+
+ return data ^0xff;
+}
+
+READ8_DEVICE_HANDLER( cbmb_keyboard_line_b )
+{
+ cbmb_state *state = device->machine().driver_data<cbmb_state>();
+ int data = 0;
+ if (!(state->m_keyline_c & 0x01))
+ data |= device->machine().root_device().ioport("ROW1")->read();
+
+ if (!(state->m_keyline_c & 0x02))
+ data |= device->machine().root_device().ioport("ROW3")->read();
+
+ if (!(state->m_keyline_c & 0x04))
+ data |= device->machine().root_device().ioport("ROW5")->read();
+
+ if (!(state->m_keyline_c & 0x08))
+ data |= device->machine().root_device().ioport("ROW7")->read();
+
+ if (!(state->m_keyline_c & 0x10))
+ data |= device->machine().root_device().ioport("ROW9")->read() | ((device->machine().root_device().ioport("SPECIAL")->read() & 0x04) ? 1 : 0 );
+
+ if (!(state->m_keyline_c & 0x20))
+ data |= state->ioport("ROW11")->read();
+
+ return data ^0xff;
+}
+
+READ8_DEVICE_HANDLER( cbmb_keyboard_line_c )
+{
+ int data = 0;
+ cbmb_state *state = device->machine().driver_data<cbmb_state>();
+ if ((device->machine().root_device().ioport("ROW0")->read() & ~state->m_keyline_a) ||
+ (device->machine().root_device().ioport("ROW1")->read() & ~state->m_keyline_b))
+ data |= 0x01;
+
+ if ((device->machine().root_device().ioport("ROW2")->read() & ~state->m_keyline_a) ||
+ (device->machine().root_device().ioport("ROW3")->read() & ~state->m_keyline_b))
+ data |= 0x02;
+
+ if ((device->machine().root_device().ioport("ROW4")->read() & ~state->m_keyline_a) ||
+ (device->machine().root_device().ioport("ROW5")->read() & ~state->m_keyline_b))
+ data |= 0x04;
+
+ if ((device->machine().root_device().ioport("ROW6")->read() & ~state->m_keyline_a) ||
+ (device->machine().root_device().ioport("ROW7")->read() & ~state->m_keyline_b))
+ data |= 0x08;
+
+ if ((device->machine().root_device().ioport("ROW8")->read() & ~state->m_keyline_a) ||
+ ((device->machine().root_device().ioport("ROW9")->read() | ((device->machine().root_device().ioport("SPECIAL")->read() & 0x04) ? 1 : 0)) & ~state->m_keyline_b))
+ data |= 0x10;
+
+ if ((device->machine().root_device().ioport("ROW10")->read() & ~state->m_keyline_a) ||
+ (state->ioport("ROW11")->read() & ~state->m_keyline_b))
+ data |= 0x20;
+
+ if (!state->m_p500)
+ {
+ if (!state->m_cbm_ntsc)
+ data |= 0x40;
+
+ if (!state->m_cbm700)
+ data |= 0x80;
+ }
+ return data ^0xff;
+}
+
+WRITE_LINE_DEVICE_HANDLER( cbmb_irq )
+{
+ cbmb_state *driver_state = device->machine().driver_data<cbmb_state>();
+ if (state != driver_state->m_old_level)
+ {
+ DBG_LOG(device->machine(), 3, "mos6509", ("irq %s\n", state ? "start" : "end"));
+ cputag_set_input_line(device->machine(), "maincpu", M6502_IRQ_LINE, state);
+ driver_state->m_old_level = state;
+ }
+}
+
+/*
+ port a ieee in/out
+ pa7 trigger gameport 2
+ pa6 trigger gameport 1
+ pa1 ?
+ pa0 ?
+ pb7 .. 4 gameport 2
+ pb3 .. 0 gameport 1
+ */
+
+const mos6526_interface cbmb_cia =
+{
+ 60,
+ DEVCB_DEVICE_LINE("tpi6525_0", tpi6525_i2_w),
+ DEVCB_NULL, /* pc_func */
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(IEEE488_TAG, ieee488_device, dio_r),
+ DEVCB_DEVICE_MEMBER(IEEE488_TAG, ieee488_device, dio_w),
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+WRITE8_MEMBER(cbmb_state::cbmb_colorram_w)
+{
+ m_colorram[offset] = data | 0xf0;
+}
+
+WRITE_LINE_DEVICE_HANDLER( cbmb_change_font )
+{
+ cbmb_vh_set_font(device->machine(), state);
+}
+
+static void cbmb_common_driver_init( running_machine &machine )
+{
+ cbmb_state *state = machine.driver_data<cbmb_state>();
+ state->m_chargen = state->memregion("maincpu")->base() + 0x100000;
+ /* memset(c64_memory, 0, 0xfd00); */
+
+ machine.scheduler().timer_pulse(attotime::from_msec(10), FUNC(cbmb_frame_interrupt));
+
+ state->m_p500 = 0;
+ state->m_cbm700 = 0;
+}
+
+DRIVER_INIT_MEMBER(cbmb_state,cbm600)
+{
+ cbmb_common_driver_init(machine());
+ m_cbm_ntsc = 1;
+ cbm600_vh_init(machine());
+}
+
+DRIVER_INIT_MEMBER(cbmb_state,cbm600pal)
+{
+ cbmb_common_driver_init(machine());
+ m_cbm_ntsc = 0;
+ cbm600_vh_init(machine());
+}
+
+DRIVER_INIT_MEMBER(cbmb_state,cbm600hu)
+{
+ cbmb_common_driver_init(machine());
+ m_cbm_ntsc = 0;
+}
+
+DRIVER_INIT_MEMBER(cbmb_state,cbm700)
+{
+ cbmb_common_driver_init(machine());
+ m_cbm700 = 1;
+ m_cbm_ntsc = 0;
+ cbm700_vh_init(machine());
+}
+
+DRIVER_INIT_MEMBER(cbmb_state,p500)
+{
+ cbmb_common_driver_init(machine());
+ m_p500 = 1;
+ m_cbm_ntsc = 1;
+}
+
+MACHINE_RESET( cbmb )
+{
+//removed cbm_drive_0_config (IEEE8ON ? IEEE : 0, 8);
+//removed cbm_drive_1_config (IEEE9ON ? IEEE : 0, 9);
+}
+
+
+static TIMER_CALLBACK( p500_lightpen_tick )
+{
+ if ((machine.root_device().ioport("CTRLSEL")->read_safe(0x00) & 0x07) == 0x04)
+ {
+ /* enable lightpen crosshair */
+ crosshair_set_screen(machine, 0, CROSSHAIR_SCREEN_ALL);
+ }
+ else
+ {
+ /* disable lightpen crosshair */
+ crosshair_set_screen(machine, 0, CROSSHAIR_SCREEN_NONE);
+ }
+}
+
+static TIMER_CALLBACK(cbmb_frame_interrupt)
+{
+ cbmb_state *state = machine.driver_data<cbmb_state>();
+ device_t *tpi_0 = machine.device("tpi6525_0");
+
+#if 0
+ int controller1 = machine.root_device().ioport("CTRLSEL")->read() & 0x07;
+ int controller2 = machine.root_device().ioport("CTRLSEL")->read() & 0x70;
+#endif
+
+ tpi6525_i0_w(tpi_0, state->m_irq_level);
+ state->m_irq_level = !state->m_irq_level;
+ if (state->m_irq_level) return ;
+
+#if 0
+ value = 0xff;
+ switch (controller1)
+ {
+ case 0x00:
+ value &= ~machine.root_device().ioport("JOY1_1B")->read(); /* Joy1 Directions + Button 1 */
+ break;
+
+ case 0x01:
+ if (machine.root_device().ioport("OTHER")->read() & 0x40) /* Paddle2 Button */
+ value &= ~0x08;
+ if (machine.root_device().ioport("OTHER")->read() & 0x80) /* Paddle1 Button */
+ value &= ~0x04;
+ break;
+
+ case 0x02:
+ if (machine.root_device().ioport("OTHER")->read() & 0x02) /* Mouse Button Left */
+ value &= ~0x10;
+ if (machine.root_device().ioport("OTHER")->read() & 0x01) /* Mouse Button Right */
+ value &= ~0x01;
+ break;
+
+ case 0x03:
+ value &= ~(machine.root_device().ioport("JOY1_2B")->read() & 0x1f); /* Joy1 Directions + Button 1 */
+ break;
+
+ case 0x04:
+/* was there any input on the lightpen? where is it mapped? */
+// if (machine.root_device().ioport("OTHER")->read() & 0x04) /* Lightpen Signal */
+// value &= ?? ;
+ break;
+
+ case 0x07:
+ break;
+
+ default:
+ logerror("Invalid Controller 1 Setting %d\n", controller1);
+ break;
+ }
+
+ c64_keyline[8] = value;
+
+
+ value = 0xff;
+ switch (controller2)
+ {
+ case 0x00:
+ value &= ~machine.root_device().ioport("JOY2_1B")->read(); /* Joy2 Directions + Button 1 */
+ break;
+
+ case 0x10:
+ if (machine.root_device().ioport("OTHER")->read() & 0x10) /* Paddle4 Button */
+ value &= ~0x08;
+ if (machine.root_device().ioport("OTHER")->read() & 0x20) /* Paddle3 Button */
+ value &= ~0x04;
+ break;
+
+ case 0x20:
+ if (machine.root_device().ioport("OTHER")->read() & 0x02) /* Mouse Button Left */
+ value &= ~0x10;
+ if (machine.root_device().ioport("OTHER")->read() & 0x01) /* Mouse Button Right */
+ value &= ~0x01;
+ break;
+
+ case 0x30:
+ value &= ~(machine.root_device().ioport("JOY2_2B")->read() & 0x1f); /* Joy2 Directions + Button 1 */
+ break;
+
+ case 0x40:
+/* was there any input on the lightpen? where is it mapped? */
+// if (machine.root_device().ioport("OTHER")->read() & 0x04) /* Lightpen Signal */
+// value &= ?? ;
+ break;
+
+ case 0x70:
+ break;
+
+ default:
+ logerror("Invalid Controller 2 Setting %d\n", controller2);
+ break;
+ }
+
+ c64_keyline[9] = value;
+#endif
+
+// 128u4 FIXME
+// vic2_frame_interrupt (device);
+
+ /* for p500, check if lightpen has been chosen as input: if so, enable crosshair (but c64-like inputs for p500 are not working atm) */
+ machine.scheduler().timer_set(attotime::zero, FUNC(p500_lightpen_tick));
+
+ set_led_status(machine, 1, machine.root_device().ioport("SPECIAL")->read() & 0x04 ? 1 : 0); /* Shift Lock */
+}
+
+
+/***********************************************
+
+ CBM Business Computers Cartridges
+
+***********************************************/
+
+static DEVICE_IMAGE_LOAD(cbmb_cart)
+{
+ UINT32 size = image.length();
+ const char *filetype = image.filetype();
+ UINT8 *cbmb_memory = image.device().machine().root_device().memregion("maincpu")->base();
+ int address = 0;
+
+ /* Assign loading address according to extension */
+ if (!mame_stricmp(filetype, "10"))
+ address = 0x1000;
+
+ else if (!mame_stricmp(filetype, "20"))
+ address = 0x2000;
+
+ else if (!mame_stricmp(filetype, "40"))
+ address = 0x4000;
+
+ else if (!mame_stricmp(filetype, "60"))
+ address = 0x6000;
+
+ logerror("Loading cart %s at %.4x size:%.4x\n", image.filename(), address, size);
+
+ image.fread(cbmb_memory + 0xf0000 + address, size);
+
+ return IMAGE_INIT_PASS;
+}
+
+
+MACHINE_CONFIG_FRAGMENT(cbmb_cartslot)
+ MCFG_CARTSLOT_ADD("cart1")
+ MCFG_CARTSLOT_EXTENSION_LIST("10,20,40,60")
+ MCFG_CARTSLOT_NOT_MANDATORY
+ MCFG_CARTSLOT_LOAD(cbmb_cart)
+
+ MCFG_CARTSLOT_ADD("cart2")
+ MCFG_CARTSLOT_EXTENSION_LIST("10,20,40,60")
+ MCFG_CARTSLOT_NOT_MANDATORY
+ MCFG_CARTSLOT_LOAD(cbmb_cart)
+MACHINE_CONFIG_END
diff --git a/src/mess/machine/cbmiec.c b/src/mess/machine/cbmiec.c
new file mode 100644
index 00000000000..107b098116f
--- /dev/null
+++ b/src/mess/machine/cbmiec.c
@@ -0,0 +1,659 @@
+/**********************************************************************
+
+ Commodore IEC Serial Bus emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+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<cbm_iec_device>;
+const device_type CBM_IEC_SLOT = &device_creator<cbm_iec_slot_device>;
+
+
+
+//**************************************************************************
+// 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),
+ device_slot_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// static_set_slot -
+//-------------------------------------------------
+
+void cbm_iec_slot_device::static_set_slot(device_t &device, int address)
+{
+ cbm_iec_slot_device &cbm_iec_card = dynamic_cast<cbm_iec_slot_device &>(device);
+ cbm_iec_card.m_address = address;
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void cbm_iec_slot_device::device_start()
+{
+ m_bus = machine().device<cbm_iec_device>(CBM_IEC_TAG);
+ device_cbm_iec_interface *dev = dynamic_cast<device_cbm_iec_interface *>(get_card_device());
+ if (dev) m_bus->add_device(get_card_device(), m_address);
+}
+
+
+
+//**************************************************************************
+// DEVICE CONFIGURATION
+//**************************************************************************
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void cbm_iec_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const cbm_iec_interface *intf = reinterpret_cast<const cbm_iec_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<cbm_iec_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_srq_cb, 0, sizeof(m_out_srq_cb));
+ memset(&m_out_atn_cb, 0, sizeof(m_out_atn_cb));
+ memset(&m_out_clk_cb, 0, sizeof(m_out_clk_cb));
+ memset(&m_out_data_cb, 0, sizeof(m_out_data_cb));
+ memset(&m_out_reset_cb, 0, sizeof(m_out_reset_cb));
+ }
+}
+
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// set_signal -
+//-------------------------------------------------
+
+inline 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_out_srq_func(state); break;
+ case ATN: m_out_atn_func(state); break;
+ case CLK: m_out_clk_func(state); break;
+ case DATA: m_out_data_func(state); break;
+ case RESET: m_out_reset_func(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 -
+//-------------------------------------------------
+
+inline 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;
+}
+
+
+
+//**************************************************************************
+// 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)
+{
+ 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_out_srq_func.resolve(m_out_srq_cb, *this);
+ m_out_atn_func.resolve(m_out_atn_cb, *this);
+ m_out_clk_func.resolve(m_out_clk_cb, *this);
+ m_out_data_func.resolve(m_out_data_cb, *this);
+ m_out_reset_func.resolve(m_out_reset_cb, *this);
+}
+
+
+//-------------------------------------------------
+// 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(device_t *target, int address)
+{
+ daisy_entry *entry = auto_alloc(machine(), daisy_entry(target));
+
+ entry->m_interface->m_bus = this;
+ entry->m_interface->m_address = address;
+
+ 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);
+}
+
+
+//-------------------------------------------------
+// srq_r -
+//-------------------------------------------------
+
+READ_LINE_MEMBER( cbm_iec_device::srq_r )
+{
+ return get_signal(SRQ);
+}
+
+
+//-------------------------------------------------
+// atn_r -
+//-------------------------------------------------
+
+READ_LINE_MEMBER( cbm_iec_device::atn_r )
+{
+ return get_signal(ATN);
+}
+
+
+//-------------------------------------------------
+// clk_r -
+//-------------------------------------------------
+
+READ_LINE_MEMBER( cbm_iec_device::clk_r )
+{
+ return get_signal(CLK);
+}
+
+
+//-------------------------------------------------
+// data_r -
+//-------------------------------------------------
+
+READ_LINE_MEMBER( cbm_iec_device::data_r )
+{
+ return get_signal(DATA);
+}
+
+
+//-------------------------------------------------
+// reset_r -
+//-------------------------------------------------
+
+READ_LINE_MEMBER( cbm_iec_device::reset_r )
+{
+ return get_signal(RESET);
+}
+
+
+//-------------------------------------------------
+// srq_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( cbm_iec_device::srq_w )
+{
+ set_signal(this, SRQ, state);
+}
+
+
+//-------------------------------------------------
+// atn_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( cbm_iec_device::atn_w )
+{
+ set_signal(this, ATN, state);
+}
+
+
+//-------------------------------------------------
+// clk_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( cbm_iec_device::clk_w )
+{
+ set_signal(this, CLK, state);
+}
+
+
+//-------------------------------------------------
+// data_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( cbm_iec_device::data_w )
+{
+ set_signal(this, DATA, state);
+}
+
+
+//-------------------------------------------------
+// reset_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( cbm_iec_device::reset_w )
+{
+ set_signal(this, RESET, state);
+}
+
+
+//-------------------------------------------------
+// srq_w -
+//-------------------------------------------------
+
+void cbm_iec_device::srq_w(device_t *device, int state)
+{
+ set_signal(device, SRQ, state);
+}
+
+
+//-------------------------------------------------
+// atn_w -
+//-------------------------------------------------
+
+void cbm_iec_device::atn_w(device_t *device, int state)
+{
+ set_signal(device, ATN, state);
+}
+
+
+//-------------------------------------------------
+// clk_w -
+//-------------------------------------------------
+
+void cbm_iec_device::clk_w(device_t *device, int state)
+{
+ set_signal(device, CLK, state);
+}
+
+
+//-------------------------------------------------
+// data_w -
+//-------------------------------------------------
+
+void cbm_iec_device::data_w(device_t *device, int state)
+{
+ set_signal(device, DATA, state);
+}
+
+
+//-------------------------------------------------
+// reset_w -
+//-------------------------------------------------
+
+void cbm_iec_device::reset_w(device_t *device, int state)
+{
+ set_signal(device, RESET, state);
+}
diff --git a/src/mess/machine/cbmiec.h b/src/mess/machine/cbmiec.h
new file mode 100644
index 00000000000..0ab0ad21e95
--- /dev/null
+++ b/src/mess/machine/cbmiec.h
@@ -0,0 +1,197 @@
+/**********************************************************************
+
+ Commodore IEC Serial Bus emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#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(_config) \
+ MCFG_DEVICE_ADD(CBM_IEC_TAG, CBM_IEC, 0) \
+ MCFG_DEVICE_CONFIG(_config)
+
+
+#define CBM_IEC_INTERFACE(_name) \
+ const cbm_iec_interface (_name) =
+
+
+#define MCFG_CBM_IEC_SLOT_ADD(_tag, _num, _slot_intf, _def_slot, _def_inp) \
+ MCFG_DEVICE_ADD(_tag, CBM_IEC_SLOT, 0) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false) \
+ cbm_iec_slot_device::static_set_slot(*device, _num);
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> cbm_iec_interface
+
+struct cbm_iec_interface
+{
+ devcb_write_line m_out_srq_cb;
+ devcb_write_line m_out_atn_cb;
+ devcb_write_line m_out_clk_cb;
+ devcb_write_line m_out_data_cb;
+ devcb_write_line m_out_reset_cb;
+};
+
+
+// ======================> cbm_iec_device
+
+class device_cbm_iec_interface;
+
+class cbm_iec_device : public device_t,
+ public cbm_iec_interface
+{
+public:
+ // construction/destruction
+ cbm_iec_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ void add_device(device_t *target, int address);
+
+ // reads for both host and peripherals
+ DECLARE_READ_LINE_MEMBER( srq_r );
+ DECLARE_READ_LINE_MEMBER( atn_r );
+ DECLARE_READ_LINE_MEMBER( clk_r );
+ DECLARE_READ_LINE_MEMBER( data_r );
+ DECLARE_READ_LINE_MEMBER( reset_r );
+
+ // writes for host (driver_device)
+ DECLARE_WRITE_LINE_MEMBER( srq_w );
+ DECLARE_WRITE_LINE_MEMBER( atn_w );
+ DECLARE_WRITE_LINE_MEMBER( clk_w );
+ DECLARE_WRITE_LINE_MEMBER( data_w );
+ DECLARE_WRITE_LINE_MEMBER( reset_w );
+
+ // writes for peripherals (device_t)
+ void srq_w(device_t *device, int state);
+ void atn_w(device_t *device, int state);
+ void clk_w(device_t *device, int state);
+ void data_w(device_t *device, int state);
+ void reset_w(device_t *device, int 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_config_complete();
+ 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<daisy_entry> m_device_list;
+
+private:
+ devcb_resolved_write_line m_out_atn_func;
+ devcb_resolved_write_line m_out_clk_func;
+ devcb_resolved_write_line m_out_data_func;
+ devcb_resolved_write_line m_out_srq_func;
+ devcb_resolved_write_line m_out_reset_func;
+
+ inline void set_signal(device_t *device, int signal, int state);
+ inline 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);
+
+ // device-level overrides
+ virtual void device_start();
+
+ // inline configuration
+ static void static_set_slot(device_t &device, int address);
+
+private:
+ // configuration
+ int m_address;
+ cbm_iec_device *m_bus;
+};
+
+
+// ======================> 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_atn(int state) { };
+ virtual void cbm_iec_clk(int state) { };
+ virtual void cbm_iec_data(int state) { };
+ virtual void cbm_iec_srq(int state) { };
+ virtual void cbm_iec_reset(int state) { };
+
+ cbm_iec_device *m_bus;
+ int m_address;
+};
+
+
+// device type definition
+extern const device_type CBM_IEC;
+extern const device_type CBM_IEC_SLOT;
+
+
+
+#endif
diff --git a/src/mess/machine/cbmipt.c b/src/mess/machine/cbmipt.c
new file mode 100644
index 00000000000..92ce4324890
--- /dev/null
+++ b/src/mess/machine/cbmipt.c
@@ -0,0 +1,1236 @@
+/**********************************************************************************
+ *
+ * machine/cbmipt.c
+ *
+ * Input port macros shared by various CBM computers
+ *
+ *
+ * TO DO:
+ *
+ * - investigate C128 input problem with Left Shift / Shift Lock
+ * - investigate superpet different reading of Caps Lock (check machine/pet.c)
+ * - move here lightpen inputs from vc20.c, eventually
+ * - clean up the "SPECIAL" and "CFG" input ports (e.g. there a quite a lot
+ * of settings that are not checked anymore! we have either to implement
+ * the features properly or, if they're hacks, to remove them)
+ *
+ *********************************************************************************/
+
+#include "emu.h"
+#include "machine/cbmipt.h"
+
+
+/***************************** Commodore 64 ****************************************
+ *
+ * - common_cbm_keyboard: C64 keyboard; used by C16, C65 and C128 as well
+ * - c64_special: input port for the Restore key and the Shift Lock Switch
+ * - c64_controls: joypads, paddles and lightpen; shared with C65, C128
+ * and CBMB
+ *
+ **********************************************************************************/
+
+/*
+
+C64 Keyboard Layout
+-------------------
+
+ CLR INST
+ <- 1! 2" 3# 4$ 5% 6& 7' 8( 9) 0 + - ? HOME DEL f 1
+
+
+ CTRL Q W E R T Y U I O P @ * UP RESTORE f 3
+
+RUN SHIFT
+STOP LOCK A S D F G H J K L :[ ;] = RETURN f 5
+
+ CRSR CRSR
+C= SHIFT Z X C V B N M ,< .> /? SHIFT U/D L/R f 7
+
+
+ SPACEBAR
+
+
+Notes: "C=" is a key with the Commodore logo, "UP" is an arrow pointing up, the "CRSR" keys at the
+bottom-right corner are used to move the cursor on screen (Up/Down and Left/Right resp.).
+*/
+
+
+INPUT_PORTS_START( common_cbm_keyboard )
+ PORT_START( "ROW0" )
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Crsr Down Up") PORT_CODE(KEYCODE_RALT) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) PORT_CHAR(UCHAR_MAMEKEY(UP))
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F5)) PORT_CHAR(UCHAR_MAMEKEY(F6))
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F3)) PORT_CHAR(UCHAR_MAMEKEY(F4))
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) PORT_CHAR(UCHAR_MAMEKEY(F2))
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F7)) PORT_CHAR(UCHAR_MAMEKEY(F8))
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Crsr Right Left") PORT_CODE(KEYCODE_RCONTROL) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Return") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13)
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Del Inst") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) PORT_CHAR(UCHAR_MAMEKEY(INSERT))
+
+ PORT_START( "ROW1" )
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Shift (Left)") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('E')
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('S')
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z')
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('A')
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('W')
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')
+
+ PORT_START( "ROW2" )
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('X')
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('T')
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('F')
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('C')
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&')
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('D')
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('R')
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')
+
+ PORT_START( "ROW3" )
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('V')
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('U')
+ PORT_BIT( 0x20, 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( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('(')
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('G')
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y')
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('\'')
+
+ PORT_START( "ROW4" )
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('N')
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('O')
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('K')
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('M')
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0')
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('J')
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('I')
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(')')
+
+ PORT_START( "ROW5" )
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('@')
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR(':') PORT_CHAR('[')
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('-')
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('L')
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('P')
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('+')
+
+ PORT_START( "ROW6" )
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?')
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("\xE2\x86\x91 Pi") PORT_CODE(KEYCODE_DEL) PORT_CHAR(0x2191) PORT_CHAR(0x03C0)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('=')
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Shift (Right)") PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Home Clr") PORT_CODE(KEYCODE_INSERT) PORT_CHAR(UCHAR_MAMEKEY(HOME))
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR(';') PORT_CHAR(']')
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR('*')
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH2) PORT_CHAR('\xA3')
+
+ PORT_START( "ROW7" )
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Stop Run") PORT_CODE(KEYCODE_HOME)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('Q')
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("CBM") PORT_CODE(KEYCODE_LALT)
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"')
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TAB) PORT_CHAR(UCHAR_SHIFT_2)
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("\xE2\x86\x90") PORT_CODE(KEYCODE_TILDE) PORT_CHAR(0x2190)
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')
+INPUT_PORTS_END
+
+
+INPUT_PORTS_START( c64_special )
+ PORT_START( "SPECIAL" ) /* special keys */
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Restore") PORT_CODE(KEYCODE_PRTSCR)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Shift Lock (switch)") PORT_CODE(KEYCODE_CAPSLOCK) PORT_TOGGLE PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK))
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED )
+INPUT_PORTS_END
+
+
+INPUT_PORTS_START( c64_controls )
+ PORT_START("CTRLSEL") /* Controller selection */
+ PORT_CONFNAME( 0x07, 0x00, "Gameport A" )
+ PORT_CONFSETTING( 0x00, DEF_STR( Joystick ) )
+ PORT_CONFSETTING( 0x01, "Paddles 1 & 2" )
+ PORT_CONFSETTING( 0x02, "Mouse 1351" )
+ PORT_CONFSETTING( 0x03, "Mouse (Non Proportional) 1350" )
+ PORT_CONFSETTING( 0x04, "Lightpen" )
+// PORT_CONFSETTING( 0x05, "Koala Pad" )
+ PORT_CONFSETTING( 0x06, "Lightgun" )
+ PORT_CONFSETTING( 0x07, "No Device Connected" )
+ PORT_CONFNAME( 0x70, 0x00, "Gameport B" )
+ PORT_CONFSETTING( 0x00, DEF_STR( Joystick ) )
+ PORT_CONFSETTING( 0x10, "Paddles 3 & 4" )
+// PORT_CONFSETTING( 0x20, "Mouse 1351" )
+// PORT_CONFSETTING( 0x30, "Mouse (Non Proportional) 1350" )
+ PORT_CONFSETTING( 0x70, "No Device Connected" )
+ PORT_CONFNAME( 0x80, 0x00, "Swap Gameport A and B") PORT_CODE(KEYCODE_F1) PORT_TOGGLE
+ PORT_CONFSETTING( 0x00, DEF_STR( No ) )
+ PORT_CONFSETTING( 0x80, DEF_STR( Yes ) )
+
+ PORT_START("CYCLES")
+ PORT_CONFNAME( 0x07, 0x00, "Cycles in a line" )
+ PORT_CONFSETTING( 0x00, "0" )
+ PORT_CONFSETTING( 0x01, "1" )
+ PORT_CONFSETTING( 0x02, "2" )
+ PORT_CONFSETTING( 0x03, "3" )
+ PORT_CONFSETTING( 0x04, "4" )
+ PORT_CONFSETTING( 0x07, "Off" )
+
+ PORT_START("JOY1_1B")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x00)
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x00)
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x00)
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x00)
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x00)
+ PORT_BIT( 0xe0, IP_ACTIVE_HIGH, IPT_UNUSED )
+
+ PORT_START("JOY2_1B")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(2) PORT_CODE(KEYCODE_HOME) PORT_CODE(JOYCODE_Y_UP_SWITCH) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x00)
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(2) PORT_CODE(KEYCODE_END) PORT_CODE(JOYCODE_Y_DOWN_SWITCH) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x00)
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(2) PORT_CODE(KEYCODE_DEL) PORT_CODE(JOYCODE_X_LEFT_SWITCH) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x00)
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(2) PORT_CODE(KEYCODE_PGDN) PORT_CODE(JOYCODE_X_RIGHT_SWITCH) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x00)
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_CODE(KEYCODE_INSERT) PORT_CODE(JOYCODE_BUTTON1) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x00)
+ PORT_BIT( 0xe0, IP_ACTIVE_HIGH, IPT_UNUSED )
+
+ /* Mouse Commodore 1350 was basically working as a Joystick */
+ PORT_START("JOY1_2B")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(1) PORT_NAME("Mouse 1350 Up") PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x03)
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(1) PORT_NAME("Mouse 1350 Down") PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x03)
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(1) PORT_NAME("Mouse 1350 Left") PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x03)
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(1) PORT_NAME("Mouse 1350 Right") PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x03)
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_NAME("Mouse 1350 Button 1") PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x03)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_PLAYER(1) PORT_NAME("Mouse 1350 Button 2") PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x03)
+ PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED )
+
+ /* Still to verify how many mices you were able to plug into a c64 */
+ /* Only one, for now */
+ PORT_START("JOY2_2B")
+ PORT_BIT( 0xff, IP_ACTIVE_HIGH, IPT_UNUSED )
+/* PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(2) PORT_CODE(KEYCODE_HOME) PORT_CODE(JOYCODE_Y_UP_SWITCH)
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(2) PORT_CODE(KEYCODE_END) PORT_CODE(JOYCODE_Y_DOWN_SWITCH) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x30)
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(2) PORT_CODE(KEYCODE_DEL) PORT_CODE(JOYCODE_X_LEFT_SWITCH) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x30)
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(2) PORT_CODE(KEYCODE_PGDN) PORT_CODE(JOYCODE_X_RIGHT_SWITCH) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x30)
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_CODE(KEYCODE_INSERT) PORT_CODE(JOYCODE_BUTTON1) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x30)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_PLAYER(2) PORT_CODE(KEYCODE_PGUP) PORT_CODE(JOYCODE_BUTTON2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x30)
+ PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED )
+*/
+ PORT_START("PADDLE1")
+ PORT_BIT( 0xff, 128, IPT_PADDLE) PORT_SENSITIVITY(30) PORT_KEYDELTA(20) PORT_MINMAX(0,255) PORT_CENTERDELTA(0) 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_PLAYER(1) PORT_REVERSE PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
+
+ PORT_START("PADDLE2")
+ PORT_BIT( 0xff, 128, IPT_PADDLE) PORT_SENSITIVITY(30) PORT_KEYDELTA(20) PORT_MINMAX(0,255) PORT_CENTERDELTA(0) PORT_CODE_DEC(KEYCODE_DOWN) PORT_CODE_INC(KEYCODE_UP) PORT_CODE_DEC(JOYCODE_Y_UP_SWITCH) PORT_CODE_INC(JOYCODE_Y_DOWN_SWITCH) PORT_PLAYER(2) PORT_REVERSE PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
+
+ PORT_START("PADDLE3")
+ PORT_BIT( 0xff, 128, IPT_PADDLE) PORT_SENSITIVITY(30) PORT_KEYDELTA(20) PORT_MINMAX(0,255) PORT_CENTERDELTA(0) PORT_CODE_DEC(KEYCODE_HOME) PORT_CODE_INC(KEYCODE_PGUP) PORT_PLAYER(3) PORT_REVERSE PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
+
+ PORT_START("PADDLE4")
+ PORT_BIT( 0xff, 128, IPT_PADDLE) PORT_SENSITIVITY(30) PORT_KEYDELTA(20) PORT_MINMAX(0,255) PORT_CENTERDELTA(0) PORT_CODE_DEC(KEYCODE_END) PORT_CODE_INC(KEYCODE_PGDN) PORT_PLAYER(4) PORT_REVERSE PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
+
+ PORT_START("TRACKX")
+ PORT_BIT( 0x7e, 0x00, IPT_TRACKBALL_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x02)
+
+ PORT_START("TRACKY")
+ PORT_BIT( 0x7e, 0x00, IPT_TRACKBALL_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1) PORT_REVERSE PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x02)
+
+ PORT_START("LIGHTX")
+ PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X) PORT_NAME("Lightpen X Axis") PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(30) PORT_KEYDELTA(20) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x04)
+
+ PORT_START("LIGHTY")
+ PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_Y) PORT_NAME("Lightpen Y Axis") PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(30) PORT_KEYDELTA(20) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x04)
+
+ PORT_START("OTHER")
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Paddle 1 Button") PORT_CODE(KEYCODE_LCONTROL) PORT_CODE(JOYCODE_BUTTON1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON2) PORT_NAME("Paddle 2 Button") PORT_CODE(KEYCODE_LALT) PORT_CODE(JOYCODE_BUTTON2) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_BUTTON3) PORT_NAME("Paddle 3 Button") PORT_CODE(KEYCODE_INSERT) PORT_CODE(JOYCODE_BUTTON1) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON4) PORT_NAME("Paddle 4 Button") PORT_CODE(KEYCODE_DEL) PORT_CODE(JOYCODE_BUTTON2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Lightpen Signal") PORT_CODE(KEYCODE_LCONTROL) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x04)
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Mouse Button Left") PORT_CODE(KEYCODE_LCONTROL) PORT_CODE(JOYCODE_BUTTON1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x02)
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON2) PORT_NAME("Mouse Button Right") PORT_CODE(KEYCODE_LALT) PORT_CODE(JOYCODE_BUTTON2) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x02)
+INPUT_PORTS_END
+
+
+/***************************** Commodore 16 ****************************************
+ *
+ * - C16 shares Keyboard with C64 (only few changes, see c16.c)
+ * - c16_special: input port for the Shift Lock Switch
+ * - c16_controls: control inputs
+ *
+ **********************************************************************************/
+
+/*
+
+C16 Keyboard Layout
+-------------------
+
+ INST
+ ESC 1! 2" 3# 4$ 5% 6& 7' 8( 9) 0^ LEFT RIGHT UP DOWN DEL f 1
+
+ CLEAR
+ CTRL Q W E R T Y U I O P @ + - HOME f 3
+
+ RUN SHIFT
+ STOP LOCK A S D F G H J K L :[ ;] * RETURN f 5
+
+
+ C= SHIFT Z X C V B N M ,< .> /? SHIFT ? = HELP
+
+
+ SPACEBAR
+
+
+Notes: "C=" is a key with the Commodore logo, Shift+0 produces an arrow pointing up (''^'' above).
+
+C116 Keyboard Layout
+--------------------
+
+ F1/F4 F2/F5 F3/F6 HELP/F7 HOME/CLEAR DEL/INST
+
+
+ ESC 1! 2" 3# 4$ 5% 6& 7' 8( 9) 0^ + - *
+
+
+ CONTROL Q W E R T Y U I O P @ RETURN
+
+ RUN
+ STOP ?? A S D F G H J K L :[ ;] =
+
+
+ C= SHIFT Z X C V B N M ,< .> /? SHIFT
+ UP
+ LEFT RIGHT
+ SPACEBAR DOWN
+
+
+Plus/4 (also 232/264/364 proto)
+-----------------------------------
+
+ F1/F4 F2/F5 F3/F6 HELP/F7
+
+ CLEAR INST
+ ESC 1! 2" 3# 4$ 5% 6& 7' 8( 9) 0^ + - = HOME DEL || @ + - =
+ ||
+ ||
+ CONTROL Q W E R T Y U I O P @ ? * CONTROL || 7 8 9 *
+ ||
+ RUN SHIFT ||
+ STOP LOCK A S D F G H J K L :[ ;] RETURN || 4 5 6 /
+ ||
+ || E
+ C= SHIFT Z X C V B N M ,< .> /? SHIFT || 1 2 3 n
+ UP || t
+ LEFT RIGHT || e
+ SPACEBAR DOWN || 0 . : r
+
+The 19-keys keypad on the left was present only in the 364 prototype (but probably those
+keys were simply wired to the lines of regular number keys of the keyboard).
+
+*/
+
+INPUT_PORTS_START( c16_special )
+ PORT_START("SPECIAL")
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Shift Lock (switch)") PORT_CODE(KEYCODE_CAPSLOCK) PORT_TOGGLE
+ PORT_CONFNAME( 0x40, 0x00, "Swap Gameport 1 and 2") PORT_CODE(KEYCODE_F1) PORT_TOGGLE
+ PORT_CONFSETTING( 0x00, DEF_STR( No ) )
+ PORT_CONFSETTING( 0x40, DEF_STR( Yes ) )
+INPUT_PORTS_END
+
+
+INPUT_PORTS_START( c16_controls )
+ PORT_START("CTRLSEL") /* Controller selection */
+ PORT_CONFNAME( 0x01, 0x00, "Gameport 1" )
+ PORT_CONFSETTING( 0x00, DEF_STR( Joystick ) )
+ PORT_CONFSETTING( 0x01, "No Device Connected" )
+ PORT_CONFNAME( 0x10, 0x00, "Gameport 2" )
+ PORT_CONFSETTING( 0x00, DEF_STR( Joystick ) )
+ PORT_CONFSETTING( 0x10, "No Device Connected" )
+
+ PORT_START("JOY0")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP) PORT_NAME("P1 Up") PORT_8WAY PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x00)
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN) PORT_NAME("P1 Down") PORT_8WAY PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x00)
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT) PORT_NAME("P1 Left") PORT_8WAY PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x00)
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT) PORT_NAME("P1 Right") PORT_8WAY PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x00)
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("P1 Button") PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x00)
+
+ PORT_START("JOY1")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP) PORT_NAME("P2 Up") PORT_CODE(KEYCODE_HOME) PORT_CODE(JOYCODE_Y_UP_SWITCH) PORT_8WAY PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x00)
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN) PORT_NAME("P2 Down") PORT_CODE(KEYCODE_END) PORT_CODE(JOYCODE_Y_DOWN_SWITCH) PORT_8WAY PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x00)
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT) PORT_NAME("P2 Left") PORT_CODE(KEYCODE_DEL) PORT_CODE(JOYCODE_X_LEFT_SWITCH) PORT_8WAY PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x00)
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT) PORT_NAME("P2 Right") PORT_CODE(KEYCODE_PGDN) PORT_CODE(JOYCODE_X_RIGHT_SWITCH) PORT_8WAY PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x00)
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("P2 Button") PORT_CODE(KEYCODE_LALT) PORT_CODE(JOYCODE_BUTTON1) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x00)
+INPUT_PORTS_END
+
+
+/***************************** Commodore 128 ***************************************
+ *
+ * - C128 shares Controls and Keyboard with C64 (+ a keypad, see c128.c)
+ * - c128_special: input port for the Restore key and the Shift Lock,
+ * TV/RGBI and 40/80 columns switches
+ *
+ **********************************************************************************/
+
+/*
+
+C128 Keyboard Layout
+--------------------
+
+
+ CAPS LINE 40/80 NO
+ ESC TAB ALT LOCK HELP FEED DISPLAY SCROLL UP DOWN LEFT RIGHT F1 F3 F5 F7
+
+ CLR INST
+ <- 1! 2" 3# 4$ 5% 6& 7' 8( 9) 0 + - ? HOME DEL 7 8 9 +
+
+
+ CONTROL Q W E R T Y U I O P @ * UP RESTORE 4 5 6 -
+
+ RUN SHIFT E
+ STOP LOCK A S D F G H J K L :[ ;] = RETURN 1 2 3 n
+ t
+ CRSR CRSR e
+ C= SHIFT Z X C V B N M ,< .> /? SHIFT U/D L/R 0 . r
+
+
+ SPACEBAR
+
+Notes: "C=" is a key with the Commodore logo, "UP" is an arrow pointing up, the "CRSR" keys at the bottom-right
+corner are used to move the cursor on screen (Up/Down and Left/Right resp.).
+
+*/
+
+INPUT_PORTS_START( c128_special )
+ PORT_START( "SPECIAL" ) /* special keys */
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Restore") PORT_CODE(KEYCODE_PRTSCR)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Shift Lock (switch)") PORT_CODE(KEYCODE_CAPSLOCK) PORT_TOGGLE PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK))
+ PORT_CONFNAME( 0x20, 0x00, "Caps Lock (switch)")
+ PORT_CONFSETTING( 0x00, DEF_STR( Off ) )
+ PORT_CONFSETTING( 0x20, DEF_STR( On ) )
+ PORT_CONFNAME( 0x10, 0x10, "40 80 Display (switch) (active after a rebooting)")
+ PORT_CONFSETTING( 0x00, "40 Columns (DIN/TV)")
+ PORT_CONFSETTING( 0x10, "80 Columns (RGBI)")
+ PORT_CONFNAME( 0x08, 0x08, "DIN,TV / RGBI Monitor (switch)") PORT_CODE(KEYCODE_ENTER_PAD)
+ PORT_CONFSETTING( 0x00, "DIN,TV" )
+ PORT_CONFSETTING( 0x08, "RGBI" )
+ PORT_CONFNAME( 0x06, 0x00, "Main Memory / MMU Version")
+ PORT_CONFSETTING( 0x00, "128 KByte" )
+ PORT_CONFSETTING( 0x02, "256 KByte" )
+ PORT_CONFSETTING( 0x04, "1024 KByte" )
+INPUT_PORTS_END
+
+
+/***************************** Commodore 65 ****************************************
+ *
+ * - C65 shares Keyboard and Inputs with C64 (+ some function keys, see c65.c)
+ * - c65_special: input port for the Restore key and the Shift Lock and DIN
+ * switches
+ *
+ **********************************************************************************/
+
+/*
+
+C65 Keyboard Layout
+-------------------
+
+ RUN CAPS NO
+ STOP ESC ALT LOCK SCROLL F1 F3 F5 F7 F9 F11 F13 HELP
+
+ CLR INST
+ <- 1! 2" 3# 4$ 5% 6& 7' 8( 9) 0 + - ?? HOME DEL
+
+
+ TAB Q W E R T Y U I O P @ * UP RESTORE
+
+ SHIFT
+ CTRL LOCK A S D F G H J K L :[ ;] = RETURN
+
+
+ C= SHIFT Z X C V B N M ,< .> /? SHIFT UP
+
+
+ SPACEBAR LEFT DOWN RIGHT
+
+Notes: "C=" is a key with the Commodore logo, "UP" is an arrow pointing up.
+
+*/
+INPUT_PORTS_START( c65_special )
+ PORT_START( "SPECIAL" ) /* special keys */
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Restore") PORT_CODE(KEYCODE_PRTSCR)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Shift Lock (switch)") PORT_CODE(KEYCODE_CAPSLOCK) PORT_TOGGLE PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK))
+ PORT_CONFNAME( 0x20, 0x00, "(C65) Caps Lock (switch)") PORT_CODE(KEYCODE_F3)
+ PORT_CONFSETTING( 0x00, DEF_STR( Off ) )
+ PORT_CONFSETTING( 0x20, DEF_STR( On ) )
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED )
+INPUT_PORTS_END
+
+
+/***************************** Commodore Pet ***************************************
+ *
+ * - pet_keyboard: original keyboard used by PET2001
+ * - pet_business_keyboard: business keyboard is used by the other computers
+ * in pet.c
+ * - pet_special: input port for the Shift Lock Switch
+ * - pet_config: memory and serial port configurations
+ *
+ **********************************************************************************/
+
+/*
+
+PET Keyboard Layout
+-------------------
+
+ CLR CRSR CRSR INST
+ @ ! " # $ % ' & \ ( ) <- [ ] HOME U/D L/R DEL
+
+ RVS
+ OFF Q W E R T Y U I O P UP < > 7 8 9 /
+
+ SHIFT STOP
+ LOCK A S D F G H J K L : RUN RETURN 4 5 6 *
+
+
+ SHIFT Z X C V B N M , ; ? SHIFT 1 2 3 +
+
+
+ SPACEBAR 0 . - =
+
+
+The PET Keypad has 16 keys, making impossible to map it in a satisfactory way to a PC keypad.
+Therefore, default settings for these keys in Full Emulation are currently based on the effect
+of the key and not on their real position
+
+
+PET Business Keyboard Layout
+----------------------------
+
+ CRSR STOP
+ <- 1! 2" 3# 4$ 5% 6& 7' 8( 9) 0 :* -= UP L/R RUN 7 8 9
+
+ CRSR DEL
+ TAB Q W E R T Y U I O P [ \ U/D INST 4 5 6
+
+ SHIFT
+ESC LOCK A S D F G H J K L ;+ @ ] RETURN 1 2 3
+
+RVS HOME
+OFF SHIFT Z X C V B N M ,< .> /? SHIFT REPEAT CLR 0 .
+
+
+ SPACEBAR
+
+*/
+
+INPUT_PORTS_START( pet_keyboard )
+ PORT_START( "ROW0" )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Crsr Right Left") PORT_CODE(KEYCODE_PGDN) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Home Clr Screen") PORT_CODE(KEYCODE_HOME) PORT_CHAR(UCHAR_MAMEKEY(HOME))
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("\xE2\x86\x90") PORT_CODE(KEYCODE_MINUS) PORT_CHAR(0x2190)
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('(')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('&')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('%')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('#')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('!')
+
+ PORT_START( "ROW1" )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Del Inst") PORT_CODE(KEYCODE_DEL) PORT_CHAR(8) PORT_CHAR(UCHAR_MAMEKEY(INSERT))
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Crsr Down Up") PORT_CODE(KEYCODE_PGUP) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) PORT_CHAR(UCHAR_MAMEKEY(UP))
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR(')')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('\\')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('\'')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('$')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('"')
+
+ PORT_START( "ROW2" )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9_PAD) PORT_CHAR('9')
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7_PAD) PORT_CHAR('7')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("\xE2\x86\x91 Pi") PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR(0x2191) PORT_CHAR(0x03C0)
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('O')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('U')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('T')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('E')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('Q')
+
+ PORT_START( "ROW3" )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH_PAD) PORT_CHAR('/')
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8_PAD) PORT_CHAR('8')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('P')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('I')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('R')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('W')
+
+ PORT_START( "ROW4" )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6_PAD) PORT_CHAR('6')
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4_PAD) PORT_CHAR('4')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('L')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('J')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('G')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('D')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('A')
+
+ PORT_START( "ROW5" )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ASTERISK) PORT_CHAR('*')
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5_PAD) PORT_CHAR('5')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR(':')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('K')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('H')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('F')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('S')
+
+ PORT_START( "ROW6" )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3_PAD) PORT_CHAR('3')
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1_PAD) PORT_CHAR('1')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Return") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13)
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR(';')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('M')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('B')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('C')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z')
+
+ PORT_START( "ROW7" )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR('+')
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2_PAD) PORT_CHAR('2')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('?')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('N')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('V')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('X')
+
+ PORT_START( "ROW8" )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR('-')
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0_PAD) PORT_CHAR('0')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Shift (Right)") PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('>')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(']')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('@')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Shift (Left)") PORT_CODE(KEYCODE_LSHIFT)
+
+ PORT_START( "ROW9" )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad =") PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR('=')
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR('.')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Stop Run") PORT_CODE(KEYCODE_QUOTE)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR('<')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('[')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Rvs Off") PORT_CODE(KEYCODE_TAB)
+INPUT_PORTS_END
+
+
+INPUT_PORTS_START( pet_business_keyboard )
+ PORT_START( "ROW0" )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Crsr Right Left") PORT_CODE(KEYCODE_PGUP) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD))
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('-') PORT_CHAR('=')
+ PORT_BIT( 0x04, 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_5) PORT_CHAR('5') PORT_CHAR('%')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"')
+
+ PORT_START( "ROW1" )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD))
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("\xE2\x86\x91") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(0x2191)
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD))
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD))
+ PORT_BIT( 0x04, 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_4) PORT_CHAR('4') PORT_CHAR('$')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')
+
+ PORT_START( "ROW2" )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD))
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR('+')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('K')
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR(']')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('H')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('F')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('S')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC))
+
+ PORT_START( "ROW3" )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD))
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('@')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('L')
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Return") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('J')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('G')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('D')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('A')
+
+ PORT_START( "ROW4" )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Del Inst") PORT_CODE(KEYCODE_DEL) PORT_CHAR(8) PORT_CHAR(UCHAR_MAMEKEY(INSERT))
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('P')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('I')
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR('\\')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('R')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('W')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TAB) PORT_CHAR('\t')
+
+ PORT_START( "ROW5" )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD))
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('O')
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Crsr Down Up") PORT_CODE(KEYCODE_PGDN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) PORT_CHAR(UCHAR_MAMEKEY(UP))
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('U')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('T')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('E')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('Q')
+
+ PORT_START( "ROW6" )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD))
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Shift (Right)") PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD))
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('B')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('C')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Shift (Left)") PORT_CODE(KEYCODE_LSHIFT)
+
+ PORT_START( "ROW7" )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD))
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Repeat") PORT_CODE(KEYCODE_LALT)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('N')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('V')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z')
+
+ PORT_START( "ROW8" )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD))
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Home Clr Screen") PORT_CODE(KEYCODE_HOME) PORT_CHAR(UCHAR_MAMEKEY(HOME))
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('M')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('X')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Rvs Off") PORT_CODE(KEYCODE_INSERT)
+
+ PORT_START( "ROW9" )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR(':') PORT_CHAR('*')
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Stop Run") PORT_CODE(KEYCODE_END)
+ PORT_BIT( 0x08, 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_6) PORT_CHAR('6') PORT_CHAR('\'')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("\xE2\x86\x90") PORT_CODE(KEYCODE_TILDE) PORT_CHAR(0x2190)
+INPUT_PORTS_END
+
+
+INPUT_PORTS_START( pet_special )
+ PORT_START( "SPECIAL" ) /* Special keys */
+ PORT_CONFNAME( 0x80, 0x00, "Shift Lock (switch)") PORT_CODE(KEYCODE_CAPSLOCK) PORT_TOGGLE
+ PORT_CONFSETTING(0x00, DEF_STR( Off ) )
+ PORT_CONFSETTING(0x80, DEF_STR( On ) )
+INPUT_PORTS_END
+
+
+INPUT_PORTS_START( pet_config )
+ PORT_START("CFG")
+ PORT_CONFNAME( 0x180, 0x180, "Memory")
+ PORT_CONFSETTING( 0x000, "4 KByte" )
+ PORT_CONFSETTING( 0x080, "8 KByte" )
+ PORT_CONFSETTING( 0x100, "16 KByte" )
+ PORT_CONFSETTING( 0x180, "32 KByte" )
+ PORT_BIT( 0x08, 0x00, IPT_UNUSED ) /* no 8096 hardware */
+ PORT_BIT( 0x04, 0x00, IPT_UNUSED ) /* no superpet switch */
+ PORT_CONFNAME( 0x02, 0x02, "IEEE488 Bus/Dev 8/Floppy Sim")
+ PORT_CONFSETTING( 0x00, DEF_STR( No ) )
+ PORT_CONFSETTING( 0x02, DEF_STR( Yes ) )
+ PORT_CONFNAME( 0x01, 0x00, "IEEE488 Bus/Dev 9/Floppy Sim")
+ PORT_CONFSETTING( 0x00, DEF_STR( No ) )
+ PORT_CONFSETTING( 0x01, DEF_STR( Yes ) )
+INPUT_PORTS_END
+
+
+
+/***************************** Commodore CBMB **************************************
+ *
+ * - CBMB machines share Controls (in particular Lightpen) with C64
+ * - cbmb_keyboard: Keyboard used by all the models of this series
+ * - cbmb_special: input port for the Shift Lock Switch
+ *
+ **********************************************************************************/
+
+/*
+
+CBMB Series Keyboard Layout (based on a CBM 610 keyboard)
+---------------------------------------------------------
+
+ F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 DOWN UP LEFT RIGHT HOME/CLEAR DEL/INST
+
+ INS
+ ESC 1! 2" 3# 4$ 5% 6^ 7& 8* 9( 0) - =+ <-? DEL ? CE . /
+
+ ________
+ TAB Q W E R T Y U I O P [ ] | RETURN | 7 8 9 -
+ |__ |
+ SHIFT | |
+ LOCK A S D F G H J K L ;: '" Pi | | 4 5 6 +
+ |_____|
+ E
+ SHIFT Z X C V B N M ,< .> /? SHIFT C= 1 2 3 n
+ t
+ e
+ CTRL SPACEBAR 0 . 00 r
+
+
+Notes: "C=" is a key with the Commodore logo, Shift+6 produces an arrow pointing up ("^" above).
+
+
+*/
+
+INPUT_PORTS_START( cbmb_keyboard )
+ PORT_START("ROW0")
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Stop Run") PORT_CODE(KEYCODE_DEL)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("RVS Off") PORT_CODE(KEYCODE_HOME)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Graph Norm") PORT_CODE(KEYCODE_PGUP)
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Home Clr") PORT_CODE(KEYCODE_INSERT) PORT_CHAR(UCHAR_MAMEKEY(HOME))
+ PORT_BIT( 0x08, 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_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN))
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10))
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9))
+
+ PORT_START("ROW1")
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8))
+ PORT_BIT( 0x40, 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_F6) PORT_CHAR(UCHAR_MAMEKEY(F6))
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5))
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4))
+ PORT_BIT( 0x04, 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_F2) PORT_CHAR(UCHAR_MAMEKEY(F2))
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1))
+
+ PORT_START("ROW2")
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ASTERISK) PORT_CHAR(UCHAR_MAMEKEY(SLASH_PAD))
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH_PAD) PORT_CHAR(UCHAR_MAMEKEY(ASTERISK))
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad CE") PORT_CODE(KEYCODE_NUMLOCK)
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad ?") PORT_CODE(KEYCODE_END)
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+')
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')')
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(')
+
+ PORT_START("ROW3")
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*')
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&')
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@')
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC))
+
+ PORT_START("ROW4")
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD))
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD))
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD))
+ PORT_BIT( 0x10, 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_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT))
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("\xE2\x86\x90 \xC2\xA3") PORT_CODE(KEYCODE_TILDE) PORT_CHAR(0x2190) PORT_CHAR('\xA3')
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-')
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O')
+
+ PORT_START("ROW5")
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I')
+ PORT_BIT( 0x40, 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("6 \xE2\x86\x91") PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR(0x2191)
+ PORT_BIT( 0x10, 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_E) PORT_CHAR('e') PORT_CHAR('E')
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W')
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q')
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TAB) PORT_CHAR('\t')
+
+ PORT_START("ROW6")
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(PLUS_PAD))
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD))
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD))
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD))
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Del Ins") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) PORT_CHAR(UCHAR_MAMEKEY(INSERT))
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']')
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P')
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L')
+
+ PORT_START("ROW7")
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K')
+ PORT_BIT( 0x40, 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_Y) PORT_CHAR('y') PORT_CHAR('Y')
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T')
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D')
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S')
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A')
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED )
+
+ PORT_START("ROW8")
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD))
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD))
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD))
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD))
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("CBM") PORT_CODE(KEYCODE_RALT) PORT_CHAR(UCHAR_MAMEKEY(RALT))
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Return") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13)
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[')
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':')
+
+ PORT_START("ROW9")
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M')
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H')
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G')
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F')
+ PORT_BIT( 0x04, 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_Z) PORT_CHAR('z') PORT_CHAR('Z')
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
+
+ PORT_START("ROW10")
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad 00") PORT_CODE(KEYCODE_PGDN)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD))
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD))
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Pi") PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR(0x03C0)
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('"')
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?')
+
+ PORT_START("ROW11")
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N')
+ PORT_BIT( 0x10, 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_V) PORT_CHAR('v') PORT_CHAR('V')
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C')
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_SHIFT_2)
+INPUT_PORTS_END
+
+
+INPUT_PORTS_START( cbmb_special )
+ PORT_START("SPECIAL")
+ PORT_BIT( 0x200, 0x200, IPT_UNUSED ) /* ntsc */
+ PORT_BIT( 0x100, 0x000, IPT_UNUSED ) /* cbm600 */
+ PORT_CONFNAME( 0x04, 0x00, "Shift Lock (switch)") PORT_CODE(KEYCODE_CAPSLOCK) PORT_TOGGLE
+ PORT_CONFSETTING( 0x00, DEF_STR( Off ) )
+ PORT_CONFSETTING( 0x04, DEF_STR( On ) )
+INPUT_PORTS_END
+
+
+ /***************************** Commodore Vic 20 ***********************************
+ *
+ * - vic_keyboard: basic Vic 20 keyboard
+ * - vic_special: input port for the Shift Lock Switch
+ * - vic_controls: joypads and paddles
+ * - VIC20 also has 2 lightpen ports, vic_lightpen_6560 & vic_lightpen_6561
+ * currently in vic20.c (they need visible area parameters for centering)
+ *
+ **********************************************************************************/
+
+/*
+
+VIC20 Keyboard Layout
+---------------------
+
+ CLR INST
+ <- 1! 2" 3# 4$ 5% 6& 7' 8( 9) 0 + - ? HOME DEL f 1
+
+
+ CTRL Q W E R T Y U I O P @ * UP RESTORE f 3
+
+RUN SHIFT
+STOP LOCK A S D F G H J K L :[ ;] = RETURN f 5
+
+ CRSR CRSR
+C= SHIFT Z X C V B N M ,< .> /? SHIFT U/D L/R f 7
+
+
+ SPACEBAR
+
+
+Notes: "C=" is a key with the Commodore logo, "UP" is an arrow pointing up, the "CRSR" keys at the
+bottom-right corner are used to move the cursor on screen (Up/Down and Left/Right respectively).
+Notice that this is exactly the same layout of C64 keyboard.
+
+*/
+
+INPUT_PORTS_START( vic_keyboard )
+ PORT_START( "ROW0" )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Del Inst") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) PORT_CHAR(UCHAR_MAMEKEY(INSERT))
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH2) PORT_CHAR('\xA3')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('+')
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(')')
+ PORT_BIT( 0x08, 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_5) PORT_CHAR('5') PORT_CHAR('%')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')
+
+ PORT_START( "ROW1" )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Return") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR('*')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('P')
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('I')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('R')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('W')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("\xE2\x86\x90") PORT_CODE(KEYCODE_TILDE) PORT_CHAR(0x2190)
+
+ PORT_START( "ROW2" )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Crsr Right Left") PORT_CODE(KEYCODE_RCONTROL) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR(';') PORT_CHAR(']')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('L')
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('J')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('G')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('D')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('A')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TAB) PORT_CHAR(UCHAR_SHIFT_2)
+
+ PORT_START( "ROW3" )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Crsr Down Up") PORT_CODE(KEYCODE_RALT) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) PORT_CHAR(UCHAR_MAMEKEY(UP))
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('N')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('V')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('X')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Shift (Left)") PORT_CODE(KEYCODE_LSHIFT)
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Stop Run") PORT_CODE(KEYCODE_HOME)
+
+ PORT_START( "ROW4" )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) PORT_CHAR(UCHAR_MAMEKEY(F2))
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Shift (Right)") PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('M')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('B')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('C')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
+
+ PORT_START( "ROW5" )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F3)) PORT_CHAR(UCHAR_MAMEKEY(F4))
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('=')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR(':') PORT_CHAR('[')
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('K')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('H')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('F')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('S')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("CBM") PORT_CODE(KEYCODE_LCONTROL)
+
+ PORT_START( "ROW6" )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F5)) PORT_CHAR(UCHAR_MAMEKEY(F6))
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("\xE2\x86\x91 Pi") PORT_CODE(KEYCODE_DEL) PORT_CHAR(0x2191) PORT_CHAR(0x03C0)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('@')
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('O')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('U')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('T')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('E')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('Q')
+
+ PORT_START( "ROW7" )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F7)) PORT_CHAR(UCHAR_MAMEKEY(F8))
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Home Clr") PORT_CODE(KEYCODE_INSERT) PORT_CHAR(UCHAR_MAMEKEY(HOME))
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('-')
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('(')
+ PORT_BIT( 0x04, 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_4) PORT_CHAR('4') PORT_CHAR('$')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"')
+INPUT_PORTS_END
+
+
+INPUT_PORTS_START( vic_special )
+ PORT_START( "SPECIAL" ) /* special keys */
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Restore") PORT_CODE(KEYCODE_PRTSCR)
+ PORT_CONFNAME( 0x01, 0x00, "Shift Lock (switch)") PORT_CODE(KEYCODE_CAPSLOCK) PORT_TOGGLE
+ PORT_CONFSETTING( 0x00, DEF_STR( Off ) )
+ PORT_CONFSETTING( 0x01, DEF_STR( On ) )
+INPUT_PORTS_END
+
+
+/* Paddle buttons are read in the same bits as some joystick inputs */
+static CUSTOM_INPUT( vic_custom_inputs )
+{
+ int bit_mask = (FPTR)param;
+ UINT8 port = 0;
+
+ if ((field.machine().root_device().ioport("CTRLSEL")->read() & 0xf0) == 0x10)
+ port |= (field.machine().root_device().ioport("FAKE0")->read() & bit_mask) ? 1 : 0;
+
+ if ((field.machine().root_device().ioport("CTRLSEL")->read() & 0xf0) == 0x00)
+ port |= (field.machine().root_device().ioport("FAKE1")->read() & bit_mask) ? 1 : 0;
+
+ return port;
+}
+
+INPUT_PORTS_START( vic_controls )
+ PORT_START( "CTRLSEL" )
+ PORT_CONFNAME( 0xf0, 0x00, DEF_STR( Controller ) )
+ PORT_CONFSETTING( 0x00, DEF_STR( Joystick ) )
+ PORT_CONFSETTING( 0x10, "Paddles" )
+ PORT_CONFSETTING( 0x20, "Lightpen" )
+
+ PORT_START( "JOY" )
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(vic_custom_inputs, (void *)0x02)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Lightpen Signal") PORT_CODE(KEYCODE_LALT) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x20)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(vic_custom_inputs, (void *)0x01)
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x00)
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x00)
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_8WAY PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x00)
+
+ PORT_START( "FAKE0" )
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("Paddle 2 Button") PORT_CODE(KEYCODE_DEL) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Paddle 1 Button") PORT_CODE(KEYCODE_INSERT) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
+
+ PORT_START( "FAKE1" )
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x00)
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x00)
+
+ PORT_START( "PADDLE0" )
+ PORT_BIT( 0xff,128,IPT_PADDLE) PORT_SENSITIVITY(30) PORT_KEYDELTA(20) PORT_MINMAX(0,255) PORT_CODE_DEC(KEYCODE_HOME) PORT_CODE_INC(KEYCODE_PGUP) PORT_REVERSE PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
+
+ PORT_START( "PADDLE1" )
+ PORT_BIT( 0xff,128,IPT_PADDLE) PORT_SENSITIVITY(30) PORT_KEYDELTA(20) PORT_MINMAX(0,255) PORT_CODE_DEC(KEYCODE_END) PORT_CODE_INC(KEYCODE_PGDN) PORT_PLAYER(2) PORT_REVERSE PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
+INPUT_PORTS_END
+
+SLOT_INTERFACE_START( cbm_iec_devices )
+ SLOT_INTERFACE("c1540", C1540)
+ SLOT_INTERFACE("c1541", C1541)
+ SLOT_INTERFACE("c1541c", C1541C)
+ SLOT_INTERFACE("c1541ii", C1541II)
+ SLOT_INTERFACE("fsd2", FSD2)
+ SLOT_INTERFACE("c1541dd", C1541_DOLPHIN_DOS)
+ SLOT_INTERFACE("c1541pd", C1541_PROFESSIONAL_DOS_V1)
+ SLOT_INTERFACE("c1570", C1570)
+ SLOT_INTERFACE("c1571", C1571)
+ SLOT_INTERFACE("c1581", C1581)
+ SLOT_INTERFACE("cmdhd", CMD_HD)
+ SLOT_INTERFACE("fd2000", FD2000)
+ SLOT_INTERFACE("interpod", INTERPOD)
+ SLOT_INTERFACE("minichief", MINI_CHIEF)
+ SLOT_INTERFACE("serialbox", SERIAL_BOX)
+SLOT_INTERFACE_END
+
+SLOT_INTERFACE_START( sx1541_iec_devices )
+ SLOT_INTERFACE("sx1541", SX1541)
+SLOT_INTERFACE_END
+
+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("c8250lp", C8250LP)
+ 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_END
+
+SLOT_INTERFACE_START( vic20_control_port_devices )
+ SLOT_INTERFACE("joy", VCS_JOYSTICK)
+SLOT_INTERFACE_END
+
+SLOT_INTERFACE_START( vic20_expansion_cards )
+ SLOT_INTERFACE("exp", VIC1010)
+ SLOT_INTERFACE("3k", VIC1210)
+ SLOT_INTERFACE("8k", VIC1110)
+ SLOT_INTERFACE("16k", VIC1111)
+
+ // 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
+
+SLOT_INTERFACE_START( vic20_user_port_cards )
+SLOT_INTERFACE_END
+
+SLOT_INTERFACE_START( vic10_expansion_cards )
+ // the following need ROMs from the software list
+ SLOT_INTERFACE_INTERNAL("standard", VIC10_STD)
+SLOT_INTERFACE_END
+
+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("neoram", C64_NEORAM)
+ SLOT_INTERFACE("sfxse", C64_SFX_SOUND_EXPANDER)
+
+ // the following need ROMs from the software list
+ SLOT_INTERFACE_INTERNAL("standard", C64_STD)
+ SLOT_INTERFACE_INTERNAL("comal80", C64_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("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("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("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("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
+
+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_END
+
+SLOT_INTERFACE_START( c128_expansion_cards )
+ // the following need ROMs from the software list
+ SLOT_INTERFACE_INTERNAL("c128_comal80", C128_COMAL80)
+SLOT_INTERFACE_END
+
+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
+
+SLOT_INTERFACE_START( plus4_user_port_cards )
+SLOT_INTERFACE_END
diff --git a/src/mess/machine/cbmipt.h b/src/mess/machine/cbmipt.h
new file mode 100644
index 00000000000..e0c14f3e9a7
--- /dev/null
+++ b/src/mess/machine/cbmipt.h
@@ -0,0 +1,165 @@
+#pragma once
+
+#ifndef CBMIPT_H_
+#define CBMIPT_H_
+
+#include "machine/c64_4cga.h"
+#include "machine/c64_4dxh.h"
+#include "machine/c64_4ksa.h"
+#include "machine/c64_4tba.h"
+#include "machine/c64_16kb.h"
+#include "machine/c64_bn1541.h"
+#include "machine/c64_comal80.h"
+#include "machine/c64_cpm.h"
+#include "machine/c64_currah_speech.h"
+#include "machine/c64_dela_ep256.h"
+#include "machine/c64_dela_ep64.h"
+#include "machine/c64_dela_ep7x8.h"
+#include "machine/c64_dinamic.h"
+#include "machine/c64_dqbb.h"
+#include "machine/c64_easy_calc_result.h"
+#include "machine/c64_easyflash.h"
+#include "machine/c64_epyx_fast_load.h"
+#include "machine/c64_exos.h"
+#include "machine/c64_final.h"
+#include "machine/c64_final3.h"
+#include "machine/c64_fun_play.h"
+#include "machine/c64_geocable.h"
+#include "machine/c64_georam.h"
+#include "machine/c64_ide64.h"
+#include "machine/c64_ieee488.h"
+#include "machine/c64_kingsoft.h"
+#include "machine/c64_mach5.h"
+#include "machine/c64_magic_desk.h"
+#include "machine/c64_magic_formel.h"
+#include "machine/c64_mikro_assembler.h"
+#include "machine/c64_multiscreen.h"
+#include "machine/c64_neoram.h"
+#include "machine/c64_ocean.h"
+#include "machine/c64_pagefox.h"
+#include "machine/c64_prophet64.h"
+#include "machine/c64_ps64.h"
+#include "machine/c64_rex.h"
+#include "machine/c64_rex_ep256.h"
+#include "machine/c64_ross.h"
+#include "machine/c64_sfx_sound_expander.h"
+#include "machine/c64_silverrock.h"
+#include "machine/c64_simons_basic.h"
+#include "machine/c64_stardos.h"
+#include "machine/c64_std.h"
+#include "machine/c64_structured_basic.h"
+#include "machine/c64_super_explode.h"
+#include "machine/c64_super_games.h"
+#include "machine/c64_sw8k.h"
+#include "machine/c64_system3.h"
+#include "machine/c64_tdos.h"
+#include "machine/c64_vw64.h"
+#include "machine/c64_warp_speed.h"
+#include "machine/c64_westermann.h"
+#include "machine/c64_xl80.h"
+#include "machine/c64_zaxxon.h"
+#include "machine/c128_comal80.h"
+#include "machine/c1541.h"
+#include "machine/c1551.h"
+#include "machine/c1571.h"
+#include "machine/c1581.h"
+#include "machine/c2031.h"
+#include "machine/c2040.h"
+#include "machine/c8280.h"
+#include "machine/d9060.h"
+#include "machine/cmdhd.h"
+#include "machine/fd2000.h"
+#include "machine/interpod.h"
+#include "machine/plus4_sid.h"
+#include "machine/plus4_std.h"
+#include "machine/serialbox.h"
+#include "machine/softbox.h"
+#include "machine/vic1010.h"
+#include "machine/vic1110.h"
+#include "machine/vic1111.h"
+#include "machine/vic1112.h"
+#include "machine/vic1210.h"
+#include "machine/vic10std.h"
+#include "machine/vic20std.h"
+#include "machine/vic20_megacart.h"
+#include "machine/vcs_joy.h"
+
+
+#define MCFG_CBM_IEC_ADD(_intf, _default_drive) \
+ MCFG_CBM_IEC_BUS_ADD(_intf) \
+ MCFG_CBM_IEC_SLOT_ADD("iec4", 4, cbm_iec_devices, NULL, NULL) \
+ MCFG_CBM_IEC_SLOT_ADD("iec8", 8, cbm_iec_devices, _default_drive, NULL) \
+ MCFG_CBM_IEC_SLOT_ADD("iec9", 9, cbm_iec_devices, NULL, NULL) \
+ MCFG_CBM_IEC_SLOT_ADD("iec10", 10, cbm_iec_devices, NULL, NULL) \
+ MCFG_CBM_IEC_SLOT_ADD("iec11", 11, cbm_iec_devices, NULL, NULL)
+
+
+#define MCFG_CBM_IEEE488_ADD(_intf, _default_drive) \
+ MCFG_IEEE488_BUS_ADD(_intf) \
+ MCFG_IEEE488_SLOT_ADD("ieee8", 8, cbm_ieee488_devices, _default_drive, NULL) \
+ MCFG_IEEE488_SLOT_ADD("ieee9", 9, cbm_ieee488_devices, NULL, NULL) \
+ MCFG_IEEE488_SLOT_ADD("ieee10", 10, cbm_ieee488_devices, NULL, NULL) \
+ MCFG_IEEE488_SLOT_ADD("ieee11", 11, cbm_ieee488_devices, NULL, NULL)
+
+
+/* Commodore 64 */
+
+INPUT_PORTS_EXTERN( common_cbm_keyboard ); /* shared with c16, c65, c128 */
+INPUT_PORTS_EXTERN( c64_special );
+INPUT_PORTS_EXTERN( c64_controls ); /* shared with c65, c128, cbmb */
+
+
+/* Commodore 16 */
+
+INPUT_PORTS_EXTERN( c16_special );
+INPUT_PORTS_EXTERN( c16_controls );
+
+
+/* Commodore 65 */
+
+INPUT_PORTS_EXTERN( c65_special );
+
+
+/* Commodore 128 */
+
+INPUT_PORTS_EXTERN( c128_special );
+
+
+/* PET2001 */
+
+INPUT_PORTS_EXTERN( pet_keyboard );
+INPUT_PORTS_EXTERN( pet_business_keyboard );
+INPUT_PORTS_EXTERN( pet_special );
+INPUT_PORTS_EXTERN( pet_config );
+
+
+/* CBMB 500 / 600/ 700 */
+
+INPUT_PORTS_EXTERN( cbmb_keyboard );
+INPUT_PORTS_EXTERN( cbmb_special );
+
+
+/* Vic 20 */
+
+INPUT_PORTS_EXTERN( vic_keyboard );
+INPUT_PORTS_EXTERN( vic_special );
+INPUT_PORTS_EXTERN( vic_controls );
+
+
+
+SLOT_INTERFACE_EXTERN( cbm_iec_devices );
+SLOT_INTERFACE_EXTERN( sx1541_iec_devices );
+SLOT_INTERFACE_EXTERN( cbm_ieee488_devices );
+SLOT_INTERFACE_EXTERN( vic20_control_port_devices );
+SLOT_INTERFACE_EXTERN( vic20_expansion_cards );
+SLOT_INTERFACE_EXTERN( vic20_user_port_cards );
+SLOT_INTERFACE_EXTERN( vic10_expansion_cards );
+SLOT_INTERFACE_EXTERN( c64_expansion_cards );
+SLOT_INTERFACE_EXTERN( c64_user_port_cards );
+SLOT_INTERFACE_EXTERN( c128_expansion_cards );
+SLOT_INTERFACE_EXTERN( plus4_expansion_cards );
+SLOT_INTERFACE_EXTERN( plus4_user_port_cards );
+
+
+
+#endif /* CBMIPT_H_ */
diff --git a/src/mess/machine/cgenie.c b/src/mess/machine/cgenie.c
new file mode 100644
index 00000000000..14f7bcd1872
--- /dev/null
+++ b/src/mess/machine/cgenie.c
@@ -0,0 +1,620 @@
+/***************************************************************************
+
+ machine.c
+
+ Functions to emulate general aspects of the machine
+ (RAM, ROM, interrupts, I/O ports)
+
+***************************************************************************/
+
+#include "emu.h"
+#include "cpu/z80/z80.h"
+#include "includes/cgenie.h"
+#include "machine/wd17xx.h"
+#include "imagedev/cartslot.h"
+#include "imagedev/cassette.h"
+#include "sound/ay8910.h"
+#include "sound/dac.h"
+#include "imagedev/flopdrv.h"
+#include "machine/ram.h"
+
+#define AYWriteReg(chip,port,value) \
+ ay8910_address_w(ay8910, 0,port); \
+ ay8910_data_w(ay8910, 0,value)
+
+#define TAPE_HEADER "Colour Genie - Virtual Tape File"
+
+
+
+
+#define IRQ_TIMER 0x80
+#define IRQ_FDC 0x40
+
+
+
+static TIMER_CALLBACK( handle_cassette_input )
+{
+ cgenie_state *state = machine.driver_data<cgenie_state>();
+ UINT8 new_level = ( (machine.device<cassette_image_device>(CASSETTE_TAG)->input()) > 0.0 ) ? 1 : 0;
+
+ if ( new_level != state->m_cass_level )
+ {
+ state->m_cass_level = new_level;
+ state->m_cass_bit ^= 1;
+ }
+}
+
+
+MACHINE_RESET( cgenie )
+{
+ cgenie_state *state = machine.driver_data<cgenie_state>();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ device_t *ay8910 = machine.device("ay8910");
+ UINT8 *ROM = state->memregion("maincpu")->base();
+
+ /* reset the AY8910 to be quiet, since the cgenie BIOS doesn't */
+ AYWriteReg(0, 0, 0);
+ AYWriteReg(0, 1, 0);
+ AYWriteReg(0, 2, 0);
+ AYWriteReg(0, 3, 0);
+ AYWriteReg(0, 4, 0);
+ AYWriteReg(0, 5, 0);
+ AYWriteReg(0, 6, 0);
+ AYWriteReg(0, 7, 0x3f);
+ AYWriteReg(0, 8, 0);
+ AYWriteReg(0, 9, 0);
+ AYWriteReg(0, 10, 0);
+
+ /* wipe out color RAM */
+ memset(&ROM[0x0f000], 0x00, 0x0400);
+
+ /* wipe out font RAM */
+ memset(&ROM[0x0f400], 0xff, 0x0400);
+
+ if( machine.root_device().ioport("DSW0")->read() & 0x80 )
+ {
+ logerror("cgenie floppy discs enabled\n");
+ }
+ else
+ {
+ logerror("cgenie floppy discs disabled\n");
+ }
+
+ /* copy DOS ROM, if enabled or wipe out that memory area */
+ if( machine.root_device().ioport("DSW0")->read() & 0x40 )
+ {
+ if ( machine.root_device().ioport("DSW0")->read() & 0x80 )
+ {
+ space->install_read_bank(0xc000, 0xdfff, "bank10");
+ space->nop_write(0xc000, 0xdfff);
+ state->membank("bank10")->set_base(&ROM[0x0c000]);
+ logerror("cgenie DOS enabled\n");
+ memcpy(&ROM[0x0c000],&ROM[0x10000], 0x2000);
+ }
+ else
+ {
+ space->nop_readwrite(0xc000, 0xdfff);
+ logerror("cgenie DOS disabled (no floppy image given)\n");
+ }
+ }
+ else
+ {
+ space->nop_readwrite(0xc000, 0xdfff);
+ logerror("cgenie DOS disabled\n");
+ memset(&machine.root_device().memregion("maincpu")->base()[0x0c000], 0x00, 0x2000);
+ }
+
+ /* copy EXT ROM, if enabled or wipe out that memory area */
+ if( machine.root_device().ioport("DSW0")->read() & 0x20 )
+ {
+ space->install_rom(0xe000, 0xefff, 0); // mess 0135u3 need to check
+ logerror("cgenie EXT enabled\n");
+ memcpy(&machine.root_device().memregion("maincpu")->base()[0x0e000],
+ &machine.root_device().memregion("maincpu")->base()[0x12000], 0x1000);
+ }
+ else
+ {
+ space->nop_readwrite(0xe000, 0xefff);
+ logerror("cgenie EXT disabled\n");
+ memset(&machine.root_device().memregion("maincpu")->base()[0x0e000], 0x00, 0x1000);
+ }
+
+ state->m_cass_level = 0;
+ state->m_cass_bit = 1;
+}
+
+MACHINE_START( cgenie )
+{
+ cgenie_state *state = machine.driver_data<cgenie_state>();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ UINT8 *gfx = state->memregion("gfx2")->base();
+ int i;
+
+ /* initialize static variables */
+ state->m_irq_status = 0;
+ state->m_motor_drive = 0;
+ state->m_head = 0;
+ state->m_tv_mode = -1;
+ state->m_port_ff = 0xff;
+
+ /*
+ * Every fifth cycle is a wait cycle, so I reduced
+ * the overlocking by one fitfth
+ * Underclocking causes the tape loading to not work.
+ */
+// cpunum_set_clockscale(machine, 0, 0.80);
+
+ /* Initialize some patterns to be displayed in graphics mode */
+ for( i = 0; i < 256; i++ )
+ memset(gfx + i * 8, i, 8);
+
+ /* set up RAM */
+ space->install_read_bank(0x4000, 0x4000 + machine.device<ram_device>(RAM_TAG)->size() - 1, "bank1");
+ space->install_legacy_write_handler(0x4000, 0x4000 + machine.device<ram_device>(RAM_TAG)->size() - 1, FUNC(cgenie_videoram_w));
+ state->m_videoram = machine.device<ram_device>(RAM_TAG)->pointer();
+ state->membank("bank1")->set_base(machine.device<ram_device>(RAM_TAG)->pointer());
+ machine.scheduler().timer_pulse(attotime::from_hz(11025), FUNC(handle_cassette_input));
+}
+
+/*************************************
+ *
+ * Port handlers.
+ *
+ *************************************/
+
+/* used bits on port FF */
+#define FF_CAS 0x01 /* tape output signal */
+#define FF_BGD0 0x04 /* background color enable */
+#define FF_CHR1 0x08 /* charset 0xc0 - 0xff 1:fixed 0:defined */
+#define FF_CHR0 0x10 /* charset 0x80 - 0xbf 1:fixed 0:defined */
+#define FF_CHR (FF_CHR0 | FF_CHR1)
+#define FF_FGR 0x20 /* 1: "hi" resolution graphics, 0: text mode */
+#define FF_BGD1 0x40 /* background color select 1 */
+#define FF_BGD2 0x80 /* background color select 2 */
+#define FF_BGD (FF_BGD0 | FF_BGD1 | FF_BGD2)
+
+WRITE8_HANDLER( cgenie_port_ff_w )
+{
+ cgenie_state *state = space->machine().driver_data<cgenie_state>();
+ int port_ff_changed = state->m_port_ff ^ data;
+
+ space->machine().device<cassette_image_device>(CASSETTE_TAG)->output(data & 0x01 ? -1.0 : 1.0 );
+
+ /* background bits changed ? */
+ if( port_ff_changed & FF_BGD )
+ {
+ unsigned char r, g, b;
+
+ if( data & FF_BGD0 )
+ {
+ r = 112;
+ g = 0;
+ b = 112;
+ }
+ else
+ {
+ if( state->m_tv_mode == 0 )
+ {
+ switch( data & (FF_BGD1 + FF_BGD2) )
+ {
+ case FF_BGD1:
+ r = 112;
+ g = 40;
+ b = 32;
+ break;
+ case FF_BGD2:
+ r = 40;
+ g = 112;
+ b = 32;
+ break;
+ case FF_BGD1 + FF_BGD2:
+ r = 72;
+ g = 72;
+ b = 72;
+ break;
+ default:
+ r = 0;
+ g = 0;
+ b = 0;
+ break;
+ }
+ }
+ else
+ {
+ r = 15;
+ g = 15;
+ b = 15;
+ }
+ }
+ palette_set_color_rgb(space->machine(), 0, r, g, b);
+ }
+
+ /* character mode changed ? */
+ if( port_ff_changed & FF_CHR )
+ {
+ state->m_font_offset[2] = (data & FF_CHR0) ? 0x00 : 0x80;
+ state->m_font_offset[3] = (data & FF_CHR1) ? 0x00 : 0x80;
+ }
+
+ /* graphics mode changed ? */
+ if( port_ff_changed & FF_FGR )
+ {
+ cgenie_mode_select(space->machine(), data & FF_FGR);
+ }
+
+ state->m_port_ff = data;
+}
+
+
+READ8_HANDLER( cgenie_port_ff_r )
+{
+ cgenie_state *state = space->machine().driver_data<cgenie_state>();
+ UINT8 data = state->m_port_ff & ~0x01;
+
+ data |= state->m_cass_bit;
+
+ return data;
+}
+
+int cgenie_port_xx_r( int offset )
+{
+ return 0xff;
+}
+
+/*************************************
+ * *
+ * Memory handlers *
+ * *
+ *************************************/
+
+
+READ8_HANDLER( cgenie_psg_port_a_r )
+{
+ cgenie_state *state = space->machine().driver_data<cgenie_state>();
+ return state->m_psg_a_inp;
+}
+
+READ8_HANDLER( cgenie_psg_port_b_r )
+{
+ cgenie_state *state = space->machine().driver_data<cgenie_state>();
+ if( state->m_psg_a_out < 0xd0 )
+ {
+ /* comparator value */
+ state->m_psg_b_inp = 0x00;
+
+ if( space->machine().root_device().ioport("JOY0")->read() > state->m_psg_a_out )
+ state->m_psg_b_inp |= 0x80;
+
+ if( space->machine().root_device().ioport("JOY1")->read() > state->m_psg_a_out )
+ state->m_psg_b_inp |= 0x40;
+
+ if( space->machine().root_device().ioport("JOY2")->read() > state->m_psg_a_out )
+ state->m_psg_b_inp |= 0x20;
+
+ if( state->ioport("JOY3")->read() > state->m_psg_a_out )
+ state->m_psg_b_inp |= 0x10;
+ }
+ else
+ {
+ /* read keypad matrix */
+ state->m_psg_b_inp = 0xFF;
+
+ if( !(state->m_psg_a_out & 0x01) )
+ state->m_psg_b_inp &= ~space->machine().root_device().ioport("KP0")->read();
+
+ if( !(state->m_psg_a_out & 0x02) )
+ state->m_psg_b_inp &= ~space->machine().root_device().ioport("KP1")->read();
+
+ if( !(state->m_psg_a_out & 0x04) )
+ state->m_psg_b_inp &= ~space->machine().root_device().ioport("KP2")->read();
+
+ if( !(state->m_psg_a_out & 0x08) )
+ state->m_psg_b_inp &= ~space->machine().root_device().ioport("KP3")->read();
+
+ if( !(state->m_psg_a_out & 0x10) )
+ state->m_psg_b_inp &= ~space->machine().root_device().ioport("KP4")->read();
+
+ if( !(state->m_psg_a_out & 0x20) )
+ state->m_psg_b_inp &= ~space->machine().root_device().ioport("KP5")->read();
+ }
+ return state->m_psg_b_inp;
+}
+
+WRITE8_HANDLER( cgenie_psg_port_a_w )
+{
+ cgenie_state *state = space->machine().driver_data<cgenie_state>();
+ state->m_psg_a_out = data;
+}
+
+WRITE8_HANDLER( cgenie_psg_port_b_w )
+{
+ cgenie_state *state = space->machine().driver_data<cgenie_state>();
+ state->m_psg_b_out = data;
+}
+
+ READ8_HANDLER( cgenie_status_r )
+{
+ device_t *fdc = space->machine().device("wd179x");
+ /* If the floppy isn't emulated, return 0 */
+ if( (space->machine().root_device().ioport("DSW0")->read() & 0x80) == 0 )
+ return 0;
+ return wd17xx_status_r(fdc, offset);
+}
+
+ READ8_HANDLER( cgenie_track_r )
+{
+ device_t *fdc = space->machine().device("wd179x");
+ /* If the floppy isn't emulated, return 0xff */
+ if( (space->machine().root_device().ioport("DSW0")->read() & 0x80) == 0 )
+ return 0xff;
+ return wd17xx_track_r(fdc, offset);
+}
+
+ READ8_HANDLER( cgenie_sector_r )
+{
+ device_t *fdc = space->machine().device("wd179x");
+ /* If the floppy isn't emulated, return 0xff */
+ if( (space->machine().root_device().ioport("DSW0")->read() & 0x80) == 0 )
+ return 0xff;
+ return wd17xx_sector_r(fdc, offset);
+}
+
+ READ8_HANDLER(cgenie_data_r )
+{
+ device_t *fdc = space->machine().device("wd179x");
+ /* If the floppy isn't emulated, return 0xff */
+ if( (space->machine().root_device().ioport("DSW0")->read() & 0x80) == 0 )
+ return 0xff;
+ return wd17xx_data_r(fdc, offset);
+}
+
+WRITE8_HANDLER( cgenie_command_w )
+{
+ device_t *fdc = space->machine().device("wd179x");
+ /* If the floppy isn't emulated, return immediately */
+ if( (space->machine().root_device().ioport("DSW0")->read() & 0x80) == 0 )
+ return;
+ wd17xx_command_w(fdc, offset, data);
+}
+
+WRITE8_HANDLER( cgenie_track_w )
+{
+ device_t *fdc = space->machine().device("wd179x");
+ /* If the floppy isn't emulated, ignore the write */
+ if( (space->machine().root_device().ioport("DSW0")->read() & 0x80) == 0 )
+ return;
+ wd17xx_track_w(fdc, offset, data);
+}
+
+WRITE8_HANDLER( cgenie_sector_w )
+{
+ device_t *fdc = space->machine().device("wd179x");
+ /* If the floppy isn't emulated, ignore the write */
+ if( (space->machine().root_device().ioport("DSW0")->read() & 0x80) == 0 )
+ return;
+ wd17xx_sector_w(fdc, offset, data);
+}
+
+WRITE8_HANDLER( cgenie_data_w )
+{
+ device_t *fdc = space->machine().device("wd179x");
+ /* If the floppy isn't emulated, ignore the write */
+ if( (space->machine().root_device().ioport("DSW0")->read() & 0x80) == 0 )
+ return;
+ wd17xx_data_w(fdc, offset, data);
+}
+
+ READ8_HANDLER( cgenie_irq_status_r )
+{
+ cgenie_state *state = space->machine().driver_data<cgenie_state>();
+int result = state->m_irq_status;
+
+ state->m_irq_status &= ~(IRQ_TIMER | IRQ_FDC);
+ return result;
+}
+
+INTERRUPT_GEN( cgenie_timer_interrupt )
+{
+ cgenie_state *state = device->machine().driver_data<cgenie_state>();
+ if( (state->m_irq_status & IRQ_TIMER) == 0 )
+ {
+ state->m_irq_status |= IRQ_TIMER;
+ cputag_set_input_line(device->machine(), "maincpu", 0, HOLD_LINE);
+ }
+}
+
+static WRITE_LINE_DEVICE_HANDLER( cgenie_fdc_intrq_w )
+{
+ cgenie_state *drvstate = device->machine().driver_data<cgenie_state>();
+ /* if disc hardware is not enabled, do not cause an int */
+ if (!( drvstate->ioport("DSW0")->read() & 0x80 ))
+ return;
+
+ if (state)
+ {
+ if( (drvstate->m_irq_status & IRQ_FDC) == 0 )
+ {
+ drvstate->m_irq_status |= IRQ_FDC;
+ cputag_set_input_line(device->machine(), "maincpu", 0, HOLD_LINE);
+ }
+ }
+ else
+ {
+ drvstate->m_irq_status &= ~IRQ_FDC;
+ }
+}
+
+const wd17xx_interface cgenie_wd17xx_interface =
+{
+ DEVCB_NULL,
+ DEVCB_LINE(cgenie_fdc_intrq_w),
+ DEVCB_NULL,
+ {FLOPPY_0, FLOPPY_1, FLOPPY_2, FLOPPY_3}
+};
+
+WRITE8_HANDLER( cgenie_motor_w )
+{
+ cgenie_state *state = space->machine().driver_data<cgenie_state>();
+ device_t *fdc = space->machine().device("wd179x");
+ UINT8 drive = 255;
+
+ logerror("cgenie motor_w $%02X\n", data);
+
+ if( data & 1 )
+ drive = 0;
+ if( data & 2 )
+ drive = 1;
+ if( data & 4 )
+ drive = 2;
+ if( data & 8 )
+ drive = 3;
+
+ if( drive > 3 )
+ return;
+
+ /* mask head select bit */
+ state->m_head = (data >> 4) & 1;
+
+ /* currently selected drive */
+ state->m_motor_drive = drive;
+
+ wd17xx_set_drive(fdc,drive);
+ wd17xx_set_side(fdc,state->m_head);
+}
+
+/*************************************
+ * Keyboard *
+ *************************************/
+ READ8_HANDLER( cgenie_keyboard_r )
+{
+ int result = 0;
+
+ if( offset & 0x01 )
+ result |= space->machine().root_device().ioport("ROW0")->read();
+
+ if( offset & 0x02 )
+ result |= space->machine().root_device().ioport("ROW1")->read();
+
+ if( offset & 0x04 )
+ result |= space->machine().root_device().ioport("ROW2")->read();
+
+ if( offset & 0x08 )
+ result |= space->machine().root_device().ioport("ROW3")->read();
+
+ if( offset & 0x10 )
+ result |= space->machine().root_device().ioport("ROW4")->read();
+
+ if( offset & 0x20 )
+ result |= space->machine().root_device().ioport("ROW5")->read();
+
+ if( offset & 0x40 )
+ result |= space->machine().root_device().ioport("ROW6")->read();
+
+ if( offset & 0x80 )
+ result |= space->machine().root_device().ioport("ROW7")->read();
+
+ return result;
+}
+
+/*************************************
+ * Video RAM *
+ *************************************/
+
+int cgenie_videoram_r( running_machine &machine, int offset )
+{
+ cgenie_state *state = machine.driver_data<cgenie_state>();
+ UINT8 *videoram = state->m_videoram;
+ return videoram[offset];
+}
+
+WRITE8_HANDLER( cgenie_videoram_w )
+{
+ cgenie_state *state = space->machine().driver_data<cgenie_state>();
+ UINT8 *videoram = state->m_videoram;
+ /* write to video RAM */
+ if( data == videoram[offset] )
+ return; /* no change */
+ videoram[offset] = data;
+}
+
+ READ8_HANDLER( cgenie_colorram_r )
+{
+ cgenie_state *state = space->machine().driver_data<cgenie_state>();
+ return state->m_colorram[offset] | 0xf0;
+}
+
+WRITE8_HANDLER( cgenie_colorram_w )
+{
+ cgenie_state *state = space->machine().driver_data<cgenie_state>();
+ /* only bits 0 to 3 */
+ data &= 15;
+ /* nothing changed ? */
+ if( data == state->m_colorram[offset] )
+ return;
+
+ /* set new value */
+ state->m_colorram[offset] = data;
+ /* make offset relative to video frame buffer offset */
+ offset = (offset + (cgenie_get_register(space->machine(), 12) << 8) + cgenie_get_register(space->machine(), 13)) & 0x3ff;
+}
+
+ READ8_HANDLER( cgenie_fontram_r )
+{
+ cgenie_state *state = space->machine().driver_data<cgenie_state>();
+ return state->m_fontram[offset];
+}
+
+WRITE8_HANDLER( cgenie_fontram_w )
+{
+ cgenie_state *state = space->machine().driver_data<cgenie_state>();
+ UINT8 *dp;
+
+ if( data == state->m_fontram[offset] )
+ return; /* no change */
+
+ /* store data */
+ state->m_fontram[offset] = data;
+
+ /* convert eight pixels */
+ dp = &space->machine().gfx[0]->gfxdata[(256 * 8 + offset) * space->machine().gfx[0]->width];
+ dp[0] = (data & 0x80) ? 1 : 0;
+ dp[1] = (data & 0x40) ? 1 : 0;
+ dp[2] = (data & 0x20) ? 1 : 0;
+ dp[3] = (data & 0x10) ? 1 : 0;
+ dp[4] = (data & 0x08) ? 1 : 0;
+ dp[5] = (data & 0x04) ? 1 : 0;
+ dp[6] = (data & 0x02) ? 1 : 0;
+ dp[7] = (data & 0x01) ? 1 : 0;
+}
+
+/*************************************
+ *
+ * Interrupt handlers.
+ *
+ *************************************/
+
+INTERRUPT_GEN( cgenie_frame_interrupt )
+{
+ cgenie_state *state = device->machine().driver_data<cgenie_state>();
+ if( state->m_tv_mode != (device->machine().root_device().ioport("DSW0")->read() & 0x10) )
+ {
+ state->m_tv_mode = state->ioport("DSW0")->read() & 0x10;
+ /* force setting of background color */
+ state->m_port_ff ^= FF_BGD0;
+ cgenie_port_ff_w(device->machine().device("maincpu")->memory().space(AS_PROGRAM), 0, state->m_port_ff ^ FF_BGD0);
+ }
+}
+
+
+READ8_DEVICE_HANDLER( cgenie_sh_control_port_r )
+{
+ cgenie_state *state = device->machine().driver_data<cgenie_state>();
+ return state->m_control_port;
+}
+
+WRITE8_DEVICE_HANDLER( cgenie_sh_control_port_w )
+{
+ cgenie_state *state = device->machine().driver_data<cgenie_state>();
+ state->m_control_port = data;
+ ay8910_address_w(device, offset, data);
+}
diff --git a/src/mess/machine/cmdhd.c b/src/mess/machine/cmdhd.c
new file mode 100644
index 00000000000..e7b6c1bd9b9
--- /dev/null
+++ b/src/mess/machine/cmdhd.c
@@ -0,0 +1,226 @@
+/**********************************************************************
+
+ CMD HD hard drive emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#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"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type CMD_HD = &device_creator<cmd_hd_device>;
+
+
+//-------------------------------------------------
+// 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_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() AM_DEVREADWRITE(M6522_1_TAG, via6522_device, read, write)
+ //AM_RANGE() AM_DEVREADWRITE(M6522_2_TAG, via6522_device, read, write)
+ADDRESS_MAP_END
+
+
+//-------------------------------------------------
+// via6522_interface via1_intf
+//-------------------------------------------------
+
+static const via6522_interface via1_intf =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// via6522_interface via2_intf
+//-------------------------------------------------
+
+static const via6522_interface via2_intf =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// I8255A_INTERFACE( ppi_intf )
+//-------------------------------------------------
+
+static I8255A_INTERFACE( ppi_intf )
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// 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_VIA6522_ADD(M6522_1_TAG, 2000000, via1_intf)
+ MCFG_VIA6522_ADD(M6522_2_TAG, 2000000, via2_intf)
+ MCFG_I8255A_ADD(I8255A_TAG, ppi_intf)
+
+ MCFG_HARDDISK_ADD("harddisk0")
+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),
+ device_cbm_iec_interface(mconfig, *this),
+ m_maincpu(*this, M6502_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();
+ }
+}
diff --git a/src/mess/machine/cmdhd.h b/src/mess/machine/cmdhd.h
new file mode 100644
index 00000000000..b535b40b54c
--- /dev/null
+++ b/src/mess/machine/cmdhd.h
@@ -0,0 +1,73 @@
+/**********************************************************************
+
+ CMD HD disk drive emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __CMD_HD__
+#define __CMD_HD__
+
+#define ADDRESS_MAP_MODERN
+
+#include "emu.h"
+#include "cpu/m6502/m6502.h"
+#include "imagedev/harddriv.h"
+#include "machine/6522via.h"
+#include "machine/cbmiec.h"
+#include "machine/i8255.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;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "cmdhd"; }
+
+ // 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<cpu_device> m_maincpu;
+};
+
+
+// device type definition
+extern const device_type CMD_HD;
+
+
+
+#endif
diff --git a/src/mess/machine/cntr_covox.c b/src/mess/machine/cntr_covox.c
new file mode 100644
index 00000000000..5dd4619f8aa
--- /dev/null
+++ b/src/mess/machine/cntr_covox.c
@@ -0,0 +1,112 @@
+/***************************************************************************
+
+ Covox Speech Thing
+
+***************************************************************************/
+
+#include "emu.h"
+#include "sound/dac.h"
+#include "cntr_covox.h"
+
+//**************************************************************************
+// COVOX DEVICE
+//**************************************************************************
+
+// device type definition
+const device_type CENTRONICS_COVOX = &device_creator<centronics_covox_device>;
+
+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),
+ device_centronics_peripheral_interface( mconfig, *this )
+{
+}
+//-------------------------------------------------
+// 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()
+{
+ m_dac = subdevice<dac_device>("dac");
+}
+
+void centronics_covox_device::write(UINT8 data)
+{
+ m_dac->write_unsigned8(data);
+}
+
+//**************************************************************************
+// COVOX STEREO DEVICE
+//**************************************************************************
+
+// device type definition
+const device_type CENTRONICS_COVOX_STEREO = &device_creator<centronics_covox_stereo_device>;
+
+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),
+ device_centronics_peripheral_interface( mconfig, *this )
+{
+}
+//-------------------------------------------------
+// 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()
+{
+ m_dac_left = subdevice<dac_device>("dac_left");
+ m_dac_right = subdevice<dac_device>("dac_right");
+}
+
+void centronics_covox_stereo_device::write(UINT8 data)
+{
+ if (m_strobe) m_dac_left->write_unsigned8(data);
+ if (m_auto_fd) m_dac_right->write_unsigned8(data);
+}
diff --git a/src/mess/machine/cntr_covox.h b/src/mess/machine/cntr_covox.h
new file mode 100644
index 00000000000..d56b157249b
--- /dev/null
+++ b/src/mess/machine/cntr_covox.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+
+ Covox Speech Thing
+
+***************************************************************************/
+
+#ifndef __CENTRONICS_COVOX_H__
+#define __CENTRONICS_COVOX_H__
+
+#include "machine/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;
+
+ virtual void write(UINT8 data);
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_config_complete() { m_shortname = "covox"; }
+private:
+ dac_device *m_dac;
+};
+// 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;
+
+ virtual void write(UINT8 data);
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_config_complete() { m_shortname = "covox_stereo"; }
+private:
+ dac_device *m_dac_left;
+ dac_device *m_dac_right;
+};
+// device type definition
+extern const device_type CENTRONICS_COVOX_STEREO;
+
+#endif /* __CENTRONICS_COVOX_H__ */
diff --git a/src/mess/machine/coco.c b/src/mess/machine/coco.c
new file mode 100644
index 00000000000..49482134e14
--- /dev/null
+++ b/src/mess/machine/coco.c
@@ -0,0 +1,1438 @@
+/***************************************************************************
+
+ coco.c
+
+ TRS-80 Radio Shack Color Computer Family
+
+ Functions to emulate general aspects of the machine (RAM, ROM, interrupts,
+ I/O ports)
+
+ References:
+ There are two main references for the info for this driver
+ - Tandy Color Computer Unravelled Series
+ (http://www.giftmarket.org/unravelled/unravelled.shtml)
+ - Assembly Language Programming For the CoCo 3 by Laurence A. Tepolt
+ - Kevin K. Darlings GIME reference
+ (http://www.cris.com/~Alxevans/gime.txt)
+ - Sock Masters's GIME register reference
+ (http://www.axess.com/twilight/sock/gime.html)
+ - Robert Gault's FAQ
+ (http://home.att.net/~robert.gault/Coco/FAQ/FAQ_main.htm)
+ - Discussions with L. Curtis Boyle (LCB) and John Kowalski (JK)
+
+ TODO:
+ - Implement unimplemented SAM registers
+ - Choose and implement more appropriate ratios for the speed up poke
+ - Handle resets correctly
+
+ In the CoCo, all timings should be exactly relative to each other. This
+ table shows how all clocks are relative to each other (info: JK):
+ - Main CPU Clock 0.89 MHz
+ - Horizontal Sync Interrupt 15.7 kHz/63.5us (57 clock cycles)
+ - Vertical Sync Interrupt 60 Hz (14934 clock cycles)
+ - Composite Video Color Carrier 3.58 MHz/279ns (1/4 clock cycles)
+
+ It is also noting that the CoCo 3 had two sets of VSync interrupts. To quote
+ John Kowalski:
+
+ One other thing to mention is that the old vertical interrupt and the new
+ vertical interrupt are not the same.. The old one is triggered by the
+ video's vertical sync pulse, but the new one is triggered on the next scan
+ line *after* the last scan line of the active video display. That is : new
+ vertical interrupt triggers somewheres around scan line 230 of the 262 line
+ screen (if a 200 line graphics mode is used, a bit earlier if a 192 line
+ mode is used and a bit later if a 225 line mode is used). The old vsync
+ interrupt triggers on scanline zero.
+
+ 230 is just an estimate [(262-200)/2+200]. I don't think the active part
+ of the screen is exactly centered within the 262 line total. I can
+ research that for you if you want an exact number for scanlines before the
+ screen starts and the scanline that the v-interrupt triggers..etc.
+
+Added bi-directional bitbanger support. Also fixed reading PIA 1, port A. The
+DAC and bitbanger values written should be reflected in the read.
+ tim lindner, October 2010
+
+***************************************************************************/
+
+#include "includes/coco.h"
+#include "cpu/m6809/m6809.h"
+#include "formats/coco_cas.h"
+#include "debug/debugcpu.h"
+
+
+
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
+
+#define LOG_INTERRUPTS 0
+
+
+
+//**************************************************************************
+// BODY
+//**************************************************************************
+
+//-------------------------------------------------
+// ctor
+//-------------------------------------------------
+
+coco_state::coco_state(const machine_config &mconfig, device_type type, const char *tag)
+ : driver_device(mconfig, type, tag),
+ m_maincpu(*this, MAINCPU_TAG),
+ m_pia_0(*this, PIA0_TAG),
+ m_pia_1(*this, PIA1_TAG),
+ m_dac(*this, DAC_TAG),
+ m_wave(*this, WAVE_TAG),
+ m_cococart(*this, CARTRIDGE_TAG),
+ m_ram(*this, RAM_TAG),
+ m_cassette(*this, CASSETTE_TAG),
+ m_bitbanger(*this, BITBANGER_TAG),
+ m_vhd_0(*this, VHD0_TAG),
+ m_vhd_1(*this, VHD1_TAG)
+{
+}
+
+
+
+//-------------------------------------------------
+// analog_port_start
+//-------------------------------------------------
+
+void coco_state::analog_port_start(analog_input_t *analog, const char *rx_tag, const char *ry_tag, const char *lx_tag, const char *ly_tag, const char *buttons_tag)
+{
+ analog->m_input[0][0] = machine().root_device().ioport(rx_tag);
+ analog->m_input[0][1] = machine().root_device().ioport(ry_tag);
+ analog->m_input[1][0] = machine().root_device().ioport(lx_tag);
+ analog->m_input[1][1] = machine().root_device().ioport(ly_tag);
+ analog->m_buttons = machine().root_device().ioport(buttons_tag);
+}
+
+
+
+//-------------------------------------------------
+// device_start
+//-------------------------------------------------
+
+void coco_state::device_start()
+{
+ /* call base device_start */
+ driver_device::device_start();
+
+ /* look up keyboard ports */
+ for (int i = 0; i < sizeof(m_keyboard) / sizeof(m_keyboard[0]); i++)
+ {
+ char name[32];
+ snprintf(name, sizeof(name) / sizeof(name[0]), "row%d", i);
+ m_keyboard[i] = machine().root_device().ioport(name);
+ }
+
+ /* look up analog ports */
+ analog_port_start(&m_joystick, JOYSTICK_RX_TAG, JOYSTICK_RY_TAG,
+ JOYSTICK_LX_TAG, JOYSTICK_LY_TAG, JOYSTICK_BUTTONS_TAG);
+ analog_port_start(&m_rat_mouse, RAT_MOUSE_RX_TAG, RAT_MOUSE_RY_TAG,
+ RAT_MOUSE_LX_TAG, RAT_MOUSE_LY_TAG, RAT_MOUSE_BUTTONS_TAG);
+ analog_port_start(&m_diecom_lightgun, DIECOM_LIGHTGUN_RX_TAG, DIECOM_LIGHTGUN_RY_TAG,
+ DIECOM_LIGHTGUN_LX_TAG, DIECOM_LIGHTGUN_LY_TAG, DIECOM_LIGHTGUN_BUTTONS_TAG);
+
+ /* look up miscellaneous controls */
+ m_joystick_type_control = machine().root_device().ioport(CTRL_SEL_TAG);
+ m_joystick_hires_control = machine().root_device().ioport(HIRES_INTF_TAG);
+
+ /* timers */
+ m_hiresjoy_transition_timer[0] = timer_alloc(TIMER_HIRES_JOYSTICK_X);
+ m_hiresjoy_transition_timer[1] = timer_alloc(TIMER_HIRES_JOYSTICK_Y);
+ m_diecom_lightgun_timer = timer_alloc(TIMER_DIECOM_LIGHTGUN);
+
+ /* cart base update */
+ m_cococart->set_cart_base_update(cococart_base_update_delegate(FUNC(coco_state::update_cart_base), this));
+
+ /* save state support */
+ save_item(NAME(m_dac_output));
+ save_item(NAME(m_hiresjoy_ca));
+ save_item(NAME(m_dclg_previous_bit));
+ save_item(NAME(m_dclg_output_h));
+ save_item(NAME(m_dclg_output_v));
+ save_item(NAME(m_dclg_state));
+ save_item(NAME(m_dclg_timer));
+ save_item(NAME(m_vhd_select));
+
+ /* set up disassembly override */
+ if (m_maincpu->debug())
+ {
+ m_maincpu->debug()->set_dasm_override(dasm_override);
+ }
+}
+
+
+
+//-------------------------------------------------
+// device_reset
+//-------------------------------------------------
+
+void coco_state::device_reset()
+{
+ /* call base device_start */
+ driver_device::device_reset();
+
+ /* reset state */
+ m_dac_output = 0;
+ m_hiresjoy_ca = false;
+ m_dclg_previous_bit = false;
+ m_dclg_output_h = 0;
+ m_dclg_output_v = 0;
+ m_dclg_state = 0;
+ m_dclg_timer = 0;
+ m_vhd_select = 0;
+}
+
+
+
+//-------------------------------------------------
+// device_timer
+//-------------------------------------------------
+
+void coco_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch(id)
+ {
+ case TIMER_HIRES_JOYSTICK_X:
+ case TIMER_HIRES_JOYSTICK_Y:
+ case TIMER_DIECOM_LIGHTGUN:
+ poll_keyboard();
+ break;
+ }
+}
+
+
+
+//-------------------------------------------------
+// floating_bus_read
+//-------------------------------------------------
+//
+// From Darren A on the CoCo list:
+//
+// Whenever you read from an un-mapped hardware address or from an
+// address where some of the bits are undefined (like the GIME's palette
+// and MMU registers), the value obtained for those undefined bits is
+// predictable on the CoCo.
+//
+// There are two possibilites which depend on the addressing mode you use
+// to read from such an address. If you use the "no-offset" indexed mode
+// (as in LDA ,X) the undefined bits will come from the first byte of the
+// next instruction. For any other addressing mode, the undefined bits
+// will come from the byte at $FFFF (LSB of the Reset vector).
+//
+// When you use BASIC's PEEK command to read from an un-mapped address
+// (such as $FF70), you get a value of 126. This is because PEEK reads
+// the address with a LDA ,X instruction, so the value returned is the
+// opcode of the next instruction (JMP Extended = $7E = 126). If you
+// patch the PEEK command to use a 5-bit offset (LDA 0,X), the value
+// returned for an un-mapped address will instead come from $FFFF (27 on
+// a CoCo 3 or 39 on a CoCo 1/2).
+//
+// The reason for this behavior is that the 6809 normally does a VMA
+// cycle just before reading the instruction's effective address. The
+// exception is the "no-offset" indexed mode in which case the next
+// instruction byte is read just prior to the effective address. During
+// a VMA cycle the address bus goes to Hi Impedance and the R/W line is
+// HI. This has the effect of loading the value from $FFFF onto the data
+// bus. This stale data from the previous cycle supplies the value for
+// the undefined bits.
+//
+// Here is a small routine which will demonstrate this behavior:
+//
+// ldx #$FF70
+// lda ,x
+// ldb $FF70
+// std $400
+// rts
+//
+// On a CoCo 3, you should end up with the value $F61B at $400-401. On a
+// CoCo 1/2 you should get $F627 instead.
+//-------------------------------------------------
+
+UINT8 coco_state::floating_bus_read(void)
+{
+ UINT8 byte;
+
+ // set up the ability to read address spaces
+ address_space *program = m_maincpu->space(AS_PROGRAM);
+
+ // get the previous and current PC
+ UINT16 prev_pc = cpu_get_previouspc(m_maincpu);
+ UINT16 pc = cpu_get_pc(m_maincpu);
+
+ // get the byte; and skip over header bytes
+ byte = program->read_byte(prev_pc);
+ if ((byte == 0x10) || (byte == 0x11))
+ byte = program->read_byte(++prev_pc);
+
+ // check to see if the opcode specifies the indexed addressing mode, and the secondary byte
+ // specifies no-offset
+ bool is_nooffset_indexed = (((byte & 0xF0) == 0x60) || ((byte & 0xF0) == 0xA0) || ((byte & 0xF0) == 0xE0))
+ && ((program->read_byte(prev_pc + 1) & 0xBF) == 0x84);
+
+ // finally read the byte
+ return program->read_byte(is_nooffset_indexed ? pc : 0xFFFF);
+}
+
+
+
+/***************************************************************************
+ PIA0 ($FF00-$FF1F) (Chip U8)
+
+ PIA0 PA0-PA7 - Keyboard/Joystick read
+ PIA0 PB0-PB7 - Keyboard write
+ PIA0 CA1 - MC6847 HS (Horizontal Sync)
+ PIA0 CA2 - SEL1 (Used by sound mux and joystick)
+ PIA0 CB1 - MC6847 FS (Field Sync)
+ PIA0 CB2 - SEL2 (Used by sound mux and joystick)
+***************************************************************************/
+
+//-------------------------------------------------
+// ff00_write
+//-------------------------------------------------
+
+READ8_MEMBER( coco_state::ff00_read )
+{
+ return m_pia_0->read(space, offset, mem_mask);
+}
+
+
+
+//-------------------------------------------------
+// ff00_write
+//-------------------------------------------------
+
+WRITE8_MEMBER( coco_state::ff00_write )
+{
+ m_pia_0->write(space, offset, data, mem_mask);
+}
+
+
+
+//-------------------------------------------------
+// pia0_pb_w
+//-------------------------------------------------
+
+WRITE8_MEMBER( coco_state::pia0_pb_w )
+{
+ poll_keyboard();
+}
+
+
+
+//-------------------------------------------------
+// pia0_ca2_w
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( coco_state::pia0_ca2_w )
+{
+ update_sound();
+ poll_keyboard();
+}
+
+
+
+//-------------------------------------------------
+// pia0_cb2_w
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( coco_state::pia0_cb2_w )
+{
+ update_sound();
+ poll_keyboard();
+}
+
+
+
+//-------------------------------------------------
+// pia0_irq_a
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( coco_state::pia0_irq_a )
+{
+ recalculate_irq();
+}
+
+
+
+//-------------------------------------------------
+// pia0_irq_b
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( coco_state::pia0_irq_b )
+{
+ recalculate_irq();
+}
+
+
+
+//-------------------------------------------------
+// pia0_config
+//-------------------------------------------------
+
+const pia6821_interface coco_state::pia0_config =
+{
+ DEVCB_NULL, /* port A input */
+ DEVCB_NULL, /* port B input */
+ DEVCB_NULL, /* CA1 input */
+ DEVCB_NULL, /* CB1 input */
+ DEVCB_NULL, /* CA2 input */
+ DEVCB_NULL, /* CB2 input */
+ DEVCB_NULL, /* port A output */
+ DEVCB_DRIVER_MEMBER(coco_state, pia0_pb_w), /* port B output */
+ DEVCB_DRIVER_LINE_MEMBER(coco_state, pia0_ca2_w), /* CA2 output */
+ DEVCB_DRIVER_LINE_MEMBER(coco_state, pia0_cb2_w), /* CB2 output */
+ DEVCB_DRIVER_LINE_MEMBER(coco_state, pia0_irq_a), /* IRQA output */
+ DEVCB_DRIVER_LINE_MEMBER(coco_state, pia0_irq_b) /* IRQB output */
+};
+
+
+
+/***************************************************************************
+ PIA1 ($FF20-$FF3F) (Chip U4)
+
+ PIA1 PA0 - CASSDIN
+ PIA1 PA1 - RS232 OUT (CoCo), Printer Strobe (Dragon)
+ PIA1 PA2-PA7 - DAC
+ PIA1 PB0 - RS232 IN
+ PIA1 PB1 - Single bit sound
+ PIA1 PB2 - RAMSZ (32/64K, 16K, and 4K three position switch)
+ PIA1 PB3 - M6847 CSS
+ PIA1 PB4 - M6847 INT/EXT and M6847 GM0
+ PIA1 PB5 - M6847 GM1
+ PIA1 PB6 - M6847 GM2
+ PIA1 PB7 - M6847 A/G
+ PIA1 CA1 - CD (Carrier Detect; NYI)
+ PIA1 CA2 - CASSMOT (Cassette Motor)
+ PIA1 CB1 - CART (Cartridge Detect)
+ PIA1 CB2 - SNDEN (Sound Enable)
+***************************************************************************/
+
+//-------------------------------------------------
+// ff20_read
+//-------------------------------------------------
+
+READ8_MEMBER( coco_state::ff20_read )
+{
+ return m_pia_1->read(space, offset, mem_mask);
+}
+
+
+
+//-------------------------------------------------
+// ff20_write
+//-------------------------------------------------
+
+WRITE8_MEMBER( coco_state::ff20_write )
+{
+ /* write to the PIA */
+ m_pia_1->write(space, offset, data, mem_mask);
+
+ /* we have to do this to do something that approximates the cartridge Q line behavior */
+ m_cococart->twiddle_q_lines();
+}
+
+
+
+//-------------------------------------------------
+// pia1_pa_r
+//-------------------------------------------------
+
+READ8_MEMBER( coco_state::pia1_pa_r )
+{
+ return (m_cassette->input() >= 0 ? 0x01 : 0x00)
+ | (dac_output() << 2);
+}
+
+
+
+//-------------------------------------------------
+// pia1_pb_r - this handles the reading of the
+// memory sense switch (PB2) for the CoCo 1 and
+// serial-in (PB0)
+//-------------------------------------------------
+
+READ8_MEMBER( coco_state::pia1_pb_r )
+{
+ UINT32 ram_size = m_ram->size();
+
+ // For the CoCo 1, the logic has been changed to only select 64K rams
+ // if there is more than 16K of memory, as the Color Basic 1.0 rom
+ // can only configure 4K or 16K ram banks (as documented in "Color
+ // Basic Unreveled"), doing this allows this allows the coco driver
+ // to access 32K of ram, and also allows the cocoe driver to access
+ // the full 64K, as this uses Color Basic 1.2, which can configure 64K rams
+ bool memory_sense = (ram_size >= 0x4000 && ram_size <= 0x7FFF)
+ || (ram_size >= 0x8000 && (m_pia_0->b_output() & 0x80));
+
+ // serial in (PB0)
+ bool serial_in = (m_bitbanger != NULL) && (m_bitbanger->input() ? true : false);
+
+ // composite the results
+ return (memory_sense ? 0x04 : 0x00)
+ | (serial_in ? 0x01 : 0x00);
+}
+
+
+
+//-------------------------------------------------
+// pia1_pa_w
+//-------------------------------------------------
+
+WRITE8_MEMBER( coco_state::pia1_pa_w )
+{
+ pia1_pa_changed();
+}
+
+
+
+//-------------------------------------------------
+// pia1_pb_w
+//-------------------------------------------------
+
+WRITE8_MEMBER( coco_state::pia1_pb_w )
+{
+ pia1_pb_changed();
+}
+
+
+
+//-------------------------------------------------
+// pia1_ca2_w
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( coco_state::pia1_ca2_w )
+{
+ m_cassette->change_state(
+ state ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED,
+ CASSETTE_MASK_MOTOR);
+}
+
+
+
+//-------------------------------------------------
+// pia1_cb2_w
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( coco_state::pia1_cb2_w )
+{
+ poll_keyboard();
+
+ // Theoretically, I should be calling update_sound() here; however this seems to create
+ // a buzzing in some CoCo software (e.g. - Popcorn). This is likely because this line
+ // drives the MC14529B MUX, and when disabled the output probably goes hi-Z.
+}
+
+
+
+//-------------------------------------------------
+// pia1_firq_a
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( coco_state::pia1_firq_a )
+{
+ recalculate_firq();
+}
+
+
+
+//-------------------------------------------------
+// pia1_firq_b
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( coco_state::pia1_firq_b )
+{
+ recalculate_firq();
+}
+
+
+
+//-------------------------------------------------
+// pia1_config
+//-------------------------------------------------
+
+const pia6821_interface coco_state::pia1_config =
+{
+ DEVCB_DRIVER_MEMBER(coco_state, pia1_pa_r), /* port A input */
+ DEVCB_DRIVER_MEMBER(coco_state, pia1_pb_r), /* port B input */
+ DEVCB_NULL, /* CA1 input */
+ DEVCB_NULL, /* CB1 input */
+ DEVCB_NULL, /* CA2 input */
+ DEVCB_NULL, /* CB2 input */
+ DEVCB_DRIVER_MEMBER(coco_state, pia1_pa_w), /* port A output */
+ DEVCB_DRIVER_MEMBER(coco_state, pia1_pb_w), /* port B output */
+ DEVCB_DRIVER_LINE_MEMBER(coco_state, pia1_ca2_w), /* CA2 output */
+ DEVCB_DRIVER_LINE_MEMBER(coco_state, pia1_cb2_w), /* CB2 output */
+ DEVCB_DRIVER_LINE_MEMBER(coco_state, pia1_firq_a), /* IRQA output */
+ DEVCB_DRIVER_LINE_MEMBER(coco_state, pia1_firq_b) /* IRQB output */
+};
+
+
+
+/***************************************************************************
+ CPU INTERRUPTS
+
+ The Dragon/CoCo2 have two PIAs. These PIAs can trigger interrupts. PIA0
+ is set up to trigger IRQ on the CPU, and PIA1 can trigger FIRQ. Each PIA
+ has two output lines, and an interrupt will be triggered if either of these
+ lines are asserted.
+
+ ----- IRQ
+ 6809 |-<----------- PIA0
+ |
+ |
+ |
+ |
+ |
+ |-<----------- PIA1
+ -----
+
+***************************************************************************/
+
+//-------------------------------------------------
+// irq_get_line - gets the value of the FIRQ line
+// passed into the CPU
+//-------------------------------------------------
+
+bool coco_state::irq_get_line(void)
+{
+ return m_pia_0->irq_a_state() || m_pia_0->irq_b_state();
+}
+
+
+
+//-------------------------------------------------
+// recalculate_irq
+//-------------------------------------------------
+
+void coco_state::recalculate_irq(void)
+{
+ bool line = irq_get_line();
+ if (LOG_INTERRUPTS)
+ logerror("recalculate_irq(): line=%d\n", line ? 1 : 0);
+ m_maincpu->set_input_line(M6809_IRQ_LINE, line ? ASSERT_LINE : CLEAR_LINE);
+}
+
+
+
+//-------------------------------------------------
+// firq_get_line - gets the value of the FIRQ line
+// passed into the CPU
+//-------------------------------------------------
+
+bool coco_state::firq_get_line(void)
+{
+ return m_pia_1->irq_a_state() || m_pia_1->irq_b_state();
+}
+
+
+
+//-------------------------------------------------
+// recalculate_firq
+//-------------------------------------------------
+
+void coco_state::recalculate_firq(void)
+{
+ bool line = firq_get_line();
+ if (LOG_INTERRUPTS)
+ logerror("recalculate_firq(): line=%d\n", line ? 1 : 0);
+ m_maincpu->set_input_line(M6809_FIRQ_LINE, line ? ASSERT_LINE : CLEAR_LINE);
+}
+
+
+
+/***************************************************************************
+ SOUND / KEYBOARD / JOYSTICK
+
+ The sound MUX has 4 possible settings, depend on SELA and SELB inputs:
+
+ 00 - DAC (digital - analog converter)
+ 01 - CSN (cassette)
+ 10 - SND input from cartridge (NYI because we only support the FDC)
+ 11 - Grounded (0)
+
+ Source - Tandy Color Computer Service Manual
+
+ Note on the Dragon Alpha state 11, selects the AY-3-8912, this is currently
+ un-implemented - phs.
+
+***************************************************************************/
+
+//-------------------------------------------------
+// soundmux_status
+//-------------------------------------------------
+
+coco_state::soundmux_status_t coco_state::soundmux_status(void)
+{
+ return (soundmux_status_t) (
+ (snden() ? SOUNDMUX_ENABLE : 0) |
+ (sel1() ? SOUNDMUX_SEL1 : 0) |
+ (sel2() ? SOUNDMUX_SEL2 : 0));
+}
+
+
+
+//-------------------------------------------------
+// update_sound
+//-------------------------------------------------
+
+void coco_state::update_sound(void)
+{
+ /* PB1 will drive the sound output. This is a rarely
+ * used single bit sound mode. It is always connected thus
+ * cannot be disabled.
+ *
+ * Source: Page 31 of the Tandy Color Computer Serice Manual
+ */
+ UINT8 single_bit_sound = (m_pia_1->b_output() & 0x02) ? 0x80 : 0x00;
+
+ /* determine the sound mux status */
+ soundmux_status_t status = soundmux_status();
+
+ /* determine the value to send to the DAC */
+ m_dac_output = (m_pia_1->a_output() & 0xFC) >> 2;
+ UINT8 sound_output = single_bit_sound + (status == SOUNDMUX_ENABLE ? m_dac_output << 1 : 0);
+ m_dac->write_unsigned8(sound_output);
+
+ /* determine the cassette sound status */
+ cassette_state cas_sound = (status == (SOUNDMUX_ENABLE | SOUNDMUX_SEL1))
+ ? CASSETTE_SPEAKER_ENABLED
+ : CASSETTE_SPEAKER_MUTED;
+ m_cassette->change_state(cas_sound, CASSETTE_MASK_SPEAKER);
+
+ /* determine the cartridge sound status */
+ m_cococart->cart_set_line(
+ COCOCART_LINE_SOUND_ENABLE,
+ (status == (SOUNDMUX_ENABLE | SOUNDMUX_SEL2)) ? COCOCART_LINE_VALUE_ASSERT : COCOCART_LINE_VALUE_CLEAR);
+}
+
+
+
+//-------------------------------------------------
+// joystick_type - returns the type of joystick
+// in the specified port
+//-------------------------------------------------
+
+coco_state::joystick_type_t coco_state::joystick_type(int index)
+{
+ assert((index == 0) || (index == 1));
+ return (m_joystick_type_control != NULL)
+ ? (joystick_type_t) ((m_joystick_type_control->read() >> (index * 4)) & 0x0F)
+ : JOYSTICK_NONE;
+}
+
+
+
+//-------------------------------------------------
+// hires_interface_type
+//-------------------------------------------------
+
+coco_state::hires_type_t coco_state::hires_interface_type(void)
+{
+ return (m_joystick_hires_control != NULL)
+ ? (hires_type_t) m_joystick_hires_control->read()
+ : HIRES_NONE;
+}
+
+
+
+//-------------------------------------------------
+// is_joystick_hires
+//-------------------------------------------------
+
+bool coco_state::is_joystick_hires(int joystick_index)
+{
+ bool result;
+ assert((joystick_index == 0) || (joystick_index == 1));
+
+ switch(hires_interface_type())
+ {
+ case HIRES_RIGHT:
+ case HIRES_RIGHT_COCOMAX3:
+ result = (joystick_index == 0);
+ break;
+
+ case HIRES_LEFT:
+ case HIRES_LEFT_COCOMAX3:
+ result = (joystick_index == 1);
+ break;
+
+ default:
+ result = false;
+ break;
+ }
+ return result;
+}
+
+
+
+//-------------------------------------------------
+// poll_joystick
+//-------------------------------------------------
+
+void coco_state::poll_joystick(bool *joyin, UINT8 *buttons)
+{
+ static const analog_input_t s_empty = {};
+ static const int joy_rat_table[] = {15, 24, 42, 33 };
+ static const int dclg_table[] = {0, 14, 30, 49 };
+
+ /* identify the joystick and axis */
+ int joystick_axis = sel1() ? 1 : 0;
+ int joystick = sel2() ? 1 : 0;
+
+ /* determine the JOYIN value */
+ const analog_input_t *analog;
+ bool joyin_value;
+ UINT8 joyval;
+ int dclg_vpos;
+ switch(joystick_type(joystick))
+ {
+ case JOYSTICK_NORMAL:
+ analog = &m_joystick;
+
+ /* is any Hi-Res Interface turned on? prepare masks to check it */
+ if (is_joystick_hires(joystick))
+ {
+ /* hi-res joystick or hi-res CoCo3Max joystick */
+ attotime remaining = m_hiresjoy_transition_timer[joystick_axis]->remaining();
+ joyin_value = remaining < attotime::zero;
+ }
+ else
+ {
+ /* conventional joystick */
+ joyval = analog->input(joystick, joystick_axis);
+ joyin_value = (dac_output() <= (joyval >> 2));
+ }
+ break;
+
+ case JOYSTICK_RAT_MOUSE:
+ analog = &m_rat_mouse;
+ joyval = analog->input(joystick, joystick_axis);
+ joyin_value = dac_output() <= joy_rat_table[joyval];
+ break;
+
+ case JOYSTICK_DIECOM_LIGHT_GUN:
+ analog = &m_diecom_lightgun;
+
+ /* get the vertical position of the lightgun */
+ dclg_vpos = analog->input(joystick, 1);
+
+ if (machine().primary_screen->vpos() == dclg_vpos)
+ {
+ /* if gun is pointing at the current scan line, set hit bit and cache horizontal timer value */
+ m_dclg_output_h |= 0x02;
+ m_dclg_timer = analog->input(joystick, 0) << 1;
+ }
+
+ joyin_value = (dac_output() <= dclg_table[(joystick_axis ? m_dclg_output_h : m_dclg_output_v) & 0x03]);
+
+ if (m_dclg_state == 7)
+ {
+ /* while in state 7, prepare to check next video frame for a hit */
+ attotime dclg_time = machine().primary_screen->time_until_pos(dclg_vpos, 0);
+ m_diecom_lightgun_timer->adjust(dclg_time);
+ }
+ break;
+
+ default: /* None */
+ analog = &s_empty;
+ joyin_value = false;
+ break;
+ }
+
+ *joyin = joyin_value;
+ *buttons = analog->buttons();
+}
+
+
+
+//-------------------------------------------------
+// poll_keyboard
+//-------------------------------------------------
+
+void coco_state::poll_keyboard(void)
+{
+ UINT8 pia0_pb = m_pia_0->b_output();
+ UINT8 pia0_pb_z = m_pia_0->port_b_z_mask();
+
+ UINT8 pia0_pa = 0x7F;
+ UINT8 pia0_pa_z = 0x7F;
+
+ /* poll the keyboard, and update PA6-PA0 accordingly*/
+ for (int i = 0; i < sizeof(m_keyboard) / sizeof(m_keyboard[0]); i++)
+ {
+ int value = m_keyboard[i]->read();
+ if ((value | pia0_pb) != 0xFF)
+ {
+ pia0_pa &= ~(0x01 << i);
+ }
+ if ((value | pia0_pb_z) != 0xFF)
+ {
+ pia0_pa_z &= ~(0x01 << i);
+ }
+ }
+
+ /* poll the joystick (*/
+ bool joyin;
+ UINT8 buttons;
+ poll_joystick(&joyin, &buttons);
+
+ /* PA7 comes from JOYIN */
+ pia0_pa |= joyin ? 0x80 : 0x00;
+
+ /* mask out the buttons */
+ pia0_pa &= ~buttons;
+ pia0_pa_z &= ~buttons;
+
+ /* and write the result to PIA0 */
+ update_keyboard_input(pia0_pa, pia0_pa_z);
+
+ /* hires joystick */
+ poll_hires_joystick();
+}
+
+
+
+//-------------------------------------------------
+// update_keyboard_input - writes to PIA0 PA, but
+// on the CoCo 3 controls a GIME input
+//-------------------------------------------------
+
+void coco_state::update_keyboard_input(UINT8 value, UINT8 z)
+{
+ m_pia_0->set_a_input(value, z);
+}
+
+
+
+//-------------------------------------------------
+// update_cassout - called when CASSOUT changes
+//-------------------------------------------------
+
+void coco_state::update_cassout(int cassout)
+{
+ m_cassette->output((cassout - 0x20) / 32.0);
+}
+
+
+
+//-------------------------------------------------
+// diecom_lightgun_clock - called the diecom
+// lightgun undergoes a high to low transition
+//-------------------------------------------------
+
+void coco_state::diecom_lightgun_clock(void)
+{
+ /* clock Diecom Light gun interface on a high to low transistion */
+ m_dclg_state++;
+ m_dclg_state &= 0x0f;
+
+ /* clear hit bit for every transistion */
+ m_dclg_output_h &= ~0x02;
+
+ if (m_dclg_state > 7)
+ {
+ /* Bit shift timer data on state 8 thru 15 */
+ if (((m_dclg_timer >> (m_dclg_state - 8 + 1)) & 0x01) == 1)
+ m_dclg_output_v |= 0x01;
+ else
+ m_dclg_output_v &= ~0x01;
+
+ /* Bit 9 of timer is only avaiable if state == 8*/
+ if (m_dclg_state == 8 && (((m_dclg_timer >> 9) & 0x01) == 1))
+ m_dclg_output_v |= 0x02;
+ else
+ m_dclg_output_v &= ~0x02;
+ }
+
+ /* During state 15, this bit is high. */
+ if (m_dclg_state == 15)
+ m_dclg_output_h |= 0x01;
+ else
+ m_dclg_output_h &= ~0x01;
+}
+
+
+
+//-------------------------------------------------
+// update_prinout - called when PRINOUT changes
+//-------------------------------------------------
+
+void coco_state::update_prinout(bool prinout)
+{
+ if ((joystick_type(0) == JOYSTICK_DIECOM_LIGHT_GUN) || (joystick_type(1) == JOYSTICK_DIECOM_LIGHT_GUN))
+ {
+ /* printer port is connected to diecom light gun */
+ if (m_dclg_previous_bit && !prinout)
+ {
+ diecom_lightgun_clock();
+ }
+ m_dclg_previous_bit = prinout;
+ }
+ else
+ {
+ /* output bitbanger if present (only on CoCos) */
+ if (m_bitbanger != NULL)
+ {
+ m_bitbanger->output(prinout ? 1 : 0);
+ }
+ }
+}
+
+
+
+//-------------------------------------------------
+// pia1_pa_changed - called when PIA1 PA changes
+//-------------------------------------------------
+
+void coco_state::pia1_pa_changed(void)
+{
+ update_sound();
+ poll_keyboard();
+ update_cassout(dac_output());
+ update_prinout(m_pia_1->a_output() & 0x02 ? true : false);
+}
+
+
+
+//-------------------------------------------------
+// pia1_pb_changed - called when PIA1 PB changes
+//-------------------------------------------------
+
+void coco_state::pia1_pb_changed(void)
+{
+ update_sound();
+}
+
+
+
+//-------------------------------------------------
+// keyboard_changed
+//-------------------------------------------------
+
+INPUT_CHANGED(coco_state::keyboard_changed)
+{
+ coco_state *state = field.machine().driver_data<coco_state>();
+ state->poll_keyboard();
+}
+
+
+
+//-------------------------------------------------
+// joystick_mode_changed
+//-------------------------------------------------
+
+INPUT_CHANGED(coco_state::joystick_mode_changed)
+{
+ coco_state *state = field.machine().driver_data<coco_state>();
+ state->poll_keyboard();
+}
+
+
+
+//-------------------------------------------------
+// bitbanger_changed
+//-------------------------------------------------
+
+void coco_state::bitbanger_changed(bool newvalue)
+{
+ // do nothing
+}
+
+
+
+//-------------------------------------------------
+// bitbanger_callback
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( coco_state::bitbanger_callback )
+{
+ bitbanger_changed(state ? true : false);
+}
+
+
+
+//-------------------------------------------------
+// bitbanger_config
+//-------------------------------------------------
+
+const bitbanger_config coco_state::coco_bitbanger_config =
+{
+ DEVCB_DRIVER_LINE_MEMBER(coco_state, bitbanger_callback), /* callback */
+ BITBANGER_PRINTER, /* default mode */
+ BITBANGER_600, /* default output baud */
+ BITBANGER_0PERCENT /* default fine tune adjustment */
+};
+
+
+
+//-------------------------------------------------
+// poll_hires_joystick
+//-------------------------------------------------
+
+void coco_state::poll_hires_joystick(void)
+{
+ bool newvalue;
+ bool is_cocomax3;
+ int joystick_index, axis;
+
+ /* we do different things based on the type of hires interface */
+ switch(hires_interface_type())
+ {
+ case HIRES_RIGHT:
+ newvalue = (m_pia_0->a_output() & 0x04);
+ joystick_index = 0;
+ is_cocomax3 = false;
+ break;
+
+ case HIRES_RIGHT_COCOMAX3:
+ newvalue = (dac_output() >= 0x20);
+ joystick_index = 0;
+ is_cocomax3 = true;
+ break;
+
+ case HIRES_LEFT:
+ newvalue = (m_pia_0->a_output() & 0x08);
+ joystick_index = 1;
+ is_cocomax3 = false;
+ break;
+
+ case HIRES_LEFT_COCOMAX3:
+ newvalue = (dac_output() >= 0x20);
+ joystick_index = 1;
+ is_cocomax3 = true;
+ break;
+
+ default:
+ newvalue = true;
+ joystick_index = -1;
+ is_cocomax3 = false;
+ break;
+ }
+
+ /* if the joystick isn't selected, newvalue is true */
+ newvalue = newvalue || (joystick_index < 0) || (joystick_type(joystick_index) != JOYSTICK_NORMAL);
+
+ /* make the transition */
+ for (axis = 0; axis <= 1; axis++)
+ {
+ if (m_hiresjoy_ca && !newvalue)
+ {
+ /* hi to lo */
+ double value = m_joystick.input(joystick_index, axis) / 255.0;
+ value *= is_cocomax3 ? 2500.0 : 4160.0;
+ value += is_cocomax3 ? 400.0 : 592.0;
+ attotime duration = m_maincpu->clocks_to_attotime((UINT64) value);
+ m_hiresjoy_transition_timer[axis]->adjust(duration);
+ }
+ else if (!m_hiresjoy_ca && newvalue)
+ {
+ /* lo to hi */
+ m_hiresjoy_transition_timer[axis]->reset();
+ }
+ }
+ m_hiresjoy_ca = newvalue;
+}
+
+
+
+/***************************************************************************
+ VHD
+ ***************************************************************************/
+
+//-------------------------------------------------
+// current_vhd
+//-------------------------------------------------
+
+coco_vhd_image_device *coco_state::current_vhd(void)
+{
+ switch(m_vhd_select)
+ {
+ case 0: return m_vhd_0;
+ case 1: return m_vhd_1;
+ default: return NULL;
+ }
+}
+
+
+
+//-------------------------------------------------
+// ff60_read
+//-------------------------------------------------
+
+READ8_MEMBER( coco_state::ff60_read )
+{
+ UINT8 result;
+
+ if ((current_vhd() != NULL) && (offset >= 32) && (offset <= 37))
+ {
+ result = current_vhd()->read(offset - 32);
+ }
+ else
+ {
+ result = floating_bus_read();
+ }
+
+ return result;
+}
+
+
+
+//-------------------------------------------------
+// ff60_write
+//-------------------------------------------------
+
+WRITE8_MEMBER( coco_state::ff60_write )
+{
+ if ((current_vhd() != NULL) && (offset >= 32) && (offset <= 37))
+ {
+ current_vhd()->write(offset - 32, data);
+ }
+ else if (offset == 38)
+ {
+ /* writes to $FF86 will switch the VHD */
+ m_vhd_select = data;
+ }
+}
+
+
+
+/***************************************************************************
+ CARTRIDGE & CASSETTE
+ ***************************************************************************/
+
+//-------------------------------------------------
+// ff40_read
+//-------------------------------------------------
+
+READ8_MEMBER( coco_state::ff40_read )
+{
+ return m_cococart->read(space, offset, mem_mask);
+}
+
+
+
+//-------------------------------------------------
+// ff40_write
+//-------------------------------------------------
+
+WRITE8_MEMBER( coco_state::ff40_write )
+{
+ m_cococart->write(space, offset, data, mem_mask);
+}
+
+
+
+//-------------------------------------------------
+// cart_w
+//-------------------------------------------------
+
+void coco_state::cart_w(bool state)
+{
+ m_pia_1->cb1_w(state);
+}
+
+
+
+//-------------------------------------------------
+// cartridge_config
+//-------------------------------------------------
+
+const cococart_interface coco_state::cartridge_config =
+{
+ DEVCB_DRIVER_LINE_MEMBER(coco_state, cart_w), // coco_cart_w,
+ DEVCB_CPU_INPUT_LINE(MAINCPU_TAG, INPUT_LINE_NMI), // coco_nmi_w,
+ DEVCB_CPU_INPUT_LINE(MAINCPU_TAG, INPUT_LINE_HALT) // coco_halt_w
+};
+
+
+//-------------------------------------------------
+// coco_cassette_interface
+//-------------------------------------------------
+
+const cassette_interface coco_state::coco_cassette_interface =
+{
+ coco_cassette_formats,
+ NULL,
+ (cassette_state)(CASSETTE_PLAY | CASSETTE_MOTOR_DISABLED | CASSETTE_SPEAKER_MUTED),
+ NULL,
+ NULL
+};
+
+
+
+/***************************************************************************
+ DISASSEMBLY OVERRIDE (OS9 syscalls)
+ ***************************************************************************/
+
+static const char *const os9syscalls[] =
+{
+ "F$Link", /* Link to Module */
+ "F$Load", /* Load Module from File */
+ "F$UnLink", /* Unlink Module */
+ "F$Fork", /* Start New Process */
+ "F$Wait", /* Wait for Child Process to Die */
+ "F$Chain", /* Chain Process to New Module */
+ "F$Exit", /* Terminate Process */
+ "F$Mem", /* Set Memory Size */
+ "F$Send", /* Send Signal to Process */
+ "F$Icpt", /* Set Signal Intercept */
+ "F$Sleep", /* Suspend Process */
+ "F$SSpd", /* Suspend Process */
+ "F$ID", /* Return Process ID */
+ "F$SPrior", /* Set Process Priority */
+ "F$SSWI", /* Set Software Interrupt */
+ "F$PErr", /* Print Error */
+ "F$PrsNam", /* Parse Pathlist Name */
+ "F$CmpNam", /* Compare Two Names */
+ "F$SchBit", /* Search Bit Map */
+ "F$AllBit", /* Allocate in Bit Map */
+ "F$DelBit", /* Deallocate in Bit Map */
+ "F$Time", /* Get Current Time */
+ "F$STime", /* Set Current Time */
+ "F$CRC", /* Generate CRC */
+ "F$GPrDsc", /* get Process Descriptor copy */
+ "F$GBlkMp", /* get System Block Map copy */
+ "F$GModDr", /* get Module Directory copy */
+ "F$CpyMem", /* Copy External Memory */
+ "F$SUser", /* Set User ID number */
+ "F$UnLoad", /* Unlink Module by name */
+ "F$Alarm", /* Color Computer Alarm Call (system wide) */
+ NULL,
+ NULL,
+ "F$NMLink", /* Color Computer NonMapping Link */
+ "F$NMLoad", /* Color Computer NonMapping Load */
+ NULL,
+ NULL,
+ "F$TPS", /* Return System's Ticks Per Second */
+ "F$TimAlm", /* COCO individual process alarm call */
+ "F$VIRQ", /* Install/Delete Virtual IRQ */
+ "F$SRqMem", /* System Memory Request */
+ "F$SRtMem", /* System Memory Return */
+ "F$IRQ", /* Enter IRQ Polling Table */
+ "F$IOQu", /* Enter I/O Queue */
+ "F$AProc", /* Enter Active Process Queue */
+ "F$NProc", /* Start Next Process */
+ "F$VModul", /* Validate Module */
+ "F$Find64", /* Find Process/Path Descriptor */
+ "F$All64", /* Allocate Process/Path Descriptor */
+ "F$Ret64", /* Return Process/Path Descriptor */
+ "F$SSvc", /* Service Request Table Initialization */
+ "F$IODel", /* Delete I/O Module */
+ "F$SLink", /* System Link */
+ "F$Boot", /* Bootstrap System */
+ "F$BtMem", /* Bootstrap Memory Request */
+ "F$GProcP", /* Get Process ptr */
+ "F$Move", /* Move Data (low bound first) */
+ "F$AllRAM", /* Allocate RAM blocks */
+ "F$AllImg", /* Allocate Image RAM blocks */
+ "F$DelImg", /* Deallocate Image RAM blocks */
+ "F$SetImg", /* Set Process DAT Image */
+ "F$FreeLB", /* Get Free Low Block */
+ "F$FreeHB", /* Get Free High Block */
+ "F$AllTsk", /* Allocate Process Task number */
+ "F$DelTsk", /* Deallocate Process Task number */
+ "F$SetTsk", /* Set Process Task DAT registers */
+ "F$ResTsk", /* Reserve Task number */
+ "F$RelTsk", /* Release Task number */
+ "F$DATLog", /* Convert DAT Block/Offset to Logical */
+ "F$DATTmp", /* Make temporary DAT image (Obsolete) */
+ "F$LDAXY", /* Load A [X,[Y]] */
+ "F$LDAXYP", /* Load A [X+,[Y]] */
+ "F$LDDDXY", /* Load D [D+X,[Y]] */
+ "F$LDABX", /* Load A from 0,X in task B */
+ "F$STABX", /* Store A at 0,X in task B */
+ "F$AllPrc", /* Allocate Process Descriptor */
+ "F$DelPrc", /* Deallocate Process Descriptor */
+ "F$ELink", /* Link using Module Directory Entry */
+ "F$FModul", /* Find Module Directory Entry */
+ "F$MapBlk", /* Map Specific Block */
+ "F$ClrBlk", /* Clear Specific Block */
+ "F$DelRAM", /* Deallocate RAM blocks */
+ "F$GCMDir", /* Pack module directory */
+ "F$AlHRam", /* Allocate HIGH RAM Blocks */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "F$RegDmp", /* Ron Lammardo's debugging register dump call */
+ "F$NVRAM", /* Non Volatile RAM (RTC battery backed static) read/write */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "I$Attach", /* Attach I/O Device */
+ "I$Detach", /* Detach I/O Device */
+ "I$Dup", /* Duplicate Path */
+ "I$Create", /* Create New File */
+ "I$Open", /* Open Existing File */
+ "I$MakDir", /* Make Directory File */
+ "I$ChgDir", /* Change Default Directory */
+ "I$Delete", /* Delete File */
+ "I$Seek", /* Change Current Position */
+ "I$Read", /* Read Data */
+ "I$Write", /* Write Data */
+ "I$ReadLn", /* Read Line of ASCII Data */
+ "I$WritLn", /* Write Line of ASCII Data */
+ "I$GetStt", /* Get Path Status */
+ "I$SetStt", /* Set Path Status */
+ "I$Close", /* Close Path */
+ "I$DeletX" /* Delete from current exec dir */
+};
+
+
+offs_t coco_state::dasm_override(device_t &device, char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, int options)
+{
+ unsigned call;
+ unsigned result = 0;
+
+ /* check for SWI2 instruction */
+ if ((oprom[0] == 0x10) && (oprom[1] == 0x3F))
+ {
+ call = oprom[2];
+ if ((call < ARRAY_LENGTH(os9syscalls)) && os9syscalls[call])
+ {
+ sprintf(buffer, "OS9 %s", os9syscalls[call]);
+ result = 3;
+ }
+ }
+ return result;
+}
diff --git a/src/mess/machine/coco12.c b/src/mess/machine/coco12.c
new file mode 100644
index 00000000000..d24db9899d8
--- /dev/null
+++ b/src/mess/machine/coco12.c
@@ -0,0 +1,158 @@
+/***************************************************************************
+
+ coco12.c
+
+ TRS-80 Radio Shack Color Computer 1/2 Family
+
+***************************************************************************/
+
+#include "includes/coco12.h"
+
+//-------------------------------------------------
+// ctor
+//-------------------------------------------------
+
+coco12_state::coco12_state(const machine_config &mconfig, device_type type, const char *tag)
+ : coco_state(mconfig, type, tag),
+ m_sam(*this, SAM_TAG),
+ m_vdg(*this, VDG_TAG)
+{
+}
+
+
+
+//-------------------------------------------------
+// device_start
+//-------------------------------------------------
+
+void coco12_state::device_start()
+{
+ coco_state::device_start();
+ configure_sam();
+}
+
+
+
+//-------------------------------------------------
+// configure_sam
+//-------------------------------------------------
+
+void coco12_state::configure_sam()
+{
+ cococart_slot_device *cart = m_cococart;
+ UINT8 *ram = m_ram->pointer();
+ UINT32 ram_size = m_ram->size();
+ UINT8 *rom = memregion(MAINCPU_TAG)->base();
+ UINT8 *cart_rom = cart->get_cart_base();
+
+ m_sam->configure_bank(0, ram, ram_size, false); // $0000-$7FFF
+ m_sam->configure_bank(1, &rom[0x0000], 0x2000, true); // $8000-$9FFF
+ m_sam->configure_bank(2, &rom[0x2000], 0x2000, true); // $A000-$BFFF
+ m_sam->configure_bank(3, cart_rom, 0x4000, true); // $C000-$FEFF
+
+ // $FF00-$FF1F
+ m_sam->configure_bank(4, read8_delegate(FUNC(coco12_state::ff00_read), this), write8_delegate(FUNC(coco12_state::ff00_write), this));
+
+ // $FF20-$FF3F
+ m_sam->configure_bank(5, read8_delegate(FUNC(coco12_state::ff20_read), this), write8_delegate(FUNC(coco12_state::ff20_write), this));
+
+ // $FF40-$FF5F
+ m_sam->configure_bank(6, read8_delegate(FUNC(coco12_state::ff40_read), this), write8_delegate(FUNC(coco12_state::ff40_write), this));
+
+ // $FF60-$FFBF
+ m_sam->configure_bank(7, read8_delegate(FUNC(coco12_state::ff60_read), this), write8_delegate(FUNC(coco12_state::ff60_write), this));
+}
+
+
+//-------------------------------------------------
+// horizontal_sync
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( coco12_state::horizontal_sync )
+{
+ m_pia_0->ca1_w(state);
+ m_sam->hs_w(state);
+}
+
+
+
+//-------------------------------------------------
+// field_sync
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( coco12_state::field_sync )
+{
+ m_pia_0->cb1_w(state);
+}
+
+
+
+//-------------------------------------------------
+// sam_read
+//-------------------------------------------------
+
+READ8_MEMBER( coco12_state::sam_read )
+{
+ UINT8 data = m_sam->mpu_address_space()->read_byte(offset);
+ m_vdg->as_w(data & 0x80 ? ASSERT_LINE : CLEAR_LINE);
+ m_vdg->inv_w(data & 0x40 ? ASSERT_LINE : CLEAR_LINE);
+ return data;
+}
+
+
+
+//-------------------------------------------------
+// pia1_pb_changed
+//-------------------------------------------------
+
+void coco12_state::pia1_pb_changed(void)
+{
+ /* call inherited function */
+ coco_state::pia1_pb_changed();
+
+ UINT8 data = m_pia_1->b_output();
+ m_vdg->css_w(data & 0x08);
+ m_vdg->intext_w(data & 0x10);
+ m_vdg->gm0_w(data & 0x10);
+ m_vdg->gm1_w(data & 0x20);
+ m_vdg->gm2_w(data & 0x40);
+ m_vdg->ag_w(data & 0x80);
+}
+
+
+
+//-------------------------------------------------
+// update_cart_base
+//-------------------------------------------------
+
+void coco12_state::update_cart_base(UINT8 *cart_base)
+{
+ m_sam->configure_bank(3, cart_base, 0x4000, true); // $C000-$FEFF
+}
+
+
+
+//-------------------------------------------------
+// mc6847_config
+//-------------------------------------------------
+
+const mc6847_interface coco12_state::mc6847_config =
+{
+ SCREEN_TAG,
+ DEVCB_DEVICE_MEMBER(SAM_TAG, sam6883_device, display_read),
+ DEVCB_DRIVER_LINE_MEMBER(coco12_state, horizontal_sync),
+ DEVCB_DRIVER_LINE_MEMBER(coco12_state, field_sync)
+};
+
+
+
+//-------------------------------------------------
+// sam6883_config
+//-------------------------------------------------
+
+const sam6883_interface coco12_state::sam6883_config =
+{
+ MAINCPU_TAG,
+ AS_PROGRAM,
+ DEVCB_DRIVER_MEMBER(coco12_state, sam_read)
+};
diff --git a/src/mess/machine/coco3.c b/src/mess/machine/coco3.c
new file mode 100644
index 00000000000..b0eaefd0086
--- /dev/null
+++ b/src/mess/machine/coco3.c
@@ -0,0 +1,181 @@
+/***************************************************************************
+
+ coco3.c
+
+ TRS-80 Radio Shack Color Computer 3
+
+ Functions to emulate general aspects of the machine (RAM, ROM, interrupts,
+ I/O ports)
+
+ The Dragon/CoCo2 have two PIAs. These PIAs can trigger interrupts. PIA0
+ is set up to trigger IRQ on the CPU, and PIA1 can trigger FIRQ. Each PIA
+ has two output lines, and an interrupt will be triggered if either of these
+ lines are asserted.
+
+ ----- IRQ
+ 6809 |-<----------- PIA0
+ |
+ |
+ |
+ |
+ |
+ |-<----------- PIA1
+ -----
+
+ The CoCo 3 still supports these interrupts, but the GIME can chose whether
+ "old school" interrupts are generated, or the new ones generated by the GIME
+
+ ----- IRQ
+ 6809 |-<----------- PIA0
+ | | ------
+ | -<-------<-------| |
+ | |GIME|
+ | -<-------<-------| |
+ | FIRQ | ------
+ |-<----------- PIA1
+ -----
+
+ In an email discussion with JK, he informs me that when GIME interrupts are
+ enabled, this actually does not prevent PIA interrupts. Apparently JeffV's
+ CoCo 3 emulator did not handle this properly.
+
+***************************************************************************/
+
+#include "includes/coco3.h"
+
+
+
+//-------------------------------------------------
+// ctor
+//-------------------------------------------------
+
+coco3_state::coco3_state(const machine_config &mconfig, device_type type, const char *tag)
+ : coco_state(mconfig, type, tag),
+ m_gime(*this, GIME_TAG)
+{
+}
+
+
+
+//-------------------------------------------------
+// ff20_write
+//-------------------------------------------------
+
+WRITE8_MEMBER( coco3_state::ff20_write )
+{
+ coco_state::ff20_write(space, offset, data, mem_mask);
+
+ if (offset == 0x02)
+ m_gime->ff22_write(data);
+}
+
+
+
+//-------------------------------------------------
+// ff40_read
+//-------------------------------------------------
+
+READ8_MEMBER( coco3_state::ff40_read )
+{
+ UINT8 result = 0x00;
+ if (m_gime->spare_chip_select_enabled())
+ result = coco_state::ff40_read(space, offset, mem_mask);
+ return result;
+}
+
+
+
+//-------------------------------------------------
+// ff40_write
+//-------------------------------------------------
+
+WRITE8_MEMBER( coco3_state::ff40_write )
+{
+ if (m_gime->spare_chip_select_enabled())
+ coco_state::ff40_write(space, offset, data, mem_mask);
+}
+
+
+
+//-------------------------------------------------
+// firq_get_line
+//-------------------------------------------------
+
+bool coco3_state::firq_get_line(void)
+{
+ return coco_state::firq_get_line() || m_gime->firq_r();
+}
+
+
+
+//-------------------------------------------------
+// irq_get_line
+//-------------------------------------------------
+
+bool coco3_state::irq_get_line(void)
+{
+ return coco_state::irq_get_line() || m_gime->irq_r();
+}
+
+
+
+//-------------------------------------------------
+// update_keyboard_input
+//-------------------------------------------------
+
+void coco3_state::update_keyboard_input(UINT8 value, UINT8 z)
+{
+ coco_state::update_keyboard_input(value, z);
+ m_gime->set_il1(value == 0xFF);
+}
+
+
+
+//-------------------------------------------------
+// cart_w
+//-------------------------------------------------
+
+void coco3_state::cart_w(bool state)
+{
+ coco_state::cart_w(state);
+ m_gime->set_il0(state);
+}
+
+
+
+//-------------------------------------------------
+// update_cart_base
+//-------------------------------------------------
+
+void coco3_state::update_cart_base(UINT8 *cart_base)
+{
+ m_gime->update_cart_rom();
+}
+
+
+
+//-------------------------------------------------
+// screen_update
+//-------------------------------------------------
+
+UINT32 coco3_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ bool result;
+ if (!strcmp(screen.tag(), ":" COMPOSITE_SCREEN_TAG))
+ {
+ /* composite screen */
+ result = m_gime->update_composite(bitmap, cliprect);
+ }
+ else if (!strcmp(screen.tag(), ":" RGB_SCREEN_TAG))
+ {
+ /* rgb screen */
+ result = m_gime->update_rgb(bitmap, cliprect);
+ }
+ else
+ {
+ fatalerror("Called screen_update() with invalid tag '%s'", screen.tag());
+ }
+ return result;
+}
+
+
diff --git a/src/mess/machine/coco_232.c b/src/mess/machine/coco_232.c
new file mode 100644
index 00000000000..7ff00e21bba
--- /dev/null
+++ b/src/mess/machine/coco_232.c
@@ -0,0 +1,89 @@
+/***************************************************************************
+
+ 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_ACIA6551_ADD(UART_TAG)
+MACHINE_CONFIG_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type COCO_232 = &device_creator<coco_232_device>;
+
+//**************************************************************************
+// 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),
+ 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/mess/machine/coco_232.h b/src/mess/machine/coco_232.h
new file mode 100644
index 00000000000..cb7e3a7674a
--- /dev/null
+++ b/src/mess/machine/coco_232.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#ifndef __COCO_232_H__
+#define __COCO_232_H__
+
+#include "emu.h"
+#include "machine/cococart.h"
+#include "machine/6551acia.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 void device_config_complete() { m_shortname = "coco_232"; }
+ virtual DECLARE_READ8_MEMBER(read);
+ virtual DECLARE_WRITE8_MEMBER(write);
+private:
+ // internal state
+ required_device<acia6551_device> m_uart;
+};
+
+
+// device type definition
+extern const device_type COCO_232;
+
+#endif /* __COCO_232_H__ */
diff --git a/src/mess/machine/coco_fdc.c b/src/mess/machine/coco_fdc.c
new file mode 100644
index 00000000000..12cd073d604
--- /dev/null
+++ b/src/mess/machine/coco_fdc.c
@@ -0,0 +1,733 @@
+/*********************************************************************
+
+ 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 "machine/wd17xx.h"
+#include "machine/ds1315.h"
+#include "imagedev/flopdrv.h"
+#include "formats/coco_dsk.h"
+
+
+/***************************************************************************
+ PARAMETERS
+***************************************************************************/
+
+#define LOG_FDC 0
+#define WD_TAG "wd17xx"
+#define DISTO_TAG "disto"
+#define CLOUD9_TAG "cloud9"
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/***************************************************************************
+ LOCAL VARIABLES
+***************************************************************************/
+
+static const floppy_interface coco_floppy_interface =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ FLOPPY_STANDARD_5_25_DSHD,
+ LEGACY_FLOPPY_OPTIONS_NAME(coco),
+ NULL,
+ NULL
+};
+
+
+/***************************************************************************
+ 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
+-------------------------------------------------*/
+
+static WRITE_LINE_DEVICE_HANDLER( fdc_intrq_w )
+{
+ coco_fdc_device *fdc = dynamic_cast<coco_fdc_device *>(device->owner());
+ fdc->set_intrq(state);
+ fdc->update_lines();
+}
+
+
+/*-------------------------------------------------
+ fdc_drq_w - callback from the FDC
+-------------------------------------------------*/
+
+static WRITE_LINE_DEVICE_HANDLER( fdc_drq_w )
+{
+ coco_fdc_device *fdc = dynamic_cast<coco_fdc_device *>(device->owner());
+ fdc->set_drq(state);
+ fdc->update_lines();
+}
+
+
+//**************************************************************************
+// COCO FDC
+//**************************************************************************
+
+static const wd17xx_interface coco_wd17xx_interface =
+{
+ DEVCB_NULL,
+ DEVCB_LINE(fdc_intrq_w),
+ DEVCB_LINE(fdc_drq_w),
+ {FLOPPY_0,FLOPPY_1,FLOPPY_2,FLOPPY_3}
+};
+
+static MSM6242_INTERFACE( coco_fdc_rtc_intf )
+{
+ DEVCB_NULL
+};
+
+static MACHINE_CONFIG_FRAGMENT(coco_fdc)
+ MCFG_WD1773_ADD(WD_TAG, coco_wd17xx_interface)
+ MCFG_MSM6242_ADD(DISTO_TAG, coco_fdc_rtc_intf)
+ MCFG_DS1315_ADD(CLOUD9_TAG)
+
+ MCFG_LEGACY_FLOPPY_4_DRIVES_ADD(coco_floppy_interface)
+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>;
+
+//-------------------------------------------------
+// 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)
+ : device_t(mconfig, type, name, tag, owner, clock),
+ device_cococart_interface( mconfig, *this )
+{
+}
+
+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),
+ device_cococart_interface( mconfig, *this )
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void coco_fdc_device::device_start()
+{
+ m_owner = dynamic_cast<cococart_slot_device *>(owner());
+ m_drq = 1;
+ m_disto_msm6242 = subdevice<msm6242_device>(DISTO_TAG);
+ m_ds1315 = subdevice(CLOUD9_TAG);
+ m_wd17xx = subdevice(WD_TAG);
+ m_dskreg = 0x00;
+ m_intrq = 0;
+ m_msm6242_rtc_address = 0;
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void coco_fdc_device::device_config_complete()
+{
+ m_shortname = "coco_fdc";
+}
+//-------------------------------------------------
+// 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;
+
+ device_t *floppy[4];
+
+ floppy[0] = subdevice(FLOPPY_0);
+ floppy[1] = subdevice(FLOPPY_1);
+ floppy[2] = subdevice(FLOPPY_2);
+ floppy[3] = subdevice(FLOPPY_3);
+
+ for (int i = 0; i < 4; i++)
+ {
+ floppy_mon_w(floppy[i], i == drive ? CLEAR_LINE : ASSERT_LINE);
+ }
+
+ head = ((data & 0x40) && (drive != 3)) ? 1 : 0;
+
+ m_dskreg = data;
+
+ update_lines();
+
+ wd17xx_set_drive(m_wd17xx, drive);
+ wd17xx_set_side(m_wd17xx, head);
+ wd17xx_dden_w(m_wd17xx, !BIT(m_dskreg, 5));
+}
+
+/*-------------------------------------------------
+ read
+-------------------------------------------------*/
+
+READ8_MEMBER(coco_fdc_device::read)
+{
+ UINT8 result = 0;
+
+ switch(offset & 0xEF)
+ {
+ case 8:
+ result = wd17xx_status_r(m_wd17xx, 0);
+ break;
+ case 9:
+ result = wd17xx_track_r(m_wd17xx, 0);
+ break;
+ case 10:
+ result = wd17xx_sector_r(m_wd17xx, 0);
+ break;
+ case 11:
+ result = wd17xx_data_r(m_wd17xx, 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)
+ ds1315_r_0(m_ds1315, offset);
+ break;
+
+ case 0x39: /* FF79 */
+ if (real_time_clock() == RTC_CLOUD9)
+ ds1315_r_1(m_ds1315, offset);
+ break;
+
+ case 0x3C: /* FF7C */
+ if (real_time_clock() == RTC_CLOUD9)
+ result = ds1315_r_data(m_ds1315, 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:
+ wd17xx_command_w(m_wd17xx, 0, data);
+ break;
+ case 9:
+ wd17xx_track_w(m_wd17xx, 0, data);
+ break;
+ case 10:
+ wd17xx_sector_w(m_wd17xx, 0, data);
+ break;
+ case 11:
+ wd17xx_data_w(m_wd17xx, 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(WD_TAG, coco_wd17xx_interface)
+ MCFG_LEGACY_FLOPPY_4_DRIVES_ADD(coco_floppy_interface)
+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>;
+
+//-------------------------------------------------
+// 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)
+ : coco_fdc_device(mconfig, type, name, tag, owner, clock)
+{
+}
+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)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void dragon_fdc_device::device_start()
+{
+ m_owner = dynamic_cast<cococart_slot_device *>(owner());
+ m_drq = 0;
+ m_wd17xx = subdevice(WD_TAG);
+ m_dskreg = 0x00;
+ m_intrq = 0;
+ m_msm6242_rtc_address = 0;
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void dragon_fdc_device::device_config_complete()
+{
+ m_shortname = "dragon_fdc";
+}
+//-------------------------------------------------
+// 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);
+ }
+
+ if (data & 0x04)
+ wd17xx_set_drive(m_wd17xx, data & 0x03);
+
+ wd17xx_dden_w(m_wd17xx, BIT(data, 3));
+ m_dskreg = data;
+}
+
+
+
+/*-------------------------------------------------
+ read
+-------------------------------------------------*/
+
+READ8_MEMBER(dragon_fdc_device::read)
+{
+ UINT8 result = 0;
+ switch(offset & 0xEF)
+ {
+ case 0:
+ result = wd17xx_status_r(m_wd17xx, 0);
+ break;
+ case 1:
+ result = wd17xx_track_r(m_wd17xx, 0);
+ break;
+ case 2:
+ result = wd17xx_sector_r(m_wd17xx, 0);
+ break;
+ case 3:
+ result = wd17xx_data_r(m_wd17xx, 0);
+ break;
+ }
+ return result;
+}
+
+
+
+/*-------------------------------------------------
+ write
+-------------------------------------------------*/
+
+WRITE8_MEMBER(dragon_fdc_device::write)
+{
+ switch(offset & 0xEF)
+ {
+ case 0:
+ wd17xx_command_w(m_wd17xx, 0, data);
+
+ /* disk head is encoded in the command byte */
+ /* Only for type 3 & 4 commands */
+ if (data & 0x80)
+ wd17xx_set_side(m_wd17xx, (data & 0x02) ? 1 : 0);
+ break;
+ case 1:
+ wd17xx_track_w(m_wd17xx, 0, data);
+ break;
+ case 2:
+ wd17xx_sector_w(m_wd17xx, 0, data);
+ break;
+ case 3:
+ wd17xx_data_w(m_wd17xx, 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>;
+
+//-------------------------------------------------
+// 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)
+{
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void sdtandy_fdc_device::device_config_complete()
+{
+ m_shortname = "sdtandy_fdc";
+}
+
+//-------------------------------------------------
+// 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>;
+
+//-------------------------------------------------
+// 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)
+{
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void coco_fdc_v11_device::device_config_complete()
+{
+ m_shortname = "coco_fdc_v11";
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *coco_fdc_v11_device::device_rom_region() const
+{
+ return ROM_NAME( coco_fdc_v11 );
+}
+
+//**************************************************************************
+// 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>;
+
+//-------------------------------------------------
+// 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)
+{
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void cp400_fdc_device::device_config_complete()
+{
+ m_shortname = "cp400_fdc";
+}
+
+//-------------------------------------------------
+// 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/mess/machine/coco_fdc.h b/src/mess/machine/coco_fdc.h
new file mode 100644
index 00000000000..c4ec20d921d
--- /dev/null
+++ b/src/mess/machine/coco_fdc.h
@@ -0,0 +1,162 @@
+#pragma once
+
+#ifndef __COCO_FDC_H__
+#define __COCO_FDC_H__
+
+#include "emu.h"
+#include "machine/cococart.h"
+#include "machine/msm6242.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> coco_rtc_type_t
+
+typedef enum
+{
+ RTC_DISTO = 0x00,
+ RTC_CLOUD9 = 0x01,
+
+ RTC_NONE = 0xFF
+} coco_rtc_type_t;
+
+// ======================> 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);
+
+ // 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; }
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_config_complete();
+ 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;
+
+ device_t *m_wd17xx; /* WD17xx */
+ device_t *m_ds1315; /* DS1315 */
+
+ /* Disto RTC */
+ msm6242_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;
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+};
+
+
+// device type definition
+extern const device_type COCO_FDC_V11;
+
+// ======================> 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;
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+};
+
+
+// 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);
+
+ // 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 void device_config_complete();
+ 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;
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+};
+
+
+// device type definition
+extern const device_type SDTANDY_FDC;
+
+#endif /* __COCO_FDC_H__ */
diff --git a/src/mess/machine/coco_multi.c b/src/mess/machine/coco_multi.c
new file mode 100644
index 00000000000..3d18754f766
--- /dev/null
+++ b/src/mess/machine/coco_multi.c
@@ -0,0 +1,266 @@
+/***************************************************************************
+
+ 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("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_DEVICE_HANDLER(multi_cart_w)
+{
+ cococart_slot_device *cart = dynamic_cast<cococart_slot_device *>(device->owner()->owner());
+ cart->m_cart_callback.writeline(device,state);
+}
+
+WRITE_LINE_DEVICE_HANDLER(multi_nmi_w)
+{
+ cococart_slot_device *cart = dynamic_cast<cococart_slot_device *>(device->owner()->owner());
+ cart->m_nmi_callback.writeline(device,state);
+}
+
+WRITE_LINE_DEVICE_HANDLER(multi_halt_w)
+{
+ cococart_slot_device *cart = dynamic_cast<cococart_slot_device *>(device->owner()->owner());
+ cart->m_halt_callback.writeline(device,state);
+}
+
+static const cococart_interface multi_cococart_interface =
+{
+ DEVCB_LINE(multi_cart_w),
+ DEVCB_LINE(multi_nmi_w),
+ DEVCB_LINE(multi_halt_w)
+};
+
+static MACHINE_CONFIG_FRAGMENT(coco_multi)
+ MCFG_COCO_CARTRIDGE_ADD(SLOT1_TAG, multi_cococart_interface, coco_cart_slot1_3, NULL, NULL)
+ MCFG_COCO_CARTRIDGE_ADD(SLOT2_TAG, multi_cococart_interface, coco_cart_slot1_3, NULL, NULL)
+ MCFG_COCO_CARTRIDGE_ADD(SLOT3_TAG, multi_cococart_interface, coco_cart_slot1_3, NULL, NULL)
+ MCFG_COCO_CARTRIDGE_ADD(SLOT4_TAG, multi_cococart_interface, coco_cart_slot4, "fdcv11", NULL)
+MACHINE_CONFIG_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type COCO_MULTIPAK = &device_creator<coco_multipak_device>;
+
+
+
+//**************************************************************************
+// 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),
+ device_cococart_interface( mconfig, *this )
+{
+}
+
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void coco_multipak_device::device_start()
+{
+ // identify slots
+ m_slots[0] = dynamic_cast<cococart_slot_device *>(subdevice(SLOT1_TAG));
+ m_slots[1] = dynamic_cast<cococart_slot_device *>(subdevice(SLOT2_TAG));
+ m_slots[2] = dynamic_cast<cococart_slot_device *>(subdevice(SLOT3_TAG));
+ m_slots[3] = dynamic_cast<cococart_slot_device *>(subdevice(SLOT4_TAG));
+ m_owner = dynamic_cast<cococart_slot_device *>(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/mess/machine/coco_multi.h b/src/mess/machine/coco_multi.h
new file mode 100644
index 00000000000..16c1a167bac
--- /dev/null
+++ b/src/mess/machine/coco_multi.h
@@ -0,0 +1,65 @@
+/***************************************************************************
+
+ coco_multi.h
+
+ Multi-Pak interface emulation
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __COCO_MULTI_H__
+#define __COCO_MULTI_H__
+
+#include "emu.h"
+#include "machine/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();
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "coco_multipak"; }
+ 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
+ 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/mess/machine/coco_orch90.c b/src/mess/machine/coco_orch90.c
new file mode 100644
index 00000000000..127789addee
--- /dev/null
+++ b/src/mess/machine/coco_orch90.c
@@ -0,0 +1,83 @@
+/***************************************************************************
+
+ 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<coco_orch90_device>;
+
+//**************************************************************************
+// 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),
+ device_cococart_interface( mconfig, *this )
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void coco_orch90_device::device_start()
+{
+ m_left_dac = subdevice<dac_device>("dac_left");
+ m_right_dac = subdevice<dac_device>("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/mess/machine/coco_orch90.h b/src/mess/machine/coco_orch90.h
new file mode 100644
index 00000000000..7aeaef9364f
--- /dev/null
+++ b/src/mess/machine/coco_orch90.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#ifndef __COCO_ORCH90_H__
+#define __COCO_ORCH90_H__
+
+#include "emu.h"
+#include "sound/dac.h"
+#include "machine/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 void device_config_complete() { m_shortname = "coco_orch90"; }
+ 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/mess/machine/coco_pak.c b/src/mess/machine/coco_pak.c
new file mode 100644
index 00000000000..c1db2997905
--- /dev/null
+++ b/src/mess/machine/coco_pak.c
@@ -0,0 +1,199 @@
+/***************************************************************************
+
+ coco_pak.c
+
+ Code for emulating standard CoCo cartridges
+
+***************************************************************************/
+
+#include "emu.h"
+#include "coco_pak.h"
+#include "includes/coco.h"
+#include "imagedev/cartslot.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)
+ ROM_CART_LOAD(CARTSLOT_TAG, 0x0000, 0x8000, ROM_OPTIONAL | ROM_MIRROR)
+ROM_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type COCO_PAK = &device_creator<coco_pak_device>;
+
+//**************************************************************************
+// 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)
+ : device_t(mconfig, type, name, tag, owner, clock),
+ 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),
+ device_cococart_interface( mconfig, *this )
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void coco_pak_device::device_start()
+{
+ m_cart = dynamic_cast<device_image_interface *>(owner());
+ m_owner = dynamic_cast<cococart_slot_device *>(owner());
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void coco_pak_device::device_config_complete()
+{
+ m_shortname = "cocopak";
+}
+//-------------------------------------------------
+// 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<coco_pak_banked_device>;
+
+//**************************************************************************
+// 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)
+{
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void coco_pak_banked_device::device_config_complete()
+{
+ m_shortname = "cocopak_banked";
+}
+
+/*-------------------------------------------------
+ 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/mess/machine/coco_pak.h b/src/mess/machine/coco_pak.h
new file mode 100644
index 00000000000..42f2add7999
--- /dev/null
+++ b/src/mess/machine/coco_pak.h
@@ -0,0 +1,65 @@
+#pragma once
+
+#ifndef __COCO_PAK_H__
+#define __COCO_PAK_H__
+
+#include "emu.h"
+#include "machine/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);
+
+ // 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();
+ virtual void device_config_complete();
+
+ // 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 void device_config_complete();
+ 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/mess/machine/coco_vhd.c b/src/mess/machine/coco_vhd.c
new file mode 100644
index 00000000000..fe4ade801b0
--- /dev/null
+++ b/src/mess/machine/coco_vhd.c
@@ -0,0 +1,280 @@
+/***************************************************************************
+
+ coco_vhd.c
+
+ Color Computer Virtual Hard Drives
+
+****************************************************************************
+
+ Technical specs on the Virtual Hard Disk interface
+
+ Address Description
+ ------- -----------
+ FF80 Logical record number (high byte)
+ FF81 Logical record number (middle byte)
+ FF82 Logical record number (low byte)
+ FF83 Command/status register
+ FF84 Buffer address (high byte)
+ FF85 Buffer address (low byte)
+
+ Set the other registers, and then issue a command to FF83 as follows:
+
+ 0 = read 256-byte sector at LRN
+ 1 = write 256-byte sector at LRN
+ 2 = flush write cache (Closes and then opens the image file)
+
+ Error values:
+
+ 0 = no error
+ -1 = power-on state (before the first command is received)
+ -2 = invalid command
+ 2 = VHD image does not exist
+ 4 = Unable to open VHD image file
+ 5 = access denied (may not be able to write to VHD image)
+
+ IMPORTANT: The I/O buffer must NOT cross an 8K MMU bank boundary.
+
+ ***************************************************************************/
+
+#include "emu.h"
+#include "coco_vhd.h"
+#include "includes/coco.h"
+#include "machine/ram.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define VERBOSE 1
+
+#define VHDSTATUS_OK 0x00
+#define VHDSTATUS_NO_VHD_ATTACHED 0x02
+#define VHDSTATUS_ACCESS_DENIED 0x05
+#define VHDSTATUS_UNKNOWN_COMMAND 0xFE
+#define VHDSTATUS_POWER_ON_STATE 0xFF
+
+#define VHDCMD_READ 0
+#define VHDCMD_WRITE 1
+#define VHDCMD_FLUSH 2
+
+
+/***************************************************************************
+ CORE IMPLEMENTATION
+***************************************************************************/
+
+const device_type COCO_VHD = &device_creator<coco_vhd_image_device>;
+
+//-------------------------------------------------
+// coco_vhd_image_device - constructor
+//-------------------------------------------------
+
+coco_vhd_image_device::coco_vhd_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, COCO_VHD, "Virtual Hard Disk", tag, owner, clock),
+ device_image_interface(mconfig, *this)
+{
+
+}
+
+//-------------------------------------------------
+// coco_vhd_image_device - destructor
+//-------------------------------------------------
+
+coco_vhd_image_device::~coco_vhd_image_device()
+{
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void coco_vhd_image_device::device_config_complete()
+{
+ // set brief and instance name
+ update_names();
+}
+
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void coco_vhd_image_device::device_start()
+{
+ m_status = VHDSTATUS_NO_VHD_ATTACHED;
+ m_cpu = machine().device<cpu_device>(MAINCPU_TAG);
+ m_cpu_space = m_cpu->space(AS_PROGRAM);
+}
+
+
+
+//-------------------------------------------------
+// call_load
+//-------------------------------------------------
+
+bool coco_vhd_image_device::call_load()
+{
+ m_status = VHDSTATUS_POWER_ON_STATE;
+ m_logical_record_number = 0;
+ m_buffer_address = 0;
+ return IMAGE_INIT_PASS;
+}
+
+
+
+//-------------------------------------------------
+// coco_vhd_readwrite
+//-------------------------------------------------
+
+void coco_vhd_image_device::coco_vhd_readwrite(UINT8 data)
+{
+ int result, i;
+ UINT32 bytes_to_read;
+ UINT32 bytes_to_write;
+ UINT64 seek_position;
+ UINT64 total_size;
+ char buffer[1024];
+
+ /* access the image */
+ if (!exists())
+ {
+ m_status = VHDSTATUS_NO_VHD_ATTACHED;
+ return;
+ }
+
+ /* perform the seek */
+ seek_position = ((UINT64) 256) * m_logical_record_number;
+ total_size = length();
+ result = fseek(MIN(seek_position, total_size), SEEK_SET);
+ if (result < 0)
+ {
+ m_status = VHDSTATUS_ACCESS_DENIED;
+ return;
+ }
+
+ /* expand the disk, if necessary */
+ if (data == VHDCMD_WRITE)
+ {
+ while(total_size < seek_position)
+ {
+ memset(buffer, 0, sizeof(buffer));
+
+ bytes_to_write = (UINT32) MIN(seek_position - total_size, (UINT64) sizeof(buffer));
+ result = fwrite(buffer, bytes_to_write);
+ if (result != bytes_to_write)
+ {
+ m_status = VHDSTATUS_ACCESS_DENIED;
+ return;
+ }
+
+ total_size += bytes_to_write;
+ }
+ }
+
+ switch(data)
+ {
+ case VHDCMD_READ: /* Read sector */
+ memset(buffer, 0, 256);
+ if (total_size > seek_position)
+ {
+ bytes_to_read = (UINT32) MIN((UINT64) 256, total_size - seek_position);
+ result = fread(buffer, bytes_to_read);
+ if (result != bytes_to_read)
+ {
+ m_status = VHDSTATUS_ACCESS_DENIED;
+ return;
+ }
+ }
+
+ /* write the bytes to memory */
+ for (i = 0; i < 256; i++)
+ m_cpu_space->write_byte(m_buffer_address + i, buffer[i]);
+
+ m_status = VHDSTATUS_OK;
+ break;
+
+ case VHDCMD_WRITE: /* Write Sector */
+ /* read the bytes from memory */
+ for (i = 0; i < 256; i++)
+ buffer[i] = m_cpu_space->read_byte(m_buffer_address + i);
+
+ /* and write to disk */
+ result = fwrite(buffer, 256);
+ if (result != 256)
+ {
+ m_status = VHDSTATUS_ACCESS_DENIED;
+ return;
+ }
+
+ m_status = VHDSTATUS_OK;
+ break;
+
+ case VHDCMD_FLUSH: /* Flush file cache */
+ m_status = VHDSTATUS_OK;
+ break;
+
+ default:
+ m_status = VHDSTATUS_UNKNOWN_COMMAND;
+ break;
+ }
+}
+
+
+
+UINT8 coco_vhd_image_device::read(offs_t offset)
+{
+ UINT8 result = 0;
+
+ switch(offset)
+ {
+ case 0xff83 - 0xff80:
+ if (VERBOSE)
+ logerror("vhd: Status read: %d\n", m_status);
+ result = m_status;
+ break;
+ }
+ return result;
+}
+
+
+
+void coco_vhd_image_device::write(offs_t offset, UINT8 data)
+{
+ int pos;
+
+ switch(offset)
+ {
+ case 0xff80 - 0xff80:
+ case 0xff81 - 0xff80:
+ case 0xff82 - 0xff80:
+ pos = ((0xff82 - 0xff80) - offset) * 8;
+ m_logical_record_number &= ~(0xFF << pos);
+ m_logical_record_number += data << pos;
+ if (VERBOSE)
+ logerror("vhd: LRN write: %6.6X\n", m_logical_record_number);
+ break;
+
+ case 0xff83 - 0xff80:
+ coco_vhd_readwrite(data);
+ if (VERBOSE)
+ logerror("vhd: Command: %d\n", data);
+ break;
+
+ case 0xff84 - 0xff80:
+ m_buffer_address &= 0xFFFF00FF;
+ m_buffer_address += data << 8;
+ if (VERBOSE)
+ logerror("vhd: BA write: %X (%2.2X..)\n", m_buffer_address, data);
+ break;
+
+ case 0xff85 - 0xff80:
+ m_buffer_address &= 0xFFFFFF00;
+ m_buffer_address += data;
+ if (VERBOSE)
+ logerror("vhd: BA write: %X (..%2.2X)\n", m_buffer_address, data);
+ break;
+ }
+}
diff --git a/src/mess/machine/coco_vhd.h b/src/mess/machine/coco_vhd.h
new file mode 100644
index 00000000000..4badd7ced5c
--- /dev/null
+++ b/src/mess/machine/coco_vhd.h
@@ -0,0 +1,73 @@
+/***************************************************************************
+
+ coco_vhd.h
+
+ Color Computer Virtual Hard Drives
+
+***************************************************************************/
+
+#ifndef COCOVHD_H
+#define COCOVHD_H
+
+#include "image.h"
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+// ======================> coco_vhd_image_device
+
+class coco_vhd_image_device : public device_t,
+ public device_image_interface
+{
+public:
+ // construction/destruction
+ coco_vhd_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ virtual ~coco_vhd_image_device();
+
+ // image-level overrides
+ virtual bool call_load();
+
+ 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 "vhd"; }
+ virtual const option_guide *create_option_guide() const { return NULL; }
+
+ // specific implementation
+ DECLARE_READ8_MEMBER(read) { return read(offset); }
+ DECLARE_WRITE8_MEMBER(write) { write(offset, data); }
+ UINT8 read(offs_t offset);
+ void write(offs_t offset, UINT8 data);
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+ virtual void device_start();
+
+ void coco_vhd_readwrite(UINT8 data);
+
+private:
+ cpu_device * m_cpu;
+ address_space * m_cpu_space;
+ UINT32 m_logical_record_number;
+ UINT32 m_buffer_address;
+ UINT8 m_status;
+};
+
+// device type definition
+extern const device_type COCO_VHD;
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+#define MCFG_COCO_VHD_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, COCO_VHD, 0) \
+
+#endif /* COCOVHD_H */
diff --git a/src/mess/machine/cococart.c b/src/mess/machine/cococart.c
new file mode 100644
index 00000000000..9e11b8f9b5a
--- /dev/null
+++ b/src/mess/machine/cococart.c
@@ -0,0 +1,477 @@
+/*********************************************************************
+
+ 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<cococart_slot_device>;
+
+
+
+//**************************************************************************
+// 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),
+ device_slot_interface(mconfig, *this),
+ device_image_interface(mconfig, *this)
+{
+}
+
+
+
+//-------------------------------------------------
+// cococart_slot_device - destructor
+//-------------------------------------------------
+
+cococart_slot_device::~cococart_slot_device()
+{
+}
+
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void cococart_slot_device::device_start()
+{
+ for(int i=0; i<TIMER_POOL; i++ )
+ {
+ m_cart_line.timer[i] = machine().scheduler().timer_alloc(FUNC(cart_timer_callback), (void *) this);
+ m_nmi_line.timer[i] = machine().scheduler().timer_alloc(FUNC(nmi_timer_callback), (void *) this);
+ m_halt_line.timer[i] = machine().scheduler().timer_alloc(FUNC(halt_timer_callback), (void *) this);
+ }
+
+ m_cart_line.timer_index = 0;
+ m_cart_line.delay = 0;
+ m_cart_line.value = COCOCART_LINE_VALUE_CLEAR;
+ m_cart_line.q_count = 0;
+ m_cart_line.callback.resolve(m_cart_callback, *this);
+
+ m_nmi_line.timer_index = 0;
+ /* 12 allowed one more instruction to finished after the line is pulled */
+ m_nmi_line.delay = 12;
+ m_nmi_line.value = COCOCART_LINE_VALUE_CLEAR;
+ m_nmi_line.q_count = 0;
+ m_nmi_line.callback.resolve(m_nmi_callback, *this);
+
+ m_halt_line.timer_index = 0;
+ /* 6 allowed one more instruction to finished after the line is pulled */
+ m_halt_line.delay = 6;
+ m_halt_line.value = COCOCART_LINE_VALUE_CLEAR;
+ m_halt_line.q_count = 0;
+ m_halt_line.callback.resolve(m_halt_callback, *this);
+
+ m_cart = dynamic_cast<device_cococart_interface *>(get_card_device());
+}
+
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void cococart_slot_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const cococart_interface *intf = reinterpret_cast<const cococart_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<cococart_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_cart_callback, 0, sizeof(m_cart_callback));
+ memset(&m_nmi_callback, 0, sizeof(m_nmi_callback));
+ memset(&m_halt_callback, 0, sizeof(m_halt_callback));
+ }
+
+ // set brief and instance name
+ update_names();
+}
+
+
+
+//-------------------------------------------------
+// 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");
+ break;
+ }
+ 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);
+ }
+}
+
+
+
+//-------------------------------------------------
+// TIMER_CALLBACK( cart_timer_callback )
+//-------------------------------------------------
+
+TIMER_CALLBACK( cococart_slot_device::cart_timer_callback )
+{
+ cococart_slot_device *device = (cococart_slot_device *) ptr;
+ device->set_line("CART", &device->m_cart_line, (cococart_line_value) param);
+}
+
+
+
+//-------------------------------------------------
+// TIMER_CALLBACK( nmi_timer_callback )
+//-------------------------------------------------
+
+TIMER_CALLBACK( cococart_slot_device::nmi_timer_callback )
+{
+ cococart_slot_device *device = (cococart_slot_device *) ptr;
+ device->set_line("NMI", &device->m_nmi_line, (cococart_line_value) param);
+}
+
+
+//-------------------------------------------------
+// TIMER_CALLBACK( halt_timer_callback )
+//-------------------------------------------------
+
+TIMER_CALLBACK( cococart_slot_device::halt_timer_callback )
+{
+ cococart_slot_device *device = (cococart_slot_device *) ptr;
+ device->set_line("HALT", &device->m_halt_line, (cococart_line_value) param);
+}
+
+
+
+//-------------------------------------------------
+// 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(char *swlist, char *swname, rom_entry *start_entry)
+{
+ load_software_part_region(this, swlist, swname, start_entry );
+ return TRUE;
+}
+
+
+
+//-------------------------------------------------
+// get_default_card_software
+//-------------------------------------------------
+
+const char * cococart_slot_device::get_default_card_software(const machine_config &devlist, emu_options &options)
+{
+ return software_get_default_slot(devlist, options, this, "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/mess/machine/cococart.h b/src/mess/machine/cococart.h
new file mode 100644
index 00000000000..aab37e60bb9
--- /dev/null
+++ b/src/mess/machine/cococart.h
@@ -0,0 +1,174 @@
+/*********************************************************************
+
+ cococart.h
+
+ CoCo/Dragon cartridge management
+
+*********************************************************************/
+
+#ifndef __COCOCART_H__
+#define __COCOCART_H__
+
+#include "image.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 */
+};
+typedef enum _cococart_line cococart_line;
+
+/* 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
+};
+typedef enum _cococart_line_value cococart_line_value;
+
+typedef struct _coco_cartridge_line coco_cartridge_line;
+struct _coco_cartridge_line
+{
+ emu_timer *timer[TIMER_POOL];
+ int timer_index;
+ int delay;
+ cococart_line_value value;
+ int line;
+ int q_count;
+ devcb_resolved_write_line callback;
+};
+
+// ======================> cococart_interface
+
+struct cococart_interface
+{
+ devcb_write_line m_cart_callback;
+ devcb_write_line m_nmi_callback;
+ devcb_write_line m_halt_callback;
+};
+
+// ======================> cococart_base_update_delegate
+
+// direct region update handler
+typedef delegate<void (UINT8 *)> cococart_base_update_delegate;
+
+
+// ======================> cococart_slot_device
+class device_cococart_interface;
+
+class cococart_slot_device : public device_t,
+ public cococart_interface,
+ 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);
+ virtual ~cococart_slot_device();
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_config_complete();
+
+ // image-level overrides
+ virtual bool call_load();
+ virtual bool call_softlist_load(char *swlist, char *swname, 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 const char * get_default_card_software(const machine_config &config, emu_options &options);
+
+ /* 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);
+
+protected:
+ static TIMER_CALLBACK( cart_timer_callback );
+ static TIMER_CALLBACK( nmi_timer_callback );
+ static TIMER_CALLBACK( halt_timer_callback );
+
+ 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);
+
+ // configuration
+ coco_cartridge_line m_cart_line;
+ coco_cartridge_line m_nmi_line;
+ coco_cartridge_line m_halt_line;
+
+ device_cococart_interface *m_cart;
+};
+
+// 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,_config,_slot_intf,_def_slot, _def_inp) \
+ MCFG_DEVICE_ADD(_tag, COCOCART_SLOT, 0) \
+ MCFG_DEVICE_CONFIG(_config) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false)
+
+#define MCFG_COCO_CARTRIDGE_REMOVE(_tag) \
+ MCFG_DEVICE_REMOVE(_tag)
+
+#endif /* __COCOCART_H__ */
diff --git a/src/mess/machine/coleco.c b/src/mess/machine/coleco.c
new file mode 100644
index 00000000000..38e92bbae8b
--- /dev/null
+++ b/src/mess/machine/coleco.c
@@ -0,0 +1,267 @@
+#include "emu.h"
+#include "machine/coleco.h"
+
+UINT8 coleco_scan_paddles(running_machine &machine, UINT8 *joy_status0, UINT8 *joy_status1)
+{
+ UINT8 ctrl_sel = machine.root_device().ioport("CTRLSEL")->read_safe(0);
+
+ /* which controller shall we read? */
+ if ((ctrl_sel & 0x07) == 0x02) // Super Action Controller P1
+ *joy_status0 = machine.root_device().ioport("SAC_SLIDE1")->read_safe(0);
+ else if ((ctrl_sel & 0x07) == 0x03) // Driving Controller P1
+ *joy_status0 = machine.root_device().ioport("DRIV_WHEEL1")->read_safe(0);
+
+ if ((ctrl_sel & 0x70) == 0x20) // Super Action Controller P2
+ *joy_status1 = machine.root_device().ioport("SAC_SLIDE2")->read_safe(0);
+ else if ((ctrl_sel & 0x70) == 0x30) // Driving Controller P2
+ *joy_status1 = machine.root_device().ioport("DRIV_WHEEL2")->read_safe(0);
+
+ /* In principle, even if not supported by any game, I guess we could have two Super
+ Action Controllers plugged into the Roller controller ports. Since I found no info
+ about the behavior of sliders in such a configuration, we overwrite SAC sliders with
+ the Roller trackball inputs and actually use the latter ones, when both are selected. */
+ if (ctrl_sel & 0x80) // Roller controller
+ {
+ *joy_status0 = machine.root_device().ioport("ROLLER_X")->read_safe(0);
+ *joy_status1 = machine.root_device().ioport("ROLLER_Y")->read_safe(0);
+ }
+
+ return *joy_status0 | *joy_status1;
+}
+
+
+UINT8 coleco_paddle_read(running_machine &machine, int port, int joy_mode, UINT8 joy_status)
+{
+ UINT8 ctrl_sel = machine.root_device().ioport("CTRLSEL")->read_safe(0);
+ UINT8 ctrl_extra = ctrl_sel & 0x80;
+ ctrl_sel = ctrl_sel >> (port*4) & 7;
+
+ /* Keypad and fire 1 (SAC Yellow Button) */
+ if (joy_mode == 0)
+ {
+ /* No key pressed by default */
+ UINT8 data = 0x0f;
+ UINT16 ipt = 0xffff;
+
+ if (ctrl_sel == 0) // ColecoVision Controller
+ ipt = machine.root_device().ioport(port ? "STD_KEYPAD2" : "STD_KEYPAD1")->read();
+ else if (ctrl_sel == 2) // Super Action Controller
+ ipt = machine.root_device().ioport(port ? "SAC_KEYPAD2" : "SAC_KEYPAD1")->read();
+
+ /* Numeric pad buttons are not independent on a real ColecoVision, if you push more
+ than one, a real ColecoVision think that it is a third button, so we are going to emulate
+ the right behaviour */
+ /* Super Action Controller additional buttons are read in the same way */
+ if (!(ipt & 0x0001)) data &= 0x0a; /* 0 */
+ if (!(ipt & 0x0002)) data &= 0x0d; /* 1 */
+ if (!(ipt & 0x0004)) data &= 0x07; /* 2 */
+ if (!(ipt & 0x0008)) data &= 0x0c; /* 3 */
+ if (!(ipt & 0x0010)) data &= 0x02; /* 4 */
+ if (!(ipt & 0x0020)) data &= 0x03; /* 5 */
+ if (!(ipt & 0x0040)) data &= 0x0e; /* 6 */
+ if (!(ipt & 0x0080)) data &= 0x05; /* 7 */
+ if (!(ipt & 0x0100)) data &= 0x01; /* 8 */
+ if (!(ipt & 0x0200)) data &= 0x0b; /* 9 */
+ if (!(ipt & 0x0400)) data &= 0x06; /* # */
+ if (!(ipt & 0x0800)) data &= 0x09; /* . */
+ if (!(ipt & 0x1000)) data &= 0x04; /* Blue Action Button */
+ if (!(ipt & 0x2000)) data &= 0x08; /* Purple Action Button */
+
+ return ((ipt & 0x4000) >> 8) | 0x30 | data;
+ }
+ /* Joystick and fire 2 (SAC Red Button) */
+ else
+ {
+ UINT8 data = 0x7f;
+
+ if (ctrl_sel == 0) // ColecoVision Controller
+ data = machine.root_device().ioport(port ? "STD_JOY2" : "STD_JOY1")->read();
+ else if (ctrl_sel == 2) // Super Action Controller
+ data = machine.root_device().ioport(port ? "SAC_JOY2" : "SAC_JOY1")->read();
+ else if (ctrl_sel == 3) // Driving Controller
+ data = machine.root_device().ioport(port ? "DRIV_PEDAL2" : "DRIV_PEDAL1")->read();
+
+ /* If any extra analog contoller enabled */
+ if (ctrl_extra || ctrl_sel == 2 || ctrl_sel == 3)
+ {
+ if (joy_status & 0x80) data ^= 0x30;
+ else if (joy_status) data ^= 0x10;
+ }
+
+ return data & 0x7f;
+ }
+}
+
+
+// ColecoVision Controller
+static INPUT_PORTS_START( ctrl1 )
+ PORT_START("STD_KEYPAD1")
+ PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("0 (pad 1)") PORT_CODE(KEYCODE_0_PAD) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x00)
+ PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("1 (pad 1)") PORT_CODE(KEYCODE_1_PAD) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x00)
+ PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("2 (pad 1)") PORT_CODE(KEYCODE_2_PAD) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x00)
+ PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("3 (pad 1)") PORT_CODE(KEYCODE_3_PAD) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x00)
+ PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("4 (pad 1)") PORT_CODE(KEYCODE_4_PAD) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x00)
+ PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("5 (pad 1)") PORT_CODE(KEYCODE_5_PAD) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x00)
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("6 (pad 1)") PORT_CODE(KEYCODE_6_PAD) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x00)
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("7 (pad 1)") PORT_CODE(KEYCODE_7_PAD) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x00)
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("8 (pad 1)") PORT_CODE(KEYCODE_8_PAD) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x00)
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("9 (pad 1)") PORT_CODE(KEYCODE_9_PAD) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x00)
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("# (pad 1)") PORT_CODE(KEYCODE_MINUS_PAD) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x00)
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME(". (pad 1)") PORT_CODE(KEYCODE_PLUS_PAD) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x00)
+ PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x00)
+ PORT_BIT( 0xb000, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x00)
+
+ PORT_START("STD_JOY1")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x00)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x00)
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x00)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x00)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x00)
+ PORT_BIT( 0xb0, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x00)
+INPUT_PORTS_END
+
+static INPUT_PORTS_START( ctrl2 )
+ PORT_START("STD_KEYPAD2")
+ PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("0 (pad 2)") PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x00)
+ PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("1 (pad 2)") PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x00)
+ PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("2 (pad 2)") PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x00)
+ PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("3 (pad 2)") PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x00)
+ PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("4 (pad 2)") PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x00)
+ PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("5 (pad 2)") PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x00)
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("6 (pad 2)") PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x00)
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("7 (pad 2)") PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x00)
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("8 (pad 2)") PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x00)
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("9 (pad 2)") PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x00)
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("# (pad 2)") PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x00)
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME(". (pad 2)") PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x00)
+ PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x00)
+ PORT_BIT( 0xb000, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x00)
+
+ PORT_START("STD_JOY2")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x00)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x00)
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x00)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x00)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x00)
+ PORT_BIT( 0xb0, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x00)
+INPUT_PORTS_END
+
+
+// Super Action Controller
+static INPUT_PORTS_START( sac1 )
+ PORT_START("SAC_KEYPAD1")
+ PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("0 (SAC pad 1)") PORT_CODE(KEYCODE_0_PAD) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x02)
+ PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("1 (SAC pad 1)") PORT_CODE(KEYCODE_1_PAD) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x02)
+ PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("2 (SAC pad 1)") PORT_CODE(KEYCODE_2_PAD) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x02)
+ PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("3 (SAC pad 1)") PORT_CODE(KEYCODE_3_PAD) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x02)
+ PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("4 (SAC pad 1)") PORT_CODE(KEYCODE_4_PAD) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x02)
+ PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("5 (SAC pad 1)") PORT_CODE(KEYCODE_5_PAD) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x02)
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("6 (SAC pad 1)") PORT_CODE(KEYCODE_6_PAD) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x02)
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("7 (SAC pad 1)") PORT_CODE(KEYCODE_7_PAD) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x02)
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("8 (SAC pad 1)") PORT_CODE(KEYCODE_8_PAD) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x02)
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("9 (SAC pad 1)") PORT_CODE(KEYCODE_9_PAD) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x02)
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("# (SAC pad 1)") PORT_CODE(KEYCODE_MINUS_PAD) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x02)
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME(". (SAC pad 1)") PORT_CODE(KEYCODE_PLUS_PAD) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x02)
+ PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("Blue Action Button P1") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x02)
+ PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("Purple Action Button P1") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x02)
+ PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("Orange Action Button P1") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x02)
+ PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x02)
+
+ PORT_START("SAC_JOY1")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x02)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x02)
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x02)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x02)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("Yellow Action Button P1") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x02)
+ PORT_BIT( 0xb0, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x02)
+
+ PORT_START("SAC_SLIDE1") // SAC P1 slider
+ PORT_BIT( 0xff, 0x00, IPT_DIAL ) PORT_SENSITIVITY(100) PORT_KEYDELTA(25) PORT_CODE_DEC(KEYCODE_J) PORT_CODE_INC(KEYCODE_L) PORT_REVERSE PORT_RESET PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x02)
+INPUT_PORTS_END
+
+static INPUT_PORTS_START( sac2 )
+ PORT_START("SAC_KEYPAD2")
+ PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("0 (SAC pad 2)") PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x20)
+ PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("1 (SAC pad 2)") PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x20)
+ PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("2 (SAC pad 2)") PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x20)
+ PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("3 (SAC pad 2)") PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x20)
+ PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("4 (SAC pad 2)") PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x20)
+ PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("5 (SAC pad 2)") PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x20)
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("6 (SAC pad 2)") PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x20)
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("7 (SAC pad 2)") PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x20)
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("8 (SAC pad 2)") PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x20)
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("9 (SAC pad 2)") PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x20)
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME("# (SAC pad 2)") PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x20)
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_KEYPAD ) PORT_NAME(". (SAC pad 2)") PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x20)
+ PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("Blue Action Button P2") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x20)
+ PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("Purple Action Button P2") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x20)
+ PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("Orange Action Button P2") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x20)
+ PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x20)
+
+ PORT_START("SAC_JOY2")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x20)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x20)
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x20)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x20)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("Yellow Action Button P2") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x20)
+ PORT_BIT( 0xb0, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x20)
+
+ PORT_START("SAC_SLIDE2") // SAC P2 slider
+ PORT_BIT( 0xff, 0x00, IPT_DIAL ) PORT_SENSITIVITY(100) PORT_KEYDELTA(25) PORT_CODE_DEC(KEYCODE_I) PORT_CODE_INC(KEYCODE_K) PORT_RESET PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x20)
+INPUT_PORTS_END
+
+
+// Driving Controller
+static INPUT_PORTS_START( driv1 )
+ PORT_START("DRIV_WHEEL1")
+ PORT_BIT( 0xff, 0x00, IPT_DIAL ) PORT_SENSITIVITY(100) PORT_KEYDELTA(25) PORT_CODE_DEC(KEYCODE_J) PORT_CODE_INC(KEYCODE_L) PORT_REVERSE PORT_RESET PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x03)
+
+ PORT_START("DRIV_PEDAL1")
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x03)
+ PORT_BIT( 0xbf, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("CTRLSEL", 0x07, EQUALS, 0x03)
+INPUT_PORTS_END
+
+static INPUT_PORTS_START( driv2 )
+ PORT_START("DRIV_WHEEL2")
+ PORT_BIT( 0xff, 0x00, IPT_DIAL ) PORT_SENSITIVITY(100) PORT_KEYDELTA(25) PORT_CODE_DEC(KEYCODE_I) PORT_CODE_INC(KEYCODE_K) PORT_RESET PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x30)
+
+ PORT_START("DRIV_PEDAL2")
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x30)
+ PORT_BIT( 0xbf, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("CTRLSEL", 0x70, EQUALS, 0x30)
+INPUT_PORTS_END
+
+
+// Roller Controller
+static INPUT_PORTS_START( roller )
+ PORT_START("ROLLER_X") // Roller Controller X Axis
+ PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X ) PORT_SENSITIVITY(100) PORT_KEYDELTA(25) PORT_CODE_DEC(KEYCODE_J) PORT_CODE_INC(KEYCODE_L) PORT_REVERSE PORT_RESET PORT_CONDITION("CTRLSEL", 0x80, EQUALS, 0x80)
+
+ PORT_START("ROLLER_Y") // Roller Controller Y Axis
+ PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_Y ) PORT_SENSITIVITY(100) PORT_KEYDELTA(25) PORT_CODE_DEC(KEYCODE_I) PORT_CODE_INC(KEYCODE_K) PORT_RESET PORT_CONDITION("CTRLSEL", 0x80, EQUALS, 0x80)
+INPUT_PORTS_END
+
+
+INPUT_PORTS_START( coleco )
+ PORT_START("CTRLSEL") /* Select Controller Type */
+ PORT_CONFNAME( 0x07, 0x00, "Port 1 Controller" )
+ PORT_CONFSETTING( 0x01, DEF_STR( None ) )
+ PORT_CONFSETTING( 0x00, "ColecoVision Controller" )
+ PORT_CONFSETTING( 0x02, "Super Action Controller" )
+ PORT_CONFSETTING( 0x03, "Driving Controller" )
+ PORT_CONFNAME( 0x70, 0x00, "Port 2 Controller" )
+ PORT_CONFSETTING( 0x10, DEF_STR( None ) )
+ PORT_CONFSETTING( 0x00, "ColecoVision Controller" )
+ PORT_CONFSETTING( 0x20, "Super Action Controller" )
+ PORT_CONFSETTING( 0x30, "Driving Controller" )
+ PORT_CONFNAME( 0x80, 0x00, "Extra Controller" )
+ PORT_CONFSETTING( 0x00, DEF_STR( None ) )
+ PORT_CONFSETTING( 0x80, "Roller Controller" )
+
+ PORT_INCLUDE( ctrl1 )
+ PORT_INCLUDE( ctrl2 )
+ PORT_INCLUDE( sac1 )
+ PORT_INCLUDE( sac2 )
+ PORT_INCLUDE( driv1 )
+ PORT_INCLUDE( driv2 )
+ PORT_INCLUDE( roller )
+INPUT_PORTS_END
diff --git a/src/mess/machine/coleco.h b/src/mess/machine/coleco.h
new file mode 100644
index 00000000000..d5d43335ddd
--- /dev/null
+++ b/src/mess/machine/coleco.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#ifndef __COLECO_CONTROLLERS__
+#define __COLECO_CONTROLLERS__
+
+UINT8 coleco_scan_paddles(running_machine &machine, UINT8 *joy_status0, UINT8 *joy_status1);
+UINT8 coleco_paddle_read(running_machine &machine, int port, int joy_mode, UINT8 joy_status);
+
+INPUT_PORTS_EXTERN( coleco );
+
+#endif
diff --git a/src/mess/machine/compis.c b/src/mess/machine/compis.c
new file mode 100644
index 00000000000..770de5df14b
--- /dev/null
+++ b/src/mess/machine/compis.c
@@ -0,0 +1,1404 @@
+/******************************************************************************
+
+ compis.c
+ machine driver
+
+ Per Ola Ingvarsson
+ Tomas Karlsson
+
+ ******************************************************************************/
+
+/*-------------------------------------------------------------------------*/
+/* Include files */
+/*-------------------------------------------------------------------------*/
+
+#include "includes/compis.h"
+
+/*-------------------------------------------------------------------------*/
+/* Defines, constants, and global variables */
+/*-------------------------------------------------------------------------*/
+
+/* CPU 80186 */
+#define LATCH_INTS 1
+#define LOG_PORTS 1
+#define LOG_INTERRUPTS 1
+#define LOG_TIMER 1
+#define LOG_OPTIMIZATION 1
+#define LOG_DMA 1
+#define CPU_RESUME_TRIGGER 7123
+
+/* Keyboard */
+static const UINT8 compis_keyb_codes[6][16] = {
+{0x39, 0x32, 0x29, 0x20, 0x17, 0x0e, 0x05, 0x56, 0x4d, 0x44, 0x08, 0x57, 0x59, 0x4e, 0x43, 0x3a},
+{0x31, 0x28, 0x1f, 0x16, 0x0d, 0x04, 0x55, 0x4c, 0x4f, 0x58, 0x00, 0x07, 0xff, 0x42, 0x3b, 0x30},
+{0x27, 0x1e, 0x15, 0x0c, 0x03, 0x54, 0x06, 0x50, 0x01, 0xfe, 0x38, 0x2f, 0x26, 0x1d, 0x14, 0x0b},
+{0x02, 0x53, 0x4a, 0x48, 0x51, 0xfe, 0xfd, 0xfc, 0x40, 0xfc, 0xfd, 0x0f, 0x18, 0x21, 0x22, 0x34},
+{0x10, 0x11, 0x1a, 0x23, 0x1b, 0x2d, 0x04, 0x0a, 0x13, 0x1c, 0x2a, 0x3c, 0x33, 0x19, 0x46, 0x2b},
+{0x2c, 0x3e, 0x35, 0x12, 0x3f, 0x24, 0x25, 0x37, 0x2e, 0x45, 0x3d, 0x47, 0x36, 0x00, 0x00, 0x00}
+};
+
+enum COMPIS_KEYB_SHIFT
+{
+ KEY_CAPS_LOCK = 0xff,
+ KEY_SHIFT = 0xfe,
+ KEY_SUPER_SHIFT = 0xfd,
+ KEY_CTRL = 0xfc
+};
+
+enum COMPIS_USART_STATES
+{
+ COMPIS_USART_STATUS_TX_READY = 0x01,
+ COMPIS_USART_STATUS_RX_READY = 0x02,
+ COMPIS_USART_STATUS_TX_EMPTY = 0x04
+};
+
+/* Compis interrupt handling */
+enum COMPIS_INTERRUPTS
+{
+ COMPIS_NMI_KEYB = 0x00, /* Default not used */
+ COMPIS_INT_8251_TXRDY = 0x01, /* Default not used */
+ COMPIS_INT_8274 = 0x03
+};
+
+enum COMPIS_INTERRUPT_REQUESTS
+{
+ COMPIS_IRQ_SBX0_INT1 = 0x00,
+ COMPIS_IRQ_SBX0_INT0 = 0x01, /* Default not used */
+ COMPIS_IRQ_8251_RXRDY = 0x02,
+ COMPIS_IRQ_80150_SYSTICK = 0x03, /* Default not used */
+ COMPIS_IRQ_ACK_J7 = 0x04,
+ COMPIS_IRQ_SBX1_INT1 = 0x05, /* Default not used */
+ COMPIS_IRQ_SBX1_INT0 = 0x06, /* Default not used */
+ COMPIS_IRQ_80150_DELAY = 0x07
+};
+
+/* Main emulation */
+
+
+/*-------------------------------------------------------------------------*/
+/* Name: compis_irq_set */
+/* Desc: IRQ - Issue an interrupt request */
+/*-------------------------------------------------------------------------*/
+#ifdef UNUSED_FUNCTION
+void compis_irq_set(UINT8 irq)
+{
+ cputag_set_input_line_vector(machine, "maincpu", 0, irq);
+ cputag_set_input_line(machine, "maincpu", 0, HOLD_LINE);
+}
+#endif
+
+
+/*-------------------------------------------------------------------------*/
+/* Keyboard */
+/*-------------------------------------------------------------------------*/
+static void compis_keyb_update(running_machine &machine)
+{
+ compis_state *state = machine.driver_data<compis_state>();
+ UINT8 key_code;
+ UINT8 key_status;
+ UINT8 irow;
+ UINT8 icol;
+ UINT16 data;
+ UINT16 ibit;
+ static const char *const rownames[] = { "ROW0", "ROW1", "ROW2", "ROW3", "ROW4", "ROW5" };
+
+ key_code = 0;
+ key_status = 0x80;
+
+ for (irow = 0; irow < 6; irow++)
+ {
+ data = machine.root_device().ioport(rownames[irow])->read();
+ if (data != 0)
+ {
+ ibit = 1;
+ for (icol = 0; icol < 16; icol++)
+ {
+ if (data & ibit)
+ {
+ switch(compis_keyb_codes[irow][icol])
+ {
+ case KEY_SHIFT:
+ key_status |= 0x01;
+ break;
+ case KEY_CAPS_LOCK:
+ key_status |= 0x02;
+ break;
+ case KEY_CTRL:
+ key_status |= 0x04;
+ break;
+ case KEY_SUPER_SHIFT:
+ key_status |= 0x08;
+ break;
+ default:
+ key_code = compis_keyb_codes[irow][icol];
+ }
+ }
+ ibit <<= 1;
+ }
+ }
+ }
+ if (key_code != 0)
+ {
+ state->m_compis.keyboard.key_code = key_code;
+ state->m_compis.keyboard.key_status = key_status;
+ state->m_compis.usart.status |= COMPIS_USART_STATUS_RX_READY;
+ state->m_compis.usart.bytes_sent = 0;
+// compis_osp_pic_irq(COMPIS_IRQ_8251_RXRDY);
+ }
+}
+
+static void compis_keyb_init(compis_state *state)
+{
+ state->m_compis.keyboard.key_code = 0;
+ state->m_compis.keyboard.key_status = 0x80;
+ state->m_compis.usart.status = 0;
+ state->m_compis.usart.bytes_sent = 0;
+}
+
+/*-------------------------------------------------------------------------*/
+/* FDC iSBX-218A */
+/*-------------------------------------------------------------------------*/
+static void compis_fdc_reset(running_machine &machine)
+{
+ device_t *fdc = machine.device("upd765");
+
+ upd765_reset(fdc, 0);
+
+ /* set FDC at reset */
+ upd765_reset_w(fdc, 1);
+}
+
+void compis_state::compis_fdc_tc(int state)
+{
+ /* Terminal count if iSBX-218A has DMA enabled */
+ if (ioport("DSW1")->read())
+ {
+ upd765_tc_w(m_fdc, state);
+ }
+}
+
+WRITE_LINE_MEMBER( compis_state::compis_fdc_int )
+{
+ /* No interrupt requests if iSBX-218A has DMA enabled */
+ if (!ioport("DSW1")->read() && state)
+ {
+ if (m_8259m)
+ {
+ pic8259_ir0_w(m_8259m, 1);
+ pic8259_ir0_w(m_8259m, 0);
+ }
+ }
+}
+
+WRITE_LINE_MEMBER( compis_state::compis_fdc_dma_drq )
+{
+ /* DMA requst if iSBX-218A has DMA enabled */
+ if (ioport("DSW1")->read() && state)
+ {
+ //compis_dma_drq(state, read);
+ }
+}
+
+const upd765_interface compis_fdc_interface =
+{
+ DEVCB_DRIVER_LINE_MEMBER(compis_state, compis_fdc_int),
+ DEVCB_DRIVER_LINE_MEMBER(compis_state, compis_fdc_dma_drq),
+ NULL,
+ UPD765_RDY_PIN_CONNECTED,
+ {FLOPPY_0, FLOPPY_1, NULL, NULL}
+};
+
+READ16_MEMBER( compis_state::compis_fdc_dack_r )
+{
+ UINT16 data;
+ data = 0xffff;
+ /* DMA acknowledge if iSBX-218A has DMA enabled */
+ if (ioport("DSW1")->read())
+ {
+ data = upd765_dack_r(m_fdc, 0);
+ }
+
+ return data;
+}
+
+WRITE8_MEMBER( compis_state::compis_fdc_w )
+{
+ switch(offset)
+ {
+ case 2:
+ upd765_data_w(m_fdc, 0, data);
+ break;
+ default:
+ printf("FDC Unknown Port Write %04X = %04X\n", offset, data);
+ break;
+ }
+}
+
+READ8_MEMBER( compis_state::compis_fdc_r )
+{
+ UINT16 data;
+ data = 0xffff;
+ switch(offset)
+ {
+ case 0:
+ data = upd765_status_r(m_fdc, 0);
+ break;
+ case 2:
+ data = upd765_data_r(m_fdc, 0);
+ break;
+ default:
+ printf("FDC Unknown Port Read %04X\n", offset);
+ break;
+ }
+
+ return data;
+}
+
+
+
+/*-------------------------------------------------------------------------*/
+/* Bit 0: J5-4 */
+/* Bit 1: J5-5 */
+/* Bit 2: J6-3 Cassette read */
+/* Bit 3: J2-6 DSR / S8-4 Test */
+/* Bit 4: J4-6 DSR / S8-3 Test */
+/* Bit 5: J7-11 Centronics BUSY */
+/* Bit 6: J7-13 Centronics SELECT */
+/* Bit 7: Tmr0 */
+/*-------------------------------------------------------------------------*/
+READ8_MEMBER( compis_state::compis_ppi_port_b_r )
+{
+ UINT8 data;
+
+ /* DIP switch - Test mode */
+ data = ioport("DSW0")->read();
+
+ /* Centronics busy */
+ data |= m_centronics->busy_r() << 5;
+ data |= m_centronics->vcc_r() << 6;
+
+ return data;
+}
+
+/*-------------------------------------------------------------------------*/
+/* Bit 0: J5-1 */
+/* Bit 1: J5-2 */
+/* Bit 2: Select: 1=time measure, DSR from J2/J4 pin 6. 0=read cassette */
+/* Bit 3: Datex: Tristate datex output (low) */
+/* Bit 4: V2-5 Floppy motor on/off */
+/* Bit 5: J7-1 Centronics STROBE */
+/* Bit 6: V2-4 Floppy Soft reset */
+/* Bit 7: V2-3 Floppy Terminal count */
+/*-------------------------------------------------------------------------*/
+WRITE8_MEMBER( compis_state::compis_ppi_port_c_w )
+{
+ /* Centronics Strobe */
+ m_centronics->strobe_w(BIT(data, 5));
+
+ /* FDC Reset */
+ if (BIT(data, 6))
+ compis_fdc_reset(machine());
+
+ /* FDC Terminal count */
+ compis_fdc_tc(BIT(data, 7));
+}
+
+I8255A_INTERFACE( compis_ppi_interface )
+{
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER("centronics", centronics_device, write),
+ DEVCB_DRIVER_MEMBER(compis_state, compis_ppi_port_b_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DRIVER_MEMBER(compis_state, compis_ppi_port_c_w)
+};
+
+
+/*-------------------------------------------------------------------------*/
+/* PIT 8253 */
+/*-------------------------------------------------------------------------*/
+
+const struct pit8253_config compis_pit8253_config =
+{
+ {
+ /* Timer0 */
+ {4770000/4, DEVCB_NULL, DEVCB_NULL },
+ /* Timer1 */
+ {4770000/4, DEVCB_NULL, DEVCB_NULL },
+ /* Timer2 */
+ {4770000/4, DEVCB_NULL, DEVCB_NULL }
+ }
+};
+
+const struct pit8253_config compis_pit8254_config =
+{
+ {
+ /* Timer0 */
+ {4770000/4, DEVCB_NULL, DEVCB_NULL },
+ /* Timer1 */
+ {4770000/4, DEVCB_NULL, DEVCB_NULL },
+ /* Timer2 */
+ {4770000/4, DEVCB_NULL, DEVCB_NULL }
+ }
+};
+
+/*-------------------------------------------------------------------------*/
+/* OSP PIT 8254 */
+/*-------------------------------------------------------------------------*/
+
+READ16_MEMBER( compis_state::compis_osp_pit_r )
+{
+ return pit8253_r(m_8254, offset);
+}
+
+WRITE16_MEMBER( compis_state::compis_osp_pit_w )
+{
+ pit8253_w(m_8254, offset, data);
+}
+
+
+/*-------------------------------------------------------------------------*/
+/* USART 8251 */
+/*-------------------------------------------------------------------------*/
+WRITE_LINE_MEMBER( compis_state::compis_usart_rxready )
+{
+#if 0
+ if (state)
+ compis_pic_irq(COMPIS_IRQ_8251_RXRDY);
+#endif
+}
+
+const i8251_interface compis_usart_interface=
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DRIVER_LINE_MEMBER(compis_state, compis_usart_rxready),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+READ16_MEMBER( compis_state::compis_usart_r )
+{
+ return m_uart->data_r(space, offset);
+}
+
+WRITE16_MEMBER( compis_state::compis_usart_w )
+{
+ switch (offset)
+ {
+ case 0x00:
+ m_uart->data_w(space, 0, data);
+ break;
+ case 0x01:
+ m_uart->control_w(space, 0, data);
+ break;
+ default:
+ logerror("USART Unknown Port Write %04X = %04X\n", offset, data);
+ break;
+ }
+}
+
+/*************************************
+ *
+ * 80186 interrupt controller
+ *
+ *************************************/
+static IRQ_CALLBACK(int_callback)
+{
+ compis_state *state = device->machine().driver_data<compis_state>();
+ if (LOG_INTERRUPTS)
+ logerror("(%f) **** Acknowledged interrupt vector %02X\n", device->machine().time().as_double(), state->m_i186.intr.poll_status & 0x1f);
+
+ /* clear the interrupt */
+ device_set_input_line(device, 0, CLEAR_LINE);
+ state->m_i186.intr.pending = 0;
+
+ /* clear the request and set the in-service bit */
+#if LATCH_INTS
+ state->m_i186.intr.request &= ~state->m_i186.intr.ack_mask;
+#else
+ state->m_i186.intr.request &= ~(state->m_i186.intr.ack_mask & 0x0f);
+#endif
+ state->m_i186.intr.in_service |= state->m_i186.intr.ack_mask;
+ if (state->m_i186.intr.ack_mask == 0x0001)
+ {
+ switch (state->m_i186.intr.poll_status & 0x1f)
+ {
+ case 0x08: state->m_i186.intr.status &= ~0x01; break;
+ case 0x12: state->m_i186.intr.status &= ~0x02; break;
+ case 0x13: state->m_i186.intr.status &= ~0x04; break;
+ }
+ }
+ state->m_i186.intr.ack_mask = 0;
+
+ /* a request no longer pending */
+ state->m_i186.intr.poll_status &= ~0x8000;
+
+ /* return the vector */
+ return state->m_i186.intr.poll_status & 0x1f;
+}
+
+
+static void update_interrupt_state(running_machine &machine)
+{
+ compis_state *state = machine.driver_data<compis_state>();
+ int i, j, new_vector = 0;
+
+ if (LOG_INTERRUPTS) logerror("update_interrupt_status: req=%02X stat=%02X serv=%02X\n", state->m_i186.intr.request, state->m_i186.intr.status, state->m_i186.intr.in_service);
+
+ /* loop over priorities */
+ for (i = 0; i <= state->m_i186.intr.priority_mask; i++)
+ {
+ /* note: by checking 4 bits, we also verify that the mask is off */
+ if ((state->m_i186.intr.timer & 15) == i)
+ {
+ /* if we're already servicing something at this level, don't generate anything new */
+ if (state->m_i186.intr.in_service & 0x01)
+ return;
+
+ /* if there's something pending, generate an interrupt */
+ if (state->m_i186.intr.status & 0x07)
+ {
+ if (state->m_i186.intr.status & 1)
+ new_vector = 0x08;
+ else if (state->m_i186.intr.status & 2)
+ new_vector = 0x12;
+ else if (state->m_i186.intr.status & 4)
+ new_vector = 0x13;
+ else
+ popmessage("Invalid timer interrupt!");
+
+ /* set the clear mask and generate the int */
+ state->m_i186.intr.ack_mask = 0x0001;
+ goto generate_int;
+ }
+ }
+
+ /* check DMA interrupts */
+ for (j = 0; j < 2; j++)
+ if ((state->m_i186.intr.dma[j] & 15) == i)
+ {
+ /* if we're already servicing something at this level, don't generate anything new */
+ if (state->m_i186.intr.in_service & (0x04 << j))
+ return;
+
+ /* if there's something pending, generate an interrupt */
+ if (state->m_i186.intr.request & (0x04 << j))
+ {
+ new_vector = 0x0a + j;
+
+ /* set the clear mask and generate the int */
+ state->m_i186.intr.ack_mask = 0x0004 << j;
+ goto generate_int;
+ }
+ }
+
+ /* check external interrupts */
+ for (j = 0; j < 4; j++)
+ if ((state->m_i186.intr.ext[j] & 15) == i)
+ {
+ /* if we're already servicing something at this level, don't generate anything new */
+ if (state->m_i186.intr.in_service & (0x10 << j))
+ return;
+
+ /* if there's something pending, generate an interrupt */
+ if (state->m_i186.intr.request & (0x10 << j))
+ {
+ /* otherwise, generate an interrupt for this request */
+ new_vector = 0x0c + j;
+
+ /* set the clear mask and generate the int */
+ state->m_i186.intr.ack_mask = 0x0010 << j;
+ goto generate_int;
+ }
+ }
+ }
+ return;
+
+generate_int:
+ /* generate the appropriate interrupt */
+ state->m_i186.intr.poll_status = 0x8000 | new_vector;
+ if (!state->m_i186.intr.pending)
+ cputag_set_input_line(machine, "maincpu", 0, ASSERT_LINE);
+ state->m_i186.intr.pending = 1;
+ machine.scheduler().trigger(CPU_RESUME_TRIGGER);
+ if (LOG_OPTIMIZATION) logerror(" - trigger due to interrupt pending\n");
+ if (LOG_INTERRUPTS) logerror("(%f) **** Requesting interrupt vector %02X\n", machine.time().as_double(), new_vector);
+}
+
+
+void compis_state::handle_eoi(int data)
+{
+ int i, j;
+
+ /* specific case */
+ if (!(data & 0x8000))
+ {
+ /* turn off the appropriate in-service bit */
+ switch (data & 0x1f)
+ {
+ case 0x08: m_i186.intr.in_service &= ~0x01; break;
+ case 0x12: m_i186.intr.in_service &= ~0x01; break;
+ case 0x13: m_i186.intr.in_service &= ~0x01; break;
+ case 0x0a: m_i186.intr.in_service &= ~0x04; break;
+ case 0x0b: m_i186.intr.in_service &= ~0x08; break;
+ case 0x0c: m_i186.intr.in_service &= ~0x10; break;
+ case 0x0d: m_i186.intr.in_service &= ~0x20; break;
+ case 0x0e: m_i186.intr.in_service &= ~0x40; break;
+ case 0x0f: m_i186.intr.in_service &= ~0x80; break;
+ default: logerror("%05X:ERROR - 80186 EOI with unknown vector %02X\n", cpu_get_pc(m_maincpu), 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 (i = 0; i <= 7; i++)
+ {
+ /* check for in-service timers */
+ if ((m_i186.intr.timer & 7) == i && (m_i186.intr.in_service & 0x01))
+ {
+ m_i186.intr.in_service &= ~0x01;
+ if (LOG_INTERRUPTS) logerror("(%f) **** Got EOI for timer\n", machine().time().as_double());
+ return;
+ }
+
+ /* check for in-service DMA interrupts */
+ for (j = 0; j < 2; j++)
+ if ((m_i186.intr.dma[j] & 7) == i && (m_i186.intr.in_service & (0x04 << j)))
+ {
+ m_i186.intr.in_service &= ~(0x04 << j);
+ if (LOG_INTERRUPTS) logerror("(%f) **** Got EOI for DMA%d\n", machine().time().as_double(), j);
+ return;
+ }
+
+ /* check external interrupts */
+ for (j = 0; j < 4; j++)
+ if ((m_i186.intr.ext[j] & 7) == i && (m_i186.intr.in_service & (0x10 << j)))
+ {
+ m_i186.intr.in_service &= ~(0x10 << j);
+ if (LOG_INTERRUPTS) logerror("(%f) **** Got EOI for INT%d\n", machine().time().as_double(), j);
+ return;
+ }
+ }
+ }
+}
+
+
+/*************************************
+ *
+ * 80186 internal timers
+ *
+ *************************************/
+
+static TIMER_CALLBACK(internal_timer_int)
+{
+ compis_state *state = machine.driver_data<compis_state>();
+ int which = param;
+ struct timer_state *t = &state->m_i186.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)
+ {
+ state->m_i186.intr.status |= 0x01 << which;
+ update_interrupt_state(machine);
+ if (LOG_TIMER) logerror(" Generating timer interrupt\n");
+ }
+
+ /* if we're continuous, reset */
+ if (t->control & 0x0001)
+ {
+ int count = t->maxA ? t->maxA : 0x10000;
+ t->int_timer->adjust(attotime::from_hz(2000000) * count, which);
+ if (LOG_TIMER) logerror(" Repriming interrupt\n");
+ }
+ else
+ t->int_timer->adjust(attotime::never, which);
+}
+
+
+void compis_state::internal_timer_sync(int which)
+{
+ struct timer_state *t = &m_i186.timer[which];
+
+ /* if we have a timing timer running, adjust the count */
+ if (t->time_timer_active)
+ {
+ attotime current_time = t->time_timer->elapsed();
+ int net_clocks = ((current_time - t->last_time) * 2000000).seconds;
+ t->last_time = current_time;
+
+ /* set the max count bit if we passed the max */
+ if ((int)t->count + net_clocks >= t->maxA)
+ t->control |= 0x0020;
+
+ /* set the new count */
+ if (t->maxA != 0)
+ t->count = (t->count + net_clocks) % t->maxA;
+ else
+ t->count = t->count + net_clocks;
+ }
+}
+
+
+void compis_state::internal_timer_update(int which, int new_count, int new_maxA, int new_maxB, int new_control)
+{
+ struct timer_state *t = &m_i186.timer[which];
+ int update_int_timer = 0;
+
+ /* 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;
+
+ /* merge back in the bits we don't modify */
+ new_control = (new_control & ~0x1fc0) | (t->control & 0x1fc0);
+
+ /* 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 & 0x001c)
+ logerror("%05X:ERROR! -unsupported timer mode %04X\n",
+ cpu_get_pc(m_maincpu), 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);
+
+ /* nuke the timer and force the interrupt timer to be recomputed */
+ t->time_timer->adjust(attotime::never, which);
+ t->time_timer_active = 0;
+ update_int_timer = 1;
+ }
+
+ /* if we're going on, start the timers running */
+ else if ((diff & 0x8000) && (new_control & 0x8000))
+ {
+ /* start the timing */
+ t->time_timer->adjust(attotime::never, which);
+ t->time_timer_active = 1;
+ 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)
+ {
+ if ((t->control & 0x8000) && (t->control & 0x2000))
+ {
+ int diff = t->maxA - t->count;
+ if (diff <= 0)
+ diff += 0x10000;
+ t->int_timer->adjust(attotime::from_hz(2000000) * diff, which);
+ if (LOG_TIMER) logerror("Set interrupt timer for %d\n", which);
+ }
+ else
+ {
+ t->int_timer->adjust(attotime::never, which);
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * 80186 internal DMA
+ *
+ *************************************/
+
+static TIMER_CALLBACK(dma_timer_callback)
+{
+ compis_state *state = machine.driver_data<compis_state>();
+ int which = param;
+ struct dma_state *d = &state->m_i186.dma[which];
+
+ /* force an update and see if we're really done */
+ //stream_update(dma_stream, 0);
+
+ /* complete the status update */
+ d->control &= ~0x0002;
+ d->source += d->count;
+ d->count = 0;
+
+ /* check for interrupt generation */
+ if (d->control & 0x0100)
+ {
+ if (LOG_DMA) logerror("DMA%d timer callback - requesting interrupt: count = %04X, source = %04X\n", which, d->count, d->source);
+ state->m_i186.intr.request |= 0x04 << which;
+ update_interrupt_state(machine);
+ }
+}
+
+
+void compis_state::update_dma_control(int which, int new_control)
+{
+ struct dma_state *d = &m_i186.dma[which];
+ int diff;
+
+ /* handle the CHG bit */
+ if (!(new_control & 0x0004))
+ new_control = (new_control & ~0x0002) | (d->control & 0x0002);
+ new_control &= ~0x0004;
+
+ /* check for control bits we don't handle */
+ diff = new_control ^ d->control;
+ if (diff & 0x6811)
+ logerror("%05X:ERROR! - unsupported DMA mode %04X\n",
+ cpu_get_pc(m_maincpu), new_control);
+
+ /* if we're going live, set a timer */
+ if ((diff & 0x0002) && (new_control & 0x0002))
+ {
+ /* make sure the parameters meet our expectations */
+ if ((new_control & 0xfe00) != 0x1600)
+ {
+ logerror("Unexpected DMA control %02X\n", new_control);
+ }
+ else
+ if (/*!is_redline &&*/ ((d->dest & 1) || (d->dest & 0x3f) > 0x0b))
+ {
+ logerror("Unexpected DMA destination %02X\n", d->dest);
+ }
+ else
+ if (/*is_redline && */ (d->dest & 0xf000) != 0x4000 && (d->dest & 0xf000) != 0x5000)
+ {
+ logerror("Unexpected DMA destination %02X\n", d->dest);
+ }
+
+ /* otherwise, set a timer */
+ else
+ {
+// int count = d->count;
+
+ /* adjust for redline racer */
+ // int dacnum = (d->dest & 0x3f) / 2;
+
+ if (LOG_DMA) logerror("Initiated DMA %d - count = %04X, source = %04X, dest = %04X\n", which, d->count, d->source, d->dest);
+
+ d->finished = 0;
+/* d->finish_timer->adjust(
+ attotime::from_hz(dac[dacnum].frequency) * (double)count, which);*/
+ }
+ }
+
+ /* set the new control register */
+ d->control = new_control;
+}
+
+
+
+/*************************************
+ *
+ * 80186 internal I/O reads
+ *
+ *************************************/
+
+
+READ16_MEMBER( compis_state::compis_i186_internal_port_r )
+{
+ int temp, which;
+
+ switch (offset)
+ {
+ case 0x11:
+ logerror("%05X:ERROR - read from 80186 EOI\n", cpu_get_pc(m_maincpu));
+ break;
+
+ case 0x12:
+ if (LOG_PORTS) logerror("%05X:read 80186 interrupt poll\n", cpu_get_pc(m_maincpu));
+ if (m_i186.intr.poll_status & 0x8000)
+ int_callback(machine().device("maincpu"), 0);
+ return m_i186.intr.poll_status;
+
+ case 0x13:
+ if (LOG_PORTS) logerror("%05X:read 80186 interrupt poll status\n", cpu_get_pc(m_maincpu));
+ return m_i186.intr.poll_status;
+
+ case 0x14:
+ if (LOG_PORTS) logerror("%05X:read 80186 interrupt mask\n", cpu_get_pc(m_maincpu));
+ temp = (m_i186.intr.timer >> 3) & 0x01;
+ temp |= (m_i186.intr.dma[0] >> 1) & 0x04;
+ temp |= (m_i186.intr.dma[1] >> 0) & 0x08;
+ temp |= (m_i186.intr.ext[0] << 1) & 0x10;
+ temp |= (m_i186.intr.ext[1] << 2) & 0x20;
+ temp |= (m_i186.intr.ext[2] << 3) & 0x40;
+ temp |= (m_i186.intr.ext[3] << 4) & 0x80;
+ return temp;
+
+ case 0x15:
+ if (LOG_PORTS) logerror("%05X:read 80186 interrupt priority mask\n", cpu_get_pc(m_maincpu));
+ return m_i186.intr.priority_mask;
+
+ case 0x16:
+ if (LOG_PORTS) logerror("%05X:read 80186 interrupt in-service\n", cpu_get_pc(m_maincpu));
+ return m_i186.intr.in_service;
+
+ case 0x17:
+ if (LOG_PORTS) logerror("%05X:read 80186 interrupt request\n", cpu_get_pc(m_maincpu));
+ temp = m_i186.intr.request & ~0x0001;
+ if (m_i186.intr.status & 0x0007)
+ temp |= 1;
+ return temp;
+
+ case 0x18:
+ if (LOG_PORTS) logerror("%05X:read 80186 interrupt status\n", cpu_get_pc(m_maincpu));
+ return m_i186.intr.status;
+
+ case 0x19:
+ if (LOG_PORTS) logerror("%05X:read 80186 timer interrupt control\n", cpu_get_pc(m_maincpu));
+ return m_i186.intr.timer;
+
+ case 0x1a:
+ if (LOG_PORTS) logerror("%05X:read 80186 DMA 0 interrupt control\n", cpu_get_pc(m_maincpu));
+ return m_i186.intr.dma[0];
+
+ case 0x1b:
+ if (LOG_PORTS) logerror("%05X:read 80186 DMA 1 interrupt control\n", cpu_get_pc(m_maincpu));
+ return m_i186.intr.dma[1];
+
+ case 0x1c:
+ if (LOG_PORTS) logerror("%05X:read 80186 INT 0 interrupt control\n", cpu_get_pc(m_maincpu));
+ return m_i186.intr.ext[0];
+
+ case 0x1d:
+ if (LOG_PORTS) logerror("%05X:read 80186 INT 1 interrupt control\n", cpu_get_pc(m_maincpu));
+ return m_i186.intr.ext[1];
+
+ case 0x1e:
+ if (LOG_PORTS) logerror("%05X:read 80186 INT 2 interrupt control\n", cpu_get_pc(m_maincpu));
+ return m_i186.intr.ext[2];
+
+ case 0x1f:
+ if (LOG_PORTS) logerror("%05X:read 80186 INT 3 interrupt control\n", cpu_get_pc(m_maincpu));
+ return m_i186.intr.ext[3];
+
+ case 0x28:
+ case 0x2c:
+ case 0x30:
+ if (LOG_PORTS) logerror("%05X:read 80186 Timer %d count\n", cpu_get_pc(m_maincpu), (offset - 0x28) / 4);
+ which = (offset - 0x28) / 4;
+ if (!(offset & 1))
+ internal_timer_sync(which);
+ return m_i186.timer[which].count;
+
+ case 0x29:
+ case 0x2d:
+ case 0x31:
+ if (LOG_PORTS) logerror("%05X:read 80186 Timer %d max A\n", cpu_get_pc(m_maincpu), (offset - 0x29) / 4);
+ which = (offset - 0x29) / 4;
+ return m_i186.timer[which].maxA;
+
+ case 0x2a:
+ case 0x2e:
+ logerror("%05X:read 80186 Timer %d max B\n", cpu_get_pc(m_maincpu), (offset - 0x2a) / 4);
+ which = (offset - 0x2a) / 4;
+ return m_i186.timer[which].maxB;
+
+ case 0x2b:
+ case 0x2f:
+ case 0x33:
+ if (LOG_PORTS) logerror("%05X:read 80186 Timer %d control\n", cpu_get_pc(m_maincpu), (offset - 0x2b) / 4);
+ which = (offset - 0x2b) / 4;
+ return m_i186.timer[which].control;
+
+ case 0x50:
+ if (LOG_PORTS) logerror("%05X:read 80186 upper chip select\n", cpu_get_pc(m_maincpu));
+ return m_i186.mem.upper;
+
+ case 0x51:
+ if (LOG_PORTS) logerror("%05X:read 80186 lower chip select\n", cpu_get_pc(m_maincpu));
+ return m_i186.mem.lower;
+
+ case 0x52:
+ if (LOG_PORTS) logerror("%05X:read 80186 peripheral chip select\n", cpu_get_pc(m_maincpu));
+ return m_i186.mem.peripheral;
+
+ case 0x53:
+ if (LOG_PORTS) logerror("%05X:read 80186 middle chip select\n", cpu_get_pc(m_maincpu));
+ return m_i186.mem.middle;
+
+ case 0x54:
+ if (LOG_PORTS) logerror("%05X:read 80186 middle P chip select\n", cpu_get_pc(m_maincpu));
+ return m_i186.mem.middle_size;
+
+ case 0x60:
+ case 0x68:
+ if (LOG_PORTS) logerror("%05X:read 80186 DMA%d lower source address\n", cpu_get_pc(m_maincpu), (offset - 0x60) / 8);
+ which = (offset - 0x60) / 8;
+// stream_update(dma_stream, 0);
+ return m_i186.dma[which].source;
+
+ case 0x61:
+ case 0x69:
+ if (LOG_PORTS) logerror("%05X:read 80186 DMA%d upper source address\n", cpu_get_pc(m_maincpu), (offset - 0x61) / 8);
+ which = (offset - 0x61) / 8;
+// stream_update(dma_stream, 0);
+ return m_i186.dma[which].source >> 16;
+
+ case 0x62:
+ case 0x6a:
+ if (LOG_PORTS) logerror("%05X:read 80186 DMA%d lower dest address\n", cpu_get_pc(m_maincpu), (offset - 0x62) / 8);
+ which = (offset - 0x62) / 8;
+// stream_update(dma_stream, 0);
+ return m_i186.dma[which].dest;
+
+ case 0x63:
+ case 0x6b:
+ if (LOG_PORTS) logerror("%05X:read 80186 DMA%d upper dest address\n", cpu_get_pc(m_maincpu), (offset - 0x63) / 8);
+ which = (offset - 0x63) / 8;
+// stream_update(dma_stream, 0);
+ return m_i186.dma[which].dest >> 16;
+
+ case 0x64:
+ case 0x6c:
+ if (LOG_PORTS) logerror("%05X:read 80186 DMA%d transfer count\n", cpu_get_pc(m_maincpu), (offset - 0x64) / 8);
+ which = (offset - 0x64) / 8;
+// stream_update(dma_stream, 0);
+ return m_i186.dma[which].count;
+
+ case 0x65:
+ case 0x6d:
+ if (LOG_PORTS) logerror("%05X:read 80186 DMA%d control\n", cpu_get_pc(m_maincpu), (offset - 0x65) / 8);
+ which = (offset - 0x65) / 8;
+// stream_update(dma_stream, 0);
+ return m_i186.dma[which].control;
+
+ default:
+ logerror("%05X:read 80186 port %02X\n", cpu_get_pc(m_maincpu), offset);
+ break;
+ }
+ return 0x00;
+}
+
+/*************************************
+ *
+ * 80186 internal I/O writes
+ *
+ *************************************/
+
+WRITE16_MEMBER( compis_state::compis_i186_internal_port_w )
+{
+ address_space *mem = m_maincpu->memory().space(AS_PROGRAM);
+ address_space *io = m_maincpu->memory().space(AS_IO);
+ int temp, which, data16 = data;
+
+ switch (offset)
+ {
+ case 0x11:
+ if (LOG_PORTS) logerror("%05X:80186 EOI = %04X\n", cpu_get_pc(m_maincpu), data16);
+ handle_eoi(0x8000);
+ update_interrupt_state(machine());
+ break;
+
+ case 0x12:
+ logerror("%05X:ERROR - write to 80186 interrupt poll = %04X\n", cpu_get_pc(m_maincpu), data16);
+ break;
+
+ case 0x13:
+ logerror("%05X:ERROR - write to 80186 interrupt poll status = %04X\n", cpu_get_pc(m_maincpu), data16);
+ break;
+
+ case 0x14:
+ if (LOG_PORTS) logerror("%05X:80186 interrupt mask = %04X\n", cpu_get_pc(m_maincpu), data16);
+ m_i186.intr.timer = (m_i186.intr.timer & ~0x08) | ((data16 << 3) & 0x08);
+ m_i186.intr.dma[0] = (m_i186.intr.dma[0] & ~0x08) | ((data16 << 1) & 0x08);
+ m_i186.intr.dma[1] = (m_i186.intr.dma[1] & ~0x08) | ((data16 << 0) & 0x08);
+ m_i186.intr.ext[0] = (m_i186.intr.ext[0] & ~0x08) | ((data16 >> 1) & 0x08);
+ m_i186.intr.ext[1] = (m_i186.intr.ext[1] & ~0x08) | ((data16 >> 2) & 0x08);
+ m_i186.intr.ext[2] = (m_i186.intr.ext[2] & ~0x08) | ((data16 >> 3) & 0x08);
+ m_i186.intr.ext[3] = (m_i186.intr.ext[3] & ~0x08) | ((data16 >> 4) & 0x08);
+ update_interrupt_state(machine());
+ break;
+
+ case 0x15:
+ if (LOG_PORTS) logerror("%05X:80186 interrupt priority mask = %04X\n", cpu_get_pc(m_maincpu), data16);
+ m_i186.intr.priority_mask = data16 & 0x0007;
+ update_interrupt_state(machine());
+ break;
+
+ case 0x16:
+ if (LOG_PORTS) logerror("%05X:80186 interrupt in-service = %04X\n", cpu_get_pc(m_maincpu), data16);
+ m_i186.intr.in_service = data16 & 0x00ff;
+ update_interrupt_state(machine());
+ break;
+
+ case 0x17:
+ if (LOG_PORTS) logerror("%05X:80186 interrupt request = %04X\n", cpu_get_pc(m_maincpu), data16);
+ m_i186.intr.request = (m_i186.intr.request & ~0x00c0) | (data16 & 0x00c0);
+ update_interrupt_state(machine());
+ break;
+
+ case 0x18:
+ if (LOG_PORTS) logerror("%05X:WARNING - wrote to 80186 interrupt status = %04X\n", cpu_get_pc(m_maincpu), data16);
+ m_i186.intr.status = (m_i186.intr.status & ~0x8007) | (data16 & 0x8007);
+ update_interrupt_state(machine());
+ break;
+
+ case 0x19:
+ if (LOG_PORTS) logerror("%05X:80186 timer interrupt control = %04X\n", cpu_get_pc(m_maincpu), data16);
+ m_i186.intr.timer = data16 & 0x000f;
+ break;
+
+ case 0x1a:
+ if (LOG_PORTS) logerror("%05X:80186 DMA 0 interrupt control = %04X\n", cpu_get_pc(m_maincpu), data16);
+ m_i186.intr.dma[0] = data16 & 0x000f;
+ break;
+
+ case 0x1b:
+ if (LOG_PORTS) logerror("%05X:80186 DMA 1 interrupt control = %04X\n", cpu_get_pc(m_maincpu), data16);
+ m_i186.intr.dma[1] = data16 & 0x000f;
+ break;
+
+ case 0x1c:
+ if (LOG_PORTS) logerror("%05X:80186 INT 0 interrupt control = %04X\n", cpu_get_pc(m_maincpu), data16);
+ m_i186.intr.ext[0] = data16 & 0x007f;
+ break;
+
+ case 0x1d:
+ if (LOG_PORTS) logerror("%05X:80186 INT 1 interrupt control = %04X\n", cpu_get_pc(m_maincpu), data16);
+ m_i186.intr.ext[1] = data16 & 0x007f;
+ break;
+
+ case 0x1e:
+ if (LOG_PORTS) logerror("%05X:80186 INT 2 interrupt control = %04X\n", cpu_get_pc(m_maincpu), data16);
+ m_i186.intr.ext[2] = data16 & 0x001f;
+ break;
+
+ case 0x1f:
+ if (LOG_PORTS) logerror("%05X:80186 INT 3 interrupt control = %04X\n", cpu_get_pc(m_maincpu), data16);
+ m_i186.intr.ext[3] = data16 & 0x001f;
+ break;
+
+ case 0x28:
+ case 0x2c:
+ case 0x30:
+ if (LOG_PORTS) logerror("%05X:80186 Timer %d count = %04X\n", cpu_get_pc(m_maincpu), (offset - 0x28) / 4, data16);
+ which = (offset - 0x28) / 4;
+ internal_timer_update(which, data16, -1, -1, -1);
+ break;
+
+ case 0x29:
+ case 0x2d:
+ case 0x31:
+ if (LOG_PORTS) logerror("%05X:80186 Timer %d max A = %04X\n", cpu_get_pc(m_maincpu), (offset - 0x29) / 4, data16);
+ which = (offset - 0x29) / 4;
+ internal_timer_update(which, -1, data16, -1, -1);
+ break;
+
+ case 0x2a:
+ case 0x2e:
+ if (LOG_PORTS) logerror("%05X:80186 Timer %d max B = %04X\n", cpu_get_pc(m_maincpu), (offset - 0x2a) / 4, data16);
+ which = (offset - 0x2a) / 4;
+ internal_timer_update(which, -1, -1, data16, -1);
+ break;
+
+ case 0x2b:
+ case 0x2f:
+ case 0x33:
+ if (LOG_PORTS) logerror("%05X:80186 Timer %d control = %04X\n", cpu_get_pc(m_maincpu), (offset - 0x2b) / 4, data16);
+ which = (offset - 0x2b) / 4;
+ internal_timer_update(which, -1, -1, -1, data16);
+ break;
+
+ case 0x50:
+ if (LOG_PORTS) logerror("%05X:80186 upper chip select = %04X\n", cpu_get_pc(m_maincpu), data16);
+ m_i186.mem.upper = data16 | 0xc038;
+ break;
+
+ case 0x51:
+ if (LOG_PORTS) logerror("%05X:80186 lower chip select = %04X\n", cpu_get_pc(m_maincpu), data16);
+ m_i186.mem.lower = (data16 & 0x3fff) | 0x0038; //printf("%X\n",m_i186.mem.lower);
+ break;
+
+ case 0x52:
+ if (LOG_PORTS) logerror("%05X:80186 peripheral chip select = %04X\n", cpu_get_pc(m_maincpu), data16);
+ m_i186.mem.peripheral = data16 | 0x0038;
+ break;
+
+ case 0x53:
+ if (LOG_PORTS) logerror("%05X:80186 middle chip select = %04X\n", cpu_get_pc(m_maincpu), data16);
+ m_i186.mem.middle = data16 | 0x01f8;
+ break;
+
+ case 0x54:
+ if (LOG_PORTS) logerror("%05X:80186 middle P chip select = %04X\n", cpu_get_pc(m_maincpu), data16);
+ m_i186.mem.middle_size = data16 | 0x8038;
+
+ temp = (m_i186.mem.peripheral & 0xffc0) << 4;
+ if (m_i186.mem.middle_size & 0x0040)
+ {
+// install_mem_read_handler(2, temp, temp + 0x2ff, peripheral_r);
+// install_mem_write_handler(2, temp, temp + 0x2ff, peripheral_w);
+ }
+ else
+ {
+ temp &= 0xffff;
+// install_port_read_handler(2, temp, temp + 0x2ff, peripheral_r);
+// install_port_write_handler(2, temp, temp + 0x2ff, peripheral_w);
+ }
+
+ /* we need to do this at a time when the I86 context is swapped in */
+ /* this register is generally set once at startup and never again, so it's a good */
+ /* time to set it up */
+ device_set_irq_callback(m_maincpu, int_callback);
+ break;
+
+ case 0x60:
+ case 0x68:
+ if (LOG_PORTS) logerror("%05X:80186 DMA%d lower source address = %04X\n", cpu_get_pc(m_maincpu), (offset - 0x60) / 8, data16);
+ which = (offset - 0x60) / 8;
+// stream_update(dma_stream, 0);
+ m_i186.dma[which].source = (m_i186.dma[which].source & ~0x0ffff) | (data16 & 0x0ffff);
+ break;
+
+ case 0x61:
+ case 0x69:
+ if (LOG_PORTS) logerror("%05X:80186 DMA%d upper source address = %04X\n", cpu_get_pc(m_maincpu), (offset - 0x61) / 8, data16);
+ which = (offset - 0x61) / 8;
+// stream_update(dma_stream, 0);
+ m_i186.dma[which].source = (m_i186.dma[which].source & ~0xf0000) | ((data16 << 16) & 0xf0000);
+ break;
+
+ case 0x62:
+ case 0x6a:
+ if (LOG_PORTS) logerror("%05X:80186 DMA%d lower dest address = %04X\n", cpu_get_pc(m_maincpu), (offset - 0x62) / 8, data16);
+ which = (offset - 0x62) / 8;
+// stream_update(dma_stream, 0);
+ m_i186.dma[which].dest = (m_i186.dma[which].dest & ~0x0ffff) | (data16 & 0x0ffff);
+ break;
+
+ case 0x63:
+ case 0x6b:
+ if (LOG_PORTS) logerror("%05X:80186 DMA%d upper dest address = %04X\n", cpu_get_pc(m_maincpu), (offset - 0x63) / 8, data16);
+ which = (offset - 0x63) / 8;
+// stream_update(dma_stream, 0);
+ m_i186.dma[which].dest = (m_i186.dma[which].dest & ~0xf0000) | ((data16 << 16) & 0xf0000);
+ break;
+
+ case 0x64:
+ case 0x6c:
+ if (LOG_PORTS) logerror("%05X:80186 DMA%d transfer count = %04X\n", cpu_get_pc(m_maincpu), (offset - 0x64) / 8, data16);
+ which = (offset - 0x64) / 8;
+// stream_update(dma_stream, 0);
+ m_i186.dma[which].count = data16;
+ break;
+
+ case 0x65:
+ case 0x6d:
+ if (LOG_PORTS) logerror("%05X:80186 DMA%d control = %04X\n", cpu_get_pc(m_maincpu), (offset - 0x65) / 8, data16);
+ which = (offset - 0x65) / 8;
+// stream_update(dma_stream, 0);
+ update_dma_control(which, data16);
+ break;
+
+ case 0x7f:
+ if (LOG_PORTS) logerror("%05X:80186 relocation register = %04X\n", cpu_get_pc(m_maincpu), data16);
+
+ /* we assume here there that this doesn't happen too often */
+ /* plus, we can't really remove the old memory range, so we also assume that it's */
+ /* okay to leave us mapped where we were */
+ temp = (data16 & 0x0fff) << 8;
+ if (data16 & 0x1000)
+ {
+ mem->install_read_handler(temp, temp + 0xff, read16_delegate(FUNC(compis_state::compis_i186_internal_port_r), this));
+ mem->install_write_handler(temp, temp + 0xff, write16_delegate(FUNC(compis_state::compis_i186_internal_port_w), this));
+ }
+ else
+ {
+ temp &= 0xffff;
+ io->install_read_handler(temp, temp + 0xff, read16_delegate(FUNC(compis_state::compis_i186_internal_port_r), this));
+ io->install_write_handler(temp, temp + 0xff, write16_delegate(FUNC(compis_state::compis_i186_internal_port_w), this));
+ }
+/* popmessage("Sound CPU reset");*/
+ break;
+
+ default:
+ logerror("%05X:80186 port %02X = %04X\n", cpu_get_pc(m_maincpu), offset, data16);
+ break;
+ }
+}
+
+/*-------------------------------------------------------------------------*/
+/* Name: compis */
+/* Desc: CPU - Initialize the 80186 CPU */
+/*-------------------------------------------------------------------------*/
+static void compis_cpu_init(running_machine &machine)
+{
+ compis_state *state = machine.driver_data<compis_state>();
+ /* create timers here so they stick around */
+ state->m_i186.timer[0].int_timer = machine.scheduler().timer_alloc(FUNC(internal_timer_int));
+ state->m_i186.timer[1].int_timer = machine.scheduler().timer_alloc(FUNC(internal_timer_int));
+ state->m_i186.timer[2].int_timer = machine.scheduler().timer_alloc(FUNC(internal_timer_int));
+ state->m_i186.timer[0].time_timer = machine.scheduler().timer_alloc(FUNC_NULL);
+ state->m_i186.timer[1].time_timer = machine.scheduler().timer_alloc(FUNC_NULL);
+ state->m_i186.timer[2].time_timer = machine.scheduler().timer_alloc(FUNC_NULL);
+ state->m_i186.dma[0].finish_timer = machine.scheduler().timer_alloc(FUNC(dma_timer_callback));
+ state->m_i186.dma[1].finish_timer = machine.scheduler().timer_alloc(FUNC(dma_timer_callback));
+}
+
+/*-------------------------------------------------------------------------*/
+/* Name: compis */
+/* Desc: Driver - Init */
+/*-------------------------------------------------------------------------*/
+
+/*************************************************************
+ *
+ * pic8259 configuration
+ *
+ *************************************************************/
+
+WRITE_LINE_MEMBER( compis_state::compis_pic8259_master_set_int_line )
+{
+ cputag_set_input_line(machine(), "maincpu", 0, state ? HOLD_LINE : CLEAR_LINE);
+}
+
+WRITE_LINE_MEMBER( compis_state::compis_pic8259_slave_set_int_line )
+{
+ if (m_8259m)
+ pic8259_ir2_w(m_8259m, state);
+}
+
+READ8_MEMBER( compis_state::get_slave_ack )
+{
+ if (offset==2) { // IRQ = 2
+ return pic8259_acknowledge(m_8259s);
+ }
+ return 0;
+}
+
+const struct pic8259_interface compis_pic8259_master_config =
+{
+ DEVCB_DRIVER_LINE_MEMBER(compis_state, compis_pic8259_master_set_int_line),
+ DEVCB_LINE_VCC,
+ DEVCB_DRIVER_MEMBER(compis_state, get_slave_ack)
+};
+
+const struct pic8259_interface compis_pic8259_slave_config =
+{
+ DEVCB_DRIVER_LINE_MEMBER(compis_state, compis_pic8259_slave_set_int_line),
+ DEVCB_LINE_GND,
+ DEVCB_NULL
+};
+
+
+static IRQ_CALLBACK( compis_irq_callback )
+{
+ compis_state *state = device->machine().driver_data<compis_state>();
+ return pic8259_acknowledge(state->m_8259m);
+}
+
+
+DRIVER_INIT_MEMBER(compis_state,compis)
+{
+
+ device_set_irq_callback(machine().device("maincpu"), compis_irq_callback);
+ memset (&m_compis, 0, sizeof (m_compis) );
+}
+
+MACHINE_START( compis )
+{
+ /* CPU */
+ compis_cpu_init(machine);
+}
+/*-------------------------------------------------------------------------*/
+/* Name: compis */
+/* Desc: Machine - Init */
+/*-------------------------------------------------------------------------*/
+MACHINE_RESET( compis )
+{
+ compis_state *state = machine.driver_data<compis_state>();
+ /* FDC */
+ compis_fdc_reset(machine);
+
+ /* Keyboard */
+ compis_keyb_init(state);
+
+ /* OSP PIC 8259 */
+ device_set_irq_callback(state->m_maincpu, compis_irq_callback);
+}
+
+/*-------------------------------------------------------------------------*/
+/* Name: compis */
+/* Desc: Interrupt - Vertical Blanking Interrupt */
+/*-------------------------------------------------------------------------*/
+INTERRUPT_GEN( compis_vblank_int )
+{
+// compis_gdc_vblank_int();
+ compis_keyb_update(device->machine());
+}
diff --git a/src/mess/machine/comx_clm.c b/src/mess/machine/comx_clm.c
new file mode 100644
index 00000000000..775bfdb3c63
--- /dev/null
+++ b/src/mess/machine/comx_clm.c
@@ -0,0 +1,295 @@
+/**********************************************************************
+
+ COMX-35 80-Column Card emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+(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 "comx_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<comx_clm_device>;
+
+
+//-------------------------------------------------
+// ROM( comx_clm )
+//-------------------------------------------------
+
+ROM_START( comx_clm )
+ ROM_REGION( 0x2000, "c000", 0 )
+ ROM_LOAD( "p 1.0.cl1", 0x0000, 0x0800, CRC(b417d30a) SHA1(d428b0467945ecb9aec884211d0f4b1d8d56d738) ) // V1.0
+ ROM_LOAD( "p 1.1.cl1", 0x0000, 0x0800, CRC(0a2eaf19) SHA1(3f1f640caef964fb47aaa147cab6d215c2b30e9d) ) // V1.1
+
+ ROM_REGION( 0x800, MC6845_TAG, 0 )
+ ROM_LOAD( "c 1.0.cl4", 0x0000, 0x0800, CRC(69dd7b07) SHA1(71d368adbb299103d165eab8359a97769e463e26) ) // V1.0
+ ROM_LOAD( "c 1.1.cl4", 0x0000, 0x0800, CRC(dc9b5046) SHA1(4e041cec03dda6dba5e2598d060c49908a4fab2a) ) // V1.1
+ROM_END
+
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *comx_clm_device::device_rom_region() const
+{
+ return ROM_NAME( comx_clm );
+}
+
+
+//-------------------------------------------------
+// mc6845_interface crtc_intf
+//-------------------------------------------------
+
+void comx_clm_device::crtc_update_row(mc6845_device *device, bitmap_rgb32 &bitmap, const rectangle &cliprect, UINT16 ma, UINT8 ra, UINT16 y, UINT8 x_count, INT8 cursor_x, void *param)
+{
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ 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[addr & 0x7ff];
+
+ if (BIT(ra, 3) && column == cursor_x)
+ {
+ data = 0xff;
+ }
+
+ for (int bit = 0; bit < 8; bit++)
+ {
+ int x = (column * 8) + bit;
+ int color = BIT(data, 7) ? 7 : 0;
+
+ bitmap.pix32(y, x) = palette[color];
+
+ data <<= 1;
+ }
+ }
+}
+
+static MC6845_UPDATE_ROW( comx_clm_update_row )
+{
+ comx_clm_device *clm = downcast<comx_clm_device *>(device->owner());
+ clm->crtc_update_row(device,bitmap,cliprect,ma,ra,y,x_count,cursor_x,param);
+}
+
+WRITE_LINE_MEMBER( comx_clm_device::hsync_w )
+{
+ if (m_ds)
+ {
+ m_slot->ef4_w(state);
+ }
+ else
+ {
+ m_slot->ef4_w(CLEAR_LINE);
+ }
+}
+
+static const mc6845_interface crtc_intf =
+{
+ MC6845_SCREEN_TAG,
+ 8,
+ NULL,
+ comx_clm_update_row,
+ NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, comx_clm_device, hsync_w),
+ DEVCB_NULL,
+ NULL
+};
+
+
+//-------------------------------------------------
+// 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(comx_clm)
+
+ MCFG_MC6845_ADD(MC6845_TAG, MC6845, XTAL_14_31818MHz/7, crtc_intf)
+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),
+ device_comx_expansion_card_interface(mconfig, *this),
+ m_crtc(*this, MC6845_TAG),
+ m_ds(0)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void comx_clm_device::device_start()
+{
+ m_rom = memregion("c000")->base();
+ m_char_rom = memregion(MC6845_TAG)->base();
+ m_video_ram = auto_alloc_array(machine(), UINT8, VIDEORAM_SIZE);
+
+ // state saving
+ save_item(NAME(m_ds));
+ save_pointer(NAME(m_video_ram), VIDEORAM_SIZE);
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void comx_clm_device::device_reset()
+{
+}
+
+
+//-------------------------------------------------
+// comx_ds_w - device select write
+//-------------------------------------------------
+
+void comx_clm_device::comx_ds_w(int state)
+{
+ m_ds = state;
+}
+
+
+//-------------------------------------------------
+// comx_mrd_r - memory read
+//-------------------------------------------------
+
+UINT8 comx_clm_device::comx_mrd_r(offs_t offset, int *extrom)
+{
+ address_space *space = machine().firstcpu->memory().space(AS_PROGRAM);
+
+ UINT8 data = 0xff;
+
+ if (offset >= 0xc000 && offset < 0xc800)
+ {
+ data = m_rom[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(offs_t offset, UINT8 data)
+{
+ address_space *space = machine().firstcpu->memory().space(AS_PROGRAM);
+
+ 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/mess/machine/comx_clm.h b/src/mess/machine/comx_clm.h
new file mode 100644
index 00000000000..f7dd958eec7
--- /dev/null
+++ b/src/mess/machine/comx_clm.h
@@ -0,0 +1,68 @@
+/**********************************************************************
+
+ COMX-35 80-Column Card emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __COMX_CLM__
+#define __COMX_CLM__
+
+
+#include "emu.h"
+#include "machine/comxexp.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
+ void crtc_update_row(mc6845_device *device, bitmap_rgb32 &bitmap, const rectangle &cliprect, UINT16 ma, UINT8 ra, UINT16 y, UINT8 x_count, INT8 cursor_x, void *param);
+ DECLARE_WRITE_LINE_MEMBER( hsync_w );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "comx_clm"; }
+
+ // device_comx_expansion_card_interface overrides
+ virtual void comx_ds_w(int state);
+ virtual UINT8 comx_mrd_r(offs_t offset, int *extrom);
+ virtual void comx_mwr_w(offs_t offset, UINT8 data);
+
+private:
+ required_device<mc6845_device> m_crtc;
+
+ int m_ds; // device select
+ UINT8 *m_rom; // program ROM
+ UINT8 *m_char_rom; // character ROM
+ UINT8 *m_video_ram; // video RAM
+};
+
+
+// device type definition
+extern const device_type COMX_CLM;
+
+
+#endif
diff --git a/src/mess/machine/comx_eb.c b/src/mess/machine/comx_eb.c
new file mode 100644
index 00000000000..8bb8ebc7d0b
--- /dev/null
+++ b/src/mess/machine/comx_eb.c
@@ -0,0 +1,405 @@
+/**********************************************************************
+
+ COMX-35E Expansion Box emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+(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 "comx_eb.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<comx_eb_device>;
+
+
+//-------------------------------------------------
+// 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 );
+}
+
+
+//-------------------------------------------------
+// COMX_EXPANSION_INTERFACE( expansion_intf )
+//-------------------------------------------------
+
+static SLOT_INTERFACE_START( comx_expansion_cards )
+ 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
+
+WRITE_LINE_DEVICE_HANDLER( int_w )
+{
+ comx_eb_device *eb = downcast<comx_eb_device *>(device->owner());
+ eb->set_int(device->tag(), state);
+}
+
+WRITE_LINE_DEVICE_HANDLER( ef4_w )
+{
+ comx_eb_device *eb = downcast<comx_eb_device *>(device->owner());
+ eb->set_ef4(device->tag(), state);
+}
+
+WRITE_LINE_DEVICE_HANDLER( wait_w )
+{
+ comx_expansion_slot_device *slot = dynamic_cast<comx_expansion_slot_device *>(device->owner()->owner());
+ slot->wait_w(state);
+}
+
+WRITE_LINE_DEVICE_HANDLER( clear_w )
+{
+ comx_expansion_slot_device *slot = dynamic_cast<comx_expansion_slot_device *>(device->owner()->owner());
+ slot->clear_w(state);
+}
+
+static COMX_EXPANSION_INTERFACE( expansion_intf )
+{
+ DEVCB_LINE(int_w),
+ DEVCB_LINE(ef4_w),
+ DEVCB_LINE(wait_w),
+ DEVCB_LINE(clear_w)
+};
+
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( comx_eb )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( comx_eb )
+ MCFG_COMX_EXPANSION_SLOT_ADD(SLOT1_TAG, expansion_intf, comx_expansion_cards, "fd", NULL)
+ MCFG_COMX_EXPANSION_SLOT_ADD(SLOT2_TAG, expansion_intf, comx_expansion_cards, "clm", NULL)
+ MCFG_COMX_EXPANSION_SLOT_ADD(SLOT3_TAG, expansion_intf, comx_expansion_cards, "joy", NULL)
+ MCFG_COMX_EXPANSION_SLOT_ADD(SLOT4_TAG, expansion_intf, comx_expansion_cards, "ram", NULL)
+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 );
+}
+
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// set_int - set INT line state
+//-------------------------------------------------
+
+void comx_eb_device::set_int(const char *tag, int state)
+{
+ int slot = 0;
+
+ for (slot = 0; slot < MAX_EB_SLOTS; slot++)
+ {
+ if (!strcmp(tag, m_expansion_slot[slot]->tag())) break;
+ }
+
+ assert(slot < MAX_EB_SLOTS);
+
+ m_int[slot] = state;
+
+ int irq = CLEAR_LINE;
+
+ for (slot = 0; slot < MAX_EB_SLOTS; slot++)
+ {
+ irq |= m_int[slot];
+ }
+
+ m_slot->int_w(irq);
+}
+
+
+//-------------------------------------------------
+// set_ef4 - set EF4 line state
+//-------------------------------------------------
+
+void comx_eb_device::set_ef4(const char *tag, int state)
+{
+ int slot = 0;
+
+ for (slot = 0; slot < MAX_EB_SLOTS; slot++)
+ {
+ if (!strcmp(tag, m_expansion_slot[slot]->tag())) break;
+ }
+
+ assert(slot < MAX_EB_SLOTS);
+
+ m_ef4[slot] = state;
+
+ int ef4 = CLEAR_LINE;
+
+ for (slot = 0; slot < MAX_EB_SLOTS; slot++)
+ {
+ ef4 |= m_ef4[slot];
+ }
+
+ m_slot->ef4_w(ef4);
+}
+
+
+
+//**************************************************************************
+// 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),
+ device_comx_expansion_card_interface(mconfig, *this),
+ m_select(0)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void comx_eb_device::device_start()
+{
+ m_expansion_slot[0] = dynamic_cast<comx_expansion_slot_device *>(subdevice(SLOT1_TAG));
+ m_expansion_slot[1] = dynamic_cast<comx_expansion_slot_device *>(subdevice(SLOT2_TAG));
+ m_expansion_slot[2] = dynamic_cast<comx_expansion_slot_device *>(subdevice(SLOT3_TAG));
+ m_expansion_slot[3] = dynamic_cast<comx_expansion_slot_device *>(subdevice(SLOT4_TAG));
+
+ for (int slot = 0; slot < MAX_EB_SLOTS; slot++)
+ {
+ m_int[slot] = CLEAR_LINE;
+ m_ef4[slot] = CLEAR_LINE;
+ }
+
+ m_rom = memregion("e000")->base();
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void comx_eb_device::device_reset()
+{
+}
+
+
+//-------------------------------------------------
+// comx_q_w - Q write
+//-------------------------------------------------
+
+void comx_eb_device::comx_q_w(int state)
+{
+ for (int slot = 0; slot < MAX_EB_SLOTS; slot++)
+ {
+ if (BIT(m_select, slot) && m_expansion_slot[slot] != NULL)
+ {
+ m_expansion_slot[slot]->q_w(state);
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// comx_mrd_r - memory read
+//-------------------------------------------------
+
+UINT8 comx_eb_device::comx_mrd_r(offs_t offset, int *extrom)
+{
+ UINT8 data = 0;
+
+ if (offset >= 0x1000 && offset < 0x1800)
+ {
+ data = m_rom[offset & 0x7ff];
+ *extrom = 0;
+ }
+ else if (offset >= 0xe000 && offset < 0xf000)
+ {
+ data = m_rom[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(offset, extrom);
+ }
+ }
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// comx_mwr_w - memory write
+//-------------------------------------------------
+
+void comx_eb_device::comx_mwr_w(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(offset, data);
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// comx_io_r - I/O read
+//-------------------------------------------------
+
+UINT8 comx_eb_device::comx_io_r(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(offset);
+ }
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// comx_io_w - I/O write
+//-------------------------------------------------
+
+void comx_eb_device::comx_io_w(offs_t offset, UINT8 data)
+{
+ if (offset == 1)
+ {
+ 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(offset, data);
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// comx_screen_update - screen update
+//-------------------------------------------------
+
+UINT32 comx_eb_device::comx_screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ bool value = false;
+
+ for (int slot = 0; slot < MAX_EB_SLOTS; slot++)
+ {
+ if (BIT(m_select, slot) && m_expansion_slot[slot] != NULL)
+ {
+ m_expansion_slot[slot]->screen_update(screen, bitmap, cliprect);
+ }
+ }
+
+ return value;
+}
diff --git a/src/mess/machine/comx_eb.h b/src/mess/machine/comx_eb.h
new file mode 100644
index 00000000000..e15a4880439
--- /dev/null
+++ b/src/mess/machine/comx_eb.h
@@ -0,0 +1,86 @@
+/**********************************************************************
+
+ COMX-35E Expansion Box emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __COMX_EB__
+#define __COMX_EB__
+
+
+#include "emu.h"
+#include "machine/comxexp.h"
+#include "machine/comx_clm.h"
+#include "machine/comx_epr.h"
+#include "machine/comx_fd.h"
+#include "machine/comx_joy.h"
+#include "machine/comx_prn.h"
+#include "machine/comx_ram.h"
+#include "machine/comx_thm.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);
+
+ // optional information overrides
+ virtual const rom_entry *device_rom_region() const;
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+ // not really public
+ void set_int(const char *tag, int state);
+ void set_ef4(const char *tag, int state);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "comx_eb"; }
+
+ // device_comx_expansion_card_interface overrides
+ virtual void comx_q_w(int state);
+ virtual UINT8 comx_mrd_r(offs_t offset, int *extrom);
+ virtual void comx_mwr_w(offs_t offset, UINT8 data);
+ virtual UINT8 comx_io_r(offs_t offset);
+ virtual void comx_io_w(offs_t offset, UINT8 data);
+ virtual UINT32 comx_screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+private:
+ UINT8 *m_rom; // program ROM
+
+ comx_expansion_slot_device *m_expansion_slot[MAX_EB_SLOTS];
+ int m_int[MAX_EB_SLOTS];
+ int m_ef4[MAX_EB_SLOTS];
+
+ UINT8 m_select;
+};
+
+
+// device type definition
+extern const device_type COMX_EB;
+
+
+#endif
diff --git a/src/mess/machine/comx_epr.c b/src/mess/machine/comx_epr.c
new file mode 100644
index 00000000000..0c70a3a76a6
--- /dev/null
+++ b/src/mess/machine/comx_epr.c
@@ -0,0 +1,123 @@
+/**********************************************************************
+
+ COMX-35 F&M EPROM Card emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "comx_epr.h"
+
+
+
+//**************************************************************************
+// MACROS/CONSTANTS
+//**************************************************************************
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type COMX_EPR = &device_creator<comx_epr_device>;
+
+
+//-------------------------------------------------
+// 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),
+ device_comx_expansion_card_interface(mconfig, *this),
+ m_select(0)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void comx_epr_device::device_start()
+{
+ m_rom = memregion("f800")->base();
+ m_eprom = memregion("eprom")->base();
+
+ // 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(offs_t offset, int *extrom)
+{
+ UINT8 data = 0;
+
+ if (offset >= 0xc000 && offset < 0xe000)
+ {
+ offs_t address = (m_select << 13) | (offset & 0x1fff);
+ data = m_eprom[address];
+ }
+ else if (offset >= 0xf800)
+ {
+ data = m_rom[offset & 0x7ff];
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// comx_io_w - I/O write
+//-------------------------------------------------
+
+void comx_epr_device::comx_io_w(offs_t offset, UINT8 data)
+{
+ if (offset == 1)
+ {
+ m_select = data >> 5;
+ }
+}
diff --git a/src/mess/machine/comx_epr.h b/src/mess/machine/comx_epr.h
new file mode 100644
index 00000000000..195bcaf61e7
--- /dev/null
+++ b/src/mess/machine/comx_epr.h
@@ -0,0 +1,58 @@
+/**********************************************************************
+
+ COMX-35 F&M EPROM Card emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __COMX_EPR__
+#define __COMX_EPR__
+
+
+#include "emu.h"
+#include "machine/comxexp.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();
+ virtual void device_config_complete() { m_shortname = "comx_epr"; }
+
+ // device_comx_expansion_card_interface overrides
+ virtual UINT8 comx_mrd_r(offs_t offset, int *extrom);
+ virtual void comx_io_w(offs_t offset, UINT8 data);
+
+private:
+ UINT8 m_select;
+ UINT8 *m_rom; // program ROM
+ UINT8 *m_eprom; // EPROMs
+};
+
+
+// device type definition
+extern const device_type COMX_EPR;
+
+
+#endif
diff --git a/src/mess/machine/comx_fd.c b/src/mess/machine/comx_fd.c
new file mode 100644
index 00000000000..ed803070c49
--- /dev/null
+++ b/src/mess/machine/comx_fd.c
@@ -0,0 +1,332 @@
+/**********************************************************************
+
+ COMX-35 Disk Controller Card emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+(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 "comx_fd.h"
+
+
+
+//**************************************************************************
+// MACROS/CONSTANTS
+//**************************************************************************
+
+#define WD1770_TAG "wd1770"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type COMX_FD = &device_creator<comx_fd_device>;
+
+
+//-------------------------------------------------
+// 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 );
+}
+
+
+//-------------------------------------------------
+// wd17xx_interface fdc_intf
+//-------------------------------------------------
+
+static const floppy_interface floppy_intf =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ FLOPPY_STANDARD_5_25_DSSD,
+ LEGACY_FLOPPY_OPTIONS_NAME(comx35),
+ "floppy_5_25",
+ NULL
+};
+
+WRITE_LINE_MEMBER( comx_fd_device::intrq_w )
+{
+ m_intrq = state;
+}
+
+WRITE_LINE_MEMBER( comx_fd_device::drq_w )
+{
+ m_drq = state;
+
+ update_ef4();
+}
+
+static const wd17xx_interface fdc_intf =
+{
+ DEVCB_LINE_VCC,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, comx_fd_device, intrq_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, comx_fd_device, drq_w),
+ { FLOPPY_0, FLOPPY_1, NULL, NULL }
+};
+
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( comx_fd )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( comx_fd )
+ MCFG_WD1770_ADD(WD1770_TAG, fdc_intf)
+ MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(floppy_intf)
+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 );
+}
+
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// update_ef4 -
+//-------------------------------------------------
+
+inline void comx_fd_device::update_ef4()
+{
+ if (m_ds && !m_disb)
+ {
+ m_slot->ef4_w(!m_drq);
+ }
+ else
+ {
+ m_slot->ef4_w(CLEAR_LINE);
+ }
+}
+
+
+
+//**************************************************************************
+// 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),
+ device_comx_expansion_card_interface(mconfig, *this),
+ m_fdc(*this, WD1770_TAG),
+ m_floppy0(*this, FLOPPY_0),
+ m_floppy1(*this, FLOPPY_1),
+ m_ds(0),
+ m_q(0),
+ m_addr(0),
+ m_intrq(0),
+ m_drq(0),
+ m_disb(1)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void comx_fd_device::device_start()
+{
+ m_rom = memregion("c000")->base();
+
+ // state saving
+ save_item(NAME(m_ds));
+ save_item(NAME(m_q));
+ save_item(NAME(m_addr));
+ save_item(NAME(m_intrq));
+ save_item(NAME(m_drq));
+ save_item(NAME(m_disb));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void comx_fd_device::device_reset()
+{
+ wd17xx_reset(m_fdc);
+}
+
+
+//-------------------------------------------------
+// comx_q_w - Q write
+//-------------------------------------------------
+
+void comx_fd_device::comx_q_w(int state)
+{
+ m_q = state;
+}
+
+
+//-------------------------------------------------
+// comx_ds_w - device select write
+//-------------------------------------------------
+
+void comx_fd_device::comx_ds_w(int state)
+{
+ m_ds = state;
+
+ update_ef4();
+}
+
+
+//-------------------------------------------------
+// comx_mrd_r - memory read
+//-------------------------------------------------
+
+UINT8 comx_fd_device::comx_mrd_r(offs_t offset, int *extrom)
+{
+ UINT8 data = 0xff;
+
+ if (offset >= 0x0dd0 && offset < 0x0de0)
+ {
+ data = m_rom[offset & 0x1fff];
+ *extrom = 0;
+ }
+ if (offset >= 0xc000 && offset < 0xe000)
+ {
+ data = m_rom[offset & 0x1fff];
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// comx_io_r - I/O read
+//-------------------------------------------------
+
+UINT8 comx_fd_device::comx_io_r(offs_t offset)
+{
+ UINT8 data = 0xff;
+
+ if (offset == 2)
+ {
+ if (m_q)
+ {
+ data = m_intrq;
+ }
+ else
+ {
+ data = wd17xx_r(m_fdc, m_addr);
+ }
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// comx_io_w - I/O write
+//-------------------------------------------------
+
+void comx_fd_device::comx_io_w(offs_t offset, UINT8 data)
+{
+ if (offset == 2)
+ {
+ if (m_q)
+ {
+ /*
+
+ bit description
+
+ 0 A0
+ 1 A1
+ 2 DRIVE0
+ 3 DRIVE1
+ 4 F9 DISB
+ 5 SIDE SELECT
+
+ */
+
+ // latch data to F3
+ m_addr = data & 0x03;
+
+ if (BIT(data, 2))
+ {
+ wd17xx_set_drive(m_fdc, 0);
+ }
+ else if (BIT(data, 3))
+ {
+ wd17xx_set_drive(m_fdc, 1);
+ }
+
+ m_disb = !BIT(data, 4);
+ update_ef4();
+
+ wd17xx_set_side(m_fdc, BIT(data, 5));
+ }
+ else
+ {
+ // write data to WD1770
+ wd17xx_w(m_fdc, m_addr, data);
+ }
+ }
+}
diff --git a/src/mess/machine/comx_fd.h b/src/mess/machine/comx_fd.h
new file mode 100644
index 00000000000..32f36a0cef4
--- /dev/null
+++ b/src/mess/machine/comx_fd.h
@@ -0,0 +1,82 @@
+/**********************************************************************
+
+ COMX-35 Disk Controller Card emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __COMX_FD__
+#define __COMX_FD__
+
+
+#include "emu.h"
+#include "formats/basicdsk.h"
+#include "formats/comx35_dsk.h"
+#include "imagedev/flopdrv.h"
+#include "machine/comxexp.h"
+#include "machine/wd17xx.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;
+
+ // not really public
+ DECLARE_WRITE_LINE_MEMBER( intrq_w );
+ DECLARE_WRITE_LINE_MEMBER( drq_w );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "comx_fd"; }
+
+ // device_comx_expansion_card_interface overrides
+ virtual void comx_ds_w(int state);
+ virtual void comx_q_w(int state);
+ virtual UINT8 comx_mrd_r(offs_t offset, int *extrom);
+ virtual UINT8 comx_io_r(offs_t offset);
+ virtual void comx_io_w(offs_t offset, UINT8 data);
+
+private:
+ inline void update_ef4();
+
+ // internal state
+ required_device<device_t> m_fdc;
+ required_device<device_t> m_floppy0;
+ required_device<device_t> m_floppy1;
+
+ // floppy state
+ int m_ds; // device select
+ UINT8 *m_rom;
+ int m_q; // FDC register select
+ int m_addr; // FDC address
+ int m_intrq; // interrupt request
+ int m_drq; // data request
+ int m_disb; // data request disable
+};
+
+
+// device type definition
+extern const device_type COMX_FD;
+
+
+#endif
diff --git a/src/mess/machine/comx_joy.c b/src/mess/machine/comx_joy.c
new file mode 100644
index 00000000000..8b28d6888eb
--- /dev/null
+++ b/src/mess/machine/comx_joy.c
@@ -0,0 +1,113 @@
+/**********************************************************************
+
+ COMX-35 F&M Joycard emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "comx_joy.h"
+
+
+
+//**************************************************************************
+// MACROS/CONSTANTS
+//**************************************************************************
+
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type COMX_JOY = &device_creator<comx_joy_device>;
+
+
+//-------------------------------------------------
+// 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),
+ device_comx_expansion_card_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// 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(offs_t offset)
+{
+ UINT8 data = 0;
+
+ if (offset == 2)
+ {
+ data = ioport("JOY1")->read();
+ }
+ else if (offset == 4)
+ {
+ data = ioport("JOY2")->read();
+ }
+
+ return data;
+}
diff --git a/src/mess/machine/comx_joy.h b/src/mess/machine/comx_joy.h
new file mode 100644
index 00000000000..dd7944fbad3
--- /dev/null
+++ b/src/mess/machine/comx_joy.h
@@ -0,0 +1,52 @@
+/**********************************************************************
+
+ COMX-35 F&M Joycard emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __COMX_JOY__
+#define __COMX_JOY__
+
+
+#include "emu.h"
+#include "machine/comxexp.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();
+ virtual void device_config_complete() { m_shortname = "comx_joy"; }
+
+ // device_comx_expansion_card_interface overrides
+ virtual UINT8 comx_io_r(offs_t offset);
+};
+
+
+// device type definition
+extern const device_type COMX_JOY;
+
+
+#endif
diff --git a/src/mess/machine/comx_prn.c b/src/mess/machine/comx_prn.c
new file mode 100644
index 00000000000..45f8d322aad
--- /dev/null
+++ b/src/mess/machine/comx_prn.c
@@ -0,0 +1,143 @@
+/**********************************************************************
+
+ COMX-35 Serial/Parallel Printer Card emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "comx_prn.h"
+
+
+
+//**************************************************************************
+// MACROS/CONSTANTS
+//**************************************************************************
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type COMX_PRN = &device_creator<comx_prn_device>;
+
+
+//-------------------------------------------------
+// ROM( comx_prn )
+//-------------------------------------------------
+
+ROM_START( comx_prn )
+ ROM_REGION( 0x2000, "c000", 0 )
+ ROM_LOAD( "printer.bin", 0x0000, 0x0800, CRC(3bbc2b2e) SHA1(08bf7ea4174713ab24969c553affd5c1401876b8) )
+
+ ROM_REGION( 0x2000, "printer_fm", 0 )
+ ROM_LOAD( "f&m.printer.1.2.bin", 0x0000, 0x1000, CRC(2feb997d) SHA1(ee9cb91042696c88ff5f2f44d2f702dc93369ba0) )
+
+ ROM_REGION( 0x2000, "rs232", 0 )
+ ROM_LOAD( "rs232.bin", 0x0000, 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 );
+}
+
+
+//**************************************************************************
+// 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 F&M Printer Card", tag, owner, clock),
+ device_comx_expansion_card_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void comx_prn_device::device_start()
+{
+ m_rom = memregion("c000")->base();
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void comx_prn_device::device_reset()
+{
+}
+
+
+//-------------------------------------------------
+// comx_mrd_r - memory read
+//-------------------------------------------------
+
+UINT8 comx_prn_device::comx_mrd_r(offs_t offset, int *extrom)
+{
+ UINT8 data = 0;
+
+ if (offset >= 0xc000 && offset < 0xd000)
+ {
+ data = m_rom[offset & 0xfff];
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// comx_io_r - I/O read
+//-------------------------------------------------
+
+UINT8 comx_prn_device::comx_io_r(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.
+ */
+
+ return 0;
+}
+
+
+//-------------------------------------------------
+// comx_io_w - I/O write
+//-------------------------------------------------
+
+void comx_prn_device::comx_io_w(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
+ */
+}
diff --git a/src/mess/machine/comx_prn.h b/src/mess/machine/comx_prn.h
new file mode 100644
index 00000000000..c049dc9c58b
--- /dev/null
+++ b/src/mess/machine/comx_prn.h
@@ -0,0 +1,57 @@
+/**********************************************************************
+
+ COMX-35 Serial/Parallel Printer Card emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __COMX_PRN__
+#define __COMX_PRN__
+
+
+#include "emu.h"
+#include "machine/comxexp.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;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "comx_prn"; }
+
+ // device_comx_expansion_card_interface overrides
+ virtual UINT8 comx_mrd_r(offs_t offset, int *extrom);
+ virtual UINT8 comx_io_r(offs_t offset);
+ virtual void comx_io_w(offs_t offset, UINT8 data);
+
+private:
+ UINT8 *m_rom; // program ROM
+};
+
+
+// device type definition
+extern const device_type COMX_PRN;
+
+
+#endif
diff --git a/src/mess/machine/comx_ram.c b/src/mess/machine/comx_ram.c
new file mode 100644
index 00000000000..ffdab39b161
--- /dev/null
+++ b/src/mess/machine/comx_ram.c
@@ -0,0 +1,106 @@
+/**********************************************************************
+
+ COMX-35 RAM Card emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "comx_ram.h"
+
+
+
+//**************************************************************************
+// MACROS/CONSTANTS
+//**************************************************************************
+
+#define RAM_SIZE 0x8000
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type COMX_RAM = &device_creator<comx_ram_device>;
+
+
+//**************************************************************************
+// 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),
+ device_comx_expansion_card_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void comx_ram_device::device_start()
+{
+ m_ram = auto_alloc_array(machine(), UINT8, RAM_SIZE);
+
+ // state saving
+ save_pointer(NAME(m_ram), 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(offs_t offset, int *extrom)
+{
+ UINT8 data = 0;
+
+ if (offset >= 0xc000 && offset < 0xd000)
+ {
+ data = m_ram[(m_ram_bank << 12) | (offset & 0xfff)];
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// comx_mwr_w - memory write
+//-------------------------------------------------
+
+void comx_ram_device::comx_mwr_w(offs_t offset, UINT8 data)
+{
+ if (offset >= 0xc000 && offset < 0xd000)
+ {
+ m_ram[(m_ram_bank << 12) | (offset & 0xfff)] = data;
+ }
+}
+
+
+//-------------------------------------------------
+// comx_io_w - I/O write
+//-------------------------------------------------
+
+void comx_ram_device::comx_io_w(offs_t offset, UINT8 data)
+{
+ if (offset == 1)
+ {
+ m_ram_bank = (data >> 4) & 0x03;
+ }
+}
diff --git a/src/mess/machine/comx_ram.h b/src/mess/machine/comx_ram.h
new file mode 100644
index 00000000000..571d202fa58
--- /dev/null
+++ b/src/mess/machine/comx_ram.h
@@ -0,0 +1,55 @@
+/**********************************************************************
+
+ COMX-35 RAM Card emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __COMX_RAM__
+#define __COMX_RAM__
+
+
+#include "emu.h"
+#include "machine/comxexp.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();
+ virtual void device_config_complete() { m_shortname = "comx_ram"; }
+
+ // device_comx_expansion_card_interface overrides
+ virtual UINT8 comx_mrd_r(offs_t offset, int *extrom);
+ virtual void comx_mwr_w(offs_t offset, UINT8 data);
+ virtual void comx_io_w(offs_t offset, UINT8 data);
+
+private:
+ UINT8 *m_ram;
+ int m_ram_bank;
+};
+
+
+// device type definition
+extern const device_type COMX_RAM;
+
+
+#endif
diff --git a/src/mess/machine/comx_thm.c b/src/mess/machine/comx_thm.c
new file mode 100644
index 00000000000..8900b66bd91
--- /dev/null
+++ b/src/mess/machine/comx_thm.c
@@ -0,0 +1,128 @@
+/**********************************************************************
+
+ COMX-35 Thermal Printer Card emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "comx_thm.h"
+
+
+
+//**************************************************************************
+// MACROS/CONSTANTS
+//**************************************************************************
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type COMX_THM = &device_creator<comx_thm_device>;
+
+
+//-------------------------------------------------
+// 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),
+ device_comx_expansion_card_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void comx_thm_device::device_start()
+{
+ m_rom = memregion("c000")->base();
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void comx_thm_device::device_reset()
+{
+}
+
+
+//-------------------------------------------------
+// comx_mrd_r - memory read
+//-------------------------------------------------
+
+UINT8 comx_thm_device::comx_mrd_r(offs_t offset, int *extrom)
+{
+ UINT8 data = 0;
+
+ if (offset >= 0xc000 && offset < 0xd000)
+ {
+ data = m_rom[offset & 0xfff];
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// comx_io_r - I/O read
+//-------------------------------------------------
+
+UINT8 comx_thm_device::comx_io_r(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(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/mess/machine/comx_thm.h b/src/mess/machine/comx_thm.h
new file mode 100644
index 00000000000..b603f920962
--- /dev/null
+++ b/src/mess/machine/comx_thm.h
@@ -0,0 +1,57 @@
+/**********************************************************************
+
+ COMX-35 Thermal Printer Card emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __COMX_THM__
+#define __COMX_THM__
+
+
+#include "emu.h"
+#include "machine/comxexp.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();
+ virtual void device_config_complete() { m_shortname = "comx_thm"; }
+
+ // device_comx_expansion_card_interface overrides
+ virtual UINT8 comx_mrd_r(offs_t offset, int *extrom);
+ virtual UINT8 comx_io_r(offs_t offset);
+ virtual void comx_io_w(offs_t offset, UINT8 data);
+
+private:
+ UINT8 *m_rom; // program ROM
+};
+
+
+// device type definition
+extern const device_type COMX_THM;
+
+
+#endif
diff --git a/src/mess/machine/comxexp.c b/src/mess/machine/comxexp.c
new file mode 100644
index 00000000000..a6fd487221c
--- /dev/null
+++ b/src/mess/machine/comxexp.c
@@ -0,0 +1,228 @@
+/**********************************************************************
+
+ COMX-35 Expansion Slot emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "emu.h"
+#include "emuopts.h"
+#include "machine/comxexp.h"
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type COMX_EXPANSION_SLOT = &device_creator<comx_expansion_slot_device>;
+
+
+//**************************************************************************
+// 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_slot = dynamic_cast<comx_expansion_slot_device *>(device.owner());
+}
+
+
+//-------------------------------------------------
+// ~device_comx_expansion_card_interface - destructor
+//-------------------------------------------------
+
+device_comx_expansion_card_interface::~device_comx_expansion_card_interface()
+{
+}
+
+
+
+//**************************************************************************
+// 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),
+ device_slot_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// comx_expansion_slot_device - destructor
+//-------------------------------------------------
+
+comx_expansion_slot_device::~comx_expansion_slot_device()
+{
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void comx_expansion_slot_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const comx_expansion_slot_interface *intf = reinterpret_cast<const comx_expansion_slot_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<comx_expansion_slot_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_int_cb, 0, sizeof(m_out_int_cb));
+ memset(&m_out_ef4_cb, 0, sizeof(m_out_ef4_cb));
+ memset(&m_out_wait_cb, 0, sizeof(m_out_wait_cb));
+ memset(&m_out_clear_cb, 0, sizeof(m_out_clear_cb));
+ }
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void comx_expansion_slot_device::device_start()
+{
+ m_card = dynamic_cast<device_comx_expansion_card_interface *>(get_card_device());
+
+ // resolve callbacks
+ m_out_int_func.resolve(m_out_int_cb, *this);
+ m_out_ef4_func.resolve(m_out_ef4_cb, *this);
+ m_out_wait_func.resolve(m_out_wait_cb, *this);
+ m_out_clear_func.resolve(m_out_clear_cb, *this);
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void comx_expansion_slot_device::device_reset()
+{
+}
+
+
+//-------------------------------------------------
+// mrd_r - memory read
+//-------------------------------------------------
+
+UINT8 comx_expansion_slot_device::mrd_r(offs_t offset, int *extrom)
+{
+ UINT8 data = 0;
+
+ if (m_card != NULL)
+ {
+ data = m_card->comx_mrd_r(offset, extrom);
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// mwr_w - memory write
+//-------------------------------------------------
+
+void comx_expansion_slot_device::mwr_w(offs_t offset, UINT8 data)
+{
+ if (m_card != NULL)
+ {
+ m_card->comx_mwr_w(offset, data);
+ }
+}
+
+
+//-------------------------------------------------
+// io_r - I/O read
+//-------------------------------------------------
+
+UINT8 comx_expansion_slot_device::io_r(offs_t offset)
+{
+ UINT8 data = 0;
+
+ if (m_card != NULL)
+ {
+ data = m_card->comx_io_r(offset);
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// sout_w - I/O write
+//-------------------------------------------------
+
+void comx_expansion_slot_device::io_w(offs_t offset, UINT8 data)
+{
+ if (m_card != NULL)
+ {
+ m_card->comx_io_w(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);
+ }
+}
+
+
+//-------------------------------------------------
+// screen_update -
+//-------------------------------------------------
+
+UINT32 comx_expansion_slot_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ bool value = false;
+
+ if (m_card != NULL)
+ {
+ value = m_card->comx_screen_update(screen, bitmap, cliprect);
+ }
+
+ return value;
+}
+
+
+WRITE_LINE_MEMBER( comx_expansion_slot_device::int_w ) { m_out_int_func(state); }
+WRITE_LINE_MEMBER( comx_expansion_slot_device::ef4_w ) { m_out_ef4_func(state); }
+WRITE_LINE_MEMBER( comx_expansion_slot_device::wait_w ) { m_out_wait_func(state); }
+WRITE_LINE_MEMBER( comx_expansion_slot_device::clear_w ) { m_out_clear_func(state); }
diff --git a/src/mess/machine/comxexp.h b/src/mess/machine/comxexp.h
new file mode 100644
index 00000000000..354a30fad58
--- /dev/null
+++ b/src/mess/machine/comxexp.h
@@ -0,0 +1,163 @@
+/**********************************************************************
+
+ COMX-35 Expansion Slot emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+
+ 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 COMX_EXPANSION_INTERFACE(_name) \
+ const comx_expansion_slot_interface (_name) =
+
+
+#define MCFG_COMX_EXPANSION_SLOT_ADD(_tag, _config, _slot_intf, _def_slot, _def_inp) \
+ MCFG_DEVICE_ADD(_tag, COMX_EXPANSION_SLOT, 0) \
+ MCFG_DEVICE_CONFIG(_config) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false)
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> comx_expansion_slot_interface
+
+struct comx_expansion_slot_interface
+{
+ devcb_write_line m_out_int_cb;
+ devcb_write_line m_out_ef4_cb;
+ devcb_write_line m_out_wait_cb;
+ devcb_write_line m_out_clear_cb;
+};
+
+
+// ======================> comx_expansion_slot_device
+
+class device_comx_expansion_card_interface;
+
+class comx_expansion_slot_device : public device_t,
+ public comx_expansion_slot_interface,
+ 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();
+
+ UINT8 mrd_r(offs_t offset, int *extrom);
+ void mwr_w(offs_t offset, UINT8 data);
+
+ UINT8 io_r(offs_t offset);
+ void io_w(offs_t offset, UINT8 data);
+
+ DECLARE_WRITE_LINE_MEMBER( ds_w );
+ DECLARE_WRITE_LINE_MEMBER( q_w );
+
+ DECLARE_WRITE_LINE_MEMBER( int_w );
+ DECLARE_WRITE_LINE_MEMBER( ef4_w );
+ DECLARE_WRITE_LINE_MEMBER( wait_w );
+ DECLARE_WRITE_LINE_MEMBER( clear_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();
+ virtual void device_config_complete();
+
+ devcb_resolved_write_line m_out_int_func;
+ devcb_resolved_write_line m_out_ef4_func;
+ devcb_resolved_write_line m_out_wait_func;
+ devcb_resolved_write_line m_out_clear_func;
+
+ 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 void comx_ds_w(int state) { };
+ virtual void comx_q_w(int state) { };
+
+ // memory access
+ virtual UINT8 comx_mrd_r(offs_t offset, int *extrom) { return 0; };
+ virtual void comx_mwr_w(offs_t offset, UINT8 data) { };
+
+ // I/O access
+ virtual UINT8 comx_io_r(offs_t offset) { return 0; };
+ virtual void comx_io_w(offs_t offset, UINT8 data) { };
+
+ // video
+ virtual UINT32 comx_screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { return false; }
+
+ comx_expansion_slot_device *m_slot;
+};
+
+
+// device type definition
+extern const device_type COMX_EXPANSION_SLOT;
+
+
+
+#endif
diff --git a/src/mess/machine/comxpl80.c b/src/mess/machine/comxpl80.c
new file mode 100644
index 00000000000..940f780340b
--- /dev/null
+++ b/src/mess/machine/comxpl80.c
@@ -0,0 +1,347 @@
+/**********************************************************************
+
+ COMX PL-80 plotter emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ TODO:
+
+ - CPU type?
+
+*/
+
+#include "comxpl80.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define CX005_TAG "cx005"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type COMXPL80 = &device_creator<comxpl80_device>;
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void comxpl80_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const comxpl80_interface *intf = reinterpret_cast<const comxpl80_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<comxpl80_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ }
+
+ m_shortname = "comxpl80";
+}
+
+
+//-------------------------------------------------
+// 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 *comxpl80_device::device_rom_region() const
+{
+ return ROM_NAME( comxpl80 );
+}
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( comxpl80_mem )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( comxpl80_mem, AS_PROGRAM, 8, comxpl80_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, comxpl80_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 comxpl80_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 comxpl80_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( comxpl80 );
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// comxpl80_device - constructor
+//-------------------------------------------------
+
+comxpl80_device::comxpl80_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, COMXPL80, "COMX PL-80", tag, owner, clock)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void comxpl80_device::device_start()
+{
+ // state saving
+ save_item(NAME(m_centronics_data));
+ 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 comxpl80_device::device_reset()
+{
+}
+
+
+//-------------------------------------------------
+// pa_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( comxpl80_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 = (ioport("FONT")->read() & 0x03) * 0x2000;
+
+ m_plotter_data = memregion("gfx2")->base()[font_rom | m_font_addr];
+ }
+
+ if (!BIT(data, 6))
+ {
+ // read data from Centronics bus
+ m_plotter_data = m_centronics_data;
+ }
+
+ if (BIT(data, 7))
+ {
+ // read switches
+ m_plotter_data = ioport("SW")->read();
+ }
+}
+
+
+//-------------------------------------------------
+// pb_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( comxpl80_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( comxpl80_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( comxpl80_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/mess/machine/comxpl80.h b/src/mess/machine/comxpl80.h
new file mode 100644
index 00000000000..188c46f11e3
--- /dev/null
+++ b/src/mess/machine/comxpl80.h
@@ -0,0 +1,98 @@
+/**********************************************************************
+
+ COMX PL-80 plotter emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __COMXPL80__
+#define __COMXPL80__
+
+#include "emu.h"
+#include "cpu/m6805/m6805.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define COMXPL80_TAG "comxpl80"
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_COMXPL80_ADD() \
+ MCFG_DEVICE_ADD(COMXPL80_TAG, COMXPL80, 0)
+
+
+#define COMXPL80_INTERFACE(_name) \
+ const comxpl80_interface (_name) =
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> comxpl80_interface
+
+struct comxpl80_interface
+{
+ devcb_write_line m_out_txd_cb;
+ devcb_write_line m_out_clock_cb;
+ devcb_write_line m_out_keydown_cb;
+};
+
+// ======================> comxpl80_device
+
+class comxpl80_device : public device_t,
+ public comxpl80_interface
+{
+public:
+ // construction/destruction
+ comxpl80_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( 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 void device_config_complete();
+
+private:
+ // printer state
+ UINT8 m_centronics_data; // centronics data
+
+ // 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
+};
+
+
+// device type definition
+extern const device_type COMXPL80;
+
+
+
+#endif
diff --git a/src/mess/machine/concept.c b/src/mess/machine/concept.c
new file mode 100644
index 00000000000..42812eee9df
--- /dev/null
+++ b/src/mess/machine/concept.c
@@ -0,0 +1,728 @@
+/*
+ Corvus Concept driver
+
+ Raphael Nabet, Brett Wyer, 2003-2005
+*/
+
+#include "emu.h"
+#include "includes/concept.h"
+#include "machine/6522via.h"
+#include "machine/mm58274c.h" /* mm58274 seems to be compatible with mm58174 */
+//#include "machine/6551acia.h"
+#include "machine/wd17xx.h"
+#include "cpu/m68000/m68000.h"
+#include "includes/corvushd.h"
+#include "imagedev/flopdrv.h"
+
+
+#define VERBOSE 1
+
+#define LOG(x) do { if (VERBOSE > 0) logerror x; } while (0)
+#define VLOG(x) do { if (VERBOSE > 1) logerror x; } while (0)
+
+
+/* interrupt priority encoder */
+enum
+{
+ IOCINT_level = 1, /* serial lines (CTS, DSR & DCD) and I/O ports */
+ SR1INT_level, /* serial port 1 acia */
+ OMINT_level, /* omninet */
+ SR0INT_level, /* serial port 0 acia */
+ TIMINT_level, /* via */
+ KEYINT_level, /* keyboard acia */
+ NMIINT_level /* reserved */
+};
+
+/* Clock interface */
+
+/* Omninet */
+/*static int ready;*/ /* ready line from monochip, role unknown */
+
+/* Via */
+static READ8_DEVICE_HANDLER(via_in_a);
+static WRITE8_DEVICE_HANDLER(via_out_a);
+static READ8_DEVICE_HANDLER(via_in_b);
+static WRITE8_DEVICE_HANDLER(via_out_b);
+static WRITE8_DEVICE_HANDLER(via_out_cb2);
+static void via_irq_func(device_t *device, int state);
+
+
+const via6522_interface concept_via6522_intf =
+{ /* main via */
+ DEVCB_HANDLER(via_in_a), DEVCB_HANDLER(via_in_b),
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_HANDLER(via_out_a), DEVCB_HANDLER(via_out_b),
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_NULL, DEVCB_HANDLER(via_out_cb2),
+ DEVCB_LINE(via_irq_func)
+};
+
+/* keyboard interface */
+
+/* Expansion slots */
+
+static void concept_fdc_init(running_machine &machine, int slot);
+static void concept_hdc_init(running_machine &machine, int slot);
+
+MACHINE_START(concept)
+{
+ concept_state *state = machine.driver_data<concept_state>();
+ /* initialize int state */
+ state->m_pending_interrupts = 0;
+
+ /* initialize clock interface */
+ state->m_clock_enable = 0/*1*/;
+
+ /* clear keyboard interface state */
+ state->m_KeyQueueHead = state->m_KeyQueueLen = 0;
+ memset(state->m_KeyStateSave, 0, sizeof(state->m_KeyStateSave));
+
+ /* initialize expansion slots */
+ memset(state->m_expansion_slots, 0, sizeof(state->m_expansion_slots));
+
+ concept_hdc_init(machine, 1); /* Flat cable Hard Disk Controller in Slot 2 */
+ concept_fdc_init(machine, 2); /* Floppy Disk Controller in Slot 3 */
+}
+
+static void install_expansion_slot(running_machine &machine, int slot,
+ read8_space_func reg_read, write8_space_func reg_write,
+ read8_space_func rom_read, write8_space_func rom_write)
+{
+ concept_state *state = machine.driver_data<concept_state>();
+ state->m_expansion_slots[slot].reg_read = reg_read;
+ state->m_expansion_slots[slot].reg_write = reg_write;
+ state->m_expansion_slots[slot].rom_read = rom_read;
+ state->m_expansion_slots[slot].rom_write = rom_write;
+}
+
+VIDEO_START(concept)
+{
+}
+
+SCREEN_UPDATE_IND16(concept)
+{
+ /* resolution is 720*560 */
+ concept_state *state = screen.machine().driver_data<concept_state>();
+ UINT16 *videoram = state->m_videoram;
+ int x, y;
+ UINT16 *line;
+
+ for (y = 0; y < 560; y++)
+ {
+ line = &bitmap.pix16(560-1-y);
+ for (x = 0; x < 720; x++)
+ line[720-1-x] = (videoram[(x+48+y*768)>>4] & (0x8000 >> ((x+48+y*768) & 0xf))) ? 0 : 1;
+ }
+ return 0;
+}
+
+static void concept_set_interrupt(running_machine &machine, int level, int state)
+{
+ concept_state *drvstate = machine.driver_data<concept_state>();
+ int interrupt_mask;
+ int final_level;
+
+ if (state)
+ drvstate->m_pending_interrupts |= 1 << level;
+ else
+ drvstate->m_pending_interrupts &= ~ (1 << level);
+
+ for (final_level = 7, interrupt_mask = drvstate->m_pending_interrupts; (final_level > 0) && ! (interrupt_mask & 0x80); final_level--, interrupt_mask <<= 1)
+ ;
+
+ if (final_level)
+ /* assert interrupt */
+ cputag_set_input_line_and_vector(machine, "maincpu", M68K_IRQ_1 + final_level - 1, ASSERT_LINE, M68K_INT_ACK_AUTOVECTOR);
+ else
+ /* clear all interrupts */
+ cputag_set_input_line_and_vector(machine, "maincpu", M68K_IRQ_1, CLEAR_LINE, M68K_INT_ACK_AUTOVECTOR);
+}
+
+INLINE void post_in_KeyQueue(concept_state *state, int keycode)
+{
+ state->m_KeyQueue[(state->m_KeyQueueHead+state->m_KeyQueueLen) % KeyQueueSize] = keycode;
+ state->m_KeyQueueLen++;
+}
+
+static void poll_keyboard(running_machine &machine)
+{
+ concept_state *state = machine.driver_data<concept_state>();
+ UINT32 keystate;
+ UINT32 key_transitions;
+ int i, j;
+ int keycode;
+ static const char *const keynames[] = { "KEY0", "KEY1", "KEY2", "KEY3", "KEY4", "KEY5" };
+
+ for(i = 0; (i < /*4*/3) && (state->m_KeyQueueLen <= (KeyQueueSize-MaxKeyMessageLen)); i++)
+ {
+ keystate = machine.root_device().ioport(keynames[2*i])->read() | (machine.root_device().ioport(keynames[2*i + 1])->read() << 16);
+ key_transitions = keystate ^ state->m_KeyStateSave[i];
+ if(key_transitions)
+ {
+ for(j = 0; (j < 32) && (state->m_KeyQueueLen <= (KeyQueueSize-MaxKeyMessageLen)); j++)
+ {
+ if((key_transitions >> j) & 1)
+ {
+ keycode = (i << 5) | j;
+
+ if (((keystate >> j) & 1))
+ {
+ /* key is pressed */
+ state->m_KeyStateSave[i] |= (1 << j);
+ keycode |= 0x80;
+ }
+ else
+ /* key is released */
+ state->m_KeyStateSave[i] &= ~ (1 << j);
+
+ post_in_KeyQueue(state, keycode);
+ concept_set_interrupt(machine, KEYINT_level, 1);
+ }
+ }
+ }
+ }
+}
+
+INTERRUPT_GEN( concept_interrupt )
+{
+ poll_keyboard(device->machine());
+}
+
+/*
+ VIA port A
+
+ 0: omninet ready (I)
+ 1: CTS0 (I)
+ 2: CTS1 (I)
+ 3: DSR0 (I)
+ 4: DSR1 (I)
+ 5: DCD0 (I)
+ 6: DCD1 (I)
+ 7: IOX (O)
+*/
+static READ8_DEVICE_HANDLER(via_in_a)
+{
+ LOG(("via_in_a: VIA port A (Omninet and COMM port status) read\n"));
+ return 1; /* omninet ready always 1 */
+}
+
+static WRITE8_DEVICE_HANDLER(via_out_a)
+{
+ LOG(("via_out_a: VIA port A status written: data=0x%2.2x\n", data));
+ /*iox = (data & 0x80) != 0;*/
+}
+
+/*
+ VIA port B
+
+ 0: video off (O)
+ 1: video address 17 (O)
+ 2: video address 18 (O)
+ 3: monitor orientation (I)
+ 4: CH rate select DC0 (serial port line) (O)
+ 5: CH rate select DC1 (serial port line) (O)
+ 6: boot switch 0 (I)
+ 7: boot switch 1 (I)
+*/
+static READ8_DEVICE_HANDLER(via_in_b)
+{
+ UINT8 status;
+
+ status = ((device->machine().root_device().ioport("DSW0")->read() & 0x80) >> 1) | ((device->machine().root_device().ioport("DSW0")->read() & 0x40) << 1);
+ LOG(("via_in_b: VIA port B (DIP switches, Video, Comm Rate) - status: 0x%2.2x\n", status));
+ return status;
+}
+
+static WRITE8_DEVICE_HANDLER(via_out_b)
+{
+ VLOG(("via_out_b: VIA port B (Video Control and COMM rate select) written: data=0x%2.2x\n", data));
+}
+
+/*
+ VIA CB2: used as sound output
+*/
+static WRITE8_DEVICE_HANDLER(via_out_cb2)
+{
+ LOG(("via_out_cb2: Sound control written: data=0x%2.2x\n", data));
+}
+
+/*
+ VIA irq -> 68k level 5
+*/
+static void via_irq_func(device_t *device, int state)
+{
+ concept_set_interrupt(device->machine(), TIMINT_level, state);
+}
+
+READ16_MEMBER(concept_state::concept_io_r)
+{
+ if (! ACCESSING_BITS_0_7)
+ return 0;
+
+ switch ((offset >> 8) & 7)
+ {
+ case 0:
+ /* I/O slot regs */
+ switch ((offset >> 4) & 7)
+ {
+ case 1:
+ /* IO1 registers */
+ case 2:
+ /* IO2 registers */
+ case 3:
+ /* IO3 registers */
+ case 4:
+ /* IO4 registers */
+ {
+ int slot = ((offset >> 4) & 7) - 1;
+ if (m_expansion_slots[slot].reg_read)
+ return m_expansion_slots[slot].reg_read(&space, offset & 0xf);
+ }
+ break;
+
+ default:
+ /* ??? */
+ logerror("concept_io_r: Slot I/O memory accessed for unknown purpose at address 0x03%4.4x\n", offset << 1);
+ break;
+ }
+ break;
+
+ case 1:
+ /* IO1 ROM */
+ case 2:
+ /* IO2 ROM */
+ case 3:
+ /* IO3 ROM */
+ case 4:
+ /* IO4 ROM */
+ {
+ int slot = ((offset >> 8) & 7) - 1;
+ LOG(("concept_io_r: Slot ROM memory accessed for slot %d at address 0x03%4.4x\n", slot, offset << 1));
+ if (m_expansion_slots[slot].rom_read)
+ return m_expansion_slots[slot].rom_read(&space, offset & 0xff);
+ }
+ break;
+
+ case 5:
+ /* slot status */
+ LOG(("concept_io_r: Slot status read at address 0x03%4.4x\n", offset << 1));
+ break;
+
+ case 6:
+ /* calendar R/W */
+ VLOG(("concept_io_r: Calendar read at address 0x03%4.4x\n", offset << 1));
+ if (!m_clock_enable)
+ return mm58274c_r(machine().device("mm58274c"), m_clock_address);
+ break;
+
+ case 7:
+ /* I/O ports */
+ switch ((offset >> 4) & 7)
+ {
+ case 0:
+ /* NKBP keyboard */
+ switch (offset & 0xf)
+ {
+ int reply;
+
+ case 0:
+ /* data */
+ reply = 0;
+
+ if (m_KeyQueueLen)
+ {
+ reply = m_KeyQueue[m_KeyQueueHead];
+ m_KeyQueueHead = (m_KeyQueueHead + 1) % KeyQueueSize;
+ m_KeyQueueLen--;
+ }
+
+ if (!m_KeyQueueLen)
+ concept_set_interrupt(machine(), KEYINT_level, 0);
+
+ return reply;
+
+ case 1:
+ /* always tell transmit is empty */
+ reply = m_KeyQueueLen ? 0x98 : 0x10;
+ break;
+ }
+ break;
+ case 1:
+ /* NSR0 data comm port 0 */
+ case 2:
+ /* NSR1 data comm port 1 */
+ LOG(("concept_io_r: Data comm port read at address 0x03%4.4x\n", offset << 1));
+ if ((offset & 0xf) == 1)
+ return 0x10;
+ break;
+
+ case 3:
+ /* NVIA versatile system interface */
+ LOG(("concept_io_r: VIA read at address 0x03%4.4x\n", offset << 1));
+ {
+ via6522_device *via_0 = machine().device<via6522_device>("via6522_0");
+ return via_0->read(space, offset & 0xf);
+ }
+ break;
+
+ case 4:
+ /* NCALM clock calendar address and strobe register */
+ /* write-only? */
+ LOG(("concept_io_r: NCALM clock/calendar read at address 0x03%4.4x\n", offset << 1));
+ break;
+
+ case 5:
+ /* NOMNI omninet strobe */
+ logerror("concept_io_r: NOMNI Omninet Transporter register read at address 0x03%4.4x\n", offset << 1);
+ break;
+
+ case 6:
+ /* NOMOFF reset omninet interrupt flip-flop */
+ logerror("concept_io_r: NOMOFF Omninet interrupt flip-flop read at address 0x03%4.4x\n", offset << 1);
+ break;
+
+ case 7:
+ /* NIOSTRB external I/O ROM strobe (disables interface RAM) */
+ logerror("concept_io_r: NIOSTRB External I/O ROM strobe read at address 0x03%4.4x\n", offset << 1);
+ break;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+WRITE16_MEMBER(concept_state::concept_io_w)
+{
+ if (! ACCESSING_BITS_0_7)
+ return;
+
+ data &= 0xff;
+
+ switch ((offset >> 8) & 7)
+ {
+ case 0:
+ /* I/O slot regs */
+ switch ((offset >> 4) & 7)
+ {
+ case 1:
+ /* IO1 registers */
+ case 2:
+ /* IO2 registers */
+ case 3:
+ /* IO3 registers */
+ case 4:
+ /* IO4 registers */
+ {
+ int slot = ((offset >> 4) & 7) - 1;
+ LOG(("concept_io_w: Slot I/O register written for slot %d at address 0x03%4.4x, data: 0x%4.4x\n",
+ slot, offset << 1, data));
+ if (m_expansion_slots[slot].reg_write)
+ m_expansion_slots[slot].reg_write(&space, offset & 0xf, data);
+ }
+ break;
+
+ default:
+ /* ??? */
+ logerror("concept_io_w: Slot I/O memory written for unknown purpose at address 0x03%4.4x, data: 0x%4.4x\n", offset << 1, data);
+ break;
+ }
+ break;
+
+ case 1:
+ /* IO1 ROM */
+ case 2:
+ /* IO2 ROM */
+ case 3:
+ /* IO3 ROM */
+ case 4:
+ /* IO4 ROM */
+ {
+ int slot = ((offset >> 8) & 7) - 1;
+ LOG(("concept_io_w: Slot ROM memory written to for slot %d at address 0x03%4.4x, data: 0x%4.4x\n", slot, offset << 1, data));
+ if (m_expansion_slots[slot].rom_write)
+ m_expansion_slots[slot].rom_write(&space, offset & 0xff, data);
+ }
+ break;
+
+ case 5:
+ /* slot status */
+ logerror("concept_io_w: Slot status written at address 0x03%4.4x, data: 0x%4.4x\n", offset << 1, data);
+ break;
+
+ case 6:
+ /* calendar R/W */
+ LOG(("concept_io_w: Calendar written to at address 0x03%4.4x, data: 0x%4.4x\n", offset << 1, data));
+ if (!m_clock_enable)
+ mm58274c_w(machine().device("mm58274c"), m_clock_address, data & 0xf);
+ break;
+
+ case 7:
+ /* I/O ports */
+ switch ((offset >> 4) & 7)
+ {
+ case 0:
+ /* NKBP keyboard */
+ case 1:
+ /* NSR0 data comm port 0 */
+ case 2:
+ /* NSR1 data comm port 1 */
+ /*acia_6551_w((offset >> 4) & 7, offset & 0x3, data);*/
+ break;
+
+ case 3:
+ /* NVIA versatile system interface */
+ {
+ via6522_device *via_0 = machine().device<via6522_device>("via6522_0");
+ via_0->write(space, offset & 0xf, data);
+ }
+ break;
+
+ case 4:
+ /* NCALM clock calendar address and strobe register */
+ if (m_clock_enable != ((data & 0x10) != 0))
+ {
+ m_clock_enable = (data & 0x10) != 0;
+ if (! m_clock_enable)
+ /* latch address when enable goes low */
+ m_clock_address = data & 0x0f;
+ }
+ /*volume_control = (data & 0x20) != 0;*/
+ /*alt_map = (data & 0x40) != 0;*/
+ break;
+
+ case 5:
+ /* NOMNI omninet strobe */
+ logerror("concept_io_w: NOMNI Omninet Transporter register written at address 0x03%4.4x, data: 0x%4.4x\n", offset << 1, data);
+ break;
+
+ case 6:
+ /* NOMOFF reset omninet interrupt flip-flop */
+ logerror("concept_io_w: NOMOFF Omninet flip-flop reset at address 0x03%4.4x, data: 0x%4.4x\n", offset << 1, data);
+ break;
+
+ case 7:
+ /* NIOSTRB external I/O ROM strobe */
+ logerror("concept_io_w: NIOSTRB External I/O ROM strobe written at address 0x03%4.4x, data: 0x%4.4x\n", offset << 1, data);
+ break;
+ }
+ break;
+ }
+}
+
+/*
+ Concept fdc controller
+*/
+
+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)
+};
+
+
+static READ8_HANDLER(concept_fdc_reg_r);
+static WRITE8_HANDLER(concept_fdc_reg_w);
+static READ8_HANDLER(concept_fdc_rom_r);
+
+static void concept_fdc_init(running_machine &machine, int slot)
+{
+ concept_state *state = machine.driver_data<concept_state>();
+ state->m_fdc_local_status = 0;
+ state->m_fdc_local_command = 0;
+
+ install_expansion_slot(machine, slot, concept_fdc_reg_r, concept_fdc_reg_w, concept_fdc_rom_r, NULL);
+}
+
+static WRITE_LINE_DEVICE_HANDLER( concept_fdc_intrq_w )
+{
+ concept_state *drvstate = device->machine().driver_data<concept_state>();
+ if (state)
+ drvstate->m_fdc_local_status |= LS_INT_mask;
+ else
+ drvstate->m_fdc_local_status &= ~LS_INT_mask;
+}
+
+static WRITE_LINE_DEVICE_HANDLER( concept_fdc_drq_w )
+{
+ concept_state *drvstate = device->machine().driver_data<concept_state>();
+ if (state)
+ drvstate->m_fdc_local_status |= LS_DRQ_mask;
+ else
+ drvstate->m_fdc_local_status &= ~LS_DRQ_mask;
+}
+
+const wd17xx_interface concept_wd17xx_interface =
+{
+ DEVCB_NULL,
+ DEVCB_LINE(concept_fdc_intrq_w),
+ DEVCB_LINE(concept_fdc_drq_w),
+ {FLOPPY_0, FLOPPY_1, FLOPPY_2, FLOPPY_3}
+};
+
+static READ8_HANDLER(concept_fdc_reg_r)
+{
+ concept_state *state = space->machine().driver_data<concept_state>();
+ device_t *fdc = space->machine().device("wd179x");
+ switch (offset)
+ {
+ case 0:
+ /* local Status reg */
+ return state->m_fdc_local_status;
+
+ case 8:
+ /* FDC STATUS REG */
+ return wd17xx_status_r(fdc, offset);
+
+ case 9:
+ /* FDC TRACK REG */
+ return wd17xx_track_r(fdc, offset);
+
+ case 10:
+ /* FDC SECTOR REG */
+ return wd17xx_sector_r(fdc, offset);
+
+ case 11:
+ /* FDC DATA REG */
+ return wd17xx_data_r(fdc, offset);
+ }
+
+ return 0;
+}
+
+static WRITE8_HANDLER(concept_fdc_reg_w)
+{
+ concept_state *state = space->machine().driver_data<concept_state>();
+ int current_drive;
+ device_t *fdc = space->machine().device("wd179x");
+ switch (offset)
+ {
+ case 0:
+ /* local command reg */
+ state->m_fdc_local_command = data;
+
+ wd17xx_set_side(fdc,(data & LC_FLPSD1_mask) != 0);
+ current_drive = ((data >> LC_DE0_bit) & 1) | ((data >> (LC_DE1_bit-1)) & 2);
+ wd17xx_set_drive(fdc, current_drive);
+ /*motor_on = (data & LC_MOTOROF_mask) == 0;*/
+ // floppy_drive_set_motor_state(floppy_get_device(machine, current_drive), (data & LC_MOTOROF_mask) == 0 ? 1 : 0);
+ /*flp_8in = (data & LC_FLP8IN_mask) != 0;*/
+ wd17xx_dden_w(fdc, BIT(data, 7));
+ floppy_drive_set_ready_state(floppy_get_device(space->machine(), current_drive), 1, 0);
+ break;
+
+ case 8:
+ /* FDC COMMAMD REG */
+ wd17xx_command_w(fdc, offset, data);
+ break;
+
+ case 9:
+ /* FDC TRACK REG */
+ wd17xx_track_w(fdc, offset, data);
+ break;
+
+ case 10:
+ /* FDC SECTOR REG */
+ wd17xx_sector_w(fdc, offset, data);
+ break;
+
+ case 11:
+ /* FDC DATA REG */
+ wd17xx_data_w(fdc, offset, data);
+ break;
+ }
+}
+
+static READ8_HANDLER(concept_fdc_rom_r)
+{
+ static const UINT8 data[] = "CORVUS01";
+ return (offset < 8) ? data[offset] : 0;
+}
+
+/*
+ * Concept Hard Disk Controller (hdc)
+ */
+
+static READ8_HANDLER(concept_hdc_reg_r);
+static WRITE8_HANDLER(concept_hdc_reg_w);
+static READ8_HANDLER(concept_hdc_rom_r);
+
+/*
+ * Hook up the Register and ROM R/W routines into the Slot I/O Space
+ */
+
+static void concept_hdc_init(running_machine &machine, int slot)
+{
+ if(corvus_hdc_init(machine))
+ install_expansion_slot(machine, slot, concept_hdc_reg_r, concept_hdc_reg_w, concept_hdc_rom_r, NULL);
+}
+
+/*
+ * Handle reads against the Hard Disk Controller's onboard registers
+ */
+static READ8_HANDLER(concept_hdc_reg_r)
+{
+ switch (offset)
+ {
+ case 0:
+ /* HDC Data Register */
+ return corvus_hdc_data_r(space, offset);
+
+ case 1:
+ /* HDC Status Register */
+ return corvus_hdc_status_r(space, offset);
+ }
+
+ return 0;
+}
+
+/*
+ * Handle writes against the Hard Disk Controller's onboard registers
+ */
+static WRITE8_HANDLER(concept_hdc_reg_w)
+{
+ switch (offset)
+ {
+ case 0:
+ /* HDC Data Register */
+ corvus_hdc_data_w(space, offset, data);
+ break;
+ }
+}
+
+/*
+ * Handle reads agsint the Hard Disk Controller's onboard ROM
+ */
+static READ8_HANDLER(concept_hdc_rom_r)
+{
+ static const UINT8 data[8] = { 0xa9, 0x20, 0xa9, 0x00, 0xa9, 0x03, 0xa9, 0x3c }; /* Same as Apple II */
+ return (offset < 8) ? data[offset] : 0;
+}
diff --git a/src/mess/machine/corvushd.c b/src/mess/machine/corvushd.c
new file mode 100644
index 00000000000..8d963348067
--- /dev/null
+++ b/src/mess/machine/corvushd.c
@@ -0,0 +1,1708 @@
+//
+// 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 Multiple physical drive support - Up to four
+// 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 "includes/corvushd.h"
+#include <ctype.h>
+
+
+#define VERBOSE 0
+#define VERBOSE_RESPONSES 0
+#define VERSION 1
+#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)
+//
+// Structures
+//
+
+// Sector addressing scheme for Rev B/H drives used in various commands (Called a DADR in the docs)
+typedef struct {
+ 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
+} dadr_t;
+
+// Controller structure
+typedef struct {
+ UINT8 status; // Controller status byte (DIRECTION + BUSY/READY)
+ char prep_mode; // Whether the controller is in Prep Mode or not
+ // Physical drive info
+ UINT8 sectors_per_track; // Number of sectors per track for this drive
+ UINT8 tracks_per_cylinder;// Number of tracks per cylinder (heads)
+ UINT16 cylinders_per_drive;// Number of cylinders per drive
+ // Command Processing
+ UINT16 offset; // Current offset into raw_data buffer
+ char awaiting_modifier; // We've received a two-byte command and we're waiting for the mod
+ UINT16 recv_bytes; // Number of bytes expected to be received from Host
+ UINT16 xmit_bytes; // Number of bytes expected to be transmitted to host
+ // Timing-related values
+ UINT16 last_cylinder; // Last cylinder accessed - for calculating seek times
+ UINT32 delay; // Delay in microseconds for callback
+ emu_timer *timeout_timer; // Four-second timer for timeouts
+ UINT8 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_reponse;
+ //
+ // 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[33]; // Firmware message
+ 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;
+ //
+ // 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;
+ } buffer;
+} corvus_hdc_t;
+
+// Structure of Block #1, the Disk Parameter Block
+typedef struct {
+ 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];
+} disk_parameter_block_t;
+
+// Structure of Block #3, the Constellation Parameter Block
+typedef struct {
+ 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];
+} constellation_parameter_block_t;
+
+// Structure of Block #7, the Semaphore Table Block
+typedef struct {
+ 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
+} semaphore_table_block_t;
+
+// Command size structure (number of bytes to xmit and recv for each command)
+typedef struct {
+ UINT16 recv_bytes; // Number of bytes from host for this command
+ UINT16 xmit_bytes; // Number of bytes to return to host
+} corvus_cmd_t;
+
+//
+// Prototypes
+//
+static hard_disk_file *corvus_hdc_file(running_machine &machine, int id);
+static TIMER_CALLBACK(corvus_hdc_callback);
+
+//
+// Globals
+//
+static corvus_hdc_t corvus_hdc; // The controller itself
+static corvus_cmd_t corvus_cmd[0xf5][0xc1]; // Command sizes and their return sizes
+static corvus_cmd_t corvus_prep_cmd[0x82]; // Prep Command sizes and their return sizes
+
+
+
+//
+// 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
+//
+static void 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)
+//
+static UINT8 parse_hdc_command(UINT8 data) {
+
+ corvus_hdc_t *c = &corvus_hdc;
+
+ c->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, c->prep_mode));
+
+ if(!c->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:
+ c->recv_bytes = corvus_cmd[data][0].recv_bytes;
+ c->xmit_bytes = corvus_cmd[data][0].xmit_bytes;
+ LOG(("parse_hdc_command: Single byte command recoginized: 0x%2.2x, to recv: %d, to xmit: %d\n", data,
+ c->recv_bytes, c->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:
+ c->awaiting_modifier = TRUE;
+ LOG(("parse_hdc_command: Double byte command recoginized: 0x%2.2x\n", data));
+ break;
+
+ default: // This is an INVALID command
+ c->recv_bytes = 1;
+ c->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: // Apparently I need to be able to do this while in Prep mode
+ case PREP_RESET_DRIVE:
+ case PREP_FORMAT_DRIVE:
+ case PREP_FILL_DRIVE_OMNI:
+ case PREP_VERIFY:
+ case PREP_READ_FIRMWARE:
+ case PREP_WRITE_FIRMWARE:
+ c->recv_bytes = corvus_prep_cmd[data].recv_bytes;
+ c->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,
+ c->recv_bytes, c->xmit_bytes));
+ break;
+
+ default: // This is an INVALID prep command
+ c->recv_bytes = 1;
+ c->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: Drive number to write to
+// 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
+//
+static UINT8 corvus_write_sector(running_machine &machine, UINT8 drv, UINT32 sector, UINT8 *buffer, int len) {
+
+ corvus_hdc_t
+ *c = &corvus_hdc;
+ 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(machine, 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) c->sectors_per_track / (double) c->tracks_per_cylinder;
+ c->delay = abs(c->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
+ c->delay += INTERSECTOR_DELAY; // Add another delay because of the Read / Write
+ hard_disk_write(disk, sector, tbuffer); // Re-write the data
+ }
+
+ c->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
+//
+static UINT8 corvus_write_logical_sector(running_machine &machine, dadr_t *dadr, UINT8 *buffer, int len) {
+
+ corvus_hdc_t
+ *c = &corvus_hdc;
+ UINT8 status; // Status returned from Physical Sector read
+ UINT8 drv; // Drive number (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) - 1;
+ 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));
+
+ //
+ // Shift the logical sector address forward by the number of firmware cylinders (2) + the number of spare tracks (7)
+ //
+ sector += (c->tracks_per_cylinder * c->sectors_per_track * 2) + (SPARE_TRACKS * c->sectors_per_track);
+
+ status = corvus_write_sector(machine, drv, sector, buffer, len);
+
+ if(status != STAT_SUCCESS)
+ c->xmit_bytes = 1;
+
+ return status;
+}
+
+
+//
+// Corvus_Read_Sector
+//
+// Read a variably-sized chunk of data from the CHD file
+//
+// Pass:
+// drv: Drive number to read from
+// 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
+//
+static UINT8 corvus_read_sector(running_machine &machine, UINT8 drv, UINT32 sector, UINT8 *buffer, int len) {
+
+ corvus_hdc_t
+ *c = &corvus_hdc;
+ 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(machine, 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) c->sectors_per_track / (double) c->tracks_per_cylinder;
+ c->delay = abs(c->last_cylinder - cylinder) * TRACK_SEEK_TIME + INTERSECTOR_DELAY;
+
+ hard_disk_read(disk, sector, tbuffer);
+
+ memcpy(buffer, tbuffer, len);
+
+ c->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
+//
+static UINT8 corvus_read_logical_sector(running_machine &machine, dadr_t *dadr, UINT8 *buffer, int len) {
+
+ corvus_hdc_t
+ *c = &corvus_hdc;
+ UINT8 status; // Status returned from Physical Sector read
+ UINT8 drv; // Drive number (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) - 1;
+ 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));
+
+ //
+ // Shift the logical sector address forward by the number of firmware cylinders (2) + the number of spare tracks (7)
+ //
+ sector += (c->tracks_per_cylinder * c->sectors_per_track * 2) + (SPARE_TRACKS * c->sectors_per_track);
+
+ status = corvus_read_sector(machine, drv, sector, buffer, len);
+
+ if(status != STAT_SUCCESS)
+ c->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
+//
+static UINT8 corvus_lock_semaphore(running_machine &machine, UINT8 *name) {
+
+ corvus_hdc_t
+ *c = &corvus_hdc;
+ semaphore_table_block_t
+ semaphore_table;
+ UINT8 offset = 0;
+ UINT8 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(machine, 0, 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);
+ c->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) {
+ c->buffer.semaphore_locking_response.result = SEM_TABLE_FULL; // No space for the semaphore!
+ } else {
+ c->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(machine, 0, 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);
+ c->buffer.semaphore_locking_response.result = SEM_DISK_ERROR;
+ return status;
+ }
+ }
+ } else {
+ c->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
+//
+static UINT8 corvus_unlock_semaphore(running_machine &machine, UINT8 *name) {
+
+ corvus_hdc_t
+ *c = &corvus_hdc;
+ semaphore_table_block_t
+ semaphore_table;
+ UINT8 offset = 0;
+ UINT8 found = FALSE;
+ UINT8 status; // Status returned from Physical Sector read
+
+ //
+ // Read the semaphore table from the drive
+ //
+ status = corvus_read_sector(machine, 0, 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);
+ c->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) {
+ c->buffer.semaphore_locking_response.result = SEM_PRIOR_STATE_NOT_SET; // It wasn't there already
+ } else {
+ c->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(machine, 0, 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);
+ c->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
+//
+//
+static UINT8 corvus_init_semaphore_table( running_machine &machine ) {
+
+ semaphore_table_block_t
+ semaphore_table;
+ UINT8 status;
+
+ memset(semaphore_table.semaphore_block.semaphore_table, 0x20, 256);
+
+ status = corvus_write_sector(machine, 0, 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: Drive number to get parameters from
+//
+// Returns:
+// Status of command
+//
+static UINT8 corvus_get_drive_parameters(running_machine &machine, UINT8 drv) {
+
+ corvus_hdc_t
+ *c = &corvus_hdc;
+ 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
+ //
+ drv -= 1; // Internally, drives start at 0
+
+ if ( ! corvus_hdc_file( machine, drv ) )
+ {
+ logerror("corvus_get_drive_parameters: Attempt to retrieve parameters from non-existant drive: %d\n", drv);
+ c->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(machine, 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);
+ c->xmit_bytes = 1;
+ return status;
+ }
+
+ //
+ // Read the Constellation Parameter Block (Sector 3) from the drive
+ //
+ status = corvus_read_sector(machine, 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);
+ c->xmit_bytes = 1;
+ return status;
+ }
+
+ //
+ // Build up the parameter packet
+ //
+ strcpy((char *) c->buffer.drive_param_response.firmware, "V18.4AP -- CONST II - 11/82 %"); // Pulled from some firmware...
+ c->buffer.drive_param_response.rom_version = VERSION;
+ c->buffer.drive_param_response.track_info.sectors_per_track = c->sectors_per_track;
+ c->buffer.drive_param_response.track_info.tracks_per_cylinder = c->tracks_per_cylinder;
+ c->buffer.drive_param_response.track_info.cylinders_per_drive.msb = (c->cylinders_per_drive & 0xff00) >> 8;
+ c->buffer.drive_param_response.track_info.cylinders_per_drive.lsb = (c->cylinders_per_drive & 0x00ff);
+
+ //
+ // Calculate the user capacity of the drive based on total capacity less spare tracks and firmware tracks
+ //
+ raw_capacity = c->tracks_per_cylinder * c->cylinders_per_drive * c->sectors_per_track; // Total capacity
+ capacity = raw_capacity - ((c->tracks_per_cylinder * c->sectors_per_track * 2) + (SPARE_TRACKS * c->sectors_per_track));
+ c->buffer.drive_param_response.capacity.msb = (capacity & 0xff0000) >> 16;
+ c->buffer.drive_param_response.capacity.midb = (capacity & 0x00ff00) >> 8;
+ c->buffer.drive_param_response.capacity.lsb = (capacity & 0x0000ff);
+
+ //
+ // Fill in the information from the Disk Parameter Block and Constellation Parameter Block
+ //
+ c->buffer.drive_param_response.interleave = raw_disk_parameter_block.dpb.interleave;
+ memcpy(c->buffer.drive_param_response.table_info.mux_parameters, raw_constellation_parameter_block.cpb.mux_parameters, 12);
+ memcpy(c->buffer.drive_param_response.table_info.pipe_name_table_ptr,
+ raw_constellation_parameter_block.cpb.pipe_name_table_ptr, 2);
+ memcpy(c->buffer.drive_param_response.table_info.pipe_ptr_table_ptr,
+ raw_constellation_parameter_block.cpb.pipe_ptr_table_ptr, 2);
+ memcpy(c->buffer.drive_param_response.table_info.pipe_area_size, raw_constellation_parameter_block.cpb.pipe_area_size, 2);
+ memcpy(c->buffer.drive_param_response.table_info.vdo_table, raw_disk_parameter_block.dpb.vdo_table, 14);
+ memcpy(c->buffer.drive_param_response.table_info.lsi11_vdo_table, raw_disk_parameter_block.dpb.lsi11_vdo_table, 8);
+ memcpy(c->buffer.drive_param_response.table_info.lsi11_spare_table, raw_disk_parameter_block.dpb.lsi11_spare_table, 8);
+
+ c->buffer.drive_param_response.drive_number = drv + 1;
+ c->buffer.drive_param_response.physical_capacity.msb = (raw_capacity & 0xff0000) >> 16;
+ c->buffer.drive_param_response.physical_capacity.midb = (raw_capacity & 0x00ff00) >> 8;
+ c->buffer.drive_param_response.physical_capacity.lsb = (raw_capacity & 0x0000ff);
+
+ LOG(("corvus_get_drive_parameters: Drive Parameter packet follows:\n"));
+ LOG_BUFFER(c->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
+//
+static UINT8 corvus_read_boot_block(running_machine &machine, UINT8 block) {
+
+ corvus_hdc_t *c = &corvus_hdc; // Pick up global controller structure
+
+ LOG(("corvus_read_boot_block: Reading boot block: %d\n", block));
+
+ return corvus_read_sector(machine, 0, 25 + block, c->buffer.read_512_response.data, 512);
+
+}
+
+
+
+//
+// Corvus_Read_Firmware_Block
+//
+// Reads firmware information from the first cylinder of the drive
+//
+// Pass:
+// head: Head number
+// sector: Sector number
+//
+// Returns:
+// Status of command
+//
+static UINT8 corvus_read_firmware_block(running_machine &machine, UINT8 head, UINT8 sector) {
+
+ corvus_hdc_t
+ *c = &corvus_hdc; // Pick up global controller structure
+ UINT16 relative_sector; // Relative sector on drive for Physical Read
+ UINT8 status;
+
+ relative_sector = head * c->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(machine, 0, relative_sector, c->buffer.read_512_response.data, 512); // TODO: Which drive should Prep Mode talk to ???
+ return status;
+}
+
+
+
+//
+// Corvus_Write_Firmware_Block
+//
+// 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
+//
+static UINT8 corvus_write_firmware_block(running_machine &machine, UINT8 head, UINT8 sector, UINT8 *buffer) {
+
+ corvus_hdc_t
+ *c = &corvus_hdc; // Pick up global controller structure
+ UINT16 relative_sector; // Relative sector on drive for Physical Read
+ UINT8 status;
+
+ relative_sector = head * c->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(machine, 0, relative_sector, buffer, 512); // TODO: Which drive should Prep Mode talk to ???
+ return status;
+}
+
+
+
+//
+// Corvus_Format_Drive
+//
+// 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
+//
+static UINT8 corvus_format_drive(running_machine &machine, UINT8 *pattern, UINT16 len) {
+
+ corvus_hdc_t
+ *c = &corvus_hdc;
+ UINT32 sector;
+ UINT32 max_sector;
+ UINT8 status = 0;
+ UINT8 tbuffer[512];
+
+ max_sector = c->sectors_per_track * c->tracks_per_cylinder * c->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(machine, 0, 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:
+// id: Drive number (1 - 15)
+//
+// Returns:
+// hard_disk_file object
+//
+static hard_disk_file *corvus_hdc_file(running_machine &machine, int id) {
+ static const char *const tags[] = {
+ "harddisk1"
+ };
+ harddisk_image_device *img;
+
+ /* Only one harddisk supported right now */
+ assert ( id == 0 );
+
+ img = dynamic_cast<harddisk_image_device *>(machine.device(tags[id]));
+
+ if ( !img )
+ return NULL;
+
+ if (!img->exists())
+ return NULL;
+
+ return img->get_hard_disk_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
+//
+static void corvus_process_command_packet(running_machine &machine, UINT8 invalid_command_flag) {
+
+ corvus_hdc_t *c = &corvus_hdc;
+
+ if (VERBOSE_RESPONSES)
+ {
+ LOG(("corvus_hdc_data_w: Complete packet received. Dump follows:\n"));
+ LOG_BUFFER(c->buffer.raw_data, c->offset);
+ }
+
+ if(!invalid_command_flag) {
+ if(!c->prep_mode) {
+ switch(c->buffer.command.code) {
+ //
+ // Read / Write Chunk commands
+ //
+ case READ_CHUNK_128:
+ c->buffer.read_128_response.status =
+ corvus_read_logical_sector(machine, &c->buffer.read_sector_command.dadr, c->buffer.read_128_response.data, 128);
+ break;
+ case READ_SECTOR_256:
+ case READ_CHUNK_256:
+ c->buffer.read_256_reponse.status =
+ corvus_read_logical_sector(machine, &c->buffer.read_sector_command.dadr, c->buffer.read_256_reponse.data, 256);
+ break;
+ case READ_CHUNK_512:
+ c->buffer.read_512_response.status =
+ corvus_read_logical_sector(machine, &c->buffer.read_sector_command.dadr, c->buffer.read_512_response.data, 512);
+ break;
+ case WRITE_CHUNK_128:
+ c->buffer.single_byte_response.status =
+ corvus_write_logical_sector(machine, &c->buffer.write_128_command.dadr, c->buffer.write_128_command.data, 128);
+ break;
+ case WRITE_SECTOR_256:
+ case WRITE_CHUNK_256:
+ c->buffer.single_byte_response.status =
+ corvus_write_logical_sector(machine, &c->buffer.write_256_command.dadr, c->buffer.write_256_command.data, 256);
+ break;
+ case WRITE_CHUNK_512:
+ c->buffer.single_byte_response.status =
+ corvus_write_logical_sector(machine, &c->buffer.write_512_command.dadr, c->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(c->buffer.command.modifier) {
+ case SEMAPHORE_LOCK_MOD:
+ c->buffer.semaphore_locking_response.status = corvus_lock_semaphore(machine, c->buffer.lock_semaphore_command.name);
+ break;
+ case SEMAPHORE_UNLOCK_MOD:
+ c->buffer.semaphore_locking_response.status =
+ corvus_unlock_semaphore(machine, c->buffer.unlock_semaphore_command.name);
+ break;
+ case SEMAPHORE_INIT_MOD:
+ c->buffer.single_byte_response.status = corvus_init_semaphore_table(machine);
+ break;
+ case SEMAPHORE_STATUS_MOD:
+ c->buffer.semaphore_status_response.status =
+ corvus_read_sector(machine, 0, 7, c->buffer.semaphore_status_response.table, 256);
+ break;
+ default:
+ invalid_command_flag = TRUE;
+ }
+ break;
+ //
+ // Miscellaneous commands
+ //
+ case BOOT:
+ c->buffer.read_512_response.status =
+ corvus_read_boot_block(machine, c->buffer.old_boot_command.boot_block);
+ break;
+ case GET_DRIVE_PARAMETERS:
+ c->buffer.drive_param_response.status =
+ corvus_get_drive_parameters(machine, c->buffer.get_drive_parameters_command.drive);
+ break;
+ case PREP_MODE_SELECT:
+ c->prep_mode = TRUE;
+ c->buffer.single_byte_response.status = STAT_SUCCESS;
+ break;
+ default:
+ c->xmit_bytes = 1; // Return a fatal status
+ c->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(c->buffer.command.code) {
+ case PREP_MODE_SELECT:
+ c->prep_mode = TRUE;
+ c->buffer.single_byte_response.status = STAT_SUCCESS;
+ break;
+ case PREP_RESET_DRIVE:
+ c->prep_mode = FALSE;
+ c->buffer.single_byte_response.status = STAT_SUCCESS;
+ break;
+ case PREP_READ_FIRMWARE:
+ c->buffer.drive_param_response.status =
+ corvus_read_firmware_block(machine, (c->buffer.read_firmware_command.encoded_h_s & 0xe0) >> 5,
+ c->buffer.read_firmware_command.encoded_h_s & 0x1f);
+ break;
+ case PREP_WRITE_FIRMWARE:
+ c->buffer.drive_param_response.status =
+ corvus_write_firmware_block(machine, (c->buffer.write_firmware_command.encoded_h_s & 0xe0) >> 5,
+ c->buffer.write_firmware_command.encoded_h_s & 0x1f, c->buffer.write_firmware_command.data);
+ break;
+ case PREP_FORMAT_DRIVE:
+ c->buffer.drive_param_response.status =
+ corvus_format_drive(machine, c->buffer.format_drive_revbh_command.pattern, c->offset - 512);
+ break;
+ default:
+ c->xmit_bytes = 1;
+ c->buffer.single_byte_response.status = STAT_FAULT | STAT_FATAL_ERR;
+ logerror("corvus_hdc_data_w: Unimplemented Prep command, returning FATAL FAULT status!\n");
+ }
+ }
+ if (VERBOSE_RESPONSES)
+ {
+ LOG(("corvus_hdc_data_w: Command execution complete, status: 0x%2.2x. Response dump follows:\n",
+ c->buffer.single_byte_response.status));
+ LOG_BUFFER(c->buffer.raw_data, c->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)
+ //
+ c->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, status: 0x%2.2x\n", c->buffer.single_byte_response.status);
+ }
+ //
+ // Command execution complete, free up the controller
+ //
+ c->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", c->delay));
+
+ //
+ // Set up timers for command completion and timeout from host
+ //
+ machine.scheduler().timer_set(attotime::from_usec(c->delay), FUNC(corvus_hdc_callback), CALLBACK_CTH_MODE);
+ c->timeout_timer->enable(0); // We've received enough data, disable the timeout timer
+
+ c->delay = 0; // Reset delay for next function
+}
+
+
+
+//
+// Corvus_HDC_Callback
+//
+// Callback routine for completion of controller functions
+//
+// Pass:
+// Callback Function
+//
+// Returns:
+// Nothing
+//
+static TIMER_CALLBACK(corvus_hdc_callback)
+{
+ int function = param;
+ corvus_hdc_t *c = &corvus_hdc;
+
+ switch(function) {
+ case CALLBACK_CTH_MODE:
+ c->status |= CONTROLLER_DIRECTION; // Set to Controller-to-Host, Ready mode
+ c->status &= ~(CONTROLLER_BUSY);
+
+ LOG(("corvus_hdc_callback: Callback executed with function CALLBACK_CTH_MODE\n"));
+
+ break;
+ case CALLBACK_HTC_MODE:
+ c->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:
+ c->status &= ~(CONTROLLER_BUSY); // Set the controller to Ready mode
+
+ break;
+ case CALLBACK_TIMEOUT: // We reached a four-second timeout threshold
+ if(c->offset < c->recv_bytes || (c->offset > c->recv_bytes && c->recv_bytes != 0)) {
+ c->buffer.single_byte_response.status = STAT_TIMEOUT;
+ c->status |= CONTROLLER_DIRECTION;
+ c->status &= ~(CONTROLLER_BUSY);
+ c->recv_bytes = 0;
+ c->xmit_bytes = 1;
+ logerror("corvus_hdc_callback: Exceeded four-second timeout for data from host, resetting communications\n");
+ } else { // if(c->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(machine, 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) {
+ c->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
+//
+UINT8 corvus_hdc_init(running_machine &machine) {
+
+ corvus_hdc_t *c = &corvus_hdc; // Pick up global controller structure
+ hard_disk_file *disk; // Structures for interface to CHD routines
+ hard_disk_info *info;
+
+ if((disk = corvus_hdc_file(machine, 0))) // Attach to the CHD file
+ info = hard_disk_get_info(disk); // Pick up the Head/Cylinder/Sector info
+ else
+ return 0;
+
+ c->status &= ~(CONTROLLER_DIRECTION | CONTROLLER_BUSY); // Host-to-controller mode, Idle (awaiting command from Host mode)
+ c->prep_mode = FALSE; // We're not in Prep Mode
+ c->sectors_per_track = info->sectors;
+ c->tracks_per_cylinder = info->heads;
+ c->cylinders_per_drive = info->cylinders;
+ c->offset = 0; // Buffer is empty
+ c->awaiting_modifier = FALSE; // We're not in the middle of a two-byte command
+ c->xmit_bytes = 0; // We don't have anything to say to the host
+ c->recv_bytes = 0; // We aren't waiting on additional data from the host
+
+ c->timeout_timer = machine.scheduler().timer_alloc(FUNC(corvus_hdc_callback)); // Set up a timer to handle the four-second host-to-controller timeout
+ c->timeout_timer->adjust(attotime::from_seconds(4), CALLBACK_TIMEOUT);
+ c->timeout_timer->enable(0); // Start this timer out disabled
+
+ LOG(("corvus_hdc_init: Attached to drive image: H:%d, C:%d, S:%d\n", info->heads, info->cylinders, info->sectors));
+
+ //
+ // 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 = 0;
+ 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"));
+
+ return TRUE;
+}
+
+
+
+//
+// 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_HANDLER ( corvus_hdc_status_r ) {
+
+ corvus_hdc_t *c = &corvus_hdc;
+
+ return c->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_HANDLER ( corvus_hdc_data_r ) {
+
+ corvus_hdc_t *c = &corvus_hdc;
+ UINT8 result;
+
+ if((c->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", c->status);
+ return 0;
+ }
+
+ if((c->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", c->status);
+ return 0;
+ }
+
+ result = c->buffer.raw_data[c->offset++];
+
+ if(c->offset == c->xmit_bytes) {
+ LOG(("corvus_hdc_data_r: Finished transmitting %d bytes of data. Returning to idle mode.\n", c->xmit_bytes));
+
+ c->offset = 0; // We've reached the end of valid data
+ c->xmit_bytes = 0; // We don't have anything more to say
+ c->recv_bytes = 0; // No active commands
+
+ space->machine().scheduler().timer_set((attotime::from_usec(INTERBYTE_DELAY)), FUNC(corvus_hdc_callback), CALLBACK_HTC_MODE);
+
+// c->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
+ //
+ space->machine().scheduler().timer_set((attotime::from_usec(INTERBYTE_DELAY)), FUNC(corvus_hdc_callback), 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_HANDLER ( corvus_hdc_data_w ) {
+
+ corvus_hdc_t *c = &corvus_hdc;
+
+ //
+ // Received a byte -- check to see if we should really respond
+ //
+ if((c->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",
+ c->status, data);
+ return;
+ }
+
+ if((c->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",
+ c->status, data);
+ return;
+ }
+
+ //
+ // We're supposed to be paying attention. Make a decision about the data received
+ //
+ if(c->offset == 0) { // First byte of a packet
+ LOG(("corvus_hdc_data_w: Received a byte with c->offset == 0. Processing as command: 0x%2.2x\n", data));
+ c->invalid_command_flag = parse_hdc_command(data);
+ c->timeout_timer->reset((attotime::from_seconds(4)));
+ c->timeout_timer->enable(1); // Start our four-second timer
+ } else if(c->offset == 1 && c->awaiting_modifier) { // Second byte of a packet
+ LOG(("corvus_hdc_data_w: Received a byte while awaiting modifier with c->offset == 0. Processing as modifier: 0x%2.2x\n", data));
+ c->awaiting_modifier = FALSE;
+ c->recv_bytes = corvus_cmd[c->buffer.command.code][data].recv_bytes;
+ c->xmit_bytes = corvus_cmd[c->buffer.command.code][data].xmit_bytes;
+ }
+
+ c->buffer.raw_data[c->offset++] = data;
+
+ assert(c->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(c->offset == c->recv_bytes) { // We've received enough data to process
+ corvus_process_command_packet(space->machine(), c->invalid_command_flag);
+ } else {
+ //
+ // Reset the four-second timer since we received some data
+ //
+ c->timeout_timer->reset((attotime::from_seconds(4)));
+
+ //
+ // Make the controller busy for a few microseconds while the command is processed
+ //
+ c->status |= CONTROLLER_BUSY;
+ space->machine().scheduler().timer_set((attotime::from_usec(INTERBYTE_DELAY)), FUNC(corvus_hdc_callback), CALLBACK_SAME_MODE);
+ }
+}
diff --git a/src/mess/machine/cpc_rom.c b/src/mess/machine/cpc_rom.c
new file mode 100644
index 00000000000..1909b107c9a
--- /dev/null
+++ b/src/mess/machine/cpc_rom.c
@@ -0,0 +1,137 @@
+/*
+ * cpc_rom.c
+ * Amstrad CPC mountable ROM image device
+ *
+ */
+
+#include "emu.h"
+#include "machine/cpc_rom.h"
+#include "includes/amstrad.h"
+
+const device_type CPC_ROM = &device_creator<cpc_rom_device>;
+
+
+//**************************************************************************
+// DEVICE CONFIG INTERFACE
+//**************************************************************************
+
+CPC_EXPANSION_INTERFACE(sub_exp_intf)
+{
+ DEVCB_LINE(cpc_irq_w),
+ DEVCB_LINE(cpc_nmi_w),//LINE_MEMBER(cpc_expansion_slot_device,nmi_w),
+ DEVCB_NULL, // RESET
+ DEVCB_LINE(cpc_romdis), // ROMDIS
+ DEVCB_LINE(cpc_romen) // /ROMEN
+};
+
+// 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")
+
+ // pass-through
+ MCFG_CPC_EXPANSION_SLOT_ADD("exp",sub_exp_intf,cpc_exp_cards,NULL,NULL)
+
+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),
+ 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>;
+
+//-------------------------------------------------
+// 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),
+ 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 = (UINT8*)malloc(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()
+{
+ free(m_base);
+ m_base = NULL;
+}
diff --git a/src/mess/machine/cpc_rom.h b/src/mess/machine/cpc_rom.h
new file mode 100644
index 00000000000..33e3a1aeccb
--- /dev/null
+++ b/src/mess/machine/cpc_rom.h
@@ -0,0 +1,90 @@
+/*
+ * cpc_rom.h
+ * Amstrad CPC mountable ROM image device
+ *
+ */
+
+#ifndef CPC_ROM_H_
+#define CPC_ROM_H_
+
+#include "emu.h"
+#include "machine/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 0; }
+ 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 <= 6) return m_rom[slot]->base(); else return NULL; }
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "cpc_rom"; }
+
+private:
+ cpc_expansion_slot_device *m_slot;
+
+ rom_image_device* m_rom[6];
+};
+
+// device type definition
+extern const device_type CPC_ROM;
+
+
+#endif
diff --git a/src/mess/machine/cpc_ssa1.c b/src/mess/machine/cpc_ssa1.c
new file mode 100644
index 00000000000..f15225c2c76
--- /dev/null
+++ b/src/mess/machine/cpc_ssa1.c
@@ -0,0 +1,227 @@
+/*
+ * 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<cpc_ssa1_device>;
+const device_type CPC_DKSPEECH = &device_creator<cpc_dkspeech_device>;
+
+CPC_EXPANSION_INTERFACE(sub_exp_intf)
+{
+ DEVCB_LINE(cpc_irq_w),
+ DEVCB_LINE(cpc_nmi_w),
+ DEVCB_NULL, // RESET
+ DEVCB_LINE(cpc_romdis), // ROMDIS
+ DEVCB_LINE(cpc_romen) // /ROMEN
+};
+
+//-------------------------------------------------
+// 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)
+{
+ sp0256_ALD_w(m_sp0256_device,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)
+{
+ sp0256_ALD_w(m_sp0256_device,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);
+}
+
+static sp0256_interface sp0256_intf =
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER,cpc_ssa1_device,lrq_cb),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER,cpc_ssa1_device,sby_cb)
+};
+
+static sp0256_interface sp0256_dk_intf =
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER,cpc_dkspeech_device,lrq_cb),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER,cpc_dkspeech_device,sby_cb)
+};
+
+//-------------------------------------------------
+// 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. For now, we'll let the user choose to load the software via ROM (using a ROM box slot device) or cassette.
+ROM_START( cpc_dkspeech )
+ ROM_REGION( 0x10000, "sp0256", 0 )
+ ROM_LOAD( "sp0256-al2.bin", 0x1000, 0x0800, CRC(b504ac15) SHA1(e60fcb5fa16ff3f3b69d36c7a6e955744d3feafc) )
+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_SOUND_CONFIG(sp0256_intf)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00)
+
+ // pass-through
+ MCFG_CPC_EXPANSION_SLOT_ADD("exp",sub_exp_intf,cpc_exp_cards,NULL,NULL)
+
+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_SOUND_CONFIG(sp0256_dk_intf)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00)
+
+ // pass-through
+ MCFG_CPC_EXPANSION_SLOT_ADD("exp",sub_exp_intf,cpc_exp_cards,NULL,NULL)
+
+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),
+ 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),
+ 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<cpc_expansion_slot_device *>(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<cpc_expansion_slot_device *>(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/mess/machine/cpc_ssa1.h b/src/mess/machine/cpc_ssa1.h
new file mode 100644
index 00000000000..7c091c88be2
--- /dev/null
+++ b/src/mess/machine/cpc_ssa1.h
@@ -0,0 +1,128 @@
+/*
+ * 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 "machine/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();
+ virtual void device_config_complete() { m_shortname = "cpc_ssa1"; }
+
+private:
+ cpc_expansion_slot_device *m_slot;
+
+ UINT8 *m_rom;
+ UINT8 m_lrq;
+ UINT8 m_sby;
+
+ required_device<device_t> 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();
+ virtual void device_config_complete() { m_shortname = "cpc_dkspeech"; }
+
+private:
+ cpc_expansion_slot_device *m_slot;
+
+ UINT8 *m_rom;
+ UINT8 m_lrq;
+ UINT8 m_sby;
+
+ required_device<device_t> 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/mess/machine/cpcexp.c b/src/mess/machine/cpcexp.c
new file mode 100644
index 00000000000..45af07348ed
--- /dev/null
+++ b/src/mess/machine/cpcexp.c
@@ -0,0 +1,109 @@
+/*
+ * cpcexp.c -- Amstrad CPC Expansion port
+ *
+ * Created on: 16/07/2011
+ *
+ */
+
+
+#include "emu.h"
+#include "emuopts.h"
+#include "machine/cpcexp.h"
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type CPC_EXPANSION_SLOT = &device_creator<cpc_expansion_slot_device>;
+
+
+//**************************************************************************
+// 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),
+ device_slot_interface(mconfig, *this)
+{
+}
+
+cpc_expansion_slot_device::~cpc_expansion_slot_device()
+{
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void cpc_expansion_slot_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const cpc_expansion_slot_interface *intf = reinterpret_cast<const cpc_expansion_slot_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<cpc_expansion_slot_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_irq_cb, 0, sizeof(m_out_irq_cb));
+ memset(&m_out_nmi_cb, 0, sizeof(m_out_nmi_cb));
+ memset(&m_out_reset_cb, 0, sizeof(m_out_reset_cb));
+ memset(&m_out_romdis_cb, 0, sizeof(m_out_romdis_cb));
+ memset(&m_out_romen_cb, 0, sizeof(m_out_romen_cb));
+ }
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void cpc_expansion_slot_device::device_start()
+{
+ m_card = dynamic_cast<device_cpc_expansion_card_interface *>(get_card_device());
+
+ // resolve callbacks
+ m_out_irq_func.resolve(m_out_irq_cb, *this);
+ m_out_nmi_func.resolve(m_out_nmi_cb, *this);
+ m_out_reset_func.resolve(m_out_reset_cb, *this);
+ m_out_romdis_func.resolve(m_out_romdis_cb, *this);
+ m_out_romen_func.resolve(m_out_romen_cb, *this);
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void cpc_expansion_slot_device::device_reset()
+{
+}
+
+
+WRITE_LINE_MEMBER( cpc_expansion_slot_device::irq_w ) { m_out_irq_func(state); }
+WRITE_LINE_MEMBER( cpc_expansion_slot_device::nmi_w ) { m_out_nmi_func(state); }
+WRITE_LINE_MEMBER( cpc_expansion_slot_device::reset_w ) { m_out_reset_func(state); }
+WRITE_LINE_MEMBER( cpc_expansion_slot_device::romdis_w ) { m_out_romdis_func(state); }
+WRITE_LINE_MEMBER( cpc_expansion_slot_device::romen_w ) { m_out_romen_func(state); }
diff --git a/src/mess/machine/cpcexp.h b/src/mess/machine/cpcexp.h
new file mode 100644
index 00000000000..42f808578c9
--- /dev/null
+++ b/src/mess/machine/cpcexp.h
@@ -0,0 +1,131 @@
+/*
+ * 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
+ */
+
+#pragma once
+
+#ifndef CPCEXP_H_
+#define CPCEXP_H_
+
+#include "emu.h"
+
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
+
+#define CPC_EXP_SLOT_TAG "cpcexp"
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define CPC_EXPANSION_INTERFACE(_name) \
+ const cpc_expansion_slot_interface (_name) =
+
+
+#define MCFG_CPC_EXPANSION_SLOT_ADD(_tag, _config, _slot_intf, _def_slot, _def_inp) \
+ MCFG_DEVICE_ADD(_tag, CPC_EXPANSION_SLOT, 0) \
+ MCFG_DEVICE_CONFIG(_config) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false)
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// expansion slot interface
+
+struct cpc_expansion_slot_interface
+{
+ 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_write_line m_out_romen_cb;
+};
+
+
+// ======================> 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() { };
+};
+
+
+// ======================> cpc_expansion_slot_device
+
+class cpc_expansion_slot_device : public device_t,
+ public cpc_expansion_slot_interface,
+ 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();
+
+ 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_WRITE_LINE_MEMBER( romen_w );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete();
+
+ devcb_resolved_write_line m_out_irq_func;
+ devcb_resolved_write_line m_out_nmi_func;
+ devcb_resolved_write_line m_out_reset_func;
+ devcb_resolved_write_line m_out_romdis_func;
+ devcb_resolved_write_line m_out_romen_func;
+
+ device_cpc_expansion_card_interface *m_card;
+};
+
+
+// device type definition
+extern const device_type CPC_EXPANSION_SLOT;
+
+#endif /* CPCEXP_H_ */
diff --git a/src/mess/machine/cs4031.c b/src/mess/machine/cs4031.c
new file mode 100644
index 00000000000..ed75bbd3817
--- /dev/null
+++ b/src/mess/machine/cs4031.c
@@ -0,0 +1,333 @@
+/***************************************************************************
+
+ 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
+ - 2x 8257 DMA controller
+ - 2x 8259 interrupt controller
+ - 8254 timer
+ - MC14818 RTC
+
+***************************************************************************/
+
+#include "emu.h"
+#include "machine/ram.h"
+#include "machine/cs4031.h"
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+#define LOG_REGISTER 1
+#define LOG_MEMORY 1
+
+const device_type CS4031 = &device_creator<cs4031_device>;
+
+enum
+{
+ DMA_WAIT_STATE = 0x01,
+ PERFORMANCE = 0x08,
+ F84035_MISC = 0x09,
+ DMA_CLOCK = 0x0a,
+ SHADOW_READ = 0x19,
+ SHADOW_WRITE = 0x1a,
+ ROMCS = 0x1b
+};
+
+static const char *const 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"
+};
+
+
+//**************************************************************************
+// 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),
+ m_address(0),
+ m_address_valid(false)
+{
+}
+
+void cs4031_device::static_set_cputag(device_t &device, const char *tag)
+{
+ cs4031_device &cs4031 = downcast<cs4031_device &>(device);
+ cs4031.m_cputag = tag;
+}
+
+void cs4031_device::static_set_isatag(device_t &device, const char *tag)
+{
+ cs4031_device &cs4031 = downcast<cs4031_device &>(device);
+ cs4031.m_isatag = tag;
+}
+
+void cs4031_device::static_set_biostag(device_t &device, const char *tag)
+{
+ cs4031_device &cs4031 = downcast<cs4031_device &>(device);
+ cs4031.m_biostag = tag;
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void cs4031_device::device_start()
+{
+ ram_device *ram_dev = machine().device<ram_device>(RAM_TAG);
+
+ // make sure the ram device is already running
+ if (!ram_dev->started())
+ throw device_missing_dependencies();
+
+ device_t *cpu = machine().device(m_cputag);
+ m_space = cpu->memory().space(AS_PROGRAM);
+ m_isa = machine().root_device().memregion(m_isatag)->base();
+ m_bios = machine().root_device().memregion(m_biostag)->base();
+
+ 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);
+}
+
+//-------------------------------------------------
+// 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();
+}
+
+
+//**************************************************************************
+// READ/WRITE HANDLERS
+//**************************************************************************
+
+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);
+}
+
+WRITE8_MEMBER( cs4031_device::address_w )
+{
+ m_address = data;
+ m_address_valid = (m_address < 0x20) ? true : false;
+}
+
+READ8_MEMBER( cs4031_device::data_r )
+{
+ UINT8 result = 0xff;
+
+ if (m_address_valid)
+ {
+ if (LOG_REGISTER)
+ logerror("cs4031_device: read %s = %02x\n", 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::data_w )
+{
+ if (m_address_valid)
+ {
+ if (LOG_REGISTER)
+ logerror("cs4031_device: write %s = %02x\n", register_names[m_address], data);
+
+ // update register with new data
+ m_registers[m_address] = data;
+
+ // execute command
+ switch (m_address)
+ {
+ case 0x01: break;
+ case 0x05: break;
+ case 0x06: break;
+ case 0x07: break;
+ case 0x08: break;
+ case 0x09: break;
+ case 0x0a: 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 0x19:
+ update_read_regions();
+ break;
+
+ case 0x1a:
+ update_write_regions();
+ break;
+
+ case 0x1b:
+ update_read_regions();
+ update_write_regions();
+ break;
+
+ case 0x1c: break;
+ }
+ }
+
+ // after a write the selected address needs to be reset
+ m_address_valid = false;
+}
diff --git a/src/mess/machine/cs4031.h b/src/mess/machine/cs4031.h
new file mode 100644
index 00000000000..73cfbaf0311
--- /dev/null
+++ b/src/mess/machine/cs4031.h
@@ -0,0 +1,95 @@
+/***************************************************************************
+
+ 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
+ - 2x 8257 DMA controller
+ - 2x 8259 interrupt controller
+ - 8254 timer
+ - MC14818 RTC
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __CS4031_H__
+#define __CS4031_H__
+
+#include "emu.h"
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_CS4031_ADD(_tag, _cputag, _isatag, _biostag) \
+ MCFG_DEVICE_ADD(_tag, CS4031, 0) \
+ cs4031_device::static_set_cputag(*device, _cputag); \
+ cs4031_device::static_set_isatag(*device, _isatag); \
+ cs4031_device::static_set_biostag(*device, _biostag);
+
+
+//**************************************************************************
+// 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);
+
+ 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:
+ 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
+ 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[0x20];
+};
+
+
+// device type definition
+extern const device_type CS4031;
+
+
+#endif /* __CS4031_H__ */
diff --git a/src/mess/machine/cs8221.c b/src/mess/machine/cs8221.c
new file mode 100644
index 00000000000..c7c4739a9f1
--- /dev/null
+++ b/src/mess/machine/cs8221.c
@@ -0,0 +1,165 @@
+/***************************************************************************
+
+ 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<cs8221_device>;
+
+
+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),
+ m_address(0),
+ m_address_valid(false)
+{
+}
+
+void cs8221_device::static_set_cputag(device_t &device, const char *tag)
+{
+ cs8221_device &cs8221 = downcast<cs8221_device &>(device);
+ cs8221.m_cputag = tag;
+}
+
+void cs8221_device::static_set_isatag(device_t &device, const char *tag)
+{
+ cs8221_device &cs8221 = downcast<cs8221_device &>(device);
+ cs8221.m_isatag = tag;
+}
+
+void cs8221_device::static_set_biostag(device_t &device, const char *tag)
+{
+ cs8221_device &cs8221 = downcast<cs8221_device &>(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/mess/machine/cs8221.h b/src/mess/machine/cs8221.h
new file mode 100644
index 00000000000..c7bf73fe26d
--- /dev/null
+++ b/src/mess/machine/cs8221.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+
+ 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/mess/machine/cuda.c b/src/mess/machine/cuda.c
new file mode 100644
index 00000000000..547e90e1eb1
--- /dev/null
+++ b/src/mess/machine/cuda.c
@@ -0,0 +1,563 @@
+/*
+ Apple "Cuda" ADB/system controller MCU
+ Emulation by R. Belmont
+
+ Port definitions, primarily from the schematics.
+
+ Port A:
+
+ x------- O ADB data line out
+ -x------ I ADB data line in
+ --x----- I "1" for passive or soft power, "off sense" for secure
+ ---x---- O DFAC latch
+ ----x--- O "Fast Reset"
+ -----x-- I Keyboard power switch
+ ------x- I 1 for secure or passive power, chassis switch for soft
+ -------x ? 1 for passive, power supply control on secure/soft power, input on secure/soft also?
+
+ Port B:
+
+ x------- O DFAC bit clock
+ -x------ B DFAC data I/O (used in both directions)
+ --x----- B VIA shift register data (used in both directions)
+ ---x---- O VIA clock
+ ----x--- I VIA TIP
+ -----x-- I VIA BYTEACK
+ ------x- O VIA TREQ
+ -------x I +5v sense
+
+ Port C:
+ x--- O 680x0 reset
+ -x-- ? 680x0 IPL 2 (used in both directions)
+ --x- ? IPL 1/pull up for passive power, trickle sense for soft and secure
+ ---x ? IPL 0 for passive power, pull-up for soft power, file server switch for secure power
+*/
+
+
+//#define CUDA_SUPER_VERBOSE
+
+#include "emu.h"
+#include "cuda.h"
+#include "cpu/m6805/m6805.h"
+#include "machine/6522via.h"
+#include "sound/asc.h"
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define CUDA_CPU_TAG "cuda"
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type CUDA = &device_creator<cuda_device>;
+
+ROM_START( cuda )
+ ROM_REGION(0x4400, CUDA_CPU_TAG, 0)
+ ROM_LOAD( "341s0060.bin", 0x1100, 0x1100, CRC(0f5e7b4a) SHA1(972b3778146d9787b18c3a9874d505cf606b3e15) )
+ ROM_LOAD( "341s0788.bin", 0x2200, 0x1100, CRC(df6e1b43) SHA1(ec23cc6214c472d61b98964928c40589517a3172) )
+ ROM_LOAD( "341s0417.bin", 0x3300, 0x1100, CRC(571f24c9) SHA1(a2ae12492389a00e5f4b1ef19b267d6f3a8eadc3) )
+ROM_END
+
+//-------------------------------------------------
+// ADDRESS_MAP
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( cuda_map, AS_PROGRAM, 8, cuda_device )
+ AM_RANGE(0x0000, 0x0002) AM_READWRITE(ports_r, ports_w)
+ AM_RANGE(0x0004, 0x0006) AM_READWRITE(ddr_r, ddr_w)
+ AM_RANGE(0x0007, 0x0007) AM_READWRITE(pll_r, pll_w)
+ AM_RANGE(0x0008, 0x0008) AM_READWRITE(timer_ctrl_r, timer_ctrl_w)
+ AM_RANGE(0x0009, 0x0009) AM_READWRITE(timer_counter_r, timer_counter_w)
+ AM_RANGE(0x0012, 0x0012) AM_READWRITE(onesec_r, onesec_w)
+ AM_RANGE(0x0090, 0x00ff) AM_RAM // work RAM and stack
+ AM_RANGE(0x0100, 0x01ff) AM_READWRITE(pram_r, pram_w)
+ AM_RANGE(0x0f00, 0x1fff) AM_ROM AM_REGION(CUDA_CPU_TAG, 0)
+ADDRESS_MAP_END
+
+//-------------------------------------------------
+// MACHINE_CONFIG
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( cuda )
+ MCFG_CPU_ADD(CUDA_CPU_TAG, M68HC05EG, XTAL_32_768kHz*192) // 32.768 kHz input clock, can be PLL'ed to x128 = 4.1 MHz under s/w control
+ MCFG_CPU_PROGRAM_MAP(cuda_map)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor cuda_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( cuda );
+}
+
+const rom_entry *cuda_device::device_rom_region() const
+{
+ return ROM_NAME( cuda );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+void cuda_device::send_port(address_space &space, UINT8 offset, UINT8 data)
+{
+// printf("PORT %c write %02x (DDR = %02x) (PC=%x)\n", 'A' + offset, data, ddrs[offset], cpu_get_pc(m_maincpu));
+
+ switch (offset)
+ {
+ case 0: // port A
+/* printf("PORT A ADB:%d DFAC:%d PFW:%d\n",
+ (data & 0x80) ? 1 : 0,
+ (data & 0x10) ? 1 : 0,
+ (data & 0x01) ? 1 : 0);*/
+
+ if ((data & 0x80) != last_adb)
+ {
+/* if (data & 0x80)
+ {
+ printf("CU ADB: 1->0 time %lld\n", m_maincpu->total_cycles()-last_adb_time);
+ }
+ else
+ {
+ printf("CU ADB: 0->1 time %lld\n", m_maincpu->total_cycles()-last_adb_time);
+ } */
+ last_adb = data & 0x80;
+ last_adb_time = m_maincpu->total_cycles();
+ }
+ break;
+
+ case 1: // port B
+ {
+ if (treq != ((data>>1)&1))
+ {
+ #ifdef CUDA_SUPER_VERBOSE
+ printf("CU-> TREQ: %d (PC=%x)\n", (data>>1)&1, cpu_get_pc(m_maincpu));
+ #endif
+ treq = (data>>1) & 1;
+ }
+ if (via_data != ((data>>5)&1))
+ {
+ #ifdef CUDA_SUPER_VERBOSE
+ printf("CU-> VIA_DATA: %d (PC=%x)\n", (data>>5)&1, cpu_get_pc(m_maincpu));
+ #endif
+ via_data = (data>>5) & 1;
+ }
+ if (via_clock != ((data>>4)&1))
+ {
+ #ifdef CUDA_SUPER_VERBOSE
+ printf("CU-> VIA_CLOCK: %d (PC=%x)\n", ((data>>4)&1)^1, cpu_get_pc(m_maincpu));
+ #endif
+ via_clock = (data>>4) & 1;
+ via6522_device *via1 = machine().device<via6522_device>("via6522_0");
+ via1->write_cb1(via_clock);
+ }
+ }
+ break;
+
+ case 2: // port C
+ if ((data & 8) != reset_line)
+ {
+ #ifdef CUDA_SUPER_VERBOSE
+ printf("680x0 reset: %d -> %d (PC=%x)\n", (ports[2] & 8)>>3, (data & 8)>>3, cpu_get_pc(m_maincpu));
+ #endif
+ reset_line = (data & 8);
+ // falling edge, should reset the machine too
+ if ((ports[2] & 8) && !(data&8))
+ {
+ m_out_reset_func(ASSERT_LINE);
+ m_out_reset_func(CLEAR_LINE);
+
+ // if PRAM's waiting to be loaded, transfer it now
+ if (!pram_loaded)
+ {
+// memcpy(pram, disk_pram, 0x100);
+ pram_loaded = true;
+ }
+ }
+ }
+ break;
+ }
+}
+
+READ8_MEMBER( cuda_device::ddr_r )
+{
+ return ddrs[offset];
+}
+
+WRITE8_MEMBER( cuda_device::ddr_w )
+{
+// printf("%02x to PORT %c DDR (PC=%x)\n", data, 'A' + offset, cpu_get_pc(m_maincpu));
+
+ send_port(space, offset, ports[offset] & data);
+
+ ddrs[offset] = data;
+}
+
+READ8_MEMBER( cuda_device::ports_r )
+{
+ UINT8 incoming = 0;
+
+ switch (offset)
+ {
+ case 0: // port A
+// incoming |= adb_in ? 0x40 : 0;
+
+ if (cuda_controls_power)
+ {
+ incoming = 0x20; // pull up + chassis switch (which is 0 = on)
+ }
+ else
+ {
+ incoming = 0x02 | 0x01; // pull-up + PFW
+ }
+ break;
+
+ case 1: // port B
+// printf("Read: byteack %d tip %d via_data %d\n", byteack, tip, via_data);
+ incoming |= 0x01; // +5v sense
+ incoming |= byteack<<2;
+ incoming |= tip<<3;
+ incoming |= via_data<<5;
+ incoming |= 0xc0; // show DFAC lines high
+ break;
+
+ case 2: // port C
+ if (cuda_controls_power)
+ {
+ incoming = 0x02 | 0x01; // soft power: trickle sense + pull-up
+ }
+ else
+ {
+ incoming = 0x02 | 0x01; // secure power: pull-up + file server
+ }
+ break;
+ }
+
+ // apply data direction registers
+ incoming &= (ddrs[offset] ^ 0xff);
+ // add in ddr-masked version of port writes
+ incoming |= (ports[offset] & ddrs[offset]);
+
+ // HACK: don't know how this works on h/w...
+ if (!offset)
+ {
+ incoming |= 0x01;
+ }
+
+// printf("PORT %c read = %02x (DDR = %02x latch = %02x) (PC=%x)\n", 'A' + offset, ports[offset], ddrs[offset], ports[offset], cpu_get_pc(m_maincpu));
+
+ return incoming;
+}
+
+WRITE8_MEMBER( cuda_device::ports_w )
+{
+ send_port(space, offset, data);
+
+ ports[offset] = data;
+}
+
+READ8_MEMBER( cuda_device::pll_r )
+{
+ return pll_ctrl;
+}
+
+WRITE8_MEMBER( cuda_device::pll_w )
+{
+ #ifdef CUDA_SUPER_VERBOSE
+ if (pll_ctrl != data)
+ {
+ static const int clocks[4] = { 524288, 1048576, 2097152, 4194304 };
+ printf("PLL ctrl: clock %d TCS:%d BCS:%d AUTO:%d BWC:%d PLLON:%d (PC=%x)\n", clocks[data&3],
+ (data & 0x80) ? 1 : 0,
+ (data & 0x40) ? 1 : 0,
+ (data & 0x20) ? 1 : 0,
+ (data & 0x10) ? 1 : 0,
+ (data & 0x08) ? 1 : 0, cpu_get_pc(m_maincpu));
+ }
+ #endif
+ pll_ctrl = data;
+}
+
+READ8_MEMBER( cuda_device::timer_ctrl_r )
+{
+ return timer_ctrl;
+}
+
+WRITE8_MEMBER( cuda_device::timer_ctrl_w )
+{
+ static const attotime rates[4][5] =
+ {
+ { attotime::from_seconds(1), attotime::from_msec(31.3f), attotime::from_msec(15.6f), attotime::from_msec(7.8f), attotime::from_msec(3.9f) },
+ { attotime::from_seconds(2), attotime::from_msec(62.5f), attotime::from_msec(31.3f), attotime::from_msec(15.6f), attotime::from_msec(7.8f) },
+ { attotime::from_seconds(4), attotime::from_msec(125.0f), attotime::from_msec(62.5f), attotime::from_msec(31.3f), attotime::from_msec(15.6f) },
+ { attotime::from_seconds(8), attotime::from_msec(250.0f), attotime::from_msec(125.1f), attotime::from_msec(62.5f), attotime::from_msec(31.3f) },
+ };
+
+// printf("%02x to timer control (PC=%x)\n", data, cpu_get_pc(m_maincpu));
+
+ if (data & 0x50)
+ {
+ m_prog_timer->adjust(rates[data & 3][(pll_ctrl&3)+1], 1, rates[data&3][(pll_ctrl&3)+1]);
+ ripple_counter = timer_counter;
+ }
+ else
+ {
+ m_prog_timer->adjust(attotime::never);
+ }
+
+ if ((timer_ctrl & 0x80) && !(data & 0x80))
+ {
+ device_set_input_line(m_maincpu, M68HC05EG_INT_TIMER, CLEAR_LINE);
+ timer_ctrl &= ~0x80;
+ }
+ else if ((timer_ctrl & 0x40) && !(data & 0x40))
+ {
+ device_set_input_line(m_maincpu, M68HC05EG_INT_TIMER, CLEAR_LINE);
+ timer_ctrl &= ~0x40;
+ }
+
+ timer_ctrl &= 0xc0;
+ timer_ctrl |= (data & ~0xc0);
+}
+
+READ8_MEMBER( cuda_device::timer_counter_r )
+{
+ return timer_counter;
+}
+
+WRITE8_MEMBER( cuda_device::timer_counter_w )
+{
+// printf("%02x to timer counter (PC=%x)\n", data, cpu_get_pc(m_maincpu));
+ timer_counter = data;
+ ripple_counter = timer_counter;
+}
+
+READ8_MEMBER( cuda_device::onesec_r )
+{
+ return onesec;
+}
+
+WRITE8_MEMBER( cuda_device::onesec_w )
+{
+ m_timer->adjust(attotime::from_seconds(1), 0, attotime::from_seconds(1));
+
+ if ((onesec & 0x40) && !(data & 0x40))
+ {
+ device_set_input_line(m_maincpu, M68HC05EG_INT_CPI, CLEAR_LINE);
+ }
+
+ onesec = data;
+}
+
+READ8_MEMBER( cuda_device::pram_r )
+{
+ return pram[offset];
+}
+
+WRITE8_MEMBER( cuda_device::pram_w )
+{
+ pram[offset] = data;
+}
+
+//-------------------------------------------------
+// cuda_device - constructor
+//-------------------------------------------------
+
+cuda_device::cuda_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, CUDA, "Apple Cuda", tag, owner, clock),
+ device_nvram_interface(mconfig, *this),
+ m_maincpu(*this, CUDA_CPU_TAG)
+{
+}
+
+//-------------------------------------------------
+// static_set_type - configuration helper to set
+// the chip type
+//-------------------------------------------------
+
+void cuda_device::static_set_type(device_t &device, int type)
+{
+ cuda_device &cuda = downcast<cuda_device &>(device);
+ cuda.rom_offset = type;
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void cuda_device::device_start()
+{
+ m_out_reset_func.resolve(m_out_reset_cb, *this);
+
+ m_timer = timer_alloc(0, NULL);
+ m_prog_timer = timer_alloc(1, NULL);
+ save_item(NAME(ddrs[0]));
+ save_item(NAME(ddrs[1]));
+ save_item(NAME(ddrs[2]));
+ save_item(NAME(ports[0]));
+ save_item(NAME(ports[1]));
+ save_item(NAME(ports[2]));
+ save_item(NAME(pll_ctrl));
+ save_item(NAME(timer_ctrl));
+ save_item(NAME(timer_counter));
+ save_item(NAME(ripple_counter));
+ save_item(NAME(onesec));
+ save_item(NAME(treq));
+ save_item(NAME(byteack));
+ save_item(NAME(tip));
+ save_item(NAME(via_data));
+ save_item(NAME(via_clock));
+ save_item(NAME(adb_in));
+ save_item(NAME(reset_line));
+ save_item(NAME(pram_loaded));
+ save_item(NAME(pram));
+ save_item(NAME(disk_pram));
+
+ astring tempstring;
+ UINT8 *rom = device().machine().root_device().memregion(device().subtag(tempstring, CUDA_CPU_TAG))->base();
+
+ if (rom)
+ {
+ memcpy(rom, rom+rom_offset, 0x1100);
+ }
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void cuda_device::device_reset()
+{
+ ddrs[0] = ddrs[1] = ddrs[2] = 0;
+ ports[0] = ports[1] = ports[2] = 0;
+
+ m_timer->adjust(attotime::never);
+ m_prog_timer->adjust(attotime::never);
+
+ cuda_controls_power = false; // set to hard power control
+ adb_in = true; // line is pulled up to +5v, so nothing plugged in would read as "1"
+ reset_line = 0;
+ tip = 0;
+ treq = 0;
+ byteack = 0;
+ via_data = 0;
+ via_clock = 0;
+ pll_ctrl = 0;
+ timer_ctrl = 0;
+ timer_counter = 32;
+ last_adb_time = m_maincpu->total_cycles();
+}
+
+void cuda_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ if (id == 0)
+ {
+ onesec |= 0x40;
+
+ if (onesec & 0x10)
+ {
+ device_set_input_line(m_maincpu, M68HC05EG_INT_CPI, ASSERT_LINE);
+ }
+ }
+ else
+ {
+ timer_ctrl |= 0x80;
+
+ if (timer_ctrl & 0x20)
+ {
+ device_set_input_line(m_maincpu, M68HC05EG_INT_TIMER, ASSERT_LINE);
+ }
+
+ ripple_counter--;
+ if (ripple_counter <= 0)
+ {
+ timer_ctrl |= 0x40;
+
+ ripple_counter = timer_counter;
+
+ if (timer_ctrl & 0x10)
+ {
+ device_set_input_line(m_maincpu, M68HC05EG_INT_TIMER, ASSERT_LINE);
+ }
+ }
+ }
+}
+
+void cuda_device::device_config_complete()
+{
+ m_shortname = "cuda";
+
+ // inherit a copy of the static data
+ const cuda_interface *intf = reinterpret_cast<const cuda_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<cuda_interface *>(this) = *intf;
+ }
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_reset_cb, 0, sizeof(m_out_reset_cb));
+ }
+}
+
+// the 6805 program clears PRAM on startup (on h/w it's always running once a battery is inserted)
+// we deal with that by loading pram from disk to a secondary buffer and then slapping it into "live"
+// once the cuda reboots the 68k
+void cuda_device::nvram_default()
+{
+ memset(pram, 0, 0x100);
+ memset(disk_pram, 0, 0x100);
+
+ pram[0x1] = 0x10;
+ pram[0x2] = 0x4f;
+ pram[0x3] = 0x48;
+ pram[0x8] = 0x13;
+ pram[0x9] = 0x88;
+ pram[0xb] = 0xcc;
+ pram[0xc] = 0x4e;
+ pram[0xd] = 0x75;
+ pram[0xe] = 0x4d;
+ pram[0xf] = 0x63;
+ pram[0x10] = 0xa8;
+ pram[0x14] = 0xcc;
+ pram[0x15] = 0x0a;
+ pram[0x16] = 0xcc;
+ pram[0x17] = 0x0a;
+ pram[0x1d] = 0x02;
+ pram[0x1e] = 0x63;
+ pram[0x4a] = 0x90;
+ pram[0x4b] = 0xc7;
+ pram[0x57] = 0x29;
+ pram[0x58] = 0x80;
+ pram[0x59] = 0x68;
+ pram[0x5a] = 0x80;
+ pram[0x5b] = 0x80;
+ pram[0x6f] = 0x28;
+ pram[0x77] = 0x01;
+ pram[0x78] = 0xff;
+ pram[0x79] = 0xff;
+ pram[0x7a] = 0xff;
+ pram[0x7b] = 0xdf;
+ pram[0xb8] = 0x35;
+ pram[0xb9] = 0x80;
+ pram_loaded = false;
+}
+
+void cuda_device::nvram_read(emu_file &file)
+{
+ file.read(disk_pram, 0x100);
+ pram_loaded = false;
+}
+
+void cuda_device::nvram_write(emu_file &file)
+{
+ file.write(pram, 0x100);
+}
diff --git a/src/mess/machine/cuda.h b/src/mess/machine/cuda.h
new file mode 100644
index 00000000000..04438e51771
--- /dev/null
+++ b/src/mess/machine/cuda.h
@@ -0,0 +1,126 @@
+#pragma once
+
+#ifndef __CUDA_H__
+#define __CUDA_H__
+
+#include "emu.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define CUDA_TAG "cuda"
+
+#define CUDA_341S0060 0x1100 // v2.40 (Most common: Performa/Quadra 6xx, PowerMac x200, x400, x500, Pippin, Gossamer G3)
+#define CUDA_341S0788 0x2200 // v2.37 (LC 475/575/Quadra 605, Quadra 660AV/840AV, PowerMac x200)
+#define CUDA_341S0417 0x3300 // v2.35 (Color Classic)
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_CUDA_ADD(_type, _config) \
+ MCFG_DEVICE_ADD(CUDA_TAG, CUDA, 0) \
+ MCFG_DEVICE_CONFIG(_config) \
+ MCFG_CUDA_TYPE(_type)
+
+#define MCFG_CUDA_REPLACE(_type, _config) \
+ MCFG_DEVICE_REPLACE(CUDA_TAG, CUDA, 0) \
+ MCFG_DEVICE_CONFIG(_config) \
+ MCFG_CUDA_TYPE(_type)
+
+#define MCFG_CUDA_REMOVE() \
+ MCFG_DEVICE_REMOVE(CUDA_TAG)
+
+#define MCFG_CUDA_TYPE(_type) \
+ cuda_device::static_set_type(*device, _type);
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+struct cuda_interface
+{
+ devcb_write_line m_out_reset_cb;
+};
+
+// ======================> cuda_device
+
+class cuda_device : public device_t, public device_nvram_interface, public cuda_interface
+{
+public:
+ // construction/destruction
+ cuda_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);
+
+ // device_config_nvram_interface overrides
+ virtual void nvram_default();
+ virtual void nvram_read(emu_file &file);
+ virtual void nvram_write(emu_file &file);
+
+ DECLARE_READ8_MEMBER( ddr_r );
+ DECLARE_WRITE8_MEMBER( ddr_w );
+ DECLARE_READ8_MEMBER( ports_r );
+ DECLARE_WRITE8_MEMBER( ports_w );
+ DECLARE_READ8_MEMBER( pll_r );
+ DECLARE_WRITE8_MEMBER( pll_w );
+ DECLARE_READ8_MEMBER( timer_ctrl_r );
+ DECLARE_WRITE8_MEMBER( timer_ctrl_w );
+ DECLARE_READ8_MEMBER( timer_counter_r );
+ DECLARE_WRITE8_MEMBER( timer_counter_w );
+ DECLARE_READ8_MEMBER( onesec_r );
+ DECLARE_WRITE8_MEMBER( onesec_w );
+ DECLARE_READ8_MEMBER( pram_r );
+ DECLARE_WRITE8_MEMBER( pram_w );
+
+ // VIA interface routines
+ UINT8 get_treq() { return treq; }
+ void set_tip(UINT8 val) { tip = val; }
+ void set_byteack(UINT8 val) { byteack = val; }
+ UINT8 get_via_data() { return via_data; }
+ void set_via_data(UINT8 dat) { via_data = dat; }
+ UINT8 get_via_clock() { return via_clock; }
+
+ int rom_offset;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete();
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+
+ required_device<cpu_device> m_maincpu;
+
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+private:
+ UINT8 ddrs[3];
+ UINT8 ports[3];
+ UINT8 pll_ctrl;
+ UINT8 timer_ctrl;
+ UINT8 timer_counter, ripple_counter;
+ UINT8 onesec;
+ UINT8 treq, byteack, tip, via_data, via_clock, last_adb;
+ UINT64 last_adb_time;
+ bool cuda_controls_power;
+ bool adb_in;
+ int reset_line;
+ emu_timer *m_timer, *m_prog_timer;
+ UINT8 pram[0x100], disk_pram[0x100];
+ bool pram_loaded;
+
+ void send_port(address_space &space, UINT8 offset, UINT8 data);
+
+ devcb_resolved_write_line m_out_reset_func;
+};
+
+// device type definition
+extern const device_type CUDA;
+
+#endif
diff --git a/src/mess/machine/cybiko.c b/src/mess/machine/cybiko.c
new file mode 100644
index 00000000000..ffe96247805
--- /dev/null
+++ b/src/mess/machine/cybiko.c
@@ -0,0 +1,674 @@
+/*
+
+ Cybiko Wireless Inter-tainment System
+
+ (c) 2001-2007 Tim Schuerewegen
+
+ Cybiko Classic (V1)
+ Cybiko Classic (V2)
+ Cybiko Xtreme
+
+*/
+
+#include "includes/cybiko.h"
+
+#define LOG_LEVEL 1
+#define _logerror(level,x) do { if (LOG_LEVEL > level) logerror x; } while (0)
+
+#define RAMDISK_SIZE (512 * 1024)
+
+/////////////////////////
+// FUNCTION PROTOTYPES //
+/////////////////////////
+
+#define MACHINE_STOP(name) \
+ static void machine_stop_##name( running_machine &machine)
+
+// machine stop
+MACHINE_STOP( cybikov1 );
+MACHINE_STOP( cybikov2 );
+MACHINE_STOP( cybikoxt );
+
+// state->m_rs232
+static void cybiko_rs232_init(running_machine &machine);
+static void cybiko_rs232_exit(void);
+static void cybiko_rs232_reset(void);
+
+////////////////////////
+// DRIVER INIT & EXIT //
+////////////////////////
+
+static void init_ram_handler(running_machine &machine, offs_t start, offs_t size, offs_t mirror)
+{
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(start, start + size - 1, 0, mirror - size, "bank1");
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_write_bank(start, start + size - 1, 0, mirror - size, "bank1");
+ machine.root_device().membank( "bank1" )->set_base( machine.device<ram_device>(RAM_TAG)->pointer());
+}
+
+DRIVER_INIT_MEMBER(cybiko_state,cybikov1)
+{
+ _logerror( 0, ("init_cybikov1\n"));
+ init_ram_handler(machine(), 0x200000, machine().device<ram_device>(RAM_TAG)->size(), 0x200000);
+}
+
+DRIVER_INIT_MEMBER(cybiko_state,cybikov2)
+{
+ _logerror( 0, ("init_cybikov2\n"));
+ init_ram_handler(machine(), 0x200000, machine().device<ram_device>(RAM_TAG)->size(), 0x200000);
+}
+
+DRIVER_INIT_MEMBER(cybiko_state,cybikoxt)
+{
+ _logerror( 0, ("init_cybikoxt\n"));
+ init_ram_handler(machine(), 0x400000, machine().device<ram_device>(RAM_TAG)->size(), 0x200000);
+}
+
+///////////////////
+// MACHINE START //
+///////////////////
+
+static emu_file *nvram_system_fopen( running_machine &machine, UINT32 openflags, const char *name)
+{
+ file_error filerr;
+ astring fname(machine.system().name, PATH_SEPARATOR, name, ".nv");
+ emu_file *file = global_alloc(emu_file(machine.options().nvram_directory(), openflags));
+ filerr = file->open(fname.cstr());
+ if (filerr == FILERR_NONE)
+ return file;
+
+ global_free(file);
+ return NULL;
+}
+
+typedef void (nvram_load_func)(running_machine &machine, emu_file *file);
+
+static int nvram_system_load( running_machine &machine, const char *name, nvram_load_func _nvram_load, int required)
+{
+ emu_file *file;
+ file = nvram_system_fopen( machine, OPEN_FLAG_READ, name);
+ if (!file)
+ {
+ if (required) mame_printf_error( "nvram load failed (%s)\n", name);
+ return FALSE;
+ }
+ (*_nvram_load)(machine, file);
+ global_free(file);
+ return TRUE;
+}
+
+typedef void (nvram_save_func)(running_machine &machine, emu_file *file);
+
+static int nvram_system_save( running_machine &machine, const char *name, nvram_save_func _nvram_save)
+{
+ emu_file *file;
+ file = nvram_system_fopen( machine, OPEN_FLAG_CREATE | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE_PATHS, name);
+ if (!file)
+ {
+ mame_printf_error( "nvram save failed (%s)\n", name);
+ return FALSE;
+ }
+ (*_nvram_save)(machine, file);
+ global_free(file);
+ return TRUE;
+}
+
+static void cybiko_pcf8593_load(running_machine &machine, emu_file *file)
+{
+ device_t *device = machine.device("rtc");
+ pcf8593_load(device, file);
+}
+
+static void cybiko_pcf8593_save(running_machine &machine, emu_file *file)
+{
+ device_t *device = machine.device("rtc");
+ pcf8593_save(device, file);
+}
+
+static void cybiko_at45dbxx_load(running_machine &machine, emu_file *file)
+{
+ device_t *device = machine.device("flash1");
+ at45dbxx_load(device, file);
+}
+
+static void cybiko_at45dbxx_save(running_machine &machine, emu_file *file)
+{
+ device_t *device = machine.device("flash1");
+ at45dbxx_save(device, file);
+}
+
+static void cybiko_sst39vfx_load(running_machine &machine, emu_file *file)
+{
+ device_t *device = machine.device("flash2");
+ sst39vfx_load(device, file);
+}
+
+static void cybiko_sst39vfx_save(running_machine &machine, emu_file *file)
+{
+ device_t *device = machine.device("flash2");
+ sst39vfx_save(device, file);
+}
+
+static void cybiko_ramdisk_load(running_machine &machine, emu_file *file)
+{
+ UINT8 *ram = machine.device<ram_device>(RAM_TAG)->pointer();
+#ifdef LSB_FIRST
+ UINT8 *temp = (UINT8*)malloc( RAMDISK_SIZE);
+ file->read( temp, RAMDISK_SIZE);
+ for (int i = 0; i < RAMDISK_SIZE; i += 2)
+ {
+ ram[i+0] = temp[i+1];
+ ram[i+1] = temp[i+0];
+ }
+ free( temp);
+#else
+ file->read( ram, RAMDISK_SIZE);
+#endif
+}
+
+static void cybiko_ramdisk_save(running_machine &machine, emu_file *file)
+{
+ UINT8 *ram = machine.device<ram_device>(RAM_TAG)->pointer();
+#ifdef LSB_FIRST
+ UINT8 *temp = (UINT8*)malloc( RAMDISK_SIZE);
+ for (int i = 0; i < RAMDISK_SIZE; i += 2)
+ {
+ temp[i+0] = ram[i+1];
+ temp[i+1] = ram[i+0];
+ }
+ file->write( temp, RAMDISK_SIZE);
+ free( temp);
+#else
+ file->write( ram, RAMDISK_SIZE);
+#endif
+}
+
+MACHINE_START( cybikov1 )
+{
+ _logerror( 0, ("machine_start_cybikov1\n"));
+ // real-time clock
+ nvram_system_load( machine, "rtc", cybiko_pcf8593_load, 0);
+ // serial dataflash
+ nvram_system_load( machine, "flash1", cybiko_at45dbxx_load, 1);
+ // serial port
+ cybiko_rs232_init(machine);
+ // other
+ machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(machine_stop_cybikov1),&machine));
+}
+
+MACHINE_START( cybikov2 )
+{
+ device_t *flash2 = machine.device("flash2");
+
+ _logerror( 0, ("machine_start_cybikov2\n"));
+ // real-time clock
+ nvram_system_load( machine, "rtc", cybiko_pcf8593_load, 0);
+ // serial dataflash
+ nvram_system_load( machine, "flash1", cybiko_at45dbxx_load, 1);
+ // multi-purpose flash
+ nvram_system_load( machine, "flash2", cybiko_sst39vfx_load, 1);
+ machine.root_device().membank( "bank2" )->set_base( sst39vfx_get_base(flash2));
+ // serial port
+ cybiko_rs232_init(machine);
+ // other
+ machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(machine_stop_cybikov2),&machine));
+}
+
+MACHINE_START( cybikoxt )
+{
+ device_t *flash2 = machine.device("flash2");
+ _logerror( 0, ("machine_start_cybikoxt\n"));
+ // real-time clock
+ nvram_system_load( machine, "rtc", cybiko_pcf8593_load, 0);
+ // multi-purpose flash
+ nvram_system_load( machine, "flash2", cybiko_sst39vfx_load, 1);
+ machine.root_device().membank( "bank2" )->set_base( sst39vfx_get_base(flash2));
+ // ramdisk
+ nvram_system_load( machine, "ramdisk", cybiko_ramdisk_load, 0);
+ // serial port
+ cybiko_rs232_init(machine);
+ // other
+ machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(machine_stop_cybikoxt),&machine));
+}
+
+///////////////////
+// MACHINE RESET //
+///////////////////
+
+MACHINE_RESET( cybikov1 )
+{
+ _logerror( 0, ("machine_reset_cybikov1\n"));
+ cybiko_rs232_reset();
+}
+
+MACHINE_RESET( cybikov2 )
+{
+ _logerror( 0, ("machine_reset_cybikov2\n"));
+ cybiko_rs232_reset();
+}
+
+MACHINE_RESET( cybikoxt )
+{
+ _logerror( 0, ("machine_reset_cybikoxt\n"));
+ cybiko_rs232_reset();
+}
+
+//////////////////
+// MACHINE STOP //
+//////////////////
+
+MACHINE_STOP( cybikov1 )
+{
+ _logerror( 0, ("machine_stop_cybikov1\n"));
+ // real-time clock
+ nvram_system_save( machine, "rtc", cybiko_pcf8593_save);
+ // serial dataflash
+ nvram_system_save( machine, "flash1", cybiko_at45dbxx_save);
+ // serial port
+ cybiko_rs232_exit();
+}
+
+MACHINE_STOP( cybikov2 )
+{
+ _logerror( 0, ("machine_stop_cybikov2\n"));
+ // real-time clock
+ nvram_system_save( machine, "rtc", cybiko_pcf8593_save);
+ // serial dataflash
+ nvram_system_save( machine, "flash1", cybiko_at45dbxx_save);
+ // multi-purpose flash
+ nvram_system_save( machine, "flash2", cybiko_sst39vfx_save);
+ // serial port
+ cybiko_rs232_exit();
+}
+
+MACHINE_STOP( cybikoxt )
+{
+ _logerror( 0, ("machine_stop_cybikoxt\n"));
+ // real-time clock
+ nvram_system_save( machine, "rtc", cybiko_pcf8593_save);
+ // multi-purpose flash
+ nvram_system_save( machine, "flash2", cybiko_sst39vfx_save);
+ // ramdisk
+ nvram_system_save( machine, "ramdisk", cybiko_ramdisk_save);
+ // serial port
+ cybiko_rs232_exit();
+}
+
+///////////
+// RS232 //
+///////////
+
+
+static void cybiko_rs232_init(running_machine &machine)
+{
+ cybiko_state *state = machine.driver_data<cybiko_state>();
+ _logerror( 0, ("cybiko_rs232_init\n"));
+ memset( &state->m_rs232, 0, sizeof( state->m_rs232));
+// machine.scheduler().timer_pulse(TIME_IN_HZ( 10), FUNC(rs232_timer_callback));
+}
+
+static void cybiko_rs232_exit()
+{
+ _logerror( 0, ("cybiko_rs232_exit\n"));
+}
+
+static void cybiko_rs232_reset()
+{
+ _logerror( 0, ("cybiko_rs232_reset\n"));
+}
+
+void cybiko_state::cybiko_rs232_write_byte( int data )
+{
+// printf( "%c", data);
+}
+
+void cybiko_state::cybiko_rs232_pin_sck( int data )
+{
+ _logerror( 3, ("cybiko_rs232_pin_sck (%d)\n", data));
+ // clock high-to-low
+ if ((m_rs232.pin.sck == 1) && (data == 0))
+ {
+ // transmit
+ if (m_rs232.pin.txd) m_rs232.tx_byte = m_rs232.tx_byte | (1 << m_rs232.tx_bits);
+ m_rs232.tx_bits++;
+ if (m_rs232.tx_bits == 8)
+ {
+ m_rs232.tx_bits = 0;
+ cybiko_rs232_write_byte(m_rs232.tx_byte);
+ m_rs232.tx_byte = 0;
+ }
+ // receive
+ m_rs232.pin.rxd = (m_rs232.rx_byte >> m_rs232.rx_bits) & 1;
+ m_rs232.rx_bits++;
+ if (m_rs232.rx_bits == 8)
+ {
+ m_rs232.rx_bits = 0;
+ m_rs232.rx_byte = 0;
+ }
+ }
+ // save sck
+ m_rs232.pin.sck = data;
+}
+
+void cybiko_state::cybiko_rs232_pin_txd( int data )
+{
+ _logerror( 3, ("cybiko_rs232_pin_txd (%d)\n", data));
+ m_rs232.pin.txd = data;
+}
+
+int cybiko_state::cybiko_rs232_pin_rxd()
+{
+ _logerror( 3, ("cybiko_rs232_pin_rxd\n"));
+ return m_rs232.pin.rxd;
+}
+
+int cybiko_state::cybiko_rs232_rx_queue()
+{
+ return 0;
+}
+
+/////////////////////////
+// READ/WRITE HANDLERS //
+/////////////////////////
+
+READ16_MEMBER( cybiko_state::cybiko_lcd_r )
+{
+ UINT16 data = 0;
+ if (ACCESSING_BITS_8_15) data |= (m_crtc->reg_idx_r(space, offset) << 8);
+ if (ACCESSING_BITS_0_7) data |= (m_crtc->reg_dat_r(space, offset) << 0);
+ return data;
+}
+
+WRITE16_MEMBER( cybiko_state::cybiko_lcd_w )
+{
+ if (ACCESSING_BITS_8_15) m_crtc->reg_idx_w(space, offset, (data >> 8) & 0xff);
+ if (ACCESSING_BITS_0_7) m_crtc->reg_dat_w(space, offset, (data >> 0) & 0xff);
+}
+
+int cybiko_state::cybiko_key_r( offs_t offset, int mem_mask)
+{
+ static const char *const keynames[] = { "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "A10", "A11", "A12", "A13", "A14", "A15" };
+ UINT16 data = 0xFFFF;
+ for (UINT8 i = 0; i < 15; i++)
+ {
+ if (!BIT(offset, i))
+ data &= ~ioport(keynames[i])->read_safe(0);
+ }
+ if (data != 0xFFFF)
+ {
+ _logerror( 1, ("cybiko_key_r (%08X/%04X) %04X\n", offset, mem_mask, data));
+ }
+ return data;
+}
+
+READ16_MEMBER( cybiko_state::cybikov1_key_r )
+{
+ return cybiko_key_r(offset, mem_mask);
+}
+
+READ16_MEMBER( cybiko_state::cybikov2_key_r )
+{
+ UINT16 data = cybiko_key_r(offset, mem_mask);
+ if (!BIT(offset, 0))
+ data |= 0x0002; // or else [esc] does not work in "lost in labyrinth"
+ return data;
+}
+
+READ16_MEMBER( cybiko_state::cybikoxt_key_r )
+{
+ return cybiko_key_r(offset, mem_mask);
+}
+
+READ8_MEMBER( cybiko_state::cybikov1_io_reg_r )
+{
+ UINT8 data = 0;
+ _logerror( 2, ("cybikov1_io_reg_r (%08X)\n", offset));
+ switch (offset)
+ {
+ // keyboard
+ case H8S_IO_PORT1 :
+ {
+ if (!BIT(ioport("A1")->read(), 1))
+ data |= (1 << 3); // "esc" key
+ }
+ break;
+ // serial dataflash
+ case H8S_IO_PORT3 :
+ {
+ if (at45dbxx_pin_so(m_flash1))
+ data |= H8S_P3_RXD1;
+ }
+ break;
+ // rs232
+ case H8S_IO_PORT5 :
+ {
+ if (cybiko_rs232_pin_rxd())
+ data |= H8S_P5_RXD2;
+ }
+ break;
+ // real-time clock
+ case H8S_IO_PORTF :
+ {
+ data = H8S_PF_PF2;
+ if (pcf8593_pin_sda_r(m_rtc))
+ data |= H8S_PF_PF0;
+ }
+ break;
+ // serial 2
+ case H8S_IO_SSR2 :
+ {
+ if (cybiko_rs232_rx_queue())
+ data |= H8S_SSR_RDRF;
+ }
+ break;
+ }
+ return data;
+}
+
+READ8_MEMBER( cybiko_state::cybikov2_io_reg_r )
+{
+ UINT8 data = 0;
+ _logerror( 2, ("cybikov2_io_reg_r (%08X)\n", offset));
+ switch (offset)
+ {
+ // keyboard
+ case H8S_IO_PORT1 :
+ {
+ if (!BIT(ioport("A1")->read(), 1))
+ data |= (1 << 3); // "esc" key
+ }
+ break;
+ // serial dataflash
+ case H8S_IO_PORT3 :
+ {
+ if (at45dbxx_pin_so(m_flash1))
+ data |= H8S_P3_RXD1;
+ }
+ break;
+ // rs232
+ case H8S_IO_PORT5 :
+ {
+ if (cybiko_rs232_pin_rxd())
+ data |= H8S_P5_RXD2;
+ }
+ break;
+ // real-time clock
+ case H8S_IO_PORTF :
+ {
+ data = H8S_PF_PF2;
+ if (pcf8593_pin_sda_r(m_rtc))
+ data |= H8S_PF_PF0;
+ }
+ break;
+ // serial 2
+ case H8S_IO_SSR2 :
+ {
+ if (cybiko_rs232_rx_queue())
+ data |= H8S_SSR_RDRF;
+ }
+ break;
+ }
+ return data;
+}
+
+READ8_MEMBER( cybiko_state::cybikoxt_io_reg_r )
+{
+ UINT8 data = 0;
+ _logerror( 2, ("cybikoxt_io_reg_r (%08X)\n", offset));
+ switch (offset)
+ {
+ // rs232
+ case H8S_IO_PORT3 :
+ {
+ if (cybiko_rs232_pin_rxd())
+ data |= H8S_P3_RXD1;
+ }
+ break;
+ // ...
+ case H8S_IO_PORTA :
+ {
+ data |= (1 << 6); // recharge batteries (xtreme)
+ data |= (1 << 7); // on/off key (xtreme)
+ }
+ break;
+ // real-time clock
+ case H8S_IO_PORTF :
+ {
+ if (pcf8593_pin_sda_r(m_rtc))
+ data |= H8S_PF_PF6;
+ }
+ break;
+ // serial 1
+ case H8S_IO_SSR1 :
+ {
+ if (cybiko_rs232_rx_queue())
+ data |= H8S_SSR_RDRF;
+ }
+ break;
+ }
+ return data;
+}
+
+WRITE8_MEMBER( cybiko_state::cybikov1_io_reg_w )
+{
+ _logerror( 2, ("cybikov1_io_reg_w (%08X/%02X)\n", offset, data));
+ switch (offset)
+ {
+ // speaker
+ case H8S_IO_P1DR :
+ {
+ speaker_level_w(m_speaker, (data & H8S_P1_TIOCB1) ? 1 : 0);
+ }
+ break;
+ // serial dataflash
+ case H8S_IO_P3DR :
+ {
+ at45dbxx_pin_cs (m_flash1, (data & H8S_P3_SCK0) ? 0 : 1);
+ at45dbxx_pin_si (m_flash1, (data & H8S_P3_TXD1) ? 1 : 0);
+ at45dbxx_pin_sck(m_flash1, (data & H8S_P3_SCK1) ? 1 : 0);
+ }
+ break;
+ // rs232
+ case H8S_IO_P5DR :
+ {
+ cybiko_rs232_pin_txd((data & H8S_P5_TXD2) ? 1 : 0);
+ cybiko_rs232_pin_sck((data & H8S_P5_SCK2) ? 1 : 0);
+ }
+ break;
+ // real-time clock
+ case H8S_IO_PFDR :
+ {
+ pcf8593_pin_scl(m_rtc, (data & H8S_PF_PF1) ? 1 : 0);
+ }
+ break;
+ // real-time clock
+ case H8S_IO_PFDDR :
+ {
+ pcf8593_pin_sda_w(m_rtc, (data & H8S_PF_PF0) ? 0 : 1);
+ }
+ break;
+ }
+}
+
+WRITE8_MEMBER( cybiko_state::cybikov2_io_reg_w )
+{
+ _logerror( 2, ("cybikov2_io_reg_w (%08X/%02X)\n", offset, data));
+ switch (offset)
+ {
+ // speaker
+ case H8S_IO_P1DR :
+ {
+ speaker_level_w(m_speaker, (data & H8S_P1_TIOCB1) ? 1 : 0);
+ }
+ break;
+ // serial dataflash
+ case H8S_IO_P3DR :
+ {
+ at45dbxx_pin_cs (m_flash1, (data & H8S_P3_SCK0) ? 0 : 1);
+ at45dbxx_pin_si (m_flash1, (data & H8S_P3_TXD1) ? 1 : 0);
+ at45dbxx_pin_sck(m_flash1, (data & H8S_P3_SCK1) ? 1 : 0);
+ }
+ break;
+ // rs232
+ case H8S_IO_P5DR :
+ {
+ cybiko_rs232_pin_txd((data & H8S_P5_TXD2) ? 1 : 0);
+ cybiko_rs232_pin_sck((data & H8S_P5_SCK2) ? 1 : 0);
+ }
+ break;
+ // real-time clock
+ case H8S_IO_PFDR :
+ {
+ pcf8593_pin_scl(m_rtc, (data & H8S_PF_PF1) ? 1 : 0);
+ }
+ break;
+ // real-time clock
+ case H8S_IO_PFDDR :
+ {
+ pcf8593_pin_sda_w(m_rtc, (data & H8S_PF_PF0) ? 0 : 1);
+ }
+ break;
+ }
+}
+
+WRITE8_MEMBER( cybiko_state::cybikoxt_io_reg_w )
+{
+ _logerror( 2, ("cybikoxt_io_reg_w (%08X/%02X)\n", offset, data));
+ switch (offset)
+ {
+ // speaker
+ case H8S_IO_P1DR :
+ {
+ speaker_level_w(m_speaker, (data & H8S_P1_TIOCB1) ? 1 : 0);
+ }
+ break;
+ // rs232
+ case H8S_IO_P3DR :
+ {
+ cybiko_rs232_pin_txd((data & H8S_P3_TXD1) ? 1 : 0);
+ cybiko_rs232_pin_sck((data & H8S_P3_SCK1) ? 1 : 0);
+ }
+ break;
+ // real-time clock
+ case H8S_IO_PFDR :
+ {
+ pcf8593_pin_scl(m_rtc, (data & H8S_PF_PF1) ? 1 : 0);
+ }
+ break;
+ // real-time clock
+ case H8S_IO_PFDDR :
+ {
+ pcf8593_pin_sda_w(m_rtc, (data & H8S_PF_PF6) ? 0 : 1);
+ }
+ break;
+ }
+}
+
+// Cybiko Xtreme writes following byte pairs to 0x200003/0x200000
+// 00/01, 00/C0, 0F/32, 0D/03, 0B/03, 09/50, 07/D6, 05/00, 04/00, 20/00, 23/08, 27/01, 2F/08, 2C/02, 2B/08, 28/01
+// 04/80, 05/02, 00/C8, 00/C8, 00/C0, 1B/2C, 00/01, 00/C0, 1B/6C, 0F/10, 0D/07, 0B/07, 09/D2, 07/D6, 05/00, 04/00,
+// 20/00, 23/08, 27/01, 2F/08, 2C/02, 2B/08, 28/01, 37/08, 34/04, 33/08, 30/03, 04/80, 05/02, 1B/6C, 00/C8
+WRITE16_MEMBER( cybiko_state::cybiko_usb_w )
+{
+ if (ACCESSING_BITS_8_15) _logerror( 2, ("[%08X] <- %02X\n", 0x200000 + offset * 2 + 0, (data >> 8) & 0xFF));
+ if (ACCESSING_BITS_0_7) _logerror( 2, ("[%08X] <- %02X\n", 0x200000 + offset * 2 + 1, (data >> 0) & 0xFF));
+}
diff --git a/src/mess/machine/d9060.c b/src/mess/machine/d9060.c
new file mode 100644
index 00000000000..e9b1564c1e7
--- /dev/null
+++ b/src/mess/machine/d9060.c
@@ -0,0 +1,601 @@
+/**********************************************************************
+
+ Commodore 9060/9090 Hard Disk Drive emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "d9060.h"
+#include "machine/scsihd.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<d9060_device>;
+const device_type D9090 = &device_creator<d9090_device>;
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void base_d9060_device::device_config_complete()
+{
+ switch (m_variant)
+ {
+ default:
+ case TYPE_9060:
+ m_shortname = "d9060";
+ break;
+
+ case TYPE_9090:
+ m_shortname = "d9090";
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// ROM( d9060 )
+//-------------------------------------------------
+
+ROM_START( d9060 )
+ ROM_REGION( 0x4000, M6502_DOS_TAG, 0 )
+ ROM_LOAD_OPTIONAL( "300516-revb.7c", 0x0000, 0x2000, CRC(2d758a14) SHA1(c959cc9dde84fc3d64e95e58a0a096a26d8107fd) )
+ ROM_LOAD( "300516-revc.7c", 0x0000, 0x2000, CRC(d6a3e88f) SHA1(bb1ddb5da94a86266012eca54818aa21dc4cef6a) )
+ ROM_LOAD_OPTIONAL( "300517-reva.7d", 0x2000, 0x2000, CRC(566df630) SHA1(b1602dfff408b165ee52a6a4ca3e2ec27e689ba9) )
+ ROM_LOAD_OPTIONAL( "300517-revb.7d", 0x2000, 0x2000, CRC(f0382bc3) SHA1(0b0a8dc520f5b41ffa832e4a636b3d226ccbb7f1) )
+ ROM_LOAD( "300517-revc.7d", 0x2000, 0x2000, CRC(2a9ad4ad) SHA1(4c17d014de48c906871b9b6c7d037d8736b1fd52) )
+
+ ROM_REGION( 0x800, M6502_HDC_TAG, 0 )
+ ROM_LOAD_OPTIONAL( "300515-reva.4c", 0x000, 0x800, CRC(99e096f7) SHA1(a3d1deb27bf5918b62b89c27fa3e488eb8f717a4) )
+ ROM_LOAD( "300515-revb.4c", 0x000, 0x800, CRC(49adf4fb) SHA1(59dafbd4855083074ba8dc96a04d4daa5b76e0d6) )
+
+ 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 *base_d9060_device::device_rom_region() const
+{
+ return ROM_NAME( d9060 );
+}
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( d9060_main_mem )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( d9060_main_mem, AS_PROGRAM, 8, base_d9060_device )
+ AM_RANGE(0x0000, 0x007f) AM_MIRROR(0x0100) AM_RAM // 6532 #1
+ AM_RANGE(0x0080, 0x00ff) AM_MIRROR(0x0100) AM_RAM // 6532 #2
+ AM_RANGE(0x0200, 0x021f) AM_MIRROR(0x0d60) AM_DEVREADWRITE_LEGACY(M6532_0_TAG, riot6532_r, riot6532_w)
+ AM_RANGE(0x0280, 0x029f) AM_MIRROR(0x0d60) AM_DEVREADWRITE_LEGACY(M6532_1_TAG, riot6532_r, riot6532_w)
+ 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, base_d9060_device )
+ 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
+
+
+//-------------------------------------------------
+// SCSIBus_interface sasi_intf
+//-------------------------------------------------
+
+static const SCSIConfigTable sasi_dev_table =
+{
+ 1,
+ {
+ { SCSI_ID_0, "harddisk0" }
+ }
+};
+
+WRITE_LINE_MEMBER( base_d9060_device::req_w )
+{
+ m_via->write_ca1(!state);
+}
+
+static const SCSIBus_interface sasi_intf =
+{
+ &sasi_dev_table,
+ NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_d9060_device, req_w),
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// riot6532_interface riot0_intf
+//-------------------------------------------------
+
+READ8_MEMBER( base_d9060_device::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( base_d9060_device::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);
+}
+
+
+static const riot6532_interface riot0_intf =
+{
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_d9060_device, dio_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_d9060_device, dio_w),
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// riot6532_interface riot1_intf
+//-------------------------------------------------
+
+READ8_MEMBER( base_d9060_device::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( base_d9060_device::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( base_d9060_device::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_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( base_d9060_device::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));
+}
+
+static const riot6532_interface riot1_intf =
+{
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_d9060_device, riot1_pa_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_d9060_device, riot1_pb_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_d9060_device, riot1_pa_w),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_d9060_device, riot1_pb_w),
+ DEVCB_CPU_INPUT_LINE(M6502_DOS_TAG, INPUT_LINE_IRQ0)
+};
+
+
+//-------------------------------------------------
+// via6522_interface via_intf
+//-------------------------------------------------
+
+READ8_MEMBER( base_d9060_device::via_pb_r )
+{
+ /*
+
+ bit description
+
+ PB0
+ PB1
+ PB2 C/D
+ PB3 BUSY
+ PB4 J14 (1=9060, 0=9090)
+ PB5 J13
+ PB6 I/O
+ PB7 MSG
+
+ */
+
+ UINT8 data = 0;
+
+ data |= !scsi_cd_r(m_sasibus) << 2;
+ data |= !scsi_bsy_r(m_sasibus) << 3;
+ data |= !scsi_io_r(m_sasibus) << 6;
+ data |= !scsi_msg_r(m_sasibus) << 7;
+
+ // drive type
+ data |= (m_variant == TYPE_9060) << 4;
+
+ return data;
+}
+
+WRITE8_MEMBER( base_d9060_device::via_pb_w )
+{
+ /*
+
+ bit description
+
+ PB0 SEL
+ PB1 RST
+ PB2
+ PB3
+ PB4
+ PB5
+ PB6
+ PB7
+
+ */
+
+ scsi_sel_w(m_sasibus, !BIT(data, 0));
+ scsi_rst_w(m_sasibus, !BIT(data, 1));
+}
+
+READ_LINE_MEMBER( base_d9060_device::req_r )
+{
+ return !scsi_req_r(m_sasibus);
+}
+
+WRITE_LINE_MEMBER( base_d9060_device::ack_w )
+{
+ scsi_ack_w(m_sasibus, state);
+}
+
+WRITE_LINE_MEMBER( base_d9060_device::enable_w )
+{
+ m_enable = state;
+}
+
+static const via6522_interface via_intf =
+{
+ DEVCB_DEVICE_HANDLER(SASIBUS_TAG, scsi_data_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_d9060_device, via_pb_r),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_d9060_device, req_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+
+ DEVCB_DEVICE_HANDLER(SASIBUS_TAG, scsi_data_w),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, base_d9060_device, via_pb_w),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_d9060_device, ack_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, base_d9060_device, enable_w),
+
+ DEVCB_CPU_INPUT_LINE(M6502_HDC_TAG, INPUT_LINE_IRQ0)
+};
+
+
+//-------------------------------------------------
+// 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_RIOT6532_ADD(M6532_0_TAG, XTAL_4MHz/4, riot0_intf)
+ MCFG_RIOT6532_ADD(M6532_1_TAG, XTAL_4MHz/4, riot1_intf)
+
+ // controller
+ MCFG_CPU_ADD(M6502_HDC_TAG, M6502, XTAL_4MHz/4)
+ MCFG_CPU_PROGRAM_MAP(d9060_hdc_mem)
+
+ MCFG_VIA6522_ADD(M6522_TAG, XTAL_4MHz/4, via_intf)
+
+ MCFG_SCSIBUS_ADD(SASIBUS_TAG, sasi_intf)
+ MCFG_DEVICE_ADD("harddisk0", SCSIHD, 0)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor base_d9060_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( d9060 );
+}
+
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// update_ieee_signals -
+//-------------------------------------------------
+
+inline void base_d9060_device::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
+//**************************************************************************
+
+//-------------------------------------------------
+// base_d9060_device - constructor
+//-------------------------------------------------
+
+base_d9060_device::base_d9060_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant)
+ : device_t(mconfig, type, name, tag, owner, clock),
+ 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_rfdo(1),
+ m_daco(1),
+ m_atna(1),
+ m_enable(1),
+ m_variant(variant)
+{
+}
+
+
+//-------------------------------------------------
+// d9060_device - constructor
+//-------------------------------------------------
+
+d9060_device::d9060_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : base_d9060_device(mconfig, D9060, "D9060", tag, owner, clock, TYPE_9060) { }
+
+
+//-------------------------------------------------
+// d9090_device - constructor
+//-------------------------------------------------
+
+d9090_device::d9090_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : base_d9060_device(mconfig, D9090, "D9090", tag, owner, clock, TYPE_9090) { }
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void base_d9060_device::device_start()
+{
+ // state saving
+ save_item(NAME(m_rfdo));
+ save_item(NAME(m_daco));
+ save_item(NAME(m_atna));
+ save_item(NAME(m_enable));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void base_d9060_device::device_reset()
+{
+ init_scsibus(m_sasibus, 256);
+
+ 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);
+}
+
+
+//-------------------------------------------------
+// ieee488_atn - attention
+//-------------------------------------------------
+
+void base_d9060_device::ieee488_atn(int state)
+{
+ update_ieee_signals();
+
+ // set RIOT PA7
+ riot6532_porta_in_set(m_riot1, !state << 7, 0x80);
+}
+
+
+//-------------------------------------------------
+// ieee488_ifc - interface clear
+//-------------------------------------------------
+
+void base_d9060_device::ieee488_ifc(int state)
+{
+ if (!state)
+ {
+ device_reset();
+ }
+}
diff --git a/src/mess/machine/d9060.h b/src/mess/machine/d9060.h
new file mode 100644
index 00000000000..afa579c23e4
--- /dev/null
+++ b/src/mess/machine/d9060.h
@@ -0,0 +1,134 @@
+/**********************************************************************
+
+ Commodore D9060/D9090 Hard Disk Drive emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+
+ D9060: Tandon TM602S
+ chdman -createblankhd d9060.chd 153 4 32 256
+
+ D9090: Tandon TM603S
+ chdman -createblankhd d9090.chd 153 6 32 256
+
+ How to format the disk:
+ HEADER "LABEL",D0,I01
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __D9060__
+#define __D9060__
+
+
+#include "emu.h"
+#include "cpu/m6502/m6502.h"
+#include "imagedev/harddriv.h"
+#include "machine/6522via.h"
+#include "machine/6532riot.h"
+#include "machine/ieee488.h"
+#include "machine/scsibus.h"
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+
+// ======================> base_d9060_device
+
+class base_d9060_device : public device_t,
+ public device_ieee488_interface
+{
+
+public:
+ enum
+ {
+ TYPE_9060,
+ TYPE_9090
+ };
+
+ // construction/destruction
+ base_d9060_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant);
+
+ // optional information overrides
+ virtual const rom_entry *device_rom_region() const;
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+ // not really public
+ DECLARE_WRITE_LINE_MEMBER( req_w );
+ 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_READ_LINE_MEMBER( req_r );
+ DECLARE_WRITE_LINE_MEMBER( ack_w );
+ DECLARE_WRITE_LINE_MEMBER( enable_w );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete();
+
+ // device_ieee488_interface overrides
+ void ieee488_atn(int state);
+ void ieee488_ifc(int state);
+
+private:
+ inline void update_ieee_signals();
+
+ required_device<cpu_device> m_maincpu;
+ required_device<cpu_device> m_hdccpu;
+ required_device<riot6532_device> m_riot0;
+ required_device<riot6532_device> m_riot1;
+ required_device<via6522_device> m_via;
+ required_device<device_t> m_sasibus;
+
+ // IEEE-488 bus
+ int m_rfdo; // not ready for data output
+ int m_daco; // not data accepted output
+ int m_atna; // attention acknowledge
+
+ // SASI bus
+ int m_enable;
+
+ int m_variant;
+};
+
+
+// ======================> d9060_device
+
+class d9060_device : public base_d9060_device
+{
+public:
+ // construction/destruction
+ d9060_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+// ======================> d9090_device
+
+class d9090_device : public base_d9060_device
+{
+public:
+ // construction/destruction
+ d9090_device(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/mess/machine/dai.c b/src/mess/machine/dai.c
new file mode 100644
index 00000000000..9ee389ae3ba
--- /dev/null
+++ b/src/mess/machine/dai.c
@@ -0,0 +1,254 @@
+/***************************************************************************
+
+ machine/dai.c
+
+ Functions to emulate general aspects of DAI (RAM, ROM, interrupts, I/O ports)
+
+ Krzysztof Strzecha
+ Nathan Woods
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/dai.h"
+
+#define DEBUG_DAI_PORTS 0
+
+#define LOG_DAI_PORT_R(_port, _data, _comment) do { if (DEBUG_DAI_PORTS) logerror ("DAI port read : %04x, Data: %02x (%s)\n", _port, _data, _comment); } while (0)
+#define LOG_DAI_PORT_W(_port, _data, _comment) do { if (DEBUG_DAI_PORTS) logerror ("DAI port write: %04x, Data: %02x (%s)\n", _port, _data, _comment); } while (0)
+
+/* Discrete I/O devices */
+
+
+/* Memory */
+
+WRITE8_MEMBER(dai_state::dai_stack_interrupt_circuit_w)
+{
+ m_tms5501->set_sensor(1);
+ m_tms5501->set_sensor(0);
+}
+
+static void dai_update_memory(running_machine &machine, int dai_rom_bank)
+{
+ dai_state *state = machine.driver_data<dai_state>();
+ state->membank("bank2")->set_entry(dai_rom_bank);
+}
+
+static TIMER_CALLBACK(dai_bootstrap_callback)
+{
+ cpu_set_reg(machine.device("maincpu"), STATE_GENPC, 0xc000);
+}
+
+
+READ8_MEMBER(dai_state::dai_keyboard_r)
+{
+ UINT8 data = 0x00;
+ static const char *const keynames[] = { "IN0", "IN1", "IN2", "IN3", "IN4", "IN5", "IN6", "IN7" };
+
+ for (int i = 0; i < 8; i++)
+ {
+ if (m_keyboard_scan_mask & (1 << i))
+ data |= ioport(keynames[i])->read();
+ }
+
+ return data;
+}
+
+WRITE8_MEMBER(dai_state::dai_keyboard_w)
+{
+ m_keyboard_scan_mask = data;
+}
+
+static TMS5501_IRQ_CALLBACK(dai_interrupt_callback)
+{
+ if (intreq)
+ cputag_set_input_line_and_vector(device.machine(), "maincpu", 0, HOLD_LINE, vector);
+ else
+ cputag_set_input_line(device.machine(), "maincpu", 0, CLEAR_LINE);
+}
+
+TMS5501_INTERFACE( dai_tms5501_interface )
+{
+ DEVCB_DRIVER_MEMBER(dai_state, dai_keyboard_r),
+ DEVCB_DRIVER_MEMBER(dai_state, dai_keyboard_w),
+ dai_interrupt_callback
+};
+
+I8255A_INTERFACE( dai_ppi82555_intf )
+{
+ DEVCB_NULL, /* Port A read */
+ DEVCB_NULL, /* Port A write */
+ DEVCB_NULL, /* Port B read */
+ DEVCB_NULL, /* Port B write */
+ DEVCB_NULL, /* Port C read */
+ DEVCB_NULL /* Port C write */
+};
+
+const struct pit8253_config dai_pit8253_intf =
+{
+ {
+ {
+ 2000000,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER("custom", dai_sound_device, set_input_ch0),
+ },
+ {
+ 2000000,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER("custom", dai_sound_device, set_input_ch1),
+ },
+ {
+ 2000000,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER("custom", dai_sound_device, set_input_ch2),
+ }
+ }
+};
+
+static TIMER_CALLBACK( dai_timer )
+{
+ dai_state *state = machine.driver_data<dai_state>();
+ state->m_tms5501->set_pio_bit_7((state->ioport("IN8")->read() & 0x04) ? 1:0);
+}
+
+MACHINE_START( dai )
+{
+ dai_state *state = machine.driver_data<dai_state>();
+
+ state->membank("bank2")->configure_entries(0, 4, state->memregion("maincpu")->base() + 0x010000, 0x1000);
+ machine.scheduler().timer_set(attotime::zero, FUNC(dai_bootstrap_callback));
+ machine.scheduler().timer_pulse(attotime::from_hz(100), FUNC(dai_timer)); /* timer for tms5501 */
+
+ memset(machine.device<ram_device>(RAM_TAG)->pointer(), 0, machine.device<ram_device>(RAM_TAG)->size());
+}
+
+MACHINE_RESET( dai )
+{
+ dai_state *state = machine.driver_data<dai_state>();
+ state->membank("bank1")->set_base(machine.device<ram_device>(RAM_TAG)->pointer());
+}
+
+/***************************************************************************
+
+ Discrete Devices IO
+
+ FD00 POR1: IN bit 0 -
+ bit 1 -
+ bit 2 PIPGE: Page signal
+ bit 3 PIDTR: Serial output ready
+ bit 4 PIBU1: Button on paddle 1 (1 = closed)
+ bit 5 PIBU1: Button on paddle 2 (1 = closed)
+ bit 6 PIRPI: Random data
+ bit 7 PICAI: Cassette input data
+
+ FD01 PDLST: IN Single pulse used to trigger paddle timer circuit
+
+ FD04 POR1: OUT bit 0-3 Volume oscillator channel 0
+ bit 4-7 Volume oscillator channel 1
+
+ FD05 POR1: OUT bit 0-3 Volume oscillator channel 2
+ bit 4-7 Volume random noise generator
+
+ FD06 POR0: OUT bit 0 POCAS: Cassette data output
+ bit 1-2 PDLMSK: Paddle select
+ bit 3 PDPNA: Paddle enable
+ bit 4 POCM1: Cassette 1 motor control (0 = run)
+ bit 5 POCM2: Cassette 2 motor control (0 = run)
+ bit 6-7 ROM bank switching
+***************************************************************************/
+
+READ8_MEMBER(dai_state::dai_io_discrete_devices_r)
+{
+ UINT8 data = 0x00;
+
+ switch(offset & 0x000f) {
+ case 0x00:
+ data = ioport("IN8")->read();
+ data |= 0x08; // serial ready
+ if (machine().rand()&0x01)
+ data |= 0x40; // random number generator
+ if (machine().device<cassette_image_device>(CASSETTE_TAG)->input() > 0.01)
+ data |= 0x80; // tape input
+ break;
+
+ default:
+ data = 0xff;
+ LOG_DAI_PORT_R (offset, data, "discrete devices - unmapped");
+
+ break;
+ }
+ return data;
+}
+
+WRITE8_MEMBER(dai_state::dai_io_discrete_devices_w)
+{
+ switch(offset & 0x000f) {
+ case 0x04:
+ m_sound->set_volume(space, offset, data);
+ LOG_DAI_PORT_W (offset, data&0x0f, "discrete devices - osc. 0 volume");
+ LOG_DAI_PORT_W (offset, (data&0xf0)>>4, "discrete devices - osc. 1 volume");
+ break;
+
+ case 0x05:
+ m_sound->set_volume(space, offset, data);
+ LOG_DAI_PORT_W (offset, data&0x0f, "discrete devices - osc. 2 volume");
+ LOG_DAI_PORT_W (offset, (data&0xf0)>>4, "discrete devices - noise volume");
+ break;
+
+ case 0x06:
+ m_paddle_select = (data&0x06)>>2;
+ m_paddle_enable = (data&0x08)>>3;
+ m_cassette_motor[0] = (data&0x10)>>4;
+ m_cassette_motor[1] = (data&0x20)>>5;
+ machine().device<cassette_image_device>(CASSETTE_TAG)->change_state(m_cassette_motor[0]?CASSETTE_MOTOR_DISABLED:CASSETTE_MOTOR_ENABLED, CASSETTE_MASK_MOTOR);
+ machine().device<cassette_image_device>(CASSETTE_TAG)->output((data & 0x01) ? -1.0 : 1.0);
+ dai_update_memory (machine(), (data&0xc0)>>6);
+ LOG_DAI_PORT_W (offset, (data&0x06)>>2, "discrete devices - paddle select");
+ LOG_DAI_PORT_W (offset, (data&0x08)>>3, "discrete devices - paddle enable");
+ LOG_DAI_PORT_W (offset, (data&0x10)>>4, "discrete devices - cassette motor 1");
+ LOG_DAI_PORT_W (offset, (data&0x20)>>5, "discrete devices - cassette motor 2");
+ LOG_DAI_PORT_W (offset, (data&0xc0)>>6, "discrete devices - ROM bank");
+ break;
+
+ default:
+ LOG_DAI_PORT_W (offset, data, "discrete devices - unmapped");
+ break;
+ }
+}
+
+/***************************************************************************
+
+ PIT8253
+
+ Offset need to be shifted by 1 to right, because the PIT is
+ connected to A1 and A2
+
+***************************************************************************/
+
+READ8_MEMBER(dai_state::dai_pit_r)
+{
+ return pit8253_r(m_pit, (offset>>1) & 3);
+}
+
+WRITE8_MEMBER(dai_state::dai_pit_w)
+{
+ pit8253_w(m_pit, (offset>>1) & 3, data);
+}
+
+/***************************************************************************
+
+ AMD 9911 mathematical coprocesor
+
+***************************************************************************/
+
+READ8_MEMBER(dai_state::dai_amd9511_r)
+{
+ /* optional and no present at this moment */
+ return 0xff;
+}
+
+WRITE8_MEMBER(dai_state::dai_amd9511_w)
+{
+ logerror ("Writing to AMD9511 math chip, %04x, %02x\n", offset, data);
+}
+
diff --git a/src/mess/machine/dccons.c b/src/mess/machine/dccons.c
new file mode 100644
index 00000000000..9931bc74bdc
--- /dev/null
+++ b/src/mess/machine/dccons.c
@@ -0,0 +1,709 @@
+/*
+
+ dc.c - Sega Dreamcast hardware
+
+ MESS (DC home console) hardware overrides (GD-ROM drive etc)
+
+ c230048 - 5 is written, want 6
+ c0d9d9e - where bad happens, from routine @ c0da260
+
+ c0d9d8e - R0 on return is the value to put in
+
+ cfffee0 - stack location when bad happens
+
+*/
+
+#include "emu.h"
+#include "cdrom.h"
+#include "debugger.h"
+#include "includes/dc.h"
+#include "cpu/sh4/sh4.h"
+#include "sound/aica.h"
+#include "includes/naomi.h"
+#include "machine/gdrom.h"
+#include "imagedev/chd_cd.h"
+
+#define ATAPI_CYCLES_PER_SECTOR (5000) // TBD for Dreamcast
+
+#define ATAPI_STAT_BSY 0x80
+#define ATAPI_STAT_DRDY 0x40
+#define ATAPI_STAT_DMARDDF 0x20
+#define ATAPI_STAT_SERVDSC 0x10
+#define ATAPI_STAT_DRQ 0x08
+#define ATAPI_STAT_CORR 0x04
+#define ATAPI_STAT_CHECK 0x01
+
+#define ATAPI_INTREASON_COMMAND 0x01
+#define ATAPI_INTREASON_IO 0x02
+#define ATAPI_INTREASON_RELEASE 0x04
+
+#define ATAPI_REG_DATA 0
+#define ATAPI_REG_FEATURES 1
+#define ATAPI_REG_INTREASON 2
+#define ATAPI_REG_SAMTAG 3
+#define ATAPI_REG_COUNTLOW 4
+#define ATAPI_REG_COUNTHIGH 5
+#define ATAPI_REG_DRIVESEL 6
+#define ATAPI_REG_CMDSTATUS 7
+#define ATAPI_REG_ERROR 16 // read-only ERROR (write is FEATURES)
+
+#define ATAPI_REG_MAX 24
+
+#define ATAPI_XFER_PIO 0x00
+#define ATAPI_XFER_PIO_FLOW 0x08
+#define ATAPI_XFER_MULTI_DMA 0x20
+#define ATAPI_XFER_ULTRA_DMA 0x40
+
+#define ATAPI_DATA_SIZE ( 64 * 1024 )
+
+static UINT8 *atapi_regs;
+static emu_timer *atapi_timer;
+static gdrom_device *gdrom;
+static UINT8 *atapi_data;
+static int atapi_data_ptr, atapi_data_len, atapi_xferlen, atapi_xferbase, atapi_cdata_wait, atapi_xfermod;
+static UINT32 gdrom_alt_status;
+static UINT8 xfer_mode = ATAPI_XFER_PIO;
+
+#define MAX_TRANSFER_SIZE ( 63488 )
+
+static void gdrom_raise_irq(running_machine &machine)
+{
+ dc_state *state = machine.driver_data<dc_state>();
+
+ state->dc_sysctrl_regs[SB_ISTEXT] |= IST_EXT_GDROM;
+ dc_update_interrupt_status(machine);
+}
+
+static TIMER_CALLBACK( atapi_xfer_end )
+{
+ dc_state *state = machine.driver_data<dc_state>();
+
+ UINT8 sector_buffer[ 4096 ];
+
+ atapi_timer->adjust(attotime::never);
+
+ printf("atapi_xfer_end atapi_xferlen = %d, atapi_xfermod=%d\n", atapi_xfermod, atapi_xferlen );
+
+ mame_printf_debug("ATAPI: xfer_end. xferlen = %d, atapi_xfermod = %d\n", atapi_xferlen, atapi_xfermod);
+
+ while (atapi_xferlen > 0 )
+ {
+ struct sh4_ddt_dma ddtdata;
+
+ // get a sector from the SCSI device
+ gdrom->ReadData( sector_buffer, 2048 );
+
+ atapi_xferlen -= 2048;
+
+ // perform the DMA
+ ddtdata.destination = atapi_xferbase; // destination address
+ ddtdata.length = 2048/4;
+ ddtdata.size = 4;
+ ddtdata.buffer = sector_buffer;
+ ddtdata.direction=1; // 0 source to buffer, 1 buffer to destination
+ ddtdata.channel= -1; // not used
+ ddtdata.mode= -1; // copy from/to buffer
+ printf("ATAPI: DMA one sector to %x, %x remaining\n", atapi_xferbase, atapi_xferlen);
+ sh4_dma_ddt(machine.device("maincpu"), &ddtdata);
+
+ atapi_xferbase += 2048;
+ }
+
+ if (atapi_xfermod > MAX_TRANSFER_SIZE)
+ {
+ atapi_xferlen = MAX_TRANSFER_SIZE;
+ atapi_xfermod = atapi_xfermod - MAX_TRANSFER_SIZE;
+ }
+ else
+ {
+ atapi_xferlen = atapi_xfermod;
+ atapi_xfermod = 0;
+ }
+
+ if (atapi_xferlen > 0)
+ {
+ printf("ATAPI: starting next piece of multi-part transfer\n");
+ atapi_regs[ATAPI_REG_COUNTLOW] = atapi_xferlen & 0xff;
+ atapi_regs[ATAPI_REG_COUNTHIGH] = (atapi_xferlen>>8)&0xff;
+
+ atapi_timer->adjust(machine.device<cpu_device>("maincpu")->cycles_to_attotime((ATAPI_CYCLES_PER_SECTOR * (atapi_xferlen/2048))));
+ }
+ else
+ {
+ printf("ATAPI: Transfer completed, dropping DRQ\n");
+ atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRDY;
+ gdrom_alt_status = ATAPI_STAT_DRDY;
+ atapi_regs[ATAPI_REG_INTREASON] = ATAPI_INTREASON_IO | ATAPI_INTREASON_COMMAND;
+
+ state->g1bus_regs[SB_GDST]=0;
+ state->dc_sysctrl_regs[SB_ISTNRM] |= IST_DMA_GDROM;
+ dc_update_interrupt_status(machine);
+ }
+
+ gdrom_raise_irq(machine);
+
+ printf( "atapi_xfer_end: %d %d\n", atapi_xferlen, atapi_xfermod );
+}
+
+static READ32_HANDLER( atapi_r )
+{
+ running_machine &machine = space->machine();
+ int reg, data;
+
+ if (mem_mask == 0x0000ffff) // word-wide command read
+ {
+// mame_printf_debug("ATAPI: packet read = %04x\n", atapi_data[atapi_data_ptr]);
+
+ // assert IRQ and drop DRQ
+ if (atapi_data_ptr == 0 && atapi_data_len == 0)
+ {
+ // get the data from the device
+ if( atapi_xferlen > 0 )
+ {
+ gdrom->ReadData( atapi_data, atapi_xferlen );
+ atapi_data_len = atapi_xferlen;
+ }
+
+ if (atapi_xfermod > MAX_TRANSFER_SIZE)
+ {
+ atapi_xferlen = MAX_TRANSFER_SIZE;
+ atapi_xfermod = atapi_xfermod - MAX_TRANSFER_SIZE;
+ }
+ else
+ {
+ atapi_xferlen = atapi_xfermod;
+ atapi_xfermod = 0;
+ }
+
+// printf( "atapi_r: atapi_xferlen=%d\n", atapi_xferlen );
+ if( atapi_xferlen != 0 )
+ {
+ atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRQ | ATAPI_STAT_SERVDSC;
+ gdrom_alt_status = ATAPI_STAT_DRQ | ATAPI_STAT_SERVDSC;
+ atapi_regs[ATAPI_REG_INTREASON] = ATAPI_INTREASON_IO;
+ }
+ else
+ {
+ //mame_printf_debug("ATAPI: dropping DRQ\n");
+ atapi_regs[ATAPI_REG_CMDSTATUS] = 0;
+ gdrom_alt_status = 0;
+ atapi_regs[ATAPI_REG_INTREASON] = ATAPI_INTREASON_IO;
+ }
+
+ atapi_regs[ATAPI_REG_COUNTLOW] = atapi_xferlen & 0xff;
+ atapi_regs[ATAPI_REG_COUNTHIGH] = (atapi_xferlen>>8)&0xff;
+
+ gdrom_raise_irq(machine);
+ }
+
+ if( atapi_data_ptr < atapi_data_len )
+ {
+ data = atapi_data[atapi_data_ptr++];
+ data |= ( atapi_data[atapi_data_ptr++] << 8 );
+ if( atapi_data_ptr >= atapi_data_len )
+ {
+// printf( "atapi_r: read all bytes\n" );
+ atapi_data_ptr = 0;
+ atapi_data_len = 0;
+
+ if( atapi_xferlen == 0 )
+ {
+ atapi_regs[ATAPI_REG_CMDSTATUS] = 0;
+ gdrom_alt_status = 0;
+ atapi_regs[ATAPI_REG_INTREASON] = ATAPI_INTREASON_IO;
+ gdrom_raise_irq(machine);
+ }
+ }
+ }
+ else
+ {
+ data = 0;
+ }
+ }
+ else
+ {
+ reg = offset;
+
+ // get read-only side of read-only/write-only registers from elsewhere
+ if (reg == ATAPI_REG_FEATURES)
+ {
+ reg = ATAPI_REG_ERROR;
+ }
+ data = atapi_regs[reg];
+
+ #if 0
+ switch( reg )
+ {
+ case ATAPI_REG_DATA:
+ printf( "atapi_r: data=%02x\n", data );
+ break;
+ case ATAPI_REG_ERROR:
+ printf( "atapi_r: error=%02x\n", data );
+ break;
+ case ATAPI_REG_INTREASON:
+ printf( "atapi_r: intreason=%02x\n", data );
+ break;
+ case ATAPI_REG_SAMTAG:
+ printf( "atapi_r: samtag=%02x\n", data );
+ break;
+ case ATAPI_REG_COUNTLOW:
+ printf( "atapi_r: countlow=%02x\n", data );
+ break;
+ case ATAPI_REG_COUNTHIGH:
+ printf( "atapi_r: counthigh=%02x\n", data );
+ break;
+ case ATAPI_REG_DRIVESEL:
+ printf( "atapi_r: drivesel=%02x\n", data );
+ break;
+ case ATAPI_REG_CMDSTATUS:
+ printf( "atapi_r: cmdstatus=%02x\n", data );
+ break;
+ }
+ #endif
+
+ mame_printf_debug("ATAPI: read reg %d = %x (PC=%x)\n", reg, data, cpu_get_pc(&space->device()));
+ }
+
+// printf( "atapi_r( %08x, %08x ) %08x\n", offset, mem_mask, data );
+ return data;
+}
+
+static WRITE32_HANDLER( atapi_w )
+{
+ running_machine &machine = space->machine();
+ int reg;
+
+// printf( "atapi_w( %08x, %08x, %08x )\n", offset, mem_mask, data );
+
+ if (mem_mask == 0x0000ffff) // word-wide command write
+ {
+// printf("atapi_w: data=%04x\n", data );
+
+// printf("ATAPI: packet write %04x\n", data);
+ atapi_data[atapi_data_ptr++] = data & 0xff;
+ atapi_data[atapi_data_ptr++] = data >> 8;
+
+ if (atapi_cdata_wait)
+ {
+// printf("ATAPI: waiting, ptr %d wait %d\n", atapi_data_ptr, atapi_cdata_wait);
+ if (atapi_data_ptr == atapi_cdata_wait)
+ {
+ // send it to the device
+ gdrom->WriteData( atapi_data, atapi_cdata_wait );
+
+ // assert IRQ
+ gdrom_raise_irq(machine);
+
+ // not sure here, but clear DRQ at least?
+ atapi_regs[ATAPI_REG_CMDSTATUS] = 0;
+ }
+ }
+
+ else if ( atapi_data_ptr == 12 )
+ {
+ int phase;
+
+// printf("atapi_w: command %02x\n", atapi_data[0]&0xff );
+
+ // reset data pointer for reading SCSI results
+ atapi_data_ptr = 0;
+ atapi_data_len = 0;
+
+ // send it to the SCSI device
+ gdrom->SetCommand( atapi_data, 12 );
+ gdrom->ExecCommand( &atapi_xferlen );
+ gdrom->GetPhase( &phase );
+
+ if (atapi_xferlen != -1)
+ {
+ printf("ATAPI: SCSI command %02x returned %d bytes from the device\n", atapi_data[0]&0xff, atapi_xferlen);
+
+ // store the returned command length in the ATAPI regs, splitting into
+ // multiple transfers if necessary
+ atapi_xfermod = 0;
+ if (atapi_xferlen > MAX_TRANSFER_SIZE)
+ {
+ atapi_xfermod = atapi_xferlen - MAX_TRANSFER_SIZE;
+ atapi_xferlen = MAX_TRANSFER_SIZE;
+ }
+
+ atapi_regs[ATAPI_REG_COUNTLOW] = atapi_xferlen & 0xff;
+ atapi_regs[ATAPI_REG_COUNTHIGH] = (atapi_xferlen>>8)&0xff;
+
+ gdrom_alt_status = 0; // (I guess?)
+
+ if (atapi_xferlen == 0)
+ {
+ // if no data to return, set the registers properly
+ atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRDY;
+ atapi_regs[ATAPI_REG_INTREASON] = ATAPI_INTREASON_IO|ATAPI_INTREASON_COMMAND;
+ }
+ else
+ {
+ // indicate data ready: set DRQ and DMA ready, and IO in INTREASON
+ if (atapi_regs[ATAPI_REG_FEATURES] & 0x01) // DMA feature
+ {
+ atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_BSY | ATAPI_STAT_DRDY | ATAPI_STAT_SERVDSC;
+ }
+ else
+ {
+ atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRQ | ATAPI_STAT_SERVDSC | ATAPI_STAT_DRQ;
+ }
+ atapi_regs[ATAPI_REG_INTREASON] = ATAPI_INTREASON_IO;
+ }
+
+ switch( phase )
+ {
+ case SCSI_PHASE_DATAOUT:
+ atapi_cdata_wait = atapi_xferlen;
+ break;
+ }
+
+ // perform special ATAPI processing of certain commands
+ switch (atapi_data[0]&0xff)
+ {
+ case 0x00: // BUS RESET / TEST UNIT READY
+ case 0xbb: // SET CDROM SPEED
+ atapi_regs[ATAPI_REG_CMDSTATUS] = 0;
+ break;
+
+ case 0x45: // PLAY
+ atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_BSY;
+ atapi_timer->adjust( downcast<cpu_device *>(&space->device())->cycles_to_attotime(ATAPI_CYCLES_PER_SECTOR ) );
+ break;
+ }
+
+ // assert IRQ
+ gdrom_raise_irq(machine);
+ }
+ else
+ {
+ printf("ATAPI: SCSI device returned error!\n");
+
+ atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRQ | ATAPI_STAT_CHECK;
+ atapi_regs[ATAPI_REG_ERROR] = 0x50; // sense key = ILLEGAL REQUEST
+ atapi_regs[ATAPI_REG_COUNTLOW] = 0;
+ atapi_regs[ATAPI_REG_COUNTHIGH] = 0;
+ }
+ }
+ }
+ else
+ {
+ reg = offset;
+#if 0
+ switch( reg )
+ {
+ case ATAPI_REG_DATA:
+ printf( "atapi_w: data=%02x\n", data );
+ break;
+ case ATAPI_REG_FEATURES:
+ printf( "atapi_w: features=%02x\n", data );
+ break;
+ case ATAPI_REG_INTREASON:
+ printf( "atapi_w: intreason=%02x\n", data );
+ break;
+ case ATAPI_REG_SAMTAG:
+ printf( "atapi_w: samtag=%02x\n", data );
+ break;
+ case ATAPI_REG_COUNTLOW:
+ printf( "atapi_w: countlow=%02x\n", data );
+ break;
+ case ATAPI_REG_COUNTHIGH:
+ printf( "atapi_w: counthigh=%02x\n", data );
+ break;
+ case ATAPI_REG_DRIVESEL:
+ printf( "atapi_w: drivesel=%02x\n", data );
+ break;
+ case ATAPI_REG_CMDSTATUS:
+ printf( "atapi_w: cmdstatus=%02x\n", data );
+ break;
+ }
+#endif
+ atapi_regs[reg] = data;
+// mame_printf_debug("ATAPI: reg %d = %x (offset %x mask %x PC=%x)\n", reg, data, offset, mem_mask, cpu_get_pc(&space->device()));
+
+ if (reg == ATAPI_REG_CMDSTATUS)
+ {
+ printf("ATAPI command %x issued! (PC=%x)\n", data, cpu_get_pc(&space->device()));
+
+ switch (data)
+ {
+ case 0xa0: // PACKET
+ atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRQ;
+ gdrom_alt_status = ATAPI_STAT_DRQ;
+ atapi_regs[ATAPI_REG_INTREASON] = ATAPI_INTREASON_COMMAND;
+
+ atapi_data_ptr = 0;
+ atapi_data_len = 0;
+
+ /* we have no data */
+ atapi_xferlen = 0;
+ atapi_xfermod = 0;
+
+ atapi_cdata_wait = 0;
+ break;
+
+ case 0xa1: // IDENTIFY PACKET DEVICE
+ atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRQ;
+ gdrom_alt_status = ATAPI_STAT_DRQ;
+
+ atapi_data_ptr = 0;
+ atapi_data_len = 512;
+
+ /* we have no data */
+ atapi_xferlen = 0;
+ atapi_xfermod = 0;
+
+ memset( atapi_data, 0, atapi_data_len );
+
+ atapi_data[ 0 ^ 1 ] = 0x86; // ATAPI device, cmd set 6 compliant, DRQ within 3 ms of PACKET command
+ atapi_data[ 1 ^ 1 ] = 0x00;
+
+ memset( &atapi_data[ 46 ], ' ', 8 );
+ atapi_data[ 46 ^ 1 ] = 'S';
+ atapi_data[ 47 ^ 1 ] = 'E';
+
+ memset( &atapi_data[ 54 ], ' ', 40 );
+ atapi_data[ 54 ^ 1 ] = 'C';
+ atapi_data[ 55 ^ 1 ] = 'D';
+ atapi_data[ 56 ^ 1 ] = '-';
+ atapi_data[ 57 ^ 1 ] = 'R';
+ atapi_data[ 58 ^ 1 ] = 'O';
+ atapi_data[ 59 ^ 1 ] = 'M';
+ atapi_data[ 60 ^ 1 ] = ' ';
+ atapi_data[ 61 ^ 1 ] = 'D';
+ atapi_data[ 62 ^ 1 ] = 'R';
+ atapi_data[ 63 ^ 1 ] = 'I';
+ atapi_data[ 64 ^ 1 ] = 'V';
+ atapi_data[ 65 ^ 1 ] = 'E';
+ atapi_data[ 66 ^ 1 ] = ' ';
+ atapi_data[ 67 ^ 1 ] = ' ';
+ atapi_data[ 68 ^ 1 ] = ' ';
+ atapi_data[ 69 ^ 1 ] = ' ';
+ atapi_data[ 70 ^ 1 ] = '6';
+ atapi_data[ 71 ^ 1 ] = '.';
+ atapi_data[ 72 ^ 1 ] = '4';
+ atapi_data[ 73 ^ 1 ] = '2';
+
+ atapi_data[ 98 ^ 1 ] = 0x04; // IORDY may be disabled
+ atapi_data[ 99 ^ 1 ] = 0x00;
+
+ atapi_regs[ATAPI_REG_COUNTLOW] = 0;
+ atapi_regs[ATAPI_REG_COUNTHIGH] = 2;
+
+ gdrom_raise_irq(space->machine());
+ break;
+
+ case 0xef: // SET FEATURES
+ // set xfer mode?
+ if (atapi_regs[ATAPI_REG_FEATURES] == 0x03)
+ {
+ printf("Set transfer mode to %x\n", atapi_regs[ATAPI_REG_COUNTLOW] & 0xf8);
+ xfer_mode = atapi_regs[ATAPI_REG_COUNTLOW] & 0xf8;
+ }
+ else
+ {
+ printf("ATAPI: Unknown set features %x\n", atapi_regs[ATAPI_REG_FEATURES]);
+ }
+
+ atapi_regs[ATAPI_REG_CMDSTATUS] = 0;
+ gdrom_alt_status = 0; // is this correct?
+
+ atapi_data_ptr = 0;
+ atapi_data_len = 0;
+
+ gdrom_raise_irq(space->machine());
+ break;
+
+ default:
+ mame_printf_debug("ATAPI: Unknown IDE command %x\n", data);
+ break;
+ }
+ }
+ }
+}
+
+void dreamcast_atapi_init(running_machine &machine)
+{
+ atapi_regs = auto_alloc_array_clear(machine, UINT8, ATAPI_REG_MAX);
+
+ atapi_regs[ATAPI_REG_CMDSTATUS] = 0;
+ atapi_regs[ATAPI_REG_ERROR] = 1;
+ atapi_regs[ATAPI_REG_COUNTLOW] = 0x14;
+ atapi_regs[ATAPI_REG_COUNTHIGH] = 0xeb;
+
+ atapi_data_ptr = 0;
+ atapi_data_len = 0;
+ atapi_cdata_wait = 0;
+
+ atapi_timer = machine.scheduler().timer_alloc(FUNC(atapi_xfer_end));
+ atapi_timer->adjust(attotime::never);
+
+ gdrom = NULL;
+
+ atapi_data = auto_alloc_array(machine, UINT8, ATAPI_DATA_SIZE );
+
+ state_save_register_global_pointer(machine, atapi_regs, ATAPI_REG_MAX );
+ state_save_register_global_pointer(machine, atapi_data, ATAPI_DATA_SIZE / 2 );
+ state_save_register_global(machine, atapi_data_ptr );
+ state_save_register_global(machine, atapi_data_len );
+ state_save_register_global(machine, atapi_xferlen );
+ state_save_register_global(machine, atapi_xferbase );
+ state_save_register_global(machine, atapi_cdata_wait );
+ state_save_register_global(machine, atapi_xfermod );
+
+ gdrom = machine.device<gdrom_device>( "cdrom" );
+}
+
+void dreamcast_atapi_reset(running_machine &machine)
+{
+ atapi_regs[ATAPI_REG_CMDSTATUS] = 0;
+ atapi_regs[ATAPI_REG_ERROR] = 1;
+ atapi_regs[ATAPI_REG_COUNTLOW] = 0x14;
+ atapi_regs[ATAPI_REG_COUNTHIGH] = 0xeb;
+
+ atapi_data_ptr = 0;
+ atapi_data_len = 0;
+ atapi_cdata_wait = 0;
+
+ atapi_xferlen = 0;
+ atapi_xfermod = 0;
+}
+
+/*
+
+ GDROM regsters:
+
+ 5f7018: alternate status/device control
+ 5f7080: data
+ 5f7084: error/features
+ 5f7088: interrupt reason/sector count
+ 5f708c: sector number
+ 5f7090: byte control low
+ 5f7094: byte control high
+ 5f7098: drive select
+ 5f709c: status/command
+
+c002910 - ATAPI packet writes
+c002796 - aux status read after that
+c000776 - DMA triggered to c008000
+
+*/
+
+READ64_HANDLER( dc_mess_gdrom_r )
+{
+ UINT32 off;
+
+ if ((int)~mem_mask & 1)
+ {
+ off=(offset << 1) | 1;
+ }
+ else
+ {
+ off=offset << 1;
+ }
+
+// printf("gdrom_r: @ %x (off %x), mask %llx (PC %x)\n", offset, off, mem_mask, cpu_get_pc(&space->device()));
+
+ if (offset == 3)
+ {
+ return gdrom_alt_status;
+ }
+ else if (off >= 0x20)
+ {
+ return atapi_r(space, off-0x20, 0xff);
+ }
+
+ return 0;
+}
+
+WRITE64_HANDLER( dc_mess_gdrom_w )
+{
+ UINT32 dat,off;
+
+ if ((int)~mem_mask & 1)
+ {
+ dat=(UINT32)(data >> 32);
+ off=(offset << 1) | 1;
+ }
+ else
+ {
+ dat=(UINT32)data;
+ off=offset << 1;
+ }
+
+// printf("GDROM: [%08x=%x]write %llx to %x, mask %llx (PC %x)\n", 0x5f7000+off*4, dat, data, offset, mem_mask, cpu_get_pc(&space->device()));
+
+ if (off >= 0x20)
+ {
+ atapi_w(space, off-0x20, dat, (UINT32)mem_mask);
+ }
+}
+
+// register decode helpers
+
+// this accepts only 32-bit accesses
+INLINE int decode_reg32_64(running_machine &machine, UINT32 offset, UINT64 mem_mask, UINT64 *shift)
+{
+ int reg = offset * 2;
+
+ *shift = 0;
+
+ // non 32-bit accesses have not yet been seen here, we need to know when they are
+ if ((mem_mask != U64(0xffffffff00000000)) && (mem_mask != U64(0x00000000ffffffff)))
+ {
+ mame_printf_verbose("%s:Wrong mask!\n", machine.describe_context());
+// debugger_break(machine);
+ }
+
+ if (mem_mask == U64(0xffffffff00000000))
+ {
+ reg++;
+ *shift = 32;
+ }
+
+ return reg;
+}
+
+READ64_HANDLER( dc_mess_g1_ctrl_r )
+{
+ dc_state *state = space->machine().driver_data<dc_state>();
+ int reg;
+ UINT64 shift;
+
+ reg = decode_reg32_64(space->machine(), offset, mem_mask, &shift);
+ mame_printf_verbose("G1CTRL: Unmapped read %08x\n", 0x5f7400+reg*4);
+ return (UINT64)state->g1bus_regs[reg] << shift;
+}
+
+WRITE64_HANDLER( dc_mess_g1_ctrl_w )
+{
+ dc_state *state = space->machine().driver_data<dc_state>();
+ int reg;
+ UINT64 shift;
+ UINT32 dat; //, old
+
+ reg = decode_reg32_64(space->machine(), offset, mem_mask, &shift);
+ dat = (UINT32)(data >> shift);
+// old = state->g1bus_regs[reg];
+
+ state->g1bus_regs[reg] = dat; // 5f7400+reg*4=dat
+ mame_printf_verbose("G1CTRL: [%08x=%x] write %" I64FMT "x to %x, mask %" I64FMT "x\n", 0x5f7400+reg*4, dat, data, offset, mem_mask);
+ switch (reg)
+ {
+ case SB_GDST:
+ if (dat & 1 && state->g1bus_regs[SB_GDEN] == 1) // 0 -> 1
+ {
+ if (state->g1bus_regs[SB_GDDIR] == 0)
+ {
+ printf("G1CTRL: unsupported transfer\n");
+ return;
+ }
+
+ atapi_xferbase = state->g1bus_regs[SB_GDSTAR];
+ atapi_timer->adjust(space->machine().device<cpu_device>("maincpu")->cycles_to_attotime((ATAPI_CYCLES_PER_SECTOR * (atapi_xferlen/2048))));
+ }
+ break;
+ }
+}
+
diff --git a/src/mess/machine/dec_lk201.c b/src/mess/machine/dec_lk201.c
new file mode 100644
index 00000000000..df1428498c0
--- /dev/null
+++ b/src/mess/machine/dec_lk201.c
@@ -0,0 +1,264 @@
+/*
+ DEC LK-201 keyboard
+ Emulation by R. Belmont
+
+ This is currently the 6805 version; there's also an 8048 version.
+*/
+
+#include "emu.h"
+#include "dec_lk201.h"
+#include "cpu/m6805/m6805.h"
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LK201_CPU_TAG "lk201"
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type LK201 = &device_creator<lk201_device>;
+
+ROM_START( lk201 )
+ ROM_REGION(0x2000, LK201_CPU_TAG, 0)
+ ROM_LOAD( "23-00159-00.bin", 0x0000, 0x2000, CRC(be293c51) SHA1(a11ae004d2d6055d7279da3560c3e56610a19fdb) )
+ROM_END
+
+//-------------------------------------------------
+// ADDRESS_MAP
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( lk201_map, AS_PROGRAM, 8, lk201_device )
+ AM_RANGE(0x0000, 0x0002) AM_READWRITE(ports_r, ports_w)
+ AM_RANGE(0x0004, 0x0006) AM_READWRITE(ddr_r, ddr_w)
+ AM_RANGE(0x000a, 0x000c) AM_READWRITE(spi_r, spi_w)
+ AM_RANGE(0x000d, 0x0011) AM_READWRITE(sci_r, sci_w)
+ AM_RANGE(0x0050, 0x00ff) AM_RAM
+ AM_RANGE(0x0100, 0x1fff) AM_ROM AM_REGION(LK201_CPU_TAG, 0x100)
+ADDRESS_MAP_END
+
+//-------------------------------------------------
+// MACHINE_CONFIG
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( lk201 )
+ MCFG_CPU_ADD(LK201_CPU_TAG, M68HC05EG, 2000000) // actually 68HC05C4
+ MCFG_CPU_PROGRAM_MAP(lk201_map)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor lk201_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( lk201 );
+}
+
+const rom_entry *lk201_device::device_rom_region() const
+{
+ return ROM_NAME( lk201 );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// lk201_device - constructor
+//-------------------------------------------------
+
+lk201_device::lk201_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, LK201, "DEC LK201 keyboard", tag, owner, clock),
+ m_maincpu(*this, LK201_CPU_TAG)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void lk201_device::device_start()
+{
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void lk201_device::device_reset()
+{
+}
+
+void lk201_device::device_config_complete()
+{
+ m_shortname = "lk201";
+}
+
+READ8_MEMBER( lk201_device::ddr_r )
+{
+ return ddrs[offset];
+}
+
+WRITE8_MEMBER( lk201_device::ddr_w )
+{
+// printf("%02x to PORT %c DDR (PC=%x)\n", data, 'A' + offset, cpu_get_pc(m_maincpu));
+
+ send_port(space, offset, ports[offset] & data);
+
+ ddrs[offset] = data;
+}
+
+READ8_MEMBER( lk201_device::ports_r )
+{
+ UINT8 incoming = 0;
+
+ switch (offset)
+ {
+ case 0: // port A
+ break;
+
+ case 1: // port B
+ break;
+
+ case 2: // port C
+ break;
+ }
+
+ // apply data direction registers
+ incoming &= (ddrs[offset] ^ 0xff);
+ // add in ddr-masked version of port writes
+ incoming |= (ports[offset] & ddrs[offset]);
+
+// printf("PORT %c read = %02x (DDR = %02x latch = %02x) (PC=%x)\n", 'A' + offset, ports[offset], ddrs[offset], ports[offset], cpu_get_pc(m_maincpu));
+
+ return incoming;
+}
+
+WRITE8_MEMBER( lk201_device::ports_w )
+{
+ send_port(space, offset, data);
+
+ ports[offset] = data;
+}
+
+void lk201_device::send_port(address_space &space, UINT8 offset, UINT8 data)
+{
+// printf("PORT %c write %02x (DDR = %02x) (PC=%x)\n", 'A' + offset, data, ddrs[offset], cpu_get_pc(m_maincpu));
+
+ switch (offset)
+ {
+ case 0: // port A
+ break;
+
+ case 1: // port B
+ break;
+
+ case 2: // port C
+ break;
+ }
+}
+
+READ8_MEMBER( lk201_device::sci_r )
+{
+ UINT8 incoming = 0;
+
+ switch (offset)
+ {
+ case 0: // baud rate
+ break;
+
+ case 1: // control 1
+ break;
+
+ case 2: // control 2
+ break;
+
+ case 3: // status
+ incoming |= 0x40; // indicate transmit ready
+ break;
+
+ case 4: // data
+ break;
+ }
+
+// printf("SCI read @ %x = %02x (PC=%x)\n", offset, incoming, cpu_get_pc(m_maincpu));
+
+ return incoming;
+}
+
+WRITE8_MEMBER( lk201_device::sci_w )
+{
+ switch (offset)
+ {
+ case 0: // baud rate
+ break;
+
+ case 1: // control 1
+ break;
+
+ case 2: // control 2
+ break;
+
+ case 3: // status
+ break;
+
+ case 4: // data
+ break;
+ }
+
+// printf("SCI %02x to %x (PC=%x)\n", data, offset, cpu_get_pc(m_maincpu));
+}
+
+READ8_MEMBER( lk201_device::spi_r )
+{
+ UINT8 incoming = 0;
+
+ switch (offset)
+ {
+ case 0: // control
+ break;
+
+ case 1: // status
+ incoming |= 0x80;
+ break;
+
+ case 2: // data
+ break;
+ }
+
+// printf("SPI read @ %x = %02x (PC=%x)\n", offset, incoming, cpu_get_pc(m_maincpu));
+
+ return incoming;
+}
+
+WRITE8_MEMBER( lk201_device::spi_w )
+{
+ switch (offset)
+ {
+ case 0: // control
+ break;
+
+ case 1: // status
+ break;
+
+ case 2: // data
+ break;
+ }
+
+// printf("SPI %02x to %x (PC=%x)\n", data, offset, cpu_get_pc(m_maincpu));
+}
+
+/*
+
+SCI 01 to 4 (PC=24b) firmware ID
+SCI 00 to 4 (PC=cb2) hardware jumpers ID (port C & 0x30)
+SCI 00 to 4 (PC=cb2) self-test result OK
+SCI 00 to 4 (PC=cb2) keycode if there was a self-test error
+
+*/
diff --git a/src/mess/machine/dec_lk201.h b/src/mess/machine/dec_lk201.h
new file mode 100644
index 00000000000..ccca2b2a34f
--- /dev/null
+++ b/src/mess/machine/dec_lk201.h
@@ -0,0 +1,68 @@
+#pragma once
+
+#ifndef __LK201_H__
+#define __LK201_H__
+
+#include "emu.h"
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LK201_TAG "lk201"
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_LK201_ADD() \
+ MCFG_DEVICE_ADD(LK201_TAG, LK201, 0)
+
+#define MCFG_LK201_REPLACE() \
+ MCFG_DEVICE_REPLACE(LK201_TAG, LK201, 0)
+
+#define MCFG_LK201_REMOVE() \
+ MCFG_DEVICE_REMOVE(LK201_TAG)
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> lk201_device
+
+class lk201_device : public device_t
+{
+public:
+ // construction/destruction
+ lk201_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ DECLARE_READ8_MEMBER( ddr_r );
+ DECLARE_WRITE8_MEMBER( ddr_w );
+ DECLARE_READ8_MEMBER( ports_r );
+ DECLARE_WRITE8_MEMBER( ports_w );
+ DECLARE_READ8_MEMBER( sci_r );
+ DECLARE_WRITE8_MEMBER( sci_w );
+ DECLARE_READ8_MEMBER( spi_r );
+ DECLARE_WRITE8_MEMBER( spi_w );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete();
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+
+ required_device<cpu_device> m_maincpu;
+
+private:
+ UINT8 ddrs[3];
+ UINT8 ports[3];
+
+ void send_port(address_space &space, UINT8 offset, UINT8 data);
+};
+
+// device type definition
+extern const device_type LK201;
+
+#endif
diff --git a/src/mess/machine/dgn_beta.c b/src/mess/machine/dgn_beta.c
new file mode 100644
index 00000000000..27fe31ce5c8
--- /dev/null
+++ b/src/mess/machine/dgn_beta.c
@@ -0,0 +1,1317 @@
+/***************************************************************************
+
+ machine\dgn_beta.c (machine.c)
+
+ Moved out of dragon.c, 2005-05-05, P.Harvey-Smith.
+
+ I decided to move this out of the main Dragon/CoCo source files, as
+ the Beta is so radically different from the other Dragon machines that
+ this made more sense (to me at least).
+
+ Functions to emulate general aspects of the machine (RAM, ROM, interrupts,
+ I/O ports)
+
+ References:
+ Disassembly of Dragon Beta ROM, examination of only (known) surviving board.
+
+ TODO:
+ Pretty much everything !
+
+ Display working with 6845 taking data from rom.
+
+ 2005-05-10
+ Memory banking seems to be working, as documented in code comments below.
+
+ 2005-05-31
+ CPU#2 now executes code correctly to do transfers from WD2797.
+
+ 2005-06-03
+
+ When fed a standard OS-9 boot disk it reads in the boot file and attempts
+ to start it, not being able to find init, it fails. Hopefully I will
+ soon have an image of a Beta boot disk.
+
+ 2005-11-29
+
+ Major track tracing excersise on scans of bare beta board, reveal where a
+ whole bunch of the PIA lines go, especially the IRQs, most of them go back
+ to the IRQ line on the main CPU.
+
+ 2005-12-07
+
+ First booted to OS9 prompt, did not execute startup scripts.
+
+ 2005-12-08
+
+ Fixed density setting on WD2797, so density of read data is now
+ correctlty set as required by OS-9. This was the reason startup
+ script was not being executed as Beta disks have a single denisty
+ boot track, however the rest of the disk is double density.
+ Booted completely to OS-9, including running startup script.
+
+ 2006-09-27
+
+ Clean up of IRQ/FIRQ handling code allows correct booting again.
+
+***************************************************************************/
+
+#include <math.h>
+#include <assert.h>
+
+#include "emu.h"
+#include "debug/debugcon.h"
+#include "cpu/m6809/m6809.h"
+#include "machine/6821pia.h"
+#include "includes/dgn_beta.h"
+#include "machine/6551acia.h"
+#include "machine/wd17xx.h"
+#include "imagedev/flopdrv.h"
+
+#include "debug/debugcpu.h"
+#include "debug/debugcon.h"
+#include "machine/ram.h"
+
+
+// Ram banking handlers.
+static WRITE8_HANDLER( dgnbeta_ram_b0_w );
+static WRITE8_HANDLER( dgnbeta_ram_b1_w );
+static WRITE8_HANDLER( dgnbeta_ram_b2_w );
+static WRITE8_HANDLER( dgnbeta_ram_b3_w );
+static WRITE8_HANDLER( dgnbeta_ram_b4_w );
+static WRITE8_HANDLER( dgnbeta_ram_b5_w );
+static WRITE8_HANDLER( dgnbeta_ram_b6_w );
+static WRITE8_HANDLER( dgnbeta_ram_b7_w );
+static WRITE8_HANDLER( dgnbeta_ram_b8_w );
+static WRITE8_HANDLER( dgnbeta_ram_b9_w );
+static WRITE8_HANDLER( dgnbeta_ram_bA_w );
+static WRITE8_HANDLER( dgnbeta_ram_bB_w );
+static WRITE8_HANDLER( dgnbeta_ram_bC_w );
+static WRITE8_HANDLER( dgnbeta_ram_bD_w );
+static WRITE8_HANDLER( dgnbeta_ram_bE_w );
+static WRITE8_HANDLER( dgnbeta_ram_bF_w );
+static WRITE8_HANDLER( dgnbeta_ram_bG_w );
+
+
+#define VERBOSE 0
+
+
+#define LOG_BANK_UPDATE(x) do { if (VERBOSE) logerror x; } while (0)
+#define LOG_DEFAULT_TASK(x) do { if (VERBOSE) logerror x; } while (0)
+#define LOG_PAGE_WRITE(x) do { if (VERBOSE) logerror x; } while (0)
+#define LOG_HALT(x) do { if (VERBOSE) logerror x; } while (0)
+#define LOG_TASK(x) do { if (VERBOSE) logerror x; } while (0)
+#define LOG_KEYBOARD(x) do { if (VERBOSE) logerror x; } while (0)
+#define LOG_VIDEO(x) do { if (VERBOSE) logerror x; } while (0)
+#define LOG_DISK(x) do { if (VERBOSE) logerror x; } while (0)
+#define LOG_INTS(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+/* Debugging commands and handlers. */
+static offs_t dgnbeta_dasm_override(device_t &device, char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, int options);
+static void execute_beta_dat_log(running_machine &machine, int ref, int params, const char *param[]);
+static void execute_beta_key_dump(running_machine &machine, int ref, int params, const char *param[]);
+
+/* Debugging variables */
+
+static READ8_DEVICE_HANDLER(d_pia0_pa_r);
+static WRITE8_DEVICE_HANDLER(d_pia0_pa_w);
+static READ8_DEVICE_HANDLER(d_pia0_pb_r);
+static WRITE8_DEVICE_HANDLER(d_pia0_pb_w);
+static WRITE8_DEVICE_HANDLER(d_pia0_cb2_w);
+static WRITE_LINE_DEVICE_HANDLER(d_pia0_irq_a);
+static WRITE_LINE_DEVICE_HANDLER(d_pia0_irq_b);
+static READ8_DEVICE_HANDLER(d_pia1_pa_r);
+static WRITE8_DEVICE_HANDLER(d_pia1_pa_w);
+static READ8_DEVICE_HANDLER(d_pia1_pb_r);
+static WRITE8_DEVICE_HANDLER(d_pia1_pb_w);
+static WRITE_LINE_DEVICE_HANDLER(d_pia1_irq_a);
+static WRITE_LINE_DEVICE_HANDLER(d_pia1_irq_b);
+static READ8_DEVICE_HANDLER(d_pia2_pa_r);
+static WRITE8_DEVICE_HANDLER(d_pia2_pa_w);
+static READ8_DEVICE_HANDLER(d_pia2_pb_r);
+static WRITE8_DEVICE_HANDLER(d_pia2_pb_w);
+static WRITE_LINE_DEVICE_HANDLER(d_pia2_irq_a);
+static WRITE_LINE_DEVICE_HANDLER(d_pia2_irq_b);
+
+static void cpu0_recalc_irq(running_machine &machine, int state);
+static void cpu0_recalc_firq(running_machine &machine, int state);
+
+static void cpu1_recalc_firq(running_machine &machine, int state);
+
+
+//static int DMA_NMI; /* DMA cpu has received an NMI */
+
+#define INVALID_KEYROW -1 /* no ketrow selected */
+#define NO_KEY_PRESSED 0x7F /* retrurned by hardware if no key pressed */
+
+const pia6821_interface dgnbeta_pia_intf[] =
+{
+ /* PIA 0 at $FC20-$FC23 I46 */
+ {
+ /*inputs : A/B,CA/B1,CA/B2 */
+ DEVCB_HANDLER(d_pia0_pa_r),
+ DEVCB_HANDLER(d_pia0_pb_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ /*outputs: A/B,CA/B2 */
+ DEVCB_HANDLER(d_pia0_pa_w),
+ DEVCB_HANDLER(d_pia0_pb_w),
+ DEVCB_NULL,
+ DEVCB_HANDLER(d_pia0_cb2_w),
+ /*irqs : A/B */
+ DEVCB_LINE(d_pia0_irq_a),
+ DEVCB_LINE(d_pia0_irq_b)
+ },
+
+ /* PIA 1 at $FC24-$FC27 I63 */
+ {
+ /*inputs : A/B,CA/B1,CA/B2 */
+ DEVCB_HANDLER(d_pia1_pa_r),
+ DEVCB_HANDLER(d_pia1_pb_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ /*outputs: A/B,CA/B2 */
+ DEVCB_HANDLER(d_pia1_pa_w),
+ DEVCB_HANDLER(d_pia1_pb_w),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ /*irqs : A/B */
+ DEVCB_LINE(d_pia1_irq_a),
+ DEVCB_LINE(d_pia1_irq_b)
+ },
+
+ /* PIA 2 at FCC0-FCC3 I28 */
+ /* This seems to control the RAM paging system, and have the DRQ */
+ /* from the WD2797 */
+ {
+ /*inputs : A/B,CA/B1,CA/B2 */
+ DEVCB_HANDLER(d_pia2_pa_r),
+ DEVCB_HANDLER(d_pia2_pb_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ /*outputs: A/B,CA/B2 */
+ DEVCB_HANDLER(d_pia2_pa_w),
+ DEVCB_HANDLER(d_pia2_pb_w),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ /*irqs : A/B */
+ DEVCB_LINE(d_pia2_irq_a),
+ DEVCB_LINE(d_pia2_irq_b)
+ }
+};
+
+// Info for bank switcher
+struct bank_info_entry
+{
+ write8_space_func func; // Pointer to write handler
+ const char *name;
+ offs_t start; // Offset of start of block
+ offs_t end; // offset of end of block
+};
+
+static const struct bank_info_entry bank_info[] =
+{
+ { FUNC(dgnbeta_ram_b0_w), 0x0000, 0x0fff },
+ { FUNC(dgnbeta_ram_b1_w), 0x1000, 0x1fff },
+ { FUNC(dgnbeta_ram_b2_w), 0x2000, 0x2fff },
+ { FUNC(dgnbeta_ram_b3_w), 0x3000, 0x3fff },
+ { FUNC(dgnbeta_ram_b4_w), 0x4000, 0x4fff },
+ { FUNC(dgnbeta_ram_b5_w), 0x5000, 0x5fff },
+ { FUNC(dgnbeta_ram_b6_w), 0x6000, 0x6fff },
+ { FUNC(dgnbeta_ram_b7_w), 0x7000, 0x7fff },
+ { FUNC(dgnbeta_ram_b8_w), 0x8000, 0x8fff },
+ { FUNC(dgnbeta_ram_b9_w), 0x9000, 0x9fff },
+ { FUNC(dgnbeta_ram_bA_w), 0xA000, 0xAfff },
+ { FUNC(dgnbeta_ram_bB_w), 0xB000, 0xBfff },
+ { FUNC(dgnbeta_ram_bC_w), 0xC000, 0xCfff },
+ { FUNC(dgnbeta_ram_bD_w), 0xD000, 0xDfff },
+ { FUNC(dgnbeta_ram_bE_w), 0xE000, 0xEfff },
+ { FUNC(dgnbeta_ram_bF_w), 0xF000, 0xFBff },
+ { FUNC(dgnbeta_ram_bG_w), 0xFF00, 0xFfff }
+};
+
+#define is_last_page(page) (((page==LastPage) || (page==LastPage+1)) ? 1 : 0)
+
+//
+// Memory pager, maps machine's 1Mb total address space into the 64K addressable by the 6809.
+// This is in some way similar to the system used on the CoCo 3, except the beta uses 4K
+// pages (instead of 8K on the CoCo), and has 16 task registers instead of the 2 on the CoCo.
+//
+// Each block of 16 page registers (1 for each task), is paged in at $FE00-$FE0F, the bottom
+// 4 bits of the PIA register at $FCC0 seem to contain which task is active.
+// bit 6 of the same port seems to enable the memory paging
+//
+// For the purpose of this driver any block that is not ram, and is not a known ROM block,
+// is mapped to the first page of the boot rom, I do not know what happens in the real
+// hardware, however this does allow the boot rom to correctly size the RAM.
+// this should probably be considdered a hack !
+//
+
+static void UpdateBanks(running_machine &machine, int first, int last)
+{
+ dgn_beta_state *state = machine.driver_data<dgn_beta_state>();
+ address_space *space_0 = machine.device(MAINCPU_TAG)->memory().space(AS_PROGRAM);
+ address_space *space_1 = machine.device(DMACPU_TAG)->memory().space(AS_PROGRAM);
+ int Page;
+ UINT8 *readbank;
+ int bank_start;
+ int bank_end;
+ int MapPage;
+ char page_num[10];
+
+ LOG_BANK_UPDATE(("\n\nUpdating banks %d to %d at PC=$%X\n",first,last,cpu_get_pc(&space_0->device())));
+ for(Page=first;Page<=last;Page++)
+ {
+ sprintf(page_num,"bank%d",Page+1);
+
+ bank_start = bank_info[Page].start;
+ bank_end = bank_info[Page].end;
+
+ // bank16 and bank17 are mapped to the same page with a hole for the IO memory
+ if (!is_last_page(Page))
+ MapPage = state->m_PageRegs[state->m_TaskReg][Page].value;
+ else
+ MapPage = state->m_PageRegs[state->m_TaskReg][LastPage].value;
+
+ //
+ // Map block, $00-$BF are ram, $FC-$FF are Boot ROM
+ //
+ if ((MapPage*4) < ((machine.device<ram_device>(RAM_TAG)->size() / 1024)-1)) // Block is ram
+ {
+ if (!is_last_page(Page))
+ {
+ readbank = &machine.device<ram_device>(RAM_TAG)->pointer()[MapPage*RamPageSize];
+ if(state->m_LogDatWrites)
+ debug_console_printf(machine, "Mapping page %X, pageno=%X, mess_ram)[%X]\n",Page,MapPage,(MapPage*RamPageSize));
+ }
+ else
+ {
+ readbank = &machine.device<ram_device>(RAM_TAG)->pointer()[(MapPage*RamPageSize)-256];
+ logerror("Error RAM in Last page !\n");
+ }
+ space_0->install_legacy_write_handler(bank_start, bank_end,bank_info[Page].func,bank_info[Page].name);
+ space_1->install_legacy_write_handler(bank_start, bank_end,bank_info[Page].func,bank_info[Page].name);
+ }
+ else // Block is rom, or undefined
+ {
+ if (MapPage>0xfB)
+ {
+ if (Page!=IOPage+1)
+ readbank=&state->m_system_rom[(MapPage-0xFC)*0x1000];
+ else
+ readbank=&state->m_system_rom[0x3F00];
+ }
+ else
+ readbank=state->m_system_rom;
+
+ space_0->unmap_write(bank_start, bank_end);
+ space_1->unmap_write(bank_start, bank_end);
+ }
+
+ state->m_PageRegs[state->m_TaskReg][Page].memory=readbank;
+ state->membank(page_num)->set_base(readbank);
+
+ LOG_BANK_UPDATE(("UpdateBanks:MapPage=$%02X readbank=$%X\n",MapPage,(int)(FPTR)readbank));
+ LOG_BANK_UPDATE(("PageRegsSet Task=%X Page=%x\n",state->m_TaskReg,Page));
+ //LOG_BANK_UPDATE(("%X)\n",state->membank(Page+1)));
+ LOG_BANK_UPDATE(("memory_install_write8_handler CPU=0\n"));
+ LOG_BANK_UPDATE(("memory_install_write8_handler CPU=1\n"));
+ }
+}
+
+//
+static void SetDefaultTask(running_machine &machine)
+{
+ dgn_beta_state *state = machine.driver_data<dgn_beta_state>();
+// UINT8 *videoram = state->m_videoram;
+ int Idx;
+
+ LOG_DEFAULT_TASK(("SetDefaultTask()\n"));
+ //if (VERBOSE) debug_console_printf(machine)->set_base("Set Default task\n");
+
+ state->m_TaskReg=NoPagingTask;
+
+ /* Reset ram pages */
+ for(Idx=0;Idx<ROMPage-1;Idx++)
+ {
+ state->m_PageRegs[state->m_TaskReg][Idx].value=NoMemPageValue;
+ }
+
+ /* Reset RAM Page */
+ state->m_PageRegs[state->m_TaskReg][RAMPage].value=RAMPageValue;
+
+ /* Reset Video mem page */
+ state->m_PageRegs[state->m_TaskReg][VideoPage].value=VideoPageValue;
+
+ /* Reset rom page */
+ state->m_PageRegs[state->m_TaskReg][ROMPage].value=ROMPageValue;
+
+ /* Reset IO Page */
+ state->m_PageRegs[state->m_TaskReg][LastPage].value=IOPageValue;
+ state->m_PageRegs[state->m_TaskReg][LastPage+1].value=IOPageValue;
+
+ UpdateBanks(machine, 0,LastPage+1);
+
+ /* Map video ram to base of area it can use, that way we can take the literal RA */
+ /* from the 6845 without having to mask it ! */
+// videoram=&machine.device<ram_device>(RAM_TAG)->pointer()[TextVidBasePage*RamPageSize];
+}
+
+// Return the value of a page register
+READ8_HANDLER( dgn_beta_page_r )
+{
+ dgn_beta_state *state = space->machine().driver_data<dgn_beta_state>();
+ return state->m_PageRegs[state->m_PIATaskReg][offset].value;
+}
+
+// Write to a page register, writes to the register, and then checks to see
+// if memory banking is active, if it is, it calls UpdateBanks, to actually
+// setup the mappings.
+
+WRITE8_HANDLER( dgn_beta_page_w )
+{
+ dgn_beta_state *state = space->machine().driver_data<dgn_beta_state>();
+ state->m_PageRegs[state->m_PIATaskReg][offset].value=data;
+
+ LOG_PAGE_WRITE(("PageRegWrite : task=$%X offset=$%X value=$%X\n",state->m_PIATaskReg,offset,data));
+
+ if (state->m_EnableMapRegs)
+ {
+ UpdateBanks(space->machine(), offset,offset);
+ if (offset==15)
+ UpdateBanks(space->machine(), offset+1,offset+1);
+ }
+}
+
+/*********************** Memory bank write handlers ************************/
+/* These actually write the data to the memory, and not to the page regs ! */
+static void dgn_beta_bank_memory(running_machine &machine, int offset, int data, int bank)
+{
+ dgn_beta_state *state = machine.driver_data<dgn_beta_state>();
+ state->m_PageRegs[state->m_TaskReg][bank].memory[offset]=data;
+}
+
+static WRITE8_HANDLER( dgnbeta_ram_b0_w )
+{
+ dgn_beta_bank_memory(space->machine(),offset,data,0);
+}
+
+static WRITE8_HANDLER( dgnbeta_ram_b1_w )
+{
+ dgn_beta_bank_memory(space->machine(),offset,data,1);
+}
+
+static WRITE8_HANDLER( dgnbeta_ram_b2_w )
+{
+ dgn_beta_bank_memory(space->machine(),offset,data,2);
+}
+
+static WRITE8_HANDLER( dgnbeta_ram_b3_w )
+{
+ dgn_beta_bank_memory(space->machine(),offset,data,3);
+}
+
+static WRITE8_HANDLER( dgnbeta_ram_b4_w )
+{
+ dgn_beta_bank_memory(space->machine(),offset,data,4);
+}
+
+static WRITE8_HANDLER( dgnbeta_ram_b5_w )
+{
+ dgn_beta_bank_memory(space->machine(),offset,data,5);
+}
+
+static WRITE8_HANDLER( dgnbeta_ram_b6_w )
+{
+ dgn_beta_bank_memory(space->machine(),offset,data,6);
+}
+
+static WRITE8_HANDLER( dgnbeta_ram_b7_w )
+{
+ dgn_beta_bank_memory(space->machine(),offset,data,7);
+}
+
+static WRITE8_HANDLER( dgnbeta_ram_b8_w )
+{
+ dgn_beta_bank_memory(space->machine(),offset,data,8);
+}
+
+static WRITE8_HANDLER( dgnbeta_ram_b9_w )
+{
+ dgn_beta_bank_memory(space->machine(),offset,data,9);
+}
+
+static WRITE8_HANDLER( dgnbeta_ram_bA_w )
+{
+ dgn_beta_bank_memory(space->machine(),offset,data,10);
+}
+
+static WRITE8_HANDLER( dgnbeta_ram_bB_w )
+{
+ dgn_beta_bank_memory(space->machine(),offset,data,11);
+}
+
+static WRITE8_HANDLER( dgnbeta_ram_bC_w )
+{
+ dgn_beta_bank_memory(space->machine(),offset,data,12);
+}
+
+static WRITE8_HANDLER( dgnbeta_ram_bD_w )
+{
+ dgn_beta_bank_memory(space->machine(),offset,data,13);
+}
+
+static WRITE8_HANDLER( dgnbeta_ram_bE_w )
+{
+ dgn_beta_bank_memory(space->machine(),offset,data,14);
+}
+
+static WRITE8_HANDLER( dgnbeta_ram_bF_w )
+{
+ dgn_beta_bank_memory(space->machine(),offset,data,15);
+}
+
+static WRITE8_HANDLER( dgnbeta_ram_bG_w )
+{
+ dgn_beta_bank_memory(space->machine(),offset,data,16);
+}
+
+/*
+The keyrow being scanned for any key is the lest significant bit
+of the output shift register that is zero, most of the time there should
+only be one row active e.g.
+
+Shifter Row being scanned
+1111111110 0
+1111111101 1
+1111111011 2
+
+etc.
+
+Returns row number or -1 if none selected.
+
+2006-12-03, P.Harvey-Smith, modified to scan from msb to lsb, and stop at
+first row with zero, as the beta_test fills the shifter with zeros, rather
+than using a walking zero as the OS-9 driver does. This meant that SelectKeyrow
+never moved past the first row, by scanning for the last active row
+the beta_test rom works, and it does not break the OS-9 driver :)
+*/
+static int SelectedKeyrow(dgn_beta_state *state, int Rows)
+{
+ int Idx;
+ int Row; /* Row selected */
+ int Mask; /* Mask to test row */
+ int Found; /* Set true when found */
+
+ Row=INVALID_KEYROW; /* Pretend no rows selected */
+ Mask=0x200; /* Start with row 9 */
+ Found=0; /* Start with not found */
+ Idx=9;
+
+ while ((Mask>0) && !Found)
+ {
+ if((~Rows & Mask) && !Found)
+ {
+ Row=Idx; /* Get row */
+ Found=1; /* Mark as found */
+ }
+ Idx=Idx-1; /* Decrement row count */
+ Mask=Mask>>1; /* Select next bit */
+ }
+
+ return Row;
+}
+
+/* GetKeyRow, returns the value of a keyrow, checking for invalid rows */
+/* and returning no key pressed if row is invalid */
+static int GetKeyRow(dgn_beta_state *state, int RowNo)
+{
+ if(RowNo==INVALID_KEYROW)
+ return NO_KEY_PRESSED; /* row is invalid, so return no key down */
+ else
+ return state->m_Keyboard[RowNo]; /* Else return keyboard data */
+}
+
+/*********************************** PIA Handlers ************************/
+/* PIA #0 at $FC20-$FC23 I46
+ This handles:-
+ The Printer port, side A,
+ PB0 R16 (pullup) -> Printer Port (PL1)
+ PB1 Printer Port
+ PB2 Keyboard (any key).
+ PB3 D4 -> R37 -> TR1 switching circuit -> PL5
+ PB4 Keyboard Data out, clocked by CB2.
+ positive edge clocks data out of the input shift register.
+ PB5 Keyboard data in, clocked by PB4.
+ PB6 R79 -> I99/6/7416 -> PL9/26/READY (from floppy)
+ PB7 Printer port
+ CB1 I36/39/6845(Horz Sync)
+ CB2 Keyboard (out) Low loads input shift reg
+*/
+static READ8_DEVICE_HANDLER(d_pia0_pa_r)
+{
+ return 0;
+}
+
+static WRITE8_DEVICE_HANDLER(d_pia0_pa_w)
+{
+}
+
+static READ8_DEVICE_HANDLER(d_pia0_pb_r)
+{
+ dgn_beta_state *state = device->machine().driver_data<dgn_beta_state>();
+ int RetVal;
+ int Idx;
+ int Selected;
+ static const char *const keynames[] = {
+ "KEY0", "KEY1", "KEY2", "KEY3", "KEY4",
+ "KEY5", "KEY6", "KEY7", "KEY8", "KEY9"
+ };
+
+ LOG_KEYBOARD(("PB Read\n"));
+
+ state->m_KAny_next = 0;
+
+ Selected = SelectedKeyrow(state, state->m_RowShifter);
+
+ /* Scan the whole keyboard, if output shifter is all low */
+ /* This actually scans in the keyboard */
+ if(state->m_RowShifter == 0x00)
+ {
+ for(Idx=0; Idx<NoKeyrows; Idx++)
+ {
+ state->m_Keyboard[Idx] = device->machine().root_device().ioport(keynames[Idx])->read();
+
+ if(state->m_Keyboard[Idx] != 0x7F)
+ state->m_KAny_next = 1;
+ }
+ }
+ else /* Just scan current row, from previously read values */
+ {
+ if(GetKeyRow(state, Selected) != NO_KEY_PRESSED)
+ state->m_KAny_next = 1;
+ }
+
+ RetVal = (state->m_KInDat_next<<5) | (state->m_KAny_next<<2);
+
+ LOG_KEYBOARD(("FC22=$%02X KAny=%d\n", RetVal, state->m_KAny_next));
+
+ return RetVal;
+}
+
+static WRITE8_DEVICE_HANDLER(d_pia0_pb_w)
+{
+ dgn_beta_state *state = device->machine().driver_data<dgn_beta_state>();
+ int InClkState;
+ //int OutClkState;
+
+ LOG_KEYBOARD(("PB Write\n"));
+
+ InClkState = data & KInClk;
+ //OutClkState = data & KOutClk;
+
+ LOG_KEYBOARD(("InClkState=$%02X OldInClkState=$%02X Keyrow=$%02X ",InClkState,(state->m_d_pia0_pb_last & KInClk),state->m_Keyrow));
+
+ /* Input clock bit has changed state */
+ if ((InClkState) != (state->m_d_pia0_pb_last & KInClk))
+ {
+ /* Clock in bit */
+ if(InClkState)
+ {
+ state->m_KInDat_next=(~state->m_Keyrow & 0x40)>>6;
+ state->m_Keyrow = ((state->m_Keyrow<<1) | 0x01) & 0x7F ;
+ LOG_KEYBOARD(("Keyrow=$%02X KInDat_next=%X\n",state->m_Keyrow,state->m_KInDat_next));
+ }
+ }
+
+ state->m_d_pia0_pb_last=data;
+}
+
+static WRITE8_DEVICE_HANDLER(d_pia0_cb2_w)
+{
+ dgn_beta_state *state = device->machine().driver_data<dgn_beta_state>();
+ int RowNo;
+ LOG_KEYBOARD(("\nCB2 Write\n"));
+
+ /* load keyrow on rising edge of CB2 */
+ if((data==1) && (state->m_d_pia0_cb2_last==0))
+ {
+ RowNo=SelectedKeyrow(state, state->m_RowShifter);
+ state->m_Keyrow=GetKeyRow(state, RowNo);
+
+ /* Output clock rising edge, clock CB2 value into rowshifterlow to high transition */
+ /* In the beta the shift registers are a cmos 4015, and a cmos 4013 in series */
+ state->m_RowShifter = (state->m_RowShifter<<1) | ((state->m_d_pia0_pb_last & KOutDat)>>4);
+ state->m_RowShifter &= 0x3FF;
+ LOG_KEYBOARD(("Rowshifter=$%02X Keyrow=$%02X\n",state->m_RowShifter,state->m_Keyrow));
+ if (VERBOSE) debug_console_printf(device->machine(), "rowshifter clocked, value=%3X, RowNo=%d, Keyrow=%2X\n",state->m_RowShifter,RowNo,state->m_Keyrow);
+ }
+
+ state->m_d_pia0_cb2_last=data;
+}
+
+
+static WRITE_LINE_DEVICE_HANDLER( d_pia0_irq_a )
+{
+ cpu0_recalc_irq(device->machine(), state);
+}
+
+static WRITE_LINE_DEVICE_HANDLER( d_pia0_irq_b )
+{
+ cpu0_recalc_firq(device->machine(), state);
+}
+
+/* PIA #1 at $FC24-$FC27 I63
+ This handles :-
+ Mouse + Disk Select on side A
+ Halt on DMA CPU PA7
+ Beeper PB0
+ Halt on main CPU PB1
+ Character set select PB6
+ Baud rate PB1..PB5 ????
+*/
+
+static READ8_DEVICE_HANDLER(d_pia1_pa_r)
+{
+ return 0;
+}
+
+static WRITE8_DEVICE_HANDLER(d_pia1_pa_w)
+{
+ dgn_beta_state *state = device->machine().driver_data<dgn_beta_state>();
+ int HALT_DMA;
+ device_t *fdc = device->machine().device(FDC_TAG);
+
+ /* Only play with halt line if halt bit changed since last write */
+ if((data & 0x80) != state->m_d_pia1_pa_last)
+ {
+ /* Bit 7 of $FF24, seems to control HALT on second CPU (through an inverter) */
+ if(data & 0x80)
+ HALT_DMA = ASSERT_LINE;
+ else
+ HALT_DMA = CLEAR_LINE;
+
+ LOG_HALT(("DMA_CPU HALT=%d\n", HALT_DMA));
+ cputag_set_input_line(device->machine(), DMACPU_TAG, INPUT_LINE_HALT, HALT_DMA);
+
+ /* CPU un-halted let it run ! */
+ if (HALT_DMA == CLEAR_LINE)
+ device_yield(device->machine().device(MAINCPU_TAG));
+
+ state->m_d_pia1_pa_last = data & 0x80;
+ }
+
+ /* Drive selects are binary encoded on PA0 & PA1 */
+ wd17xx_set_drive(fdc, ~data & DSMask);
+
+ /* Set density of WD2797 */
+ wd17xx_dden_w(fdc, BIT(data, 6));
+ LOG_DISK(("Set density %s\n", BIT(data, 6) ? "low" : "high"));
+}
+
+static READ8_DEVICE_HANDLER(d_pia1_pb_r)
+{
+ return 0;
+}
+
+static WRITE8_DEVICE_HANDLER(d_pia1_pb_w)
+{
+ dgn_beta_state *state = device->machine().driver_data<dgn_beta_state>();
+ int HALT_CPU;
+
+ /* Only play with halt line if halt bit changed since last write */
+ if((data & 0x02) != state->m_d_pia1_pb_last)
+ {
+ /* Bit 1 of $FF26, seems to control HALT on primary CPU */
+ if(data & 0x02)
+ HALT_CPU = CLEAR_LINE;
+ else
+ HALT_CPU = ASSERT_LINE;
+
+ LOG_HALT(("MAIN_CPU HALT=%d\n", HALT_CPU));
+ cputag_set_input_line(device->machine(), MAINCPU_TAG, INPUT_LINE_HALT, HALT_CPU);
+
+ state->m_d_pia1_pb_last = data & 0x02;
+
+ /* CPU un-halted let it run ! */
+ if (HALT_CPU == CLEAR_LINE)
+ device_yield(device->machine().device(DMACPU_TAG));
+ }
+}
+
+static WRITE_LINE_DEVICE_HANDLER( d_pia1_irq_a )
+{
+ cpu0_recalc_irq(device->machine(), state);
+}
+
+static WRITE_LINE_DEVICE_HANDLER( d_pia1_irq_b )
+{
+ cpu0_recalc_irq(device->machine(), state);
+}
+
+/* PIA #2 at FCC0-FCC3 I28
+ This handles :-
+ DAT task select PA0..PA3
+
+ DMA CPU NMI PA7
+
+ Graphics control PB0..PB7 ???
+ VSYNC intutrupt CB2
+*/
+static READ8_DEVICE_HANDLER(d_pia2_pa_r)
+{
+ return 0;
+}
+
+static WRITE8_DEVICE_HANDLER(d_pia2_pa_w)
+{
+ dgn_beta_state *state = device->machine().driver_data<dgn_beta_state>();
+ int OldTask;
+ int OldEnableMap;
+ int NMI;
+
+ LOG_TASK(("FCC0 write : $%02X\n", data));
+
+ /* Bit 7 of $FFC0, seems to control NMI on second CPU */
+ NMI=(data & 0x80);
+
+ /* only take action if NMI changed */
+ if(NMI != state->m_DMA_NMI_LAST)
+ {
+ LOG_INTS(("cpu1 NMI : %d\n", NMI));
+ if(!NMI)
+ {
+ cputag_set_input_line(device->machine(), DMACPU_TAG, INPUT_LINE_NMI, ASSERT_LINE);
+ logerror("device_yield()\n");
+ device_yield(device->machine().device(DMACPU_TAG)); /* Let DMA CPU run */
+ }
+ else
+ {
+ cputag_set_input_line(device->machine(), DMACPU_TAG, INPUT_LINE_NMI, CLEAR_LINE);
+ }
+
+ state->m_DMA_NMI_LAST = NMI; /* Save it for next time */
+ }
+
+ OldEnableMap = state->m_EnableMapRegs;
+ /* Bit 6 seems to enable memory paging */
+ if(data & 0x40)
+ state->m_EnableMapRegs = 0;
+ else
+ state->m_EnableMapRegs = 1;
+
+ /* Bits 0..3 seem to control which task register is selected */
+ OldTask = state->m_PIATaskReg;
+ state->m_PIATaskReg = data & 0x0F;
+
+ LOG_TASK(("OldTask=$%02X EnableMapRegs=%d OldEnableMap=%d\n", OldTask, state->m_EnableMapRegs, OldEnableMap));
+
+ // Maping was enabled or disabled, select apropreate task reg
+ // and map it in
+ if (state->m_EnableMapRegs != OldEnableMap)
+ {
+ if(state->m_EnableMapRegs)
+ state->m_TaskReg = state->m_PIATaskReg;
+ else
+ state->m_TaskReg = NoPagingTask;
+
+ UpdateBanks(device->machine(), 0, IOPage + 1);
+ }
+ else
+ {
+ // Update ram banks only if task reg changed and mapping enabled
+ if ((state->m_PIATaskReg != OldTask) && (state->m_EnableMapRegs))
+ {
+ state->m_TaskReg = state->m_PIATaskReg;
+ UpdateBanks(device->machine(), 0, IOPage + 1);
+ }
+ }
+ LOG_TASK(("TaskReg=$%02X PIATaskReg=$%02X\n", state->m_TaskReg, state->m_PIATaskReg));
+}
+
+static READ8_DEVICE_HANDLER(d_pia2_pb_r)
+{
+ return 0;
+}
+
+static WRITE8_DEVICE_HANDLER(d_pia2_pb_w)
+{
+ /* Update top video address lines */
+ dgnbeta_vid_set_gctrl(device->machine(), data);
+}
+
+static WRITE_LINE_DEVICE_HANDLER( d_pia2_irq_a )
+{
+ cpu0_recalc_irq(device->machine(), state);
+}
+
+static WRITE_LINE_DEVICE_HANDLER( d_pia2_irq_b )
+{
+ cpu0_recalc_irq(device->machine(), state);
+}
+
+/************************************ Recalculate CPU inturrupts ****************************/
+/* CPU 0 */
+static void cpu0_recalc_irq(running_machine &machine, int state)
+{
+ pia6821_device *pia_0 = machine.device<pia6821_device>( PIA_0_TAG );
+ pia6821_device *pia_1 = machine.device<pia6821_device>( PIA_1_TAG );
+ pia6821_device *pia_2 = machine.device<pia6821_device>( PIA_2_TAG );
+ UINT8 pia0_irq_a = pia_0->irq_a_state();
+ UINT8 pia1_irq_a = pia_1->irq_a_state();
+ UINT8 pia1_irq_b = pia_1->irq_b_state();
+ UINT8 pia2_irq_a = pia_2->irq_a_state();
+ UINT8 pia2_irq_b = pia_2->irq_b_state();
+ UINT8 IRQ;
+
+ if (pia0_irq_a || pia1_irq_a || pia1_irq_b || pia2_irq_a || pia2_irq_b)
+ IRQ = ASSERT_LINE;
+ else
+ IRQ = CLEAR_LINE;
+
+ cputag_set_input_line(machine, MAINCPU_TAG, M6809_IRQ_LINE, IRQ);
+ LOG_INTS(("cpu0 IRQ : %d\n", IRQ));
+}
+
+static void cpu0_recalc_firq(running_machine &machine, int state)
+{
+ pia6821_device *pia_0 = machine.device<pia6821_device>( PIA_0_TAG );
+ UINT8 pia0_irq_b = pia_0->irq_b_state();
+ UINT8 FIRQ;
+
+ if (pia0_irq_b)
+ FIRQ = ASSERT_LINE;
+ else
+ FIRQ = CLEAR_LINE;
+
+ cputag_set_input_line(machine, MAINCPU_TAG, M6809_FIRQ_LINE, FIRQ);
+
+ LOG_INTS(("cpu0 FIRQ : %d\n", FIRQ));
+}
+
+/* CPU 1 */
+
+static void cpu1_recalc_firq(running_machine &machine, int state)
+{
+ cputag_set_input_line(machine, DMACPU_TAG, M6809_FIRQ_LINE, state);
+ LOG_INTS(("cpu1 FIRQ : %d\n",state));
+}
+
+/********************************************************************************************/
+/* Dragon Beta onboard FDC */
+/********************************************************************************************/
+
+/* The INTRQ line goes through pia2 ca1, in exactly the same way as DRQ from DragonDos does */
+static WRITE_LINE_DEVICE_HANDLER( dgnbeta_fdc_intrq_w )
+{
+ dgn_beta_state *drvstate = device->machine().driver_data<dgn_beta_state>();
+ LOG_DISK(("dgnbeta_fdc_intrq_w(%d)\n", state));
+ if(drvstate->m_wd2797_written)
+ downcast<pia6821_device *>(device)->ca1_w(state);
+}
+
+/* DRQ is routed through various logic to the FIRQ inturrupt line on *BOTH* CPUs */
+static WRITE_LINE_DEVICE_HANDLER( dgnbeta_fdc_drq_w )
+{
+ LOG_DISK(("dgnbeta_fdc_drq_w(%d)\n", state));
+ cpu1_recalc_firq(device->machine(), state);
+}
+
+const wd17xx_interface dgnbeta_wd17xx_interface =
+{
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE(PIA_2_TAG, dgnbeta_fdc_intrq_w),
+ DEVCB_LINE(dgnbeta_fdc_drq_w),
+ {FLOPPY_0, FLOPPY_1, FLOPPY_2, FLOPPY_3}
+};
+
+READ8_HANDLER(dgnbeta_wd2797_r)
+{
+ int result = 0;
+ device_t *fdc = space->machine().device(FDC_TAG);
+
+ switch(offset & 0x03)
+ {
+ case 0:
+ result = wd17xx_status_r(fdc, 0);
+ LOG_DISK(("Disk status=%2.2X\n",result));
+ break;
+ case 1:
+ result = wd17xx_track_r(fdc, 0);
+ break;
+ case 2:
+ result = wd17xx_sector_r(fdc, 0);
+ break;
+ case 3:
+ result = wd17xx_data_r(fdc, 0);
+ break;
+ default:
+ break;
+ }
+
+ return result;
+}
+
+WRITE8_HANDLER(dgnbeta_wd2797_w)
+{
+ dgn_beta_state *state = space->machine().driver_data<dgn_beta_state>();
+ device_t *fdc = space->machine().device(FDC_TAG);
+
+ state->m_wd2797_written=1;
+
+ switch(offset & 0x3)
+ {
+ case 0:
+ /* disk head is encoded in the command byte */
+ /* But only for Type 3/4 commands */
+ if(data & 0x80)
+ wd17xx_set_side(fdc,(data & 0x02) ? 1 : 0);
+ wd17xx_command_w(fdc, 0, data);
+ break;
+ case 1:
+ wd17xx_track_w(fdc, 0, data);
+ break;
+ case 2:
+ wd17xx_sector_w(fdc, 0, data);
+ break;
+ case 3:
+ wd17xx_data_w(fdc, 0, data);
+ break;
+ };
+}
+
+/* Scan physical keyboard into Keyboard array */
+/* gonna try and sync this more closely with hardware as keyboard being scanned */
+/* on *EVERY* vblank ! */
+static void ScanInKeyboard(void)
+{
+#if 0
+ dgn_beta_state *state = machine.driver_data<dgn_beta_state>();
+ int Idx;
+ int Row;
+ static const char *const keynames[] = {
+ "KEY0", "KEY1", "KEY2", "KEY3", "KEY4",
+ "KEY5", "KEY6", "KEY7", "KEY8", "KEY9"
+ };
+
+ LOG_KEYBOARD(("Scanning Host keyboard\n"));
+
+ for(Idx=0; Idx<NoKeyrows; Idx++)
+ {
+ if (Idx < 10)
+ Row = machine.root_device().ioport(keynames[Idx])->read();
+
+ else
+ Row = 0x7f;
+
+ state->m_Keyboard[Idx]=Row;
+ LOG_KEYBOARD(("Keyboard[%d]=$%02X\n",Idx,Row));
+
+ if (Row != 0x7F)
+ {
+ LOG_KEYBOARD(("Found Pressed Key\n"));
+ }
+ }
+#endif
+}
+
+/* VBlank inturrupt */
+void dgn_beta_frame_interrupt (running_machine &machine, int data)
+{
+ pia6821_device *pia_2 = machine.device<pia6821_device>( PIA_2_TAG );
+
+ /* Set PIA line, so it recognises inturrupt */
+ if (!data)
+ pia_2->cb2_w(ASSERT_LINE);
+ else
+ pia_2->cb2_w(CLEAR_LINE);
+
+// LOG_VIDEO(("Vblank\n"));
+ ScanInKeyboard();
+}
+
+#ifdef UNUSED_FUNCTION
+void dgn_beta_line_interrupt (int data)
+{
+// /* Set PIA line, so it recognises inturrupt */
+// if (data)
+// {
+// pia_0_cb1_w(machine, 0,ASSERT_LINE);
+// }
+// else
+// {
+// pia_0_cb1_w(machine, 0,CLEAR_LINE);
+// }
+}
+#endif
+
+
+/********************************* Machine/Driver Initialization ****************************************/
+static void dgnbeta_reset(running_machine &machine)
+{
+ dgn_beta_state *state = machine.driver_data<dgn_beta_state>();
+ device_t *fdc = machine.device(FDC_TAG);
+ pia6821_device *pia_0 = machine.device<pia6821_device>( PIA_0_TAG );
+ pia6821_device *pia_1 = machine.device<pia6821_device>( PIA_1_TAG );
+ pia6821_device *pia_2 = machine.device<pia6821_device>( PIA_2_TAG );
+
+ logerror("MACHINE_RESET( dgnbeta )\n");
+
+ state->m_system_rom = state->memregion(MAINCPU_TAG)->base();
+
+ /* Make sure CPU 1 is started out halted ! */
+ cputag_set_input_line(machine, DMACPU_TAG, INPUT_LINE_HALT, ASSERT_LINE);
+
+ /* Reset to task 0, and map banks disabled, so standard memory map */
+ /* with ram at $0000-$BFFF, ROM at $C000-FBFF, IO at $FC00-$FEFF */
+ /* and ROM at $FF00-$FFFF */
+ state->m_TaskReg = 0;
+ state->m_PIATaskReg = 0;
+ state->m_EnableMapRegs = 0;
+ memset(state->m_PageRegs, 0, sizeof(state->m_PageRegs)); /* Reset page registers to 0 */
+ SetDefaultTask(machine);
+
+ /* Set pullups on all PIA port A, to match what hardware does */
+ pia_0->set_port_a_z_mask(0xFF);
+ pia_1->set_port_a_z_mask(0xFF);
+ pia_2->set_port_a_z_mask(0xFF);
+
+ state->m_d_pia1_pa_last = 0x00;
+ state->m_d_pia1_pb_last = 0x00;
+ state->m_RowShifter = 0x00; /* shift register to select row */
+ state->m_Keyrow = 0x00; /* Keyboard row being shifted out */
+ state->m_d_pia0_pb_last = 0x00; /* Last byte output to pia0 port b */
+ state->m_d_pia0_cb2_last = 0x00; /* Last state of CB2 */
+
+ state->m_KInDat_next = 0x00; /* Next data bit to input */
+ state->m_KAny_next = 0x00; /* Next value for KAny */
+
+ state->m_DMA_NMI_LAST = 0x80; /* start with DMA NMI inactive, as pulled up */
+// DMA_NMI = CLEAR_LINE; /* start with DMA NMI inactive */
+
+ wd17xx_dden_w(fdc, CLEAR_LINE);
+ wd17xx_set_drive(fdc, 0);
+
+ state->m_videoram.set_target(machine.device<ram_device>(RAM_TAG)->pointer(),state->m_videoram.bytes()); /* Point video ram at the start of physical ram */
+
+ wd17xx_reset(fdc);
+ state->m_wd2797_written=0;
+}
+
+MACHINE_START( dgnbeta )
+{
+ dgn_beta_state *state = machine.driver_data<dgn_beta_state>();
+ logerror("MACHINE_START( dgnbeta )\n");
+
+ if (machine.device<cpu_device>(MAINCPU_TAG)->debug()) {
+ machine.device<cpu_device>(MAINCPU_TAG)->debug()->set_dasm_override(dgnbeta_dasm_override);
+ }
+
+ machine.add_notifier(MACHINE_NOTIFY_RESET, machine_notify_delegate(FUNC(dgnbeta_reset),&machine));
+ dgnbeta_reset(machine);
+ /* setup debug commands */
+ if (machine.debug_flags & DEBUG_FLAG_ENABLED)
+ {
+ debug_console_register_command(machine, "beta_dat_log", CMDFLAG_NONE, 0, 0, 0, execute_beta_dat_log);
+ debug_console_register_command(machine, "beta_key_dump", CMDFLAG_NONE, 0, 0, 0, execute_beta_key_dump);
+ }
+ state->m_LogDatWrites=0;
+}
+
+
+/***************************************************************************
+ OS9 Syscalls for disassembly
+****************************************************************************/
+
+
+static const char *const os9syscalls[] =
+{
+ "F$Link", /* Link to Module */
+ "F$Load", /* Load Module from File */
+ "F$UnLink", /* Unlink Module */
+ "F$Fork", /* Start New Process */
+ "F$Wait", /* Wait for Child Process to Die */
+ "F$Chain", /* Chain Process to New Module */
+ "F$Exit", /* Terminate Process */
+ "F$Mem", /* Set Memory Size */
+ "F$Send", /* Send Signal to Process */
+ "F$Icpt", /* Set Signal Intercept */
+ "F$Sleep", /* Suspend Process */
+ "F$SSpd", /* Suspend Process */
+ "F$ID", /* Return Process ID */
+ "F$SPrior", /* Set Process Priority */
+ "F$SSWI", /* Set Software Interrupt */
+ "F$PErr", /* Print Error */
+ "F$PrsNam", /* Parse Pathlist Name */
+ "F$CmpNam", /* Compare Two Names */
+ "F$SchBit", /* Search Bit Map */
+ "F$AllBit", /* Allocate in Bit Map */
+ "F$DelBit", /* Deallocate in Bit Map */
+ "F$Time", /* Get Current Time */
+ "F$STime", /* Set Current Time */
+ "F$CRC", /* Generate CRC */
+ "F$GPrDsc", /* get Process Descriptor copy */
+ "F$GBlkMp", /* get System Block Map copy */
+ "F$GModDr", /* get Module Directory copy */
+ "F$CpyMem", /* Copy External Memory */
+ "F$SUser", /* Set User ID number */
+ "F$UnLoad", /* Unlink Module by name */
+ "F$Alarm", /* Color Computer Alarm Call (system wide) */
+ NULL,
+ NULL,
+ "F$NMLink", /* Color Computer NonMapping Link */
+ "F$NMLoad", /* Color Computer NonMapping Load */
+ NULL,
+ NULL,
+ "F$TPS", /* Return System's Ticks Per Second */
+ "F$TimAlm", /* COCO individual process alarm call */
+ "F$VIRQ", /* Install/Delete Virtual IRQ */
+ "F$SRqMem", /* System Memory Request */
+ "F$SRtMem", /* System Memory Return */
+ "F$IRQ", /* Enter IRQ Polling Table */
+ "F$IOQu", /* Enter I/O Queue */
+ "F$AProc", /* Enter Active Process Queue */
+ "F$NProc", /* Start Next Process */
+ "F$VModul", /* Validate Module */
+ "F$Find64", /* Find Process/Path Descriptor */
+ "F$All64", /* Allocate Process/Path Descriptor */
+ "F$Ret64", /* Return Process/Path Descriptor */
+ "F$SSvc", /* Service Request Table Initialization */
+ "F$IODel", /* Delete I/O Module */
+ "F$SLink", /* System Link */
+ "F$Boot", /* Bootstrap System */
+ "F$BtMem", /* Bootstrap Memory Request */
+ "F$GProcP", /* Get Process ptr */
+ "F$Move", /* Move Data (low bound first) */
+ "F$AllRAM", /* Allocate RAM blocks */
+ "F$AllImg", /* Allocate Image RAM blocks */
+ "F$DelImg", /* Deallocate Image RAM blocks */
+ "F$SetImg", /* Set Process DAT Image */
+ "F$FreeLB", /* Get Free Low Block */
+ "F$FreeHB", /* Get Free High Block */
+ "F$AllTsk", /* Allocate Process Task number */
+ "F$DelTsk", /* Deallocate Process Task number */
+ "F$SetTsk", /* Set Process Task DAT registers */
+ "F$ResTsk", /* Reserve Task number */
+ "F$RelTsk", /* Release Task number */
+ "F$DATLog", /* Convert DAT Block/Offset to Logical */
+ "F$DATTmp", /* Make temporary DAT image (Obsolete) */
+ "F$LDAXY", /* Load A [X,[Y]] */
+ "F$LDAXYP", /* Load A [X+,[Y]] */
+ "F$LDDDXY", /* Load D [D+X,[Y]] */
+ "F$LDABX", /* Load A from 0,X in task B */
+ "F$STABX", /* Store A at 0,X in task B */
+ "F$AllPrc", /* Allocate Process Descriptor */
+ "F$DelPrc", /* Deallocate Process Descriptor */
+ "F$ELink", /* Link using Module Directory Entry */
+ "F$FModul", /* Find Module Directory Entry */
+ "F$MapBlk", /* Map Specific Block */
+ "F$ClrBlk", /* Clear Specific Block */
+ "F$DelRAM", /* Deallocate RAM blocks */
+ "F$GCMDir", /* Pack module directory */
+ "F$AlHRam", /* Allocate HIGH RAM Blocks */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "F$RegDmp", /* Ron Lammardo's debugging register dump call */
+ "F$NVRAM", /* Non Volatile RAM (RTC battery backed static) read/write */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "I$Attach", /* Attach I/O Device */
+ "I$Detach", /* Detach I/O Device */
+ "I$Dup", /* Duplicate Path */
+ "I$Create", /* Create New File */
+ "I$Open", /* Open Existing File */
+ "I$MakDir", /* Make Directory File */
+ "I$ChgDir", /* Change Default Directory */
+ "I$Delete", /* Delete File */
+ "I$Seek", /* Change Current Position */
+ "I$Read", /* Read Data */
+ "I$Write", /* Write Data */
+ "I$ReadLn", /* Read Line of ASCII Data */
+ "I$WritLn", /* Write Line of ASCII Data */
+ "I$GetStt", /* Get Path Status */
+ "I$SetStt", /* Set Path Status */
+ "I$Close", /* Close Path */
+ "I$DeletX" /* Delete from current exec dir */
+};
+
+
+static offs_t dgnbeta_dasm_override(device_t &device, char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, int options)
+{
+ unsigned call;
+ unsigned result = 0;
+
+ if ((oprom[0] == 0x10) && (oprom[1] == 0x3F))
+ {
+ call = oprom[2];
+ if ((call < ARRAY_LENGTH(os9syscalls)) && os9syscalls[call])
+ {
+ sprintf(buffer, "OS9 %s", os9syscalls[call]);
+ result = 3;
+ }
+ }
+ return result;
+}
+
+static void execute_beta_dat_log(running_machine &machine, int ref, int params, const char *param[])
+{
+ dgn_beta_state *state = machine.driver_data<dgn_beta_state>();
+ state->m_LogDatWrites=!state->m_LogDatWrites;
+
+ debug_console_printf(machine, "DAT register write info set : %d\n",state->m_LogDatWrites);
+}
+
+static void execute_beta_key_dump(running_machine &machine, int ref, int params, const char *param[])
+{
+ dgn_beta_state *state = machine.driver_data<dgn_beta_state>();
+ int Idx;
+
+ for(Idx=0;Idx<NoKeyrows;Idx++)
+ {
+ debug_console_printf(machine, "KeyRow[%d]=%2X\n",Idx,state->m_Keyboard[Idx]);
+ }
+}
diff --git a/src/mess/machine/dgnalpha.c b/src/mess/machine/dgnalpha.c
new file mode 100644
index 00000000000..19f12c30aa1
--- /dev/null
+++ b/src/mess/machine/dgnalpha.c
@@ -0,0 +1,440 @@
+/***************************************************************************
+
+ dgnalpha.c
+
+ Dragon Alpha
+
+ The Dragon Alpha was a prototype in development when Dragon Data went bust,
+ it is basically an enhanced Dragon 64, with built in modem, disk system, and
+ graphical boot rom.
+
+ It has the following extra hardware :-
+ A third 6821 PIA mapped between FF24 and FF27
+ An AY-8912, connected to the PIA.
+
+ Port A of the PIA is connected as follows :-
+
+ b0 BDIR of AY8912
+ b1 BC1 of AY8912
+ b2 Rom select, High= boot rom, low=BASIC rom
+ b3..7 not used.
+
+ Port B
+ b0..7 connected to D0..7 of the AY8912.
+
+ CB1 DRQ of WD2797.
+
+ /irqa
+ /irqb both connected to 6809 FIRQ.
+
+
+ The analog outputs of the AY-8912 are connected to the standard sound multiplexer.
+ The AY8912 output port is used as follows :-
+
+ b0..b3 /DS0../DS3 for the drive interface (through an inverter first).
+ b4 /motor for the drive interface (through an inverter first).
+ b5..b7 not used as far as I can tell.
+
+ A 6850 for the modem.
+
+ A WD2797, used as an internal disk interface, this is however connected in a slightly strange
+ way that I am yet to completely determine.
+ 19/10/2004, WD2797 is mapped between FF2C and FF2F, however the order of the registers is
+ reversed so the command Register is at the highest address instead of the lowest. The Data
+ request pin is connected to CB1(pin 18) of PIA2, to cause an firq, the INTRQ, is connected via
+ an inverter to the 6809's NMI.
+
+ All these are as yet un-emulated.
+
+ 29-Oct-2004, AY-8912 is now emulated.
+ 30-Oct-2004, Internal disk interface now emulated, Normal DragonDos rom replaced with a re-assembled
+ version, that talks to the alpha hardware (verified on a clone of the real machine).
+
+Dragon Alpha code added 21-Oct-2004,
+ Phill Harvey-Smith (afra@aurigae.demon.co.uk)
+
+ Added AY-8912 and FDC code 30-Oct-2004.
+
+Fixed Dragon Alpha NMI enable/disable, following circuit traces on a real machine.
+ P.Harvey-Smith, 11-Aug-2005.
+
+Re-implemented Alpha NMI enable/disable, using direct PIA reads, rather than
+keeping track of it in a variable in the driver.
+ P.Harvey-Smith, 25-Sep-2006.
+
+***************************************************************************/
+
+#include "includes/dgnalpha.h"
+#include "sound/ay8910.h"
+#include "imagedev/flopdrv.h"
+
+
+//-------------------------------------------------
+// ctor
+//-------------------------------------------------
+
+dragon_alpha_state::dragon_alpha_state(const machine_config &mconfig, device_type type, const char *tag)
+ : dragon64_state(mconfig, type, tag),
+ m_pia_2(*this, PIA2_TAG),
+ m_ay8912(*this, AY8912_TAG),
+ m_fdc(*this, WD2797_TAG)
+{
+}
+
+
+//-------------------------------------------------
+// device_start
+//-------------------------------------------------
+
+void dragon_alpha_state::device_start(void)
+{
+ dragon_state::device_start();
+ save_item(NAME(m_just_reset));
+}
+
+
+
+//-------------------------------------------------
+// device_reset
+//-------------------------------------------------
+
+void dragon_alpha_state::device_reset(void)
+{
+ dragon_state::device_reset();
+ m_just_reset = 1;
+}
+
+
+
+/***************************************************************************
+ MODEM
+***************************************************************************/
+
+//-------------------------------------------------
+// modem_r
+//-------------------------------------------------
+
+UINT8 dragon_alpha_state::modem_r(offs_t offset)
+{
+ return 0xFF;
+}
+
+
+
+//-------------------------------------------------
+// modem_w
+//-------------------------------------------------
+
+void dragon_alpha_state::modem_w(offs_t offset, UINT8 data)
+{
+}
+
+
+
+/***************************************************************************
+ PIA1
+***************************************************************************/
+
+//-------------------------------------------------
+// ff20_read
+//-------------------------------------------------
+
+READ8_MEMBER( dragon_alpha_state::ff20_read )
+{
+ UINT8 result = 0x00;
+
+ switch(offset & 0x0f)
+ {
+ case 0: case 1: case 2: case 3:
+ result = dragon_state::ff20_read(space, offset, mem_mask);
+ break;
+
+ case 4: case 5: case 6: case 7:
+ result = m_pia_2->read(space, offset, mem_mask);
+ break;
+
+ case 8: case 9: case 10: case 11:
+ result = modem_r(offset);
+ break;
+
+ case 12:
+ result = wd17xx_data_r(m_fdc, 0);
+ break;
+
+ case 13:
+ result = wd17xx_sector_r(m_fdc, 0);
+ break;
+
+ case 14:
+ result = wd17xx_track_r(m_fdc, 0);
+ break;
+
+ case 15:
+ result = wd17xx_status_r(m_fdc, 0);
+ break;
+ }
+ return result;
+}
+
+
+
+//-------------------------------------------------
+// ff20_write
+//-------------------------------------------------
+
+WRITE8_MEMBER( dragon_alpha_state::ff20_write )
+{
+ switch(offset & 0x0f)
+ {
+ case 0: case 1: case 2: case 3:
+ dragon_state::ff20_write(space, offset, data, mem_mask);
+ break;
+
+ case 4: case 5: case 6: case 7:
+ m_pia_2->write(space, offset, data, mem_mask);
+ break;
+
+ case 8: case 9: case 10: case 11:
+ modem_w(offset, data);
+ break;
+
+ case 12:
+ wd17xx_data_w(m_fdc, 0, data);
+ break;
+ case 13:
+ wd17xx_sector_w(m_fdc, 0, data);
+ break;
+ case 14:
+ wd17xx_track_w(m_fdc, 0, data);
+ break;
+ case 15:
+ wd17xx_command_w(m_fdc, 0, data);
+
+ /* disk head is encoded in the command byte */
+ wd17xx_set_side(m_fdc,(data & 0x02) ? 1 : 0);
+ break;
+ }
+}
+
+
+/***************************************************************************
+ PIA2 ($FF24-$FF28) on Dragon Alpha/Professional
+
+ PIA2 PA0 bcdir to AY-8912
+ PIA2 PA1 bc0 to AY-8912
+ PIA2 PA2 Rom switch, 0=basic rom, 1=boot rom.
+ PIA2 PA3-PA7 Unknown/unused ?
+ PIA2 PB0-PB7 connected to D0..7 of the AY8912.
+ CB1 DRQ from WD2797 disk controler.
+***************************************************************************/
+
+//-------------------------------------------------
+// pia2_pa_w
+//-------------------------------------------------
+
+WRITE8_MEMBER( dragon_alpha_state::pia2_pa_w )
+{
+ /* If bit 2 of the pia2 ddra is 1 then this pin is an output so use it */
+ /* to control the paging of the boot and basic roms */
+ /* Otherwise it set as an input, with an internal pull-up so it should */
+ /* always be high (enabling boot rom) */
+ /* PIA FIXME if (pia_get_ddr_a(2) & 0x04) */
+ {
+ page_rom(data & 0x04 ? true : false); /* bit 2 controls boot or basic rom */
+ }
+
+ /* Bits 0 and 1 for pia2 port a control the BCDIR and BC1 lines of the */
+ /* AY-8912 */
+ switch (data & 0x03)
+ {
+ case 0x00: /* Inactive, do nothing */
+ break;
+ case 0x01: /* Write to selected port */
+ ay8910_data_w(m_ay8912, 0, m_pia_2->b_output());
+ break;
+ case 0x02: /* Read from selected port */
+ m_pia_2->portb_w(ay8910_r(m_ay8912, 0));
+ break;
+ case 0x03: /* Select port to write to */
+ ay8910_address_w(m_ay8912, 0, m_pia_2->b_output());
+ break;
+ }
+}
+
+
+
+//-------------------------------------------------
+// pia1_firq_a
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( dragon_alpha_state::pia2_firq_a )
+{
+ recalculate_firq();
+}
+
+
+
+//-------------------------------------------------
+// pia1_firq_b
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( dragon_alpha_state::pia2_firq_b )
+{
+ recalculate_firq();
+}
+
+
+
+//-------------------------------------------------
+// pia2_config
+//-------------------------------------------------
+
+const pia6821_interface dragon_alpha_state::pia2_config =
+{
+ DEVCB_NULL, /* port A input */
+ DEVCB_NULL, /* port B input */
+ DEVCB_NULL, /* CA1 input */
+ DEVCB_NULL, /* CB1 input */
+ DEVCB_NULL, /* CA2 input */
+ DEVCB_NULL, /* CB2 input */
+ DEVCB_DRIVER_MEMBER(dragon_alpha_state, pia2_pa_w), /* port A output */
+ DEVCB_NULL, /* port B output */
+ DEVCB_NULL, /* CA2 output */
+ DEVCB_NULL, /* CB2 output */
+ DEVCB_DRIVER_LINE_MEMBER(dragon_alpha_state, pia2_firq_a), /* IRQA output */
+ DEVCB_DRIVER_LINE_MEMBER(dragon_alpha_state, pia2_firq_b) /* IRQB output */
+};
+
+
+
+/***************************************************************************
+ CPU INTERRUPTS
+***************************************************************************/
+
+//-------------------------------------------------
+// firq_get_line - gets the value of the FIRQ line
+// passed into the CPU
+//-------------------------------------------------
+
+bool dragon_alpha_state::firq_get_line(void)
+{
+ return dragon_state::firq_get_line() || m_pia_2->irq_a_state() || m_pia_2->irq_b_state();
+}
+
+
+
+/***************************************************************************
+ AY8912
+***************************************************************************/
+
+//-------------------------------------------------
+// psg_porta_read
+//-------------------------------------------------
+
+READ8_MEMBER( dragon_alpha_state::psg_porta_read )
+{
+ return 0;
+}
+
+
+
+//-------------------------------------------------
+// psg_porta_read
+//-------------------------------------------------
+
+WRITE8_MEMBER( dragon_alpha_state::psg_porta_write )
+{
+ /* Bits 0..3 are the drive select lines for the internal floppy interface */
+ /* Bit 4 is the motor on, in the real hardware these are inverted on their way to the drive */
+ /* Bits 5,6,7 are connected to /DDEN, ENP and 5/8 on the WD2797 */
+ switch (data & 0xF)
+ {
+ case(0x01) :
+ wd17xx_set_drive(m_fdc, 0);
+ break;
+ case(0x02) :
+ wd17xx_set_drive(m_fdc, 1);
+ break;
+ case(0x04) :
+ wd17xx_set_drive(m_fdc, 2);
+ break;
+ case(0x08) :
+ wd17xx_set_drive(m_fdc, 3);
+ break;
+ }
+}
+
+
+
+//-------------------------------------------------
+// ay8912_interface - AY-8912 for Dragon Alpha, the
+// AY-8912 simply an AY-8910 with only one io port.
+//-------------------------------------------------
+
+const ay8910_interface dragon_alpha_state::ay8912_interface =
+{
+ AY8910_LEGACY_OUTPUT,
+ AY8910_DEFAULT_LOADS,
+ DEVCB_DRIVER_MEMBER(dragon_alpha_state, psg_porta_read), /* portA read */
+ DEVCB_NULL, /* portB read */
+ DEVCB_DRIVER_MEMBER(dragon_alpha_state, psg_porta_write), /* portA write */
+ DEVCB_NULL /* portB write */
+};
+
+
+
+/***************************************************************************
+ FDC
+***************************************************************************/
+
+//-------------------------------------------------
+// fdc_intrq_w - The NMI line on the Alpha is gated
+// through IC16 (early PLD), and is gated by pia2 CA2
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( dragon_alpha_state::fdc_intrq_w )
+{
+ if (state)
+ {
+ if (m_just_reset)
+ {
+ m_just_reset = 0;
+ }
+ else
+ {
+ if (m_pia_2->ca2_output_z())
+ m_maincpu->set_input_line(INPUT_LINE_NMI, ASSERT_LINE);
+ }
+ }
+ else
+ {
+ m_maincpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE);
+ }
+}
+
+
+
+//-------------------------------------------------
+// fdc_drq_w - The DRQ line goes through pia2 CB1,
+// in exactly the same way as DRQ from DragonDos
+// does for pia1 CB1
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( dragon_alpha_state::fdc_drq_w )
+{
+ m_pia_2->cb1_w(state ? ASSERT_LINE : CLEAR_LINE);
+}
+
+
+
+//-------------------------------------------------
+// fdc_interface
+//-------------------------------------------------
+
+const wd17xx_interface dragon_alpha_state::fdc_interface =
+{
+ DEVCB_NULL,
+ DEVCB_DRIVER_LINE_MEMBER(dragon_alpha_state, fdc_intrq_w),
+ DEVCB_DRIVER_LINE_MEMBER(dragon_alpha_state, fdc_drq_w),
+ {FLOPPY_0, FLOPPY_1, FLOPPY_2, FLOPPY_3}
+};
diff --git a/src/mess/machine/docg3.c b/src/mess/machine/docg3.c
new file mode 100644
index 00000000000..2c756cb17f7
--- /dev/null
+++ b/src/mess/machine/docg3.c
@@ -0,0 +1,828 @@
+/*
+
+ M-Systems DiskOnChip G3 - Flash Disk with MLC NAND and M-Systems? x2 Technology
+
+ (c) 2009 Tim Schuerewegen
+
+*/
+
+#include "emu.h"
+#include "machine/docg3.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 );
+ }
+}
+
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+// device type definition
+const device_type DISKONCHIP_G3 = &device_creator<diskonchip_g3_device>;
+
+//-------------------------------------------------
+// diskonchip_g3_device - constructor
+//-------------------------------------------------
+
+diskonchip_g3_device::diskonchip_g3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, DISKONCHIP_G3, "DiskOnChip G3", tag, owner, clock),
+ device_nvram_interface(mconfig, *this)
+{
+}
+
+
+UINT32 diskonchip_g3_device::g3_offset_data_1()
+{
+// printf( "block %d pages %d page %d planes %d plane %d user_data_size %d extra_area_size %d\n", doc->block, doc->pages, doc->page, doc->planes, doc->plane, doc->user_data_size, doc->extra_area_size);
+ return ((((m_block * m_pages) + m_page) * m_planes) + m_plane) * (m_user_data_size + m_extra_area_size);
+}
+
+UINT32 diskonchip_g3_device::g3_offset_data_2()
+{
+ return ((((m_block * m_pages) + m_page) * m_planes) + m_plane) * 16;
+}
+
+UINT32 diskonchip_g3_device::g3_offset_data_3()
+{
+ return m_block * 8;
+}
+
+UINT8 diskonchip_g3_device::g3_read_data()
+{
+ UINT8 data = 0;
+ UINT32 offset;
+ if (m_test == 0)
+ {
+ // read page data (512 + 16)
+ if (m_transfer_offset >= (m_user_data_size + m_extra_area_size))
+ {
+ m_transfer_offset = m_transfer_offset - (m_user_data_size + m_extra_area_size);
+ m_plane++;
+ }
+ offset = g3_offset_data_1() + m_transfer_offset;
+ data = m_data[0][offset];
+ }
+ else if (m_test == 1)
+ {
+ // read ??? (0x28 bytes)
+ if (m_transfer_offset < 0x20)
+ {
+ offset = g3_offset_data_1() + (m_user_data_size + m_extra_area_size) + (m_user_data_size - 16) + m_transfer_offset;
+ data = m_data[0][offset];
+ }
+ else if (m_transfer_offset < 0x28)
+ {
+ offset = g3_offset_data_3() + m_transfer_offset - 0x20;
+ data = m_data[2][offset];
+ }
+ else
+ {
+ data = 0xFF;
+ }
+ }
+ else if (m_test == 2)
+ {
+ // read erase block status
+ data = 0x00;
+ }
+ m_transfer_offset++;
+ return data;
+}
+
+READ16_MEMBER( diskonchip_g3_device::sec_1_r )
+{
+ UINT16 data;
+ if (m_sec_2[0x1B] & 0x40)
+ {
+ data = g3_read_data();
+ m_sec_2[0x1B] &= ~0x40;
+ }
+ else
+ {
+ data = (g3_read_data() << 0) | (g3_read_data() << 8);
+ }
+ verboselog( machine(), 9, "(DOC) %08X -> %04X\n", 0x0800 + (offset << 1), data);
+ return data;
+}
+
+void diskonchip_g3_device::g3_write_data(UINT8 data)
+{
+ UINT32 offset;
+ if (m_test == 3)
+ {
+ // read page data (512 + 16)
+ if (m_transfer_offset >= (m_user_data_size + m_extra_area_size))
+ {
+ m_transfer_offset = m_transfer_offset - (m_user_data_size + m_extra_area_size);
+ m_plane++;
+ }
+ if (m_transfer_offset == 0)
+ {
+ const UINT8 xxx[] = { 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ offset = g3_offset_data_2();
+ memcpy( m_data[1] + offset, xxx, 16);
+ }
+ offset = g3_offset_data_1() + m_transfer_offset;
+ m_data[0][offset] = data;
+ }
+ m_transfer_offset++;
+}
+
+WRITE16_MEMBER( diskonchip_g3_device::sec_1_w )
+{
+ verboselog( machine(), 9, "(DOC) %08X <- %04X\n", 0x0800 + (offset << 1), data);
+ if (m_sec_2[0x1B] & 0x40)
+ {
+ g3_write_data(data);
+ m_sec_2[0x1B] &= ~0x40;
+ }
+ else
+ {
+ g3_write_data((data >> 0) & 0xFF);
+ g3_write_data((data >> 8) & 0xFF);
+ }
+}
+
+// #define DoC_G3_IO 0x0800
+// #define DoC_G3_ChipID 0x1000
+// #define DoC_G3_DeviceIdSelect 0x100a
+// #define DoC_G3_Ctrl 0x100c
+// #define DoC_G3_CtrlConfirm 0x1072
+// #define DoC_G3_ReadAddress 0x101a
+// #define DoC_G3_FlashSelect 0x1032
+// #define DoC_G3_FlashCmd 0x1034
+// #define DoC_G3_FlashAddr 0x1036
+// #define DoC_G3_FlashCtrl 0x1038
+// #define DoC_G3_Nop 0x103e
+
+UINT16 diskonchip_g3_device::sec_2_read_1000()
+{
+ if (m_device == 0)
+ {
+ return 0x0200;
+ }
+ else
+ {
+ return 0x008C;
+ }
+}
+
+UINT16 diskonchip_g3_device::sec_2_read_1074()
+{
+ if (m_device == 0)
+ {
+ return 0xFDFF;
+ }
+ else
+ {
+ return 0x02B3;
+ }
+}
+
+UINT8 diskonchip_g3_device::sec_2_read_1042()
+{
+ UINT8 data;
+ if ((m_block == 0) && (m_page == 0) && (m_transfersize == 0x27))
+ {
+ data = 0x07;
+ }
+ else
+ {
+ UINT32 offset = g3_offset_data_2() + 0x02;
+ data = m_data[1][offset]; //0x07; //data & ~(1 << 7);
+ if ((m_sec_2[0x41] & 0x10) == 0)
+ {
+ data = data & ~0x20;
+ }
+ if ((m_sec_2[0x41] & 0x08) == 0)
+ {
+ data = data & ~0x80;
+ }
+ if (m_test != 0)
+ {
+ data = 0x00;
+ }
+ }
+ return data;
+}
+
+UINT8 diskonchip_g3_device::sec_2_read_1046()
+{
+ if (m_test == 0)
+ {
+ UINT32 offset = g3_offset_data_2() + 0x06;
+ return m_data[1][offset];
+ }
+ else
+ {
+ return 0x00;
+ }
+}
+
+UINT8 diskonchip_g3_device::sec_2_read_1048()
+{
+ if (m_test == 0)
+ {
+ UINT32 offset = g3_offset_data_2() + 0x08;
+ return m_data[1][offset];
+ }
+ else
+ {
+ return 0x00;
+ }
+}
+
+UINT8 diskonchip_g3_device::sec_2_read_1049()
+{
+ if (m_test == 0)
+ {
+ UINT32 offset = g3_offset_data_2() + 0x09;
+ return m_data[1][offset];
+ }
+ else
+ {
+ return 0x00;
+ }
+}
+
+UINT8 diskonchip_g3_device::sec_2_read_104A()
+{
+ if (m_test == 0)
+ {
+ UINT32 offset = g3_offset_data_2() + 0x0A;
+ return m_data[1][offset];
+ }
+ else
+ {
+ return 0x00;
+ }
+}
+
+UINT8 diskonchip_g3_device::sec_2_read_104B()
+{
+ if (m_test == 0)
+ {
+ UINT32 offset = g3_offset_data_2() + 0x0B;
+ return m_data[1][offset];
+ }
+ else
+ {
+ return 0x00;
+ }
+}
+
+UINT8 diskonchip_g3_device::sec_2_read_104C()
+{
+ if (m_test == 0)
+ {
+ UINT32 offset = g3_offset_data_2() + 0x0C;
+ return m_data[1][offset];
+ }
+ else
+ {
+ return 0x00;
+ }
+}
+
+UINT8 diskonchip_g3_device::sec_2_read_104D()
+{
+ if (m_test == 0)
+ {
+ UINT32 offset = g3_offset_data_2() + 0x0D;
+ return m_data[1][offset];
+ }
+ else
+ {
+ return 0x00;
+ }
+}
+
+UINT8 diskonchip_g3_device::sec_2_read_104E()
+{
+ if (m_test == 0)
+ {
+ UINT32 offset = g3_offset_data_2() + 0x0E;
+ return m_data[1][offset];
+ }
+ else
+ {
+ return 0x00;
+ }
+}
+
+UINT8 diskonchip_g3_device::sec_2_read_104F()
+{
+ if (m_test == 0)
+ {
+ UINT32 offset = g3_offset_data_2() + 0x0F;
+ return m_data[1][offset];
+ }
+ else
+ {
+ return 0x00;
+ }
+}
+
+UINT8 diskonchip_g3_device::sec_2_read_100E()
+{
+ return 0x81;
+}
+
+UINT8 diskonchip_g3_device::sec_2_read_1014()
+{
+ return 0x01;
+}
+
+UINT8 diskonchip_g3_device::sec_2_read_1022()
+{
+ return 0x85;
+}
+
+UINT8 diskonchip_g3_device::sec_2_read_1038()
+{
+ // bit 0 = ?
+ // bit 1 = ? error 0x7C
+ // bit 2 = ? error 0x73
+ // bit 3 = ?
+ // bit 4 = ?
+ // bit 5 = ?
+ // bit 6 = ?
+ // bit 7 = ?
+ if (m_device == 0)
+ {
+ return 0x19;
+ }
+ else
+ {
+ return 0x38;
+ }
+}
+
+UINT16 diskonchip_g3_device::sec_2_read16(UINT32 offset)
+{
+ UINT16 data = (m_sec_2[offset+0] << 0) + (m_sec_2[offset+1] << 8);
+ switch (0x1000 + offset)
+ {
+ // ?
+ case 0x1000 : data = sec_2_read_1000(); break;
+ // ?
+ case 0x100E : data = sec_2_read_100E(); break;
+ // ?
+ case 0x1014 : data = sec_2_read_1014(); break;
+ // ?
+ case 0x1022 : data = sec_2_read_1022(); break;
+ // flash control
+ case 0x1038 : data = sec_2_read_1038(); break;
+ // flash ?
+ case 0x1042 : data = sec_2_read_1042(); break;
+ // ?
+ case 0x1046 : data = sec_2_read_1046(); break;
+ // ?
+ case 0x1048 : data = (sec_2_read_1048() << 0) + (sec_2_read_1049() << 8); break;
+ case 0x104A : data = (sec_2_read_104A() << 0) + (sec_2_read_104B() << 8); break;
+ case 0x104C : data = (sec_2_read_104C() << 0) + (sec_2_read_104D() << 8); break;
+ case 0x104E : data = (sec_2_read_104E() << 0) + (sec_2_read_104F() << 8); break;
+ // ?
+ case 0x1074 : data = sec_2_read_1074(); break;
+ }
+ verboselog( machine(), 9, "(DOC) %08X -> %04X\n", 0x1000 + offset, data);
+ return data;
+}
+
+UINT8 diskonchip_g3_device::sec_2_read8(UINT32 offset)
+{
+ UINT8 data = m_sec_2[offset];
+ switch (0x1000 + offset)
+ {
+ // ?
+ case 0x100E : data = sec_2_read_100E(); break;
+ // ?
+ case 0x1014 : data = sec_2_read_1014(); break;
+ // ?
+ case 0x1022 : data = sec_2_read_1022(); break;
+ // flash control
+ case 0x1038 : data = sec_2_read_1038(); break;
+ // flash ?
+ case 0x1042 : data = sec_2_read_1042(); break;
+ // ?
+ case 0x1046 : data = sec_2_read_1046(); break;
+ // ?
+ case 0x1048 : data = sec_2_read_1048(); break;
+ case 0x1049 : data = sec_2_read_1049(); break;
+ case 0x104A : data = sec_2_read_104A(); break;
+ case 0x104B : data = sec_2_read_104B(); break;
+ case 0x104C : data = sec_2_read_104C(); break;
+ case 0x104D : data = sec_2_read_104D(); break;
+ case 0x104E : data = sec_2_read_104E(); break;
+ case 0x104F : data = sec_2_read_104F(); break;
+ }
+ verboselog( machine(), 9, "(DOC) %08X -> %02X\n", 0x1000 + offset, data);
+ return data;
+}
+
+void diskonchip_g3_device::sec_2_write_100C(UINT8 data)
+{
+ const char *mode_name[] = { "reset", "normal", "deep power down" };
+ UINT32 mode = data & 3;
+ verboselog( machine(), 5, "mode %d (%s)\n", mode, mode_name[mode]);
+ if (mode == 0)
+ {
+ m_sec_2[0x04] = 00;
+ }
+}
+
+void diskonchip_g3_device::sec_2_write_1032(UINT8 data)
+{
+ verboselog( machine(), 5, "flash select %02X\n", data);
+ if ((data == 0x12) || (data == 0x27))
+ {
+ m_transfer_offset = 0;
+ m_plane = 0;
+ m_block = 0;
+ m_page = 0;
+ }
+}
+
+void diskonchip_g3_device::g3_erase_block()
+{
+ UINT32 offset;
+ int i, j;
+ const UINT8 xxx[] = { 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0xCE, 0x00, 0xCF, 0x72, 0xFC, 0x1B, 0xA9, 0xC7, 0xB9, 0x00 };
+ verboselog( machine(), 5, "erase block %04X\n", m_block);
+ for (i=0;i<m_pages;i++)
+ {
+ m_page = i;
+ for (j=0;j<2;j++)
+ {
+ m_plane = j;
+ offset = g3_offset_data_1();
+ memset( m_data[0] + offset, 0xFF, (m_user_data_size + m_extra_area_size));
+ offset = g3_offset_data_2();
+ memcpy( m_data[1] + offset, xxx, 16);
+ }
+ }
+}
+
+// 'maincpu' (028848E4): diskonchip_sec_2_write_1034: unknown value 60/27
+// 'maincpu' (028848E4): diskonchip_sec_2_write_1034: unknown value D0/27
+// 'maincpu' (028848E4): diskonchip_sec_2_write_1034: unknown value 71/31
+// 'maincpu' (028848E4): diskonchip_sec_2_write_1034: unknown value 80/1D
+// 'maincpu' (028848E4): diskonchip_sec_2_write_1034: unknown value 11/1D
+// 'maincpu' (028848E4): diskonchip_sec_2_write_1034: unknown value 10/1D
+
+void diskonchip_g3_device::sec_2_write_1034(UINT8 data)
+{
+ verboselog( machine(), 5, "flash command %02X\n", data);
+ if ((m_sec_2[0x32] == 0x0E) && (data == 0x00))
+ {
+ m_test = 0;
+ m_address_count = 0;
+ }
+ else if ((m_sec_2[0x32] == 0x10) && (data == 0x50))
+ {
+ m_test = 1;
+ m_address_count = 0;
+ }
+ else if ((m_sec_2[0x32] == 0x03) && (data == 0x3C))
+ {
+ // do nothing
+ }
+ else if ((m_sec_2[0x32] == 0x00) && (data == 0xFF))
+ {
+ m_address_count = 0;
+ }
+ else if (m_sec_2[0x32] == 0x09)
+ {
+ if (data == 0x22)
+ {
+ // do nothing
+ }
+ else if (data == 0xA2)
+ {
+ // do nothing
+ }
+ else
+ {
+ verboselog( machine(), 0, "diskonchip_sec_2_write_1034: unknown value %02X/%02X\n", data, m_sec_2[0x32]);
+ }
+ }
+ else if (m_sec_2[0x32] == 0x12)
+ {
+ if (data == 0x60)
+ {
+ m_data_1036 = 0;
+ m_data_1036_count = 0;
+ m_address_count++;
+ }
+ else if (data == 0x30)
+ {
+ // do nothing
+ }
+ else if (data == 0x05)
+ {
+ // do nothing
+ }
+ else if (data == 0xE0)
+ {
+ // do nothing
+ }
+ else
+ {
+ verboselog( machine(), 0, "diskonchip_sec_2_write_1034: unknown value %02X/%02X\n", data, m_sec_2[0x32]);
+ }
+ }
+ else if (m_sec_2[0x32] == 0x27)
+ {
+ if (data == 0x60)
+ {
+ m_data_1036 = 0;
+ m_data_1036_count = 0;
+ m_address_count++;
+ }
+ else if (data == 0xD0)
+ {
+ g3_erase_block();
+ }
+ else
+ {
+ verboselog( machine(), 0, "diskonchip_sec_2_write_1034: unknown value %02X/%02X\n", data, m_sec_2[0x32]);
+ }
+ }
+ else if ((m_sec_2[0x32] == 0x31) && (data == 0x71))
+ {
+ // erase block status? (after: read one byte from 08xx, bit 0/1/2 is checked)
+ m_test = 2;
+ }
+ else if (m_sec_2[0x32] == 0x1D)
+ {
+ if (data == 0x80)
+ {
+ m_data_1036 = 0;
+ m_data_1036_count = 0;
+ m_address_count++;
+ }
+ else if (data == 0x11)
+ {
+ m_test = 3;
+ }
+ else
+ {
+ verboselog( machine(), 0, "diskonchip_sec_2_write_1034: unknown value %02X/%02X\n", data, m_sec_2[0x32]);
+ }
+ }
+ else
+ {
+ verboselog( machine(), 0, "diskonchip_sec_2_write_1034: unknown value %02X/%02X\n", data, m_sec_2[0x32]);
+ }
+}
+
+void diskonchip_g3_device::sec_2_write_1036(UINT8 data)
+{
+ if (m_sec_2[0x34] == 0x60)
+ {
+ m_data_1036 |= data << (8 * m_data_1036_count++);
+ if (m_data_1036_count == 3)
+ {
+ UINT32 block, page, plane;
+ block = (m_data_1036 >> 7);
+ if (block >= m_blocks) fatalerror( "DOCG3: invalid block (%d)", block);
+ plane = (m_data_1036 >> 6) & 1;
+ page = (m_data_1036 >> 0) & 0x3F;
+ verboselog( machine(), 5, "flash address %d - %06X (plane %d block %04X page %04X)\n", m_address_count, m_data_1036, plane, block, page);
+ if (m_address_count == 1)
+ {
+ m_plane = 0;
+ m_block = block;
+ m_page = page;
+ }
+ }
+ }
+ else if (m_sec_2[0x34] == 0x80)
+ {
+ m_data_1036 |= data << (8 * m_data_1036_count++);
+ if (m_data_1036_count == 4)
+ {
+ UINT32 block, page, plane, unk;
+ block = (m_data_1036 >> 15);
+ plane = (m_data_1036 >> 14) & 1;
+ page = (m_data_1036 >> 8) & 0x3F;
+ unk = (m_data_1036 >> 0) & 0xFF;
+ verboselog( machine(), 5, "flash address %d - %08X (plane %d block %04X page %04X unk %02X)\n", m_address_count, m_data_1036, plane, block, page, unk);
+ if (m_address_count == 1)
+ {
+ m_plane = 0;
+ m_block = block;
+ m_page = page;
+ m_transfer_offset = 0;
+ }
+ }
+ }
+ else if (m_sec_2[0x34] == 0x05)
+ {
+ m_transfer_offset = data << 2;
+ verboselog( machine(), 5, "flash transfer offset %04X\n", m_transfer_offset);
+ }
+}
+
+void diskonchip_g3_device::sec_2_write_1040(UINT16 data)
+{
+ m_transfersize = (data & 0x3FF);
+ verboselog( machine(), 5, "flash transfer size %04X\n", m_transfersize);
+}
+
+void diskonchip_g3_device::sec_2_write_100A(UINT8 data)
+{
+ m_device = data & 3;
+ verboselog( machine(), 5, "select device %d\n", m_device);
+}
+
+void diskonchip_g3_device::sec_2_write16(UINT32 offset, UINT16 data)
+{
+ m_sec_2[offset+0] = (data >> 0) & 0xFF;
+ m_sec_2[offset+1] = (data >> 8) & 0xFF;
+ verboselog( machine(), 9, "(DOC) %08X <- %04X\n", 0x1000 + offset, data);
+ switch (0x1000 + offset)
+ {
+ // ?
+ case 0x100C : sec_2_write_100C(data); break;
+ // Device ID Select Register
+ case 0x100A : sec_2_write_100A(data); break;
+ // flash select
+ case 0x1032 : sec_2_write_1032(data); break;
+ // flash command
+ case 0x1034 : sec_2_write_1034(data); break;
+ // flash address
+ case 0x1036 : sec_2_write_1036(data); break;
+ // ?
+ case 0x1040 : sec_2_write_1040(data); break;
+ }
+}
+
+void diskonchip_g3_device::sec_2_write8(UINT32 offset, UINT8 data)
+{
+ m_sec_2[offset] = data;
+ verboselog( machine(), 9, "(DOC) %08X <- %02X\n", 0x1000 + offset, data);
+ switch (0x1000 + offset)
+ {
+ // ?
+ case 0x100C : sec_2_write_100C(data); break;
+ // Device ID Select Register
+ case 0x100A : sec_2_write_100A(data); break;
+ // flash select
+ case 0x1032 : sec_2_write_1032(data); break;
+ // flash command
+ case 0x1034 : sec_2_write_1034(data); break;
+ // flash address
+ case 0x1036 : sec_2_write_1036(data); break;
+ }
+}
+
+READ16_MEMBER( diskonchip_g3_device::sec_2_r )
+{
+ if (mem_mask == 0xffff)
+ {
+ return sec_2_read16(offset * 2);
+ }
+ else if (mem_mask == 0x00ff)
+ {
+ return sec_2_read8(offset * 2 + 0) << 0;
+ }
+ else if (mem_mask == 0xff00)
+ {
+ return sec_2_read8( offset * 2 + 1) << 8;
+ }
+ else
+ {
+ verboselog( machine(), 0, "diskonchip_g3_sec_2_r: unknown mem_mask %08X\n", mem_mask);
+ return 0;
+ }
+}
+
+WRITE16_MEMBER( diskonchip_g3_device::sec_2_w )
+{
+ if (mem_mask == 0xffff)
+ {
+ sec_2_write16(offset * 2, data);
+ }
+ else if (mem_mask == 0x00ff)
+ {
+ sec_2_write8(offset * 2 + 0, (data >> 0) & 0xFF);
+ }
+ else if (mem_mask == 0xff00)
+ {
+ sec_2_write8(offset * 2 + 1, (data >> 8) & 0xFF);
+ }
+ else
+ {
+ verboselog( machine(), 0, "diskonchip_g3_sec_2_w: unknown mem_mask %08X\n", mem_mask);
+ }
+}
+
+READ16_MEMBER( diskonchip_g3_device::sec_3_r )
+{
+ UINT16 data = 0;
+ verboselog( machine(), 9, "(DOC) %08X -> %04X\n", 0x1800 + (offset << 1), data);
+ return data;
+}
+
+WRITE16_MEMBER( diskonchip_g3_device::sec_3_w )
+{
+ verboselog( machine(), 9, "(DOC) %08X <- %02X\n", 0x1800 + (offset << 1), data);
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+void diskonchip_g3_device::device_start()
+{
+ verboselog( machine(), 9, "(DOC) device start\n");
+
+ switch (m_size)
+ {
+ case 64 :
+ {
+ m_planes = 2;
+ m_blocks = 1024;
+ m_pages = 64;
+ m_user_data_size = 512;
+ m_extra_area_size = 16;
+ }
+ break;
+ }
+
+ m_data_size[0] = m_planes * m_blocks * m_pages * (m_user_data_size + m_extra_area_size);
+ m_data_size[1] = m_planes * m_blocks * m_pages * 16;
+ m_data_size[2] = m_blocks * 8;
+
+ m_data[0] = auto_alloc_array( machine(), UINT8, m_data_size[0]);
+ m_data[1] = auto_alloc_array( machine(), UINT8, m_data_size[1]);
+ m_data[2] = auto_alloc_array( machine(), UINT8, m_data_size[2]);
+
+// diskonchip_load( device, "diskonchip");
+
+ save_item( NAME(m_planes));
+ save_item( NAME(m_blocks));
+ save_item( NAME(m_pages));
+ save_item( NAME(m_user_data_size));
+ save_item( NAME(m_extra_area_size));
+ save_pointer( NAME(m_data[0]), m_data_size[0]);
+ save_pointer( NAME(m_data[1]), m_data_size[1]);
+ save_pointer( NAME(m_data[2]), m_data_size[2]);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void diskonchip_g3_device::device_reset()
+{
+ verboselog( machine(), 9, "(DOC) device reset\n");
+}
+
+//-------------------------------------------------
+// nvram_default - called to initialize NVRAM to
+// its default state
+//-------------------------------------------------
+
+void diskonchip_g3_device::nvram_default()
+{
+ memset(m_data[0], 0xFF, m_data_size[0]);
+ memset(m_data[1], 0x00, m_data_size[1]);
+ memset(m_data[2], 0xFF, m_data_size[2]);
+}
+
+//-------------------------------------------------
+// nvram_read - called to read NVRAM from the
+// .nv file
+//-------------------------------------------------
+
+void diskonchip_g3_device::nvram_read(emu_file &file)
+{
+ file.read(m_data[0], m_data_size[0]);
+ file.read(m_data[1], m_data_size[1]);
+ file.read(m_data[2], m_data_size[2]);
+}
+
+//-------------------------------------------------
+// nvram_write - called to write NVRAM to the
+// .nv file
+//-------------------------------------------------
+
+void diskonchip_g3_device::nvram_write(emu_file &file)
+{
+ file.write(m_data[0], m_data_size[0]);
+ file.write(m_data[1], m_data_size[1]);
+ file.write(m_data[2], m_data_size[2]);
+}
diff --git a/src/mess/machine/docg3.h b/src/mess/machine/docg3.h
new file mode 100644
index 00000000000..b50a2ff2529
--- /dev/null
+++ b/src/mess/machine/docg3.h
@@ -0,0 +1,103 @@
+/*
+
+ M-Systems DiskOnChip G3 - Flash Disk with MLC NAND and M-Systems? x2 Technology
+
+ (c) 2009 Tim Schuerewegen
+
+*/
+
+#ifndef __DOCG3_H__
+#define __DOCG3_H__
+
+#include "devlegcy.h"
+
+#define MCFG_DISKONCHIP_G3_ADD(_tag, _size) \
+ MCFG_DEVICE_ADD(_tag, DISKONCHIP_G3, 0) \
+ static_cast<diskonchip_g3_device *>(device)->set_size(_size);
+
+// ======================> diskonchip_g3_device
+
+class diskonchip_g3_device : public device_t,
+ public device_nvram_interface
+{
+public:
+ // construction/destruction
+ diskonchip_g3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ void set_size(int _size) { m_size = _size; }
+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);
+public:
+ DECLARE_READ16_MEMBER( sec_1_r );
+ DECLARE_WRITE16_MEMBER( sec_1_w );
+ DECLARE_READ16_MEMBER( sec_2_r );
+ DECLARE_WRITE16_MEMBER( sec_2_w );
+ DECLARE_READ16_MEMBER( sec_3_r );
+ DECLARE_WRITE16_MEMBER( sec_3_w );
+private:
+ UINT32 g3_offset_data_1();
+ UINT32 g3_offset_data_2();
+ UINT32 g3_offset_data_3();
+ UINT8 g3_read_data();
+ void g3_write_data(UINT8 data);
+ UINT16 sec_2_read_1000();
+ UINT16 sec_2_read_1074();
+ UINT8 sec_2_read_1042();
+ UINT8 sec_2_read_1046();
+ UINT8 sec_2_read_1048();
+ UINT8 sec_2_read_1049();
+ UINT8 sec_2_read_104A();
+ UINT8 sec_2_read_104B();
+ UINT8 sec_2_read_104C();
+ UINT8 sec_2_read_104D();
+ UINT8 sec_2_read_104E();
+ UINT8 sec_2_read_104F();
+ UINT8 sec_2_read_100E();
+ UINT8 sec_2_read_1014();
+ UINT8 sec_2_read_1022();
+ UINT8 sec_2_read_1038();
+ UINT16 sec_2_read16(UINT32 offset);
+ UINT8 sec_2_read8(UINT32 offset);
+ void sec_2_write_100C(UINT8 data);
+ void sec_2_write_1032(UINT8 data);
+ void g3_erase_block();
+ void sec_2_write_1034(UINT8 data);
+ void sec_2_write_1036(UINT8 data);
+ void sec_2_write_1040(UINT16 data);
+ void sec_2_write_100A(UINT8 data);
+ void sec_2_write16(UINT32 offset, UINT16 data);
+ void sec_2_write8(UINT32 offset, UINT8 data);
+
+ int m_size;
+
+ UINT32 m_planes;
+ UINT32 m_blocks;
+ UINT32 m_pages;
+ UINT32 m_user_data_size;
+ UINT32 m_extra_area_size;
+ UINT8 *m_data[3];
+ UINT32 m_data_size[3];
+ UINT8 m_sec_2[0x800];
+ UINT32 m_data_1036;
+ UINT32 m_data_1036_count;
+ UINT32 m_transfer_offset;
+ UINT8 m_device;
+ UINT32 m_block;
+ UINT32 m_page;
+ UINT32 m_plane;
+ UINT32 m_transfersize;
+ UINT8 m_test;
+ UINT32 m_address_count;
+};
+
+// device type definition
+extern const device_type DISKONCHIP_G3;
+
+#endif /* __DOCG3_H__ */
diff --git a/src/mess/machine/dp8390.c b/src/mess/machine/dp8390.c
new file mode 100644
index 00000000000..c6b7fe696af
--- /dev/null
+++ b/src/mess/machine/dp8390.c
@@ -0,0 +1,479 @@
+#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<dp8390d_device>;
+const device_type RTL8019A = &device_creator<rtl8019a_device>;
+
+void dp8390_device::device_config_complete() {
+ const dp8390_interface *intf = reinterpret_cast<const dp8390_interface *>(static_config());
+ if(intf != NULL)
+ *static_cast<dp8390_interface *>(this) = *intf;
+ else {
+ memset(&irq_cb, 0, sizeof(irq_cb));
+ memset(&breq_cb, 0, sizeof(breq_cb));
+ memset(&mem_read_cb, 0, sizeof(mem_read_cb));
+ memset(&mem_write_cb, 0, sizeof(mem_write_cb));
+ }
+}
+
+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) {
+ 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) {
+ 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)
+ : device_t(mconfig, type, name, tag, owner, clock),
+ device_network_interface(mconfig, *this, bandwidth) {
+}
+
+void dp8390_device::device_start() {
+ irq_func.resolve(irq_cb, *this);
+ breq_func.resolve(breq_cb, *this);
+ mem_read.resolve(mem_read_cb, *this);
+ mem_write.resolve(mem_write_cb, *this);
+}
+
+void dp8390_device::stop() {
+ m_regs.isr = 0x80; // is this right?
+ m_regs.cr |= 1;
+ irq_func(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;
+ irq_func(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() {
+ UINT8 *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 = global_alloc_array(UINT8, m_regs.tbcr);
+ for(i = 0; i < m_regs.tbcr; i++) buf[i] = mem_read(high16 + (m_regs.tpsr << 8) + i);
+
+ if(send(buf, 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();
+ global_free(buf);
+}
+
+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(!(m_regs.rcr & 4) && !memcmp((const char *)buf, "\xff\xff\xff\xff\xff\xff", 6)) return;
+ m_regs.rsr = 0x20;
+ } else m_regs.rsr = 0;
+ len &= 0xffff;
+
+ for(i = 0; i < len; i++) {
+ mem_write(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();
+ }
+ }
+ 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;
+ mem_write(start, m_regs.rsr);
+ mem_write(start+1, m_regs.curr);
+ mem_write(start+2, len & 0xff);
+ mem_write(start+3, len >> 8);
+ check_irq();
+}
+
+void dp8390_device::recv_cb(UINT8 *buf, int len) {
+ if(!LOOPBACK) recv(buf, len);
+}
+
+bool dp8390_device::mcast_chk(const UINT8 *buf, int len) {
+ if(!(m_regs.rcr & 8)) return false;
+
+ return false; // TODO: multicast
+}
+
+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 = mem_read(high16 + m_regs.crda++);
+ data |= mem_read(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 = mem_read(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;
+ default:
+ if(m_type == TYPE_RTL8019A) {
+ switch((offset & 0x0f)|(m_regs.cr & 0xc0)) {
+ case 0x0a:
+ data = 'P';
+ break;
+ case 0x0b:
+ data = 'p';
+ break;
+ case 0xc0:
+ data = m_regs.cr;
+ 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;
+ mem_write(high16 + m_regs.crda++, data & 0xff);
+ mem_write(high16 + m_regs.crda++, data >> 8);
+ m_regs.rbcr -= (m_regs.rbcr < 2)?m_regs.rbcr:2;
+ check_dma_complete();
+ } else {
+ data &= 0xff;
+ mem_write(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;
+ default:
+ if(m_type == TYPE_RTL8019A) {
+ switch((offset & 0x0f)|(m_regs.cr & 0xc0)) {
+ case 0xc0:
+ set_cr(data);
+ break;
+ // 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/mess/machine/dp8390.h b/src/mess/machine/dp8390.h
new file mode 100644
index 00000000000..dae75a36229
--- /dev/null
+++ b/src/mess/machine/dp8390.h
@@ -0,0 +1,132 @@
+#ifndef _DP8390_H_
+#define _DP8390_H_
+
+#include "emu.h"
+
+struct dp8390_interface
+{
+ devcb_write_line irq_cb;
+ devcb_write_line breq_cb;
+ devcb_read8 mem_read_cb;
+ devcb_write8 mem_write_cb;
+};
+
+// device stuff
+#define MCFG_DP8390D_ADD(_tag, _intrf) \
+ MCFG_DEVICE_ADD(_tag, DP8390D, 0) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#define MCFG_RTL8019A_ADD(_tag, _intrf) \
+ MCFG_DEVICE_ADD(_tag, RTL8019A, 0) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+class dp8390_device : public device_t,
+ public device_network_interface,
+ public dp8390_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);
+
+ 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);
+ bool mcast_chk(const UINT8* buf, int len);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete();
+ int m_type;
+
+ enum {
+ TYPE_DP8390D = 0,
+ TYPE_RTL8019A
+ };
+
+private:
+ devcb_resolved_write_line irq_func;
+ devcb_resolved_write_line breq_func;
+ devcb_resolved_read8 mem_read;
+ devcb_resolved_write8 mem_write;
+
+ void set_cr(UINT8 newcr);
+ void check_dma_complete();
+ void do_tx();
+ bool mcast_ck(const UINT8 *buf, int len);
+ void check_irq() { irq_func((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/mess/machine/dragon.c b/src/mess/machine/dragon.c
new file mode 100644
index 00000000000..f66ae22854b
--- /dev/null
+++ b/src/mess/machine/dragon.c
@@ -0,0 +1,175 @@
+/***************************************************************************
+
+ dragon.h
+
+ Dragon Family
+
+Dragon Alpha code added 21-Oct-2004,
+ Phill Harvey-Smith (afra@aurigae.demon.co.uk)
+
+ Added AY-8912 and FDC code 30-Oct-2004.
+
+Fixed Dragon Alpha NMI enable/disable, following circuit traces on a real machine.
+ P.Harvey-Smith, 11-Aug-2005.
+
+Re-implemented Alpha NMI enable/disable, using direct PIA reads, rather than
+keeping track of it in a variable in the driver.
+ P.Harvey-Smith, 25-Sep-2006.
+
+Radically re-wrote memory emulation code for CoCo 1/2 & Dragon machines, the
+new code emulates the memory mapping of the SAM, dependent on what size of
+RAM chips it is programed to use, including proper mirroring of the RAM.
+
+Replaced the kludged emulation of the cart line, with a timer based trigger
+this is set to toggle at 1Hz, this seems to be good enough to trigger the
+cartline, but is so slow in real terms that it should have very little
+impact on the emulation speed.
+
+Re-factored the code common to all machines, and seperated the code different,
+into callbacks/functions unique to the machines, in preperation for splitting
+the code for individual machine types into seperate files, I have preposed, that
+the CoCo 1/2 should stay in coco.c, and that the coco3 and dragon specifc code
+should go into coco3.c and dragon.c which should (hopefully) make the code
+easier to manage.
+ P.Harvey-Smith, Dec 2006-Feb 2007
+
+***************************************************************************/
+
+#include "includes/dragon.h"
+
+
+/***************************************************************************
+ DRAGON32
+***************************************************************************/
+
+//-------------------------------------------------
+// ctor
+//-------------------------------------------------
+
+dragon_state::dragon_state(const machine_config &mconfig, device_type type, const char *tag)
+ : coco12_state(mconfig, type, tag),
+ m_printer(*this, PRINTER_TAG)
+{
+}
+
+
+
+//-------------------------------------------------
+// pia1_pa_changed - called when PIA1 PA changes
+//-------------------------------------------------
+
+void dragon_state::pia1_pa_changed(void)
+{
+ /* call inherited function */
+ coco12_state::pia1_pa_changed();
+
+ /* if strobe bit is high send data from pia0 port b to dragon parallel printer */
+ if (m_pia_1->a_output() & 0x02)
+ {
+ UINT8 output = m_pia_1->b_output();
+ m_printer->output(output);
+ }
+}
+
+
+/***************************************************************************
+ DRAGON64
+***************************************************************************/
+
+//-------------------------------------------------
+// ctor
+//-------------------------------------------------
+
+dragon64_state::dragon64_state(const machine_config &mconfig, device_type type, const char *tag)
+ : dragon_state(mconfig, type, tag),
+ m_acia(*this, ACIA_TAG)
+{
+}
+
+
+
+//-------------------------------------------------
+// ff00_read
+//-------------------------------------------------
+
+READ8_MEMBER( dragon64_state::ff00_read )
+{
+ UINT8 result = 0x00;
+
+ switch(offset & 0x07)
+ {
+ case 0: case 1: case 2: case 3:
+ result = dragon_state::ff00_read(space, offset, mem_mask);
+ break;
+
+ case 4: case 5: case 6: case 7:
+ result = m_acia->read(space, offset, mem_mask);
+ break;
+ }
+ return result;
+}
+
+
+
+//-------------------------------------------------
+// ff00_write
+//-------------------------------------------------
+
+WRITE8_MEMBER( dragon64_state::ff00_write )
+{
+ switch(offset & 0x07)
+ {
+ case 0: case 1: case 2: case 3:
+ dragon_state::ff00_write(space, offset, data, mem_mask);
+ break;
+
+ case 4: case 5: case 6: case 7:
+ m_acia->write(space, offset, data, mem_mask);
+ break;
+ }
+}
+
+
+
+//-------------------------------------------------
+// pia1_pb_changed
+//-------------------------------------------------
+
+void dragon64_state::pia1_pb_changed(void)
+{
+ dragon_state::pia1_pb_changed();
+
+ UINT8 ddr = ~m_pia_1->port_b_z_mask();
+
+ /* If bit 2 of the pia1 ddrb is 1 then this pin is an output so use it */
+ /* to control the paging of the 32k and 64k basic roms */
+ /* Otherwise it set as an input, with an EXTERNAL pull-up so it should */
+ /* always be high (enabling 32k basic rom) */
+ if (ddr & 0x04)
+ {
+ page_rom(m_pia_1->b_output() & 0x04 ? true : false);
+ }
+}
+
+
+
+//-------------------------------------------------
+// page_rom - Controls rom paging in Dragon 64,
+// and Dragon Alpha.
+//
+// On 64, switches between the two versions of the
+// basic rom mapped in at 0x8000
+//
+// On the alpha switches between the
+// Boot/Diagnostic rom and the basic rom
+//-------------------------------------------------
+
+void dragon64_state::page_rom(bool romswitch)
+{
+ offs_t offset = romswitch
+ ? 0x0000 // This is the 32k mode basic(64)/boot rom(alpha)
+ : 0x8000; // This is the 64k mode basic(64)/basic rom(alpha)
+ m_sam->set_bank_offset(1, offset);
+ m_sam->set_bank_offset(2, offset);
+ m_sam->set_bank_offset(3, offset);
+}
diff --git a/src/mess/machine/ds1315.c b/src/mess/machine/ds1315.c
new file mode 100644
index 00000000000..4bdea7e9a88
--- /dev/null
+++ b/src/mess/machine/ds1315.c
@@ -0,0 +1,268 @@
+/*********************************************************************
+
+ ds1315.c
+
+ Dallas Semiconductor's Phantom Time Chip DS1315.
+
+ by tim lindner, November 2001.
+
+*********************************************************************/
+
+#include "ds1315.h"
+#include "coreutil.h"
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef enum
+{
+ DS_SEEK_MATCHING,
+ DS_CALENDAR_IO
+} ds1315_mode_t;
+
+
+typedef struct _ds1315_t ds1315_t;
+struct _ds1315_t
+{
+ int count;
+ ds1315_mode_t mode;
+ UINT8 raw_data[8*8];
+};
+
+
+/***************************************************************************
+ 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
+};
+
+
+/***************************************************************************
+ PROTOTYPES
+***************************************************************************/
+
+static void ds1315_fill_raw_data(device_t *device);
+static void ds1315_input_raw_data(device_t *device);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+INLINE ds1315_t *get_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == DS1315);
+ return (ds1315_t *) downcast<legacy_device_base *>(device)->token();
+}
+
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ DEVICE_START( ds1315 )
+-------------------------------------------------*/
+
+static DEVICE_START(ds1315)
+{
+ ds1315_t *ds1315 = get_token(device);
+
+ memset(ds1315, 0, sizeof(*ds1315));
+ ds1315->count = 0;
+ ds1315->mode = DS_SEEK_MATCHING;
+}
+
+
+/*-------------------------------------------------
+ DEVICE_START( ds1315 )
+-------------------------------------------------*/
+
+READ8_DEVICE_HANDLER( ds1315_r_0 )
+{
+ ds1315_t *ds1315 = get_token(device);
+
+ if (ds1315_pattern[ds1315->count++] == 0)
+ {
+ if (ds1315->count == 64)
+ {
+ /* entire pattern matched */
+ ds1315->count = 0;
+ ds1315->mode = DS_CALENDAR_IO;
+ ds1315_fill_raw_data(device);
+ }
+
+ return 0;
+ }
+
+ ds1315->count = 0;
+ ds1315->mode = DS_SEEK_MATCHING;
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ ds1315_r_1
+-------------------------------------------------*/
+
+READ8_DEVICE_HANDLER ( ds1315_r_1 )
+{
+ ds1315_t *ds1315 = get_token(device);
+
+ if (ds1315_pattern[ ds1315->count++ ] == 1)
+ {
+ ds1315->count %= 64;
+ return 0;
+ }
+
+ ds1315->count = 0;
+ ds1315->mode = DS_SEEK_MATCHING;
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ ds1315_r_data
+-------------------------------------------------*/
+
+READ8_DEVICE_HANDLER ( ds1315_r_data )
+{
+ UINT8 result;
+ ds1315_t *ds1315 = get_token(device);
+
+ if (ds1315->mode == DS_CALENDAR_IO)
+ {
+ result = ds1315->raw_data[ ds1315->count++ ];
+
+ if (ds1315->count == 64)
+ {
+ ds1315->mode = DS_SEEK_MATCHING;
+ ds1315->count = 0;
+ }
+
+ return result;
+ }
+
+ ds1315->count = 0;
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ ds1315_w_data
+-------------------------------------------------*/
+
+WRITE8_DEVICE_HANDLER ( ds1315_w_data )
+{
+ ds1315_t *ds1315 = get_token(device);
+
+ if (ds1315->mode == DS_CALENDAR_IO)
+ {
+ ds1315->raw_data[ds1315->count++] = data & 0x01;
+
+ if (ds1315->count == 64)
+ {
+ ds1315->mode = DS_SEEK_MATCHING;
+ ds1315->count = 0;
+ ds1315_input_raw_data(device);
+ }
+ return;
+ }
+
+ ds1315->count = 0;
+}
+
+
+/*-------------------------------------------------
+ ds1315_fill_raw_data
+-------------------------------------------------*/
+
+static void ds1315_fill_raw_data(device_t *device)
+{
+ /* This routine will (hopefully) call a standard 'C' library routine to get the current
+ date and time and then fill in the raw data struct.
+ */
+
+ system_time systime;
+ ds1315_t *ds1315 = get_token(device);
+ int raw[8], i, j;
+
+ /* get the current date/time from the core */
+ device->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;
+ ds1315->raw_data[i] = (raw[j] & 0x0001);
+ raw[j] = raw[j] >> 1;
+ }
+}
+
+
+/*-------------------------------------------------
+ ds1315_input_raw_data
+-------------------------------------------------*/
+
+static void ds1315_input_raw_data(device_t *device)
+{
+ /* This 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.
+
+ We always return the host's time when asked.
+ */
+}
+
+
+/*-------------------------------------------------
+ DEVICE_GET_INFO( ds1315 )
+-------------------------------------------------*/
+
+DEVICE_GET_INFO( ds1315 )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(ds1315_t); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(ds1315); break;
+ case DEVINFO_FCT_STOP: /* Nothing */ break;
+ case DEVINFO_FCT_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "Dallas Semiconductor DS1315"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "Dallas Semiconductor DS1315"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: /* Nothing */ break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(DS1315, ds1315);
diff --git a/src/mess/machine/ds1315.h b/src/mess/machine/ds1315.h
new file mode 100644
index 00000000000..29cd248a46c
--- /dev/null
+++ b/src/mess/machine/ds1315.h
@@ -0,0 +1,42 @@
+/*********************************************************************
+
+ ds1315.h
+
+ Dallas Semiconductor's Phantom Time Chip DS1315.
+
+ by tim lindner, November 2001.
+
+*********************************************************************/
+
+#ifndef __DS1315_H__
+#define __DS1315_H__
+
+#include "emu.h"
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+DECLARE_LEGACY_DEVICE(DS1315, ds1315);
+
+
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+#define MCFG_DS1315_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, DS1315, 0)
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+READ8_DEVICE_HANDLER( ds1315_r_0 );
+READ8_DEVICE_HANDLER( ds1315_r_1 );
+READ8_DEVICE_HANDLER( ds1315_r_data );
+WRITE8_DEVICE_HANDLER( ds1315_w_data );
+
+#endif /* __DS1315_H__ */
diff --git a/src/mess/machine/e01.c b/src/mess/machine/e01.c
new file mode 100644
index 00000000000..df6ed750491
--- /dev/null
+++ b/src/mess/machine/e01.c
@@ -0,0 +1,824 @@
+/**********************************************************************
+
+ Acorn FileStore E01/E01S network hard disk emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+ 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:
+
+ - memory_bank::set_entry called for bank ':econet254:e01s:bank2' with invalid bank entry 0
+ - 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 "machine/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<e01_device>;
+const device_type E01S = &device_creator<e01s_device>;
+
+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) { 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();
+}
+
+static mc146818_interface rtc_intf =
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, e01_device, rtc_irq_w)
+};
+
+
+//-------------------------------------------------
+// mc6854_interface adlc_intf
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( e01_device::adlc_irq_w )
+{
+ m_adlc_irq = state;
+
+ update_interrupts();
+}
+
+READ_LINE_MEMBER( e01_device::econet_data_r )
+{
+ return m_econet->data_r();
+}
+
+WRITE_LINE_MEMBER( e01_device::econet_data_w )
+{
+ m_econet->data_w(this, state);
+}
+
+static const mc6854_interface adlc_intf =
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, e01_device, adlc_irq_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, e01_device, econet_data_r),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, e01_device, econet_data_w),
+ NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// via6522_interface via_intf
+//-------------------------------------------------
+
+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 const via6522_interface via_intf =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+
+ DEVCB_DEVICE_MEMBER(CENTRONICS_TAG, centronics_device, write),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, e01_device, via_irq_w)
+};
+
+
+//-------------------------------------------------
+// floppy_interface e01_floppy_interface
+//-------------------------------------------------
+
+static const floppy_interface e01_floppy_interface =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ FLOPPY_STANDARD_3_5_DSDD, // NEC FD1036 A
+ LEGACY_FLOPPY_OPTIONS_NAME(default),
+ NULL,
+ NULL
+};
+
+
+//-------------------------------------------------
+// wd17xx_interface fdc_intf
+//-------------------------------------------------
+
+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();
+}
+
+static const wd17xx_interface fdc_intf =
+{
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, e01_device, fdc_irq_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, e01_device, fdc_drq_w),
+ { FLOPPY_0, FLOPPY_1, NULL, NULL }
+};
+
+
+//-------------------------------------------------
+// SCSIBus_interface scsi_intf
+//-------------------------------------------------
+
+static const SCSIConfigTable scsi_dev_table =
+{
+ 1,
+ {
+ { SCSI_ID_0, "harddisk0" }
+ }
+};
+
+WRITE_LINE_MEMBER( e01_device::scsi_bsy_w )
+{
+ if (!state)
+ {
+ scsi_sel_w(m_scsibus, 1);
+ }
+}
+
+WRITE_LINE_MEMBER( e01_device::scsi_req_w )
+{
+ if (state)
+ {
+ scsi_ack_w(m_scsibus, 1);
+ }
+
+ m_hdc_irq = !state;
+ update_interrupts();
+}
+
+static const SCSIBus_interface scsi_intf =
+{
+ &scsi_dev_table,
+ NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, e01_device, scsi_bsy_w),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, e01_device, scsi_req_w),
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// centronics_interface e01_centronics_intf
+//-------------------------------------------------
+
+static centronics_interface e01_centronics_intf =
+{
+ DEVCB_DEVICE_LINE_MEMBER(R6522_TAG, via6522_device, write_ca1),
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( e01_mem )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( e01_mem, AS_PROGRAM, 8, e01_device )
+ AM_RANGE(0x0000, 0xfbff) AM_READ_BANK("bank1") AM_WRITE_BANK("bank2")
+ 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_LEGACY(WD2793_TAG, wd17xx_r, wd17xx_w)
+ AM_RANGE(0xfc10, 0xfc1f) AM_MIRROR(0x00c0) AM_DEVREADWRITE(R6522_TAG, via6522_device, read, write)
+ AM_RANGE(0xfc20, 0xfc23) AM_MIRROR(0x00c0) AM_DEVREADWRITE_LEGACY(MC6854_TAG, mc6854_r, mc6854_w)
+ 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_READ(hdc_status_r)
+ 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)
+ AM_RANGE(0xfd00, 0xffff) AM_READ_BANK("bank3") AM_WRITE_BANK("bank4")
+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_IRQ_ADD(HD146818_TAG, MC146818_STANDARD, rtc_intf)
+
+ // devices
+ MCFG_VIA6522_ADD(R6522_TAG, XTAL_8MHz/4, via_intf)
+ MCFG_MC6854_ADD(MC6854_TAG, adlc_intf)
+ MCFG_WD2793_ADD(WD2793_TAG, fdc_intf)
+ MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(e01_floppy_interface)
+ MCFG_CENTRONICS_PRINTER_ADD(CENTRONICS_TAG, e01_centronics_intf)
+
+ MCFG_SCSIBUS_ADD(SCSIBUS_TAG, scsi_intf)
+ MCFG_DEVICE_ADD("harddisk0", SCSIHD, 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),
+ 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_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)
+ : device_t(mconfig, type, name, tag, owner, clock),
+ 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_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_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void e01_device::device_config_complete()
+{
+ switch (m_variant)
+ {
+ default:
+ case TYPE_E01:
+ m_shortname = "e01";
+ break;
+
+ case TYPE_E01S:
+ m_shortname = "e01s";
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void e01_device::device_start()
+{
+ // setup memory banking
+ UINT8 *ram = m_ram->pointer();
+ UINT8 *rom = memregion(R65C102_TAG)->base();
+
+ membank("bank1")->configure_entry(0, ram);
+ membank("bank1")->configure_entry(1, rom);
+ membank("bank1")->set_entry(1);
+
+ membank("bank2")->configure_entry(0, ram);
+// membank("bank2")->set_entry(0);
+
+ membank("bank3")->configure_entry(0, ram + 0xfd00);
+ membank("bank3")->configure_entry(1, rom + 0xfd00);
+ membank("bank3")->set_entry(1);
+
+ membank("bank4")->configure_entry(0, ram + 0xfd00);
+ membank("bank4")->set_entry(0);
+
+ // 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()
+{
+ init_scsibus(m_scsibus, 512);
+
+ m_clk_timer->adjust(attotime::zero, 0, attotime::from_hz(200000));
+
+ membank("bank1")->set_entry(1);
+ membank("bank3")->set_entry(1);
+}
+
+
+//-------------------------------------------------
+// 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);
+ }
+}
+
+
+//-------------------------------------------------
+// eprom_r - ROM/RAM select read
+//-------------------------------------------------
+
+READ8_MEMBER( e01_device::ram_select_r )
+{
+ membank("bank1")->set_entry(0);
+ membank("bank3")->set_entry(0);
+
+ 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 1 select
+ if (!BIT(data, 0)) wd17xx_set_drive(m_fdc, 0);
+
+ // floppy 2 select
+ if (!BIT(data, 1)) wd17xx_set_drive(m_fdc, 1);
+
+ // floppy side select
+ wd17xx_set_side(m_fdc, BIT(data, 2));
+
+ // TODO NVRAM select
+ //mc146818_stby_w(m_rtc, BIT(data, 3));
+
+ // floppy density
+ wd17xx_dden_w(m_fdc, BIT(data, 4));
+
+ // floppy master reset
+ wd17xx_mr_w(m_fdc, BIT(data, 5));
+
+ // TODO floppy test
+ //wd17xx_test_w(m_fdc, BIT(data, 6));
+
+ // 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 = scsi_data_r(m_scsibus, 0);
+
+ scsi_ack_w(m_scsibus, 0);
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// hdc_data_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( e01_device::hdc_data_w )
+{
+ scsi_data_w(m_scsibus, 0, data);
+
+ scsi_ack_w(m_scsibus, 0);
+}
+
+
+//-------------------------------------------------
+// hdc_status_r -
+//-------------------------------------------------
+
+READ8_MEMBER( e01_device::hdc_status_r )
+{
+ /*
+
+ bit description
+
+ 0 MSG
+ 1 BSY
+ 2 0
+ 3 0
+ 4 NIRQ
+ 5 REQ
+ 6 I/O
+ 7 C/D
+
+ */
+
+ UINT8 data = 0;
+
+ // SCSI bus
+ data |= !scsi_msg_r(m_scsibus);
+ data |= !scsi_bsy_r(m_scsibus) << 1;
+ data |= !scsi_req_r(m_scsibus) << 5;
+ data |= !scsi_io_r(m_scsibus) << 6;
+ data |= !scsi_cd_r(m_scsibus) << 7;
+
+ // TODO NIRQ
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// hdc_select_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( e01_device::hdc_select_w )
+{
+ scsi_sel_w(m_scsibus, 0);
+}
+
+
+//-------------------------------------------------
+// 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_clk(int state)
+{
+ mc6854_rxc_w(m_adlc, state);
+ mc6854_txc_w(m_adlc, state);
+}
diff --git a/src/mess/machine/e01.h b/src/mess/machine/e01.h
new file mode 100644
index 00000000000..ce4d7c0b829
--- /dev/null
+++ b/src/mess/machine/e01.h
@@ -0,0 +1,129 @@
+/**********************************************************************
+
+ Acorn FileStore E01/E01S network hard disk emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __E01__
+#define __E01__
+
+#include "emu.h"
+#include "cpu/m6502/m6502.h"
+#include "imagedev/flopdrv.h"
+#include "imagedev/harddriv.h"
+#include "machine/6522via.h"
+#include "machine/ctronics.h"
+#include "machine/econet.h"
+#include "machine/mc146818.h"
+#include "machine/mc6854.h"
+#include "machine/ram.h"
+#include "machine/scsibus.h"
+#include "machine/wd17xx.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);
+ e01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ enum
+ {
+ TYPE_E01 = 0,
+ TYPE_E01S
+ };
+
+ 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_READ_LINE_MEMBER( econet_data_r );
+ 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_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);
+
+ // 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_clk(int state);
+
+ required_device<cpu_device> m_maincpu;
+ required_device<device_t> m_fdc;
+ required_device<device_t> m_adlc;
+ required_device<mc146818_device> m_rtc;
+ required_device<ram_device> m_ram;
+ required_device<device_t> m_scsibus;
+
+ 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;
+ int m_fdc_drq;
+ int m_adlc_irq;
+
+ int m_clk_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/mess/machine/e05a03.c b/src/mess/machine/e05a03.c
new file mode 100644
index 00000000000..83ae90941fd
--- /dev/null
+++ b/src/mess/machine/e05a03.c
@@ -0,0 +1,242 @@
+/***************************************************************************
+
+ E05A03 Gate Array (used in the Epson LX-800)
+
+***************************************************************************/
+
+#include "emu.h"
+#include "e05a03.h"
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _e05a03_state e05a03_state;
+struct _e05a03_state
+{
+ /* 24-bit shift register, port 0x00, 0x01 and 0x02 */
+ UINT32 shift;
+
+ /* port 0x03 */
+ int busy_leading;
+ int busy_software;
+ int nlqlp;
+ int cndlp;
+
+#if 0
+ int pe;
+ int pelp;
+#endif
+
+ /* port 0x04 and 0x05 (9-bit) */
+ UINT16 printhead;
+
+ /* port 0x06 (4-bit) */
+ UINT8 pf_motor;
+
+ /* port 0x07 (4-bit) */
+ UINT8 cr_motor;
+
+ /* callbacks */
+ devcb_resolved_write_line out_nlq_lp_func; /* pin 2, nlq lamp output */
+ devcb_resolved_write_line out_pe_lp_func; /* pin 3, paper empty lamp output */
+ devcb_resolved_write_line out_reso_func; /* pin 25, reset output */
+ devcb_resolved_write_line out_pe_func; /* pin 35, centronics pe output */
+ devcb_resolved_read8 in_data_func; /* pin 47-54, centronics data input */
+};
+
+
+/*****************************************************************************
+ INLINE FUNCTIONS
+*****************************************************************************/
+
+INLINE e05a03_state *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == E05A03);
+
+ return (e05a03_state *)downcast<legacy_device_base *>(device)->token();
+}
+
+
+/*****************************************************************************
+ DEVICE INTERFACE
+*****************************************************************************/
+
+static DEVICE_START( e05a03 )
+{
+ e05a03_state *e05a03 = get_safe_token(device);
+ const e05a03_interface *intf = (const e05a03_interface *)device->static_config();
+
+ /* validate some basic stuff */
+ assert(device->static_config() != NULL);
+
+ /* resolve callbacks */
+ e05a03->out_nlq_lp_func.resolve(intf->out_nlq_lp_func, *device);
+ e05a03->out_pe_lp_func.resolve(intf->out_pe_lp_func, *device);
+ e05a03->out_reso_func.resolve(intf->out_reso_func, *device);
+ e05a03->out_pe_func.resolve(intf->out_pe_func, *device);
+ e05a03->in_data_func.resolve(intf->in_data_func, *device);
+
+ /* register for state saving */
+ device->save_item(NAME(e05a03->shift));
+ device->save_item(NAME(e05a03->busy_leading));
+ device->save_item(NAME(e05a03->busy_software));
+ device->save_item(NAME(e05a03->nlqlp));
+ device->save_item(NAME(e05a03->cndlp));
+#if 0
+ device->save_item(NAME(e05a03->pe));
+ device->save_item(NAME(e05a03->pelp));
+#endif
+ device->save_item(NAME(e05a03->printhead));
+ device->save_item(NAME(e05a03->pf_motor));
+ device->save_item(NAME(e05a03->cr_motor));
+}
+
+static DEVICE_RESET( e05a03 )
+{
+ e05a03_state *e05a03 = get_safe_token(device);
+
+ e05a03->printhead = 0x00;
+ e05a03->pf_motor = 0x00;
+ e05a03->cr_motor = 0x0f;
+
+ e05a03->out_pe_func(0);
+ e05a03->out_pe_lp_func(1);
+
+ e05a03->busy_software = 1;
+ e05a03->nlqlp = 1;
+ e05a03->cndlp = 1;
+}
+
+DEVICE_GET_INFO( e05a03 )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(e05a03_state); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(e05a03); break;
+ case DEVINFO_FCT_STOP: /* Nothing */ break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(e05a03); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "E05A03"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "Epson printer gate array"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright MESS Team"); break;
+ }
+}
+
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+WRITE8_DEVICE_HANDLER( e05a03_w )
+{
+ e05a03_state *e05a03 = get_safe_token(device);
+
+ logerror("%s: e05a03_w(%02x): %02x\n", device->machine().describe_context(), offset, data);
+
+ switch (offset)
+ {
+ /* shift register */
+ case 0x00: e05a03->shift = (e05a03->shift & 0x00ffff) | (data << 16); break;
+ case 0x01: e05a03->shift = (e05a03->shift & 0xff00ff) | (data << 8); break;
+ case 0x02: e05a03->shift = (e05a03->shift & 0xffff00) | (data << 0); break;
+
+ case 0x03:
+ e05a03->busy_leading = BIT(data, 7);
+ e05a03->busy_software = BIT(data, 6);
+ e05a03->nlqlp = BIT(data, 4);
+ e05a03->cndlp = BIT(data, 3);
+
+ e05a03->out_pe_func(BIT(data, 2));
+ e05a03->out_pe_lp_func(!BIT(data, 2));
+
+#if 0
+ e05a03->pe = BIT(data, 2);
+ e05a03->pelp = !BIT(data, 2);
+#endif
+
+ break;
+
+ /* printhead */
+ case 0x04: e05a03->printhead = (e05a03->printhead & 0x100) | !data; break;
+ case 0x05: e05a03->printhead = (e05a03->printhead & 0x0ff) | (!(BIT(data, 7) << 8)); break;
+
+ /* paper feed and carriage motor phase data*/
+ case 0x06: e05a03->pf_motor = (data & 0xf0) >> 4; break;
+ case 0x07: e05a03->cr_motor = (data & 0x0f) >> 0; break;
+ }
+}
+
+READ8_DEVICE_HANDLER( e05a03_r )
+{
+ e05a03_state *e05a03 = get_safe_token(device);
+ UINT8 result = 0;
+
+ logerror("%s: e05a03_r(%02x)\n", device->machine().describe_context(), offset);
+
+ switch (offset)
+ {
+ case 0x00:
+ break;
+
+ case 0x01:
+ break;
+
+ case 0x02:
+ result = e05a03->in_data_func(0);
+ break;
+
+ case 0x03:
+ result |= BIT(e05a03->shift, 23) << 7;
+ e05a03->shift <<= 1;
+ break;
+ }
+
+ return result;
+}
+
+/* home position signal */
+WRITE_LINE_DEVICE_HANDLER( e05a03_home_w )
+{
+}
+
+/* printhead solenoids trigger */
+WRITE_LINE_DEVICE_HANDLER( e05a03_fire_w )
+{
+}
+
+WRITE_LINE_DEVICE_HANDLER( e05a03_strobe_w )
+{
+}
+
+READ_LINE_DEVICE_HANDLER( e05a03_busy_r )
+{
+ return 1;
+}
+
+WRITE_LINE_DEVICE_HANDLER( e05a03_resi_w )
+{
+ e05a03_state *e05a03 = get_safe_token(device);
+
+ if (!state)
+ {
+ DEVICE_RESET_CALL( e05a03 );
+ e05a03->out_reso_func(1);
+ }
+}
+
+WRITE_LINE_DEVICE_HANDLER( e05a03_init_w )
+{
+ e05a03_resi_w(device, state);
+}
+
+DEFINE_LEGACY_DEVICE(E05A03, e05a03);
diff --git a/src/mess/machine/e05a03.h b/src/mess/machine/e05a03.h
new file mode 100644
index 00000000000..37c39e0a1d5
--- /dev/null
+++ b/src/mess/machine/e05a03.h
@@ -0,0 +1,54 @@
+/***************************************************************************
+
+ E05A03 Gate Array (used in the Epson LX-800)
+
+***************************************************************************/
+
+#ifndef __E05A03_H__
+#define __E05A03_H__
+
+#include "devcb.h"
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _e05a03_interface e05a03_interface;
+struct _e05a03_interface
+{
+ devcb_read8 in_data_func;
+
+ devcb_write_line out_nlq_lp_func;
+ devcb_write_line out_pe_lp_func;
+ devcb_write_line out_pe_func;
+ devcb_write_line out_reso_func;
+};
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+WRITE8_DEVICE_HANDLER( e05a03_w );
+READ8_DEVICE_HANDLER( e05a03_r );
+
+WRITE_LINE_DEVICE_HANDLER( e05a03_home_w ); /* home position signal */
+WRITE_LINE_DEVICE_HANDLER( e05a03_fire_w ); /* printhead solenoids trigger */
+WRITE_LINE_DEVICE_HANDLER( e05a03_strobe_w );
+READ_LINE_DEVICE_HANDLER( e05a03_busy_r );
+WRITE_LINE_DEVICE_HANDLER( e05a03_resi_w ); /* reset input */
+WRITE_LINE_DEVICE_HANDLER( e05a03_init_w ); /* centronics init */
+
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+DECLARE_LEGACY_DEVICE(E05A03, e05a03);
+
+#define MCFG_E05A03_ADD(_tag, _intf) \
+ MCFG_DEVICE_ADD(_tag, E05A03, 0) \
+ MCFG_DEVICE_CONFIG(_intf)
+
+
+#endif /* __E05A03_H__ */
diff --git a/src/mess/machine/ecb_grip.c b/src/mess/machine/ecb_grip.c
new file mode 100644
index 00000000000..2c3c7b973c8
--- /dev/null
+++ b/src/mess/machine/ecb_grip.c
@@ -0,0 +1,947 @@
+/**********************************************************************
+
+ Conitec Datensysteme GRIP graphics card emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "ecb_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<grip_device>;
+
+
+
+//**************************************************************************
+// ROMS
+//**************************************************************************
+
+//-------------------------------------------------
+// ROM( grip21 )
+//-------------------------------------------------
+
+ROM_START( grip21 )
+ ROM_REGION( 0x4000, Z80_TAG, 0 )
+ ROM_LOAD( "grip21.z2", 0x0000, 0x4000, CRC(7f6a37dd) SHA1(2e89f0b0c378257ff7e41c50d57d90865c6e214b) )
+ROM_END
+
+
+//-------------------------------------------------
+// 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
+
+
+//-------------------------------------------------
+// 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_LEGACY(Z80STI_TAG, z80sti_r, z80sti_w)
+ 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(CENTRONICS_TAG, centronics_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_LEGACY(Z80STI_TAG, z80sti_r, z80sti_w)
+ 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_LEGACY(CENTRONICS_TAG, centronics_data_w)
+ 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_interface crtc_intf
+//-------------------------------------------------
+
+void grip_device::crtc_update_row(mc6845_device *device, bitmap_rgb32 &bitmap, const rectangle &cliprect, UINT16 ma, UINT8 ra, UINT16 y, UINT8 x_count, INT8 cursor_x, void *param)
+{
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ int column, bit;
+
+ for (column = 0; column < x_count; column++)
+ {
+ UINT16 address = (m_page << 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];
+ }
+ }
+}
+
+static MC6845_UPDATE_ROW( grip_update_row )
+{
+ grip_device *grip = downcast<grip_device *>(device->owner());
+
+ grip->crtc_update_row(device,bitmap,cliprect,ma,ra,y,x_count,cursor_x,param);
+}
+/*
+static MC6845_UPDATE_ROW( grip5_update_row )
+{
+ grip5_state *state = device->machine().driver_data<grip5_state>();
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ int column, bit;
+
+ for (column = 0; column < x_count; column++)
+ {
+ UINT16 address = (state->m_dpage << 12) | (((ma + column) & 0xfff) << 3) | (ra & 0x07);
+ UINT8 data = state->m_video_ram[address];
+
+ for (bit = 0; bit < 8; bit++)
+ {
+ int x = (column * 8) + bit;
+ int color = state->m_flash ? 0 : BIT(data, bit);
+
+ bitmap.pix32(y, x) = palette[color];
+ }
+ }
+}
+
+static MC6845_ON_UPDATE_ADDR_CHANGED( grip5_update_addr_changed )
+{
+}
+*/
+
+static const INT16 speaker_levels[] = { -32768, 0, 32767, 0 };
+
+static const speaker_interface speaker_intf =
+{
+ 4,
+ speaker_levels
+};
+
+static const mc6845_interface crtc_intf =
+{
+ ":" SCREEN_TAG,
+ 8,
+ NULL,
+ grip_update_row,
+ NULL,
+ DEVCB_DEVICE_LINE(Z80STI_TAG, z80sti_i1_w),
+ DEVCB_DEVICE_LINE(Z80STI_TAG, z80sti_i2_w),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ NULL
+};
+/*
+static const mc6845_interface grip5_crtc_intf =
+{
+ SCREEN_TAG,
+ 8,
+ NULL,
+ grip5_update_row,
+ NULL,
+ DEVCB_DEVICE_LINE(Z80STI_TAG, z80sti_i1_w),
+ DEVCB_DEVICE_LINE(Z80STI_TAG, z80sti_i2_w),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ grip5_update_addr_changed
+};
+*/
+
+
+//-------------------------------------------------
+// I8255A_INTERFACE( ppi_intf )
+//-------------------------------------------------
+
+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);
+ z80sti_i4_w(m_sti, m_ib);
+
+ // keyboard buffer full
+ m_kbf = BIT(data, 1);
+
+ // PROF-80 interrupt
+ m_ia = BIT(data, 3);
+ z80sti_i7_w(m_sti, m_ia);
+
+ // PROF-80 handshaking
+ m_ppi_pc = (!BIT(data, 7) << 7) | (!BIT(data, 5) << 6) | (m_ppi->pa_r() & 0x3f);
+}
+
+static I8255A_INTERFACE( ppi_intf )
+{
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, grip_device, ppi_pa_r), // Port A read
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, grip_device, ppi_pa_w), // Port A write
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, grip_device, ppi_pb_r), // Port B read
+ DEVCB_NULL, // Port B write
+ DEVCB_NULL, // Port C read
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, grip_device, ppi_pc_w) // Port C write
+};
+
+
+//-------------------------------------------------
+// Z80STI_INTERFACE( sti_intf )
+//-------------------------------------------------
+
+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_r() << 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);
+
+ speaker_level_w(m_speaker, level);
+}
+
+static Z80STI_INTERFACE( sti_intf )
+{
+ 0, // serial receive clock
+ 0, // serial transmit clock
+ DEVCB_CPU_INPUT_LINE(Z80_TAG, INPUT_LINE_IRQ0), // interrupt
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, grip_device, sti_gpio_r), // GPIO read
+ DEVCB_NULL, // GPIO write
+ DEVCB_NULL, // serial input
+ DEVCB_NULL, // serial output
+ DEVCB_NULL, // timer A output
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, grip_device, speaker_w), // timer B output
+ DEVCB_LINE(z80sti_tc_w), // timer C output
+ DEVCB_LINE(z80sti_rc_w) // timer D output
+};
+
+
+//-------------------------------------------------
+// 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);
+ }
+}
+
+static ASCII_KEYBOARD_INTERFACE( kb_intf )
+{
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, grip_device, kb_w)
+};
+
+
+
+//**************************************************************************
+// 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)
+
+ // sound hardware
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+ MCFG_SOUND_ADD(SPEAKER_TAG, SPEAKER_SOUND, 0)
+ MCFG_SOUND_CONFIG(speaker_intf)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
+
+ // devices
+ MCFG_MC6845_ADD(MC6845_TAG, MC6845, XTAL_16MHz/4, crtc_intf)
+// MCFG_MC6845_ADD(HD6345_TAG, HD6345, XTAL_16MHz/4, grip5_crtc_intf)
+ MCFG_I8255A_ADD(I8255A_TAG, ppi_intf)
+ MCFG_Z80STI_ADD(Z80STI_TAG, XTAL_16MHz/4, sti_intf)
+ MCFG_CENTRONICS_PRINTER_ADD(CENTRONICS_TAG, standard_centronics)
+ MCFG_ASCII_KEYBOARD_ADD("keyboard", kb_intf)
+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),
+ 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_speaker(*this, SPEAKER_TAG)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void grip_device::device_start()
+{
+ m_ecb = machine().device<ecbbus_device>(ECBBUS_TAG);
+
+ // allocate video RAM
+ m_video_ram = auto_alloc_array(machine(), UINT8, 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_pointer(NAME(m_video_ram), VIDEORAM_SIZE);
+ 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 = ioport("J7")->read();
+}
+
+
+//-------------------------------------------------
+// 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 -
+//-------------------------------------------------
+
+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 (ioport("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 (ioport("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_r() << 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->strobe_w(0);
+ m_centronics->strobe_w(1);
+
+ return 0;
+}
+
+
+//-------------------------------------------------
+// cxstb_w - centronics strobe
+//-------------------------------------------------
+
+WRITE8_MEMBER( grip_device::cxstb_w )
+{
+ m_centronics->strobe_w(0);
+ m_centronics->strobe_w(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);
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// ecbbus_screen_update - screen update
+//-------------------------------------------------
+
+UINT32 grip_device::ecbbus_screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ m_crtc->screen_update(screen, bitmap, cliprect);
+
+ return false;
+}
diff --git a/src/mess/machine/ecb_grip.h b/src/mess/machine/ecb_grip.h
new file mode 100644
index 00000000000..35f09c0e6a8
--- /dev/null
+++ b/src/mess/machine/ecb_grip.h
@@ -0,0 +1,125 @@
+/**********************************************************************
+
+ Conitec Datensysteme GRIP graphics card emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __GRIP__
+#define __GRIP__
+
+
+#include "emu.h"
+#include "cpu/z80/z80.h"
+#include "cpu/z80/z80daisy.h"
+#include "machine/ctronics.h"
+#include "machine/ecbbus.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 );
+
+ void crtc_update_row(mc6845_device *device, bitmap_rgb32 &bitmap, const rectangle &cliprect, UINT16 ma, UINT8 ra, UINT16 y, UINT8 x_count, INT8 cursor_x, void *param);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "grip"; }
+
+ // device_ecbbus_card_interface overrides
+ virtual UINT8 ecbbus_io_r(offs_t offset);
+ virtual void ecbbus_io_w(offs_t offset, UINT8 data);
+ virtual UINT32 ecbbus_screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
+
+private:
+ required_device<i8255_device> m_ppi;
+ required_device<z80sti_device> m_sti;
+ required_device<mc6845_device> m_crtc;
+ required_device<centronics_device> m_centronics;
+ required_device<device_t> m_speaker;
+
+ // 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
+ UINT8 *m_video_ram; // video RAM
+ 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<hd6345_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/mess/machine/ecbbus.c b/src/mess/machine/ecbbus.c
new file mode 100644
index 00000000000..8c147a32767
--- /dev/null
+++ b/src/mess/machine/ecbbus.c
@@ -0,0 +1,286 @@
+/**********************************************************************
+
+ Conitec Datensysteme ECB Bus emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "ecbbus.h"
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ECBBUS_SLOT = &device_creator<ecbbus_slot_device>;
+
+
+
+//**************************************************************************
+// 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),
+ 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<ecbbus_slot_device &>(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<ecbbus_device>(m_bus_tag);
+ device_ecbbus_card_interface *dev = dynamic_cast<device_ecbbus_card_interface *>(get_card_device());
+ if (dev) m_bus->add_ecbbus_card(dev, m_bus_num);
+}
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ECBBUS = &device_creator<ecbbus_device>;
+
+
+void ecbbus_device::static_set_cputag(device_t &device, const char *tag)
+{
+ ecbbus_device &ecbbus = downcast<ecbbus_device &>(device);
+ ecbbus.m_cputag = tag;
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void ecbbus_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const ecbbus_interface *intf = reinterpret_cast<const ecbbus_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<ecbbus_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_int_cb, 0, sizeof(m_out_int_cb));
+ memset(&m_out_nmi_cb, 0, sizeof(m_out_nmi_cb));
+ }
+}
+
+
+
+//**************************************************************************
+// 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)
+{
+}
+
+
+//-------------------------------------------------
+// ~device_ecbbus_card_interface - destructor
+//-------------------------------------------------
+
+device_ecbbus_card_interface::~device_ecbbus_card_interface()
+{
+}
+
+
+
+//**************************************************************************
+// 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)
+{
+ for (int i = 0; i < MAX_ECBBUS_SLOTS; i++)
+ m_ecbbus_device[i] = NULL;
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void ecbbus_device::device_start()
+{
+ m_maincpu = machine().device(m_cputag);
+
+ // resolve callbacks
+ m_out_int_func.resolve(m_out_int_cb, *this);
+ m_out_nmi_func.resolve(m_out_nmi_cb, *this);
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void ecbbus_device::device_reset()
+{
+}
+
+
+//-------------------------------------------------
+// add_ecbbus_card - add ECB bus card
+//-------------------------------------------------
+
+void ecbbus_device::add_ecbbus_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);
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// int_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( ecbbus_device::int_w )
+{
+ m_out_int_func(state);
+}
+
+
+//-------------------------------------------------
+// nmi_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( ecbbus_device::nmi_w )
+{
+ m_out_nmi_func(state);
+}
+
+
+//-------------------------------------------------
+// screen_update -
+//-------------------------------------------------
+
+UINT32 ecbbus_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ bool value = false;
+
+ for (int i = 0; i < MAX_ECBBUS_SLOTS; i++)
+ {
+ if (m_ecbbus_device[i] != NULL)
+ {
+ if (m_ecbbus_device[i]->ecbbus_screen_update(screen, bitmap, cliprect))
+ {
+ value = true;
+ }
+ }
+ }
+
+ return value;
+}
diff --git a/src/mess/machine/ecbbus.h b/src/mess/machine/ecbbus.h
new file mode 100644
index 00000000000..8b9d53b20f3
--- /dev/null
+++ b/src/mess/machine/ecbbus.h
@@ -0,0 +1,163 @@
+/**********************************************************************
+
+ Conitec Datensysteme ECB Bus emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#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(_cpu_tag, _config) \
+ MCFG_DEVICE_ADD(ECBBUS_TAG, ECBBUS, 0) \
+ MCFG_DEVICE_CONFIG(_config) \
+ ecbbus_device::static_set_cputag(*device, _cpu_tag);
+
+
+#define ECBBUS_INTERFACE(_name) \
+ const ecbbus_interface (_name) =
+
+
+#define MCFG_ECBBUS_SLOT_ADD(_num, _tag, _slot_intf, _def_slot, _def_inp) \
+ MCFG_DEVICE_ADD(_tag, ECBBUS_SLOT, 0) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false) \
+ ecbbus_slot_device::static_set_ecbbus_slot(*device, ECBBUS_TAG, _num);
+
+
+
+//**************************************************************************
+// 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
+
+struct ecbbus_interface
+{
+ devcb_write_line m_out_int_cb;
+ devcb_write_line m_out_nmi_cb;
+};
+
+class device_ecbbus_card_interface;
+
+
+// ======================> ecbbus_device
+
+class ecbbus_device : public device_t,
+ public ecbbus_interface
+{
+public:
+ // construction/destruction
+ ecbbus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ // inline configuration
+ static void static_set_cputag(device_t &device, const char *tag);
+
+ void add_ecbbus_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( int_w );
+ DECLARE_WRITE_LINE_MEMBER( nmi_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_config_complete();
+
+private:
+ // internal state
+ device_t *m_maincpu;
+
+ devcb_resolved_write_line m_out_int_func;
+ devcb_resolved_write_line m_out_nmi_func;
+
+ device_ecbbus_card_interface *m_ecbbus_device[MAX_ECBBUS_SLOTS];
+ const char *m_cputag;
+};
+
+
+// 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) { };
+ virtual UINT32 ecbbus_screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { return false; }
+
+public:
+ ecbbus_device *m_ecb;
+};
+
+#endif
diff --git a/src/mess/machine/econet.c b/src/mess/machine/econet.c
new file mode 100644
index 00000000000..f366ad36c2c
--- /dev/null
+++ b/src/mess/machine/econet.c
@@ -0,0 +1,355 @@
+/**********************************************************************
+
+ Acorn Computers Econet local area network emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "econet.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LOG 0
+
+
+static const char *const SIGNAL_NAME[] = { "CLK", "DATA" };
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type ECONET = &device_creator<econet_device>;
+const device_type ECONET_SLOT = &device_creator<econet_slot_device>;
+
+
+
+//**************************************************************************
+// 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)
+{
+}
+
+
+//-------------------------------------------------
+// ~device_econet_interface - destructor
+//-------------------------------------------------
+
+device_econet_interface::~device_econet_interface()
+{
+}
+
+
+
+//**************************************************************************
+// 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),
+ 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<econet_slot_device &>(device);
+ econet_card.m_address = address;
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void econet_slot_device::device_start()
+{
+ m_econet = machine().device<econet_device>(ECONET_TAG);
+ device_econet_interface *dev = dynamic_cast<device_econet_interface *>(get_card_device());
+ if (dev) m_econet->add_device(get_card_device(), m_address);
+}
+
+
+
+//**************************************************************************
+// DEVICE CONFIGURATION
+//**************************************************************************
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void econet_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const econet_interface *intf = reinterpret_cast<const econet_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<econet_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_clk_cb, 0, sizeof(m_out_clk_cb));
+ memset(&m_out_data_cb, 0, sizeof(m_out_data_cb));
+ }
+}
+
+
+
+//**************************************************************************
+// 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_out_clk_func(state); break;
+ case DATA: m_out_data_func(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)
+{
+ 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_out_clk_func.resolve(m_out_clk_cb, *this);
+ m_out_data_func.resolve(m_out_data_cb, *this);
+}
+
+
+//-------------------------------------------------
+// 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 = auto_alloc(machine(), 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_r -
+//-------------------------------------------------
+
+READ_LINE_MEMBER( econet_device::clk_r )
+{
+ return get_signal(CLK);
+}
+
+
+//-------------------------------------------------
+// data_r -
+//-------------------------------------------------
+
+READ_LINE_MEMBER( econet_device::data_r )
+{
+ return get_signal(DATA);
+}
+
+
+//-------------------------------------------------
+// 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);
+}
diff --git a/src/mess/machine/econet.h b/src/mess/machine/econet.h
new file mode 100644
index 00000000000..ac3ef61e595
--- /dev/null
+++ b/src/mess/machine/econet.h
@@ -0,0 +1,175 @@
+/**********************************************************************
+
+ Acorn Computers Econet local area network emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __ECONET__
+#define __ECONET__
+
+#include "emu.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define ECONET_TAG "econet"
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_ECONET_ADD(_config) \
+ MCFG_DEVICE_ADD(ECONET_TAG, ECONET, 0) \
+ MCFG_DEVICE_CONFIG(_config)
+
+
+#define ECONET_INTERFACE(_name) \
+ const econet_interface (_name) =
+
+
+#define MCFG_ECONET_SLOT_ADD(_tag, _num, _slot_intf, _def_slot, _def_inp) \
+ MCFG_DEVICE_ADD(_tag, ECONET_SLOT, 0) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false) \
+ econet_slot_device::static_set_slot(*device, _num);
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> econet_interface
+
+struct econet_interface
+{
+ devcb_write_line m_out_clk_cb;
+ devcb_write_line m_out_data_cb;
+};
+
+
+// ======================> econet_device
+
+class device_econet_interface;
+
+class econet_device : public device_t,
+ public econet_interface
+{
+public:
+ // construction/destruction
+ econet_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ void add_device(device_t *target, int address);
+
+ // reads for both host and peripherals
+ DECLARE_READ_LINE_MEMBER( clk_r );
+ DECLARE_READ_LINE_MEMBER( data_r );
+
+ // 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_config_complete();
+ 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<daisy_entry> m_device_list;
+
+private:
+ devcb_resolved_write_line m_out_clk_func;
+ devcb_resolved_write_line m_out_data_func;
+
+ 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;
+
+ // optional operation overrides
+ virtual void econet_clk(int state) = 0;
+ virtual void econet_data(int state) { };
+
+ econet_device *m_econet;
+ UINT8 m_address;
+};
+
+
+// device type definition
+extern const device_type ECONET;
+extern const device_type ECONET_SLOT;
+
+
+
+#endif
diff --git a/src/mess/machine/egret.c b/src/mess/machine/egret.c
new file mode 100644
index 00000000000..230de55ed4a
--- /dev/null
+++ b/src/mess/machine/egret.c
@@ -0,0 +1,477 @@
+/*
+ Apple "Egret" ADB/system controller MCU
+ Emulation by R. Belmont
+
+ Port definitions, primarily from the schematics.
+
+ Port A:
+
+ x------- O ADB data line out
+ -x------ I ADB data line in
+ --x----- I System type. 0 = hardware power switch, 1 = Egret controls power on/off
+ ---x---- O DFAC latch
+ ----x--- O ? (asserted briefly when resetting 680x0)
+ -----x-- I Keyboard power switch
+ ------x- ? PSU enable OUT for system type 0, otherwise chassis power switch IN
+ -------x ? Control panel enable IN for system type 0 (e.g. LC), power supply enable OUT for type 1
+
+ Port B:
+
+ x------- O DFAC bit clock
+ -x------ ? DFAC data I/O (used in both directions)
+ --x----- ? VIA shift register data (used in both directions)
+ ---x---- O VIA clock
+ ----x--- I VIA SYS_SESSION
+ -----x-- I VIA VIA_FULL
+ ------x- O VIA XCEIVER SESSION
+ -------x I +5v sense
+
+ Port C:
+ x--- O 680x0 reset
+ -x-- ? 680x0 IPL 2 (used in both directions)
+ --xx ? IPL 1/0 for hardware power switch, trickle sense (bit 1) and pulled up to +5v (bit 0) if Egret controls the PSU
+*/
+
+
+//#define EGRET_SUPER_VERBOSE
+
+#include "emu.h"
+#include "egret.h"
+#include "cpu/m6805/m6805.h"
+#include "machine/6522via.h"
+#include "sound/asc.h"
+#include "includes/mac.h"
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define EGRET_CPU_TAG "egret"
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type EGRET = &device_creator<egret_device>;
+
+ROM_START( egret )
+ ROM_REGION(0x4400, EGRET_CPU_TAG, 0)
+ ROM_LOAD( "341s0851.bin", 0x1100, 0x1100, CRC(ea9ea6e4) SHA1(8b0dae3ec66cdddbf71567365d2c462688aeb571) )
+ ROM_LOAD( "341s0850.bin", 0x2200, 0x1100, CRC(4906ecd0) SHA1(95e08ba0c5d4b242f115f104aba9905dbd3fd87c) )
+ ROM_LOAD( "344s0100.bin", 0x3300, 0x1100, CRC(59e2b6b6) SHA1(540e752b7da521f1bdb16e0ad7c5f46ddc92d4e9) )
+ROM_END
+
+//-------------------------------------------------
+// ADDRESS_MAP
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( egret_map, AS_PROGRAM, 8, egret_device )
+ AM_RANGE(0x0000, 0x0002) AM_READWRITE(ports_r, ports_w)
+ AM_RANGE(0x0004, 0x0006) AM_READWRITE(ddr_r, ddr_w)
+ AM_RANGE(0x0007, 0x0007) AM_READWRITE(pll_r, pll_w)
+ AM_RANGE(0x0008, 0x0008) AM_READWRITE(timer_ctrl_r, timer_ctrl_w)
+ AM_RANGE(0x0009, 0x0009) AM_READWRITE(timer_counter_r, timer_counter_w)
+ AM_RANGE(0x0012, 0x0012) AM_READWRITE(onesec_r, onesec_w)
+ AM_RANGE(0x0090, 0x00ff) AM_RAM // work RAM and stack
+ AM_RANGE(0x0100, 0x01ff) AM_READWRITE(pram_r, pram_w)
+ AM_RANGE(0x0f00, 0x1fff) AM_ROM AM_REGION(EGRET_CPU_TAG, 0)
+ADDRESS_MAP_END
+
+//-------------------------------------------------
+// MACHINE_CONFIG
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( egret )
+ MCFG_CPU_ADD(EGRET_CPU_TAG, M68HC05EG, XTAL_32_768kHz*192) // 32.768 kHz input clock, can be PLL'ed to x128 = 4.1 MHz under s/w control
+ MCFG_CPU_PROGRAM_MAP(egret_map)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor egret_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( egret );
+}
+
+const rom_entry *egret_device::device_rom_region() const
+{
+ return ROM_NAME( egret );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+void egret_device::send_port(address_space &space, UINT8 offset, UINT8 data)
+{
+ switch (offset)
+ {
+ case 0: // port A
+/* printf("ADB:%d DFAC:%d PowerEnable:%d\n",
+ (data & 0x80) ? 1 : 0,
+ (data & 0x10) ? 1 : 0,
+ (data & 0x02) ? 1 : 0);*/
+
+ if ((data & 0x80) != last_adb)
+ {
+/* if (data & 0x80)
+ {
+ printf("EG ADB: 1->0 time %lld\n", m_maincpu->total_cycles()-last_adb_time);
+ }
+ else
+ {
+ printf("EG ADB: 0->1 time %lld\n", m_maincpu->total_cycles()-last_adb_time);
+ }*/
+ last_adb = data & 0x80;
+ last_adb_time = m_maincpu->total_cycles();
+ adb_in = (data & 0x80) ? true : false;
+ }
+ break;
+
+ case 1: // port B
+ {
+ if (xcvr_session != ((data>>1)&1))
+ {
+ #ifdef EGRET_SUPER_VERBOSE
+ printf("EG-> XCVR_SESSION: %d (PC=%x)\n", (data>>1)&1, cpu_get_pc(m_maincpu));
+ #endif
+ xcvr_session = (data>>1) & 1;
+ }
+ if (via_data != ((data>>5)&1))
+ {
+ #ifdef EGRET_SUPER_VERBOSE
+ printf("EG-> VIA_DATA: %d (PC=%x)\n", (data>>5)&1, cpu_get_pc(m_maincpu));
+ #endif
+ via_data = (data>>5) & 1;
+ }
+ if (via_clock != ((data>>4)&1))
+ {
+ #ifdef EGRET_SUPER_VERBOSE
+ printf("EG-> VIA_CLOCK: %d (PC=%x)\n", ((data>>4)&1)^1, cpu_get_pc(m_maincpu));
+ #endif
+ via_clock = (data>>4) & 1;
+ via6522_device *via1 = machine().device<via6522_device>("via6522_0");
+ via1->write_cb1(via_clock^1);
+ }
+ }
+ break;
+
+ case 2: // port C
+ if ((data & 8) != reset_line)
+ {
+ #ifdef EGRET_SUPER_VERBOSE
+ printf("680x0 reset: %d -> %d\n", (ports[2] & 8)>>3, (data & 8)>>3);
+ #endif
+ reset_line = (data & 8);
+
+ // falling edge, should reset the machine too
+ if ((ports[2] & 8) && !(data&8))
+ {
+ mac_state *mac = machine().driver_data<mac_state>();
+
+ // force the memory overlay
+ mac->set_memory_overlay(0);
+ mac->set_memory_overlay(1);
+
+ // if PRAM's waiting to be loaded, transfer it now
+ if (!pram_loaded)
+ {
+ memcpy(pram, disk_pram, 0x100);
+ pram_loaded = true;
+ }
+ }
+
+ cputag_set_input_line(machine(), "maincpu", INPUT_LINE_RESET, (reset_line & 8) ? ASSERT_LINE : CLEAR_LINE);
+ }
+ break;
+ }
+}
+
+READ8_MEMBER( egret_device::ddr_r )
+{
+ return ddrs[offset];
+}
+
+WRITE8_MEMBER( egret_device::ddr_w )
+{
+/* printf("%02x to DDR %c\n", data, 'A' + offset);*/
+
+ send_port(space, offset, ports[offset] & data);
+
+ ddrs[offset] = data;
+}
+
+READ8_MEMBER( egret_device::ports_r )
+{
+ UINT8 incoming = 0;
+
+ switch (offset)
+ {
+ case 0: // port A
+ incoming |= adb_in ? 0x40 : 0;
+
+ if (egret_controls_power)
+ {
+ incoming |= 0x02; // indicate soft power, indicate chassis switch on
+ }
+ else
+ {
+ //incoming |= 0x01; // enable control panel enabled
+ }
+ break;
+
+ case 1: // port B
+ incoming |= 0x01; // always show +5v active
+ incoming |= via_full<<2;
+ incoming |= sys_session<<3;
+ incoming |= via_data<<5;
+ incoming |= 0x40; // show DFAC line high
+ break;
+
+ case 2: // port C
+ if (egret_controls_power)
+ {
+ incoming |= 0x3; // trickle sense active, bit 0 pulled up as per schematics
+ }
+ break;
+ }
+
+ // apply data direction registers
+ incoming &= (ddrs[offset] ^ 0xff);
+ // add in ddr-masked version of port writes
+ incoming |= (ports[offset] & ddrs[offset]);
+
+ return incoming;
+}
+
+WRITE8_MEMBER( egret_device::ports_w )
+{
+ send_port(space, offset, data);
+
+ ports[offset] = data;
+}
+
+READ8_MEMBER( egret_device::pll_r )
+{
+ return pll_ctrl;
+}
+
+WRITE8_MEMBER( egret_device::pll_w )
+{
+ #ifdef EGRET_SUPER_VERBOSE
+ if (pll_ctrl != data)
+ {
+ static const int clocks[4] = { 524288, 1048576, 2097152, 4194304 };
+ printf("PLL ctrl: clock %d TCS:%d BCS:%d AUTO:%d BWC:%d PLLON:%d\n", clocks[data&3],
+ (data & 0x80) ? 1 : 0,
+ (data & 0x40) ? 1 : 0,
+ (data & 0x20) ? 1 : 0,
+ (data & 0x10) ? 1 : 0,
+ (data & 0x08) ? 1 : 0);
+ }
+ #endif
+ pll_ctrl = data;
+}
+
+READ8_MEMBER( egret_device::timer_ctrl_r )
+{
+ return timer_ctrl;
+}
+
+WRITE8_MEMBER( egret_device::timer_ctrl_w )
+{
+// printf("%02x to timer control\n", data);
+ timer_ctrl = data;
+}
+
+READ8_MEMBER( egret_device::timer_counter_r )
+{
+ return timer_counter;
+}
+
+WRITE8_MEMBER( egret_device::timer_counter_w )
+{
+// printf("%02x to timer/counter\n", data);
+ timer_counter = data;
+}
+
+READ8_MEMBER( egret_device::onesec_r )
+{
+ return onesec;
+}
+
+WRITE8_MEMBER( egret_device::onesec_w )
+{
+// printf("%02x to one-second control\n", data);
+
+ m_timer->adjust(attotime::from_seconds(1), 0, attotime::from_seconds(1));
+
+ if ((onesec & 0x40) && !(data & 0x40))
+ {
+ device_set_input_line(m_maincpu, M68HC05EG_INT_CPI, CLEAR_LINE);
+ }
+
+ onesec = data;
+}
+
+READ8_MEMBER( egret_device::pram_r )
+{
+ return pram[offset];
+}
+
+WRITE8_MEMBER( egret_device::pram_w )
+{
+ pram[offset] = data;
+}
+
+//-------------------------------------------------
+// egret_device - constructor
+//-------------------------------------------------
+
+egret_device::egret_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, EGRET, "Apple Egret", tag, owner, clock),
+ device_nvram_interface(mconfig, *this),
+ m_maincpu(*this, EGRET_CPU_TAG)
+{
+}
+
+//-------------------------------------------------
+// static_set_type - configuration helper to set
+// the chip type
+//-------------------------------------------------
+
+void egret_device::static_set_type(device_t &device, int type)
+{
+ egret_device &egret = downcast<egret_device &>(device);
+ egret.rom_offset = type;
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void egret_device::device_start()
+{
+ m_timer = timer_alloc(0, NULL);
+ save_item(NAME(ddrs[0]));
+ save_item(NAME(ddrs[1]));
+ save_item(NAME(ddrs[2]));
+ save_item(NAME(ports[0]));
+ save_item(NAME(ports[1]));
+ save_item(NAME(ports[2]));
+ save_item(NAME(pll_ctrl));
+ save_item(NAME(timer_ctrl));
+ save_item(NAME(timer_counter));
+ save_item(NAME(onesec));
+ save_item(NAME(xcvr_session));
+ save_item(NAME(via_full));
+ save_item(NAME(sys_session));
+ save_item(NAME(via_data));
+ save_item(NAME(via_clock));
+ save_item(NAME(adb_in));
+ save_item(NAME(reset_line));
+ save_item(NAME(pram_loaded));
+ save_item(NAME(pram));
+ save_item(NAME(disk_pram));
+
+ astring tempstring;
+ UINT8 *rom = device().machine().root_device().memregion(device().subtag(tempstring, EGRET_CPU_TAG))->base();
+
+ if (rom)
+ {
+ memcpy(rom, rom+rom_offset, 0x1100);
+ }
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void egret_device::device_reset()
+{
+ ddrs[0] = ddrs[1] = ddrs[2] = 0;
+ ports[0] = ports[1] = ports[2] = 0;
+
+ m_timer->adjust(attotime::never);
+
+ egret_controls_power = false; // set to hard power control
+ adb_in = true; // line is pulled up to +5v, so nothing plugged in would read as "1"
+ reset_line = 0;
+ xcvr_session = 0;
+ via_full = 0;
+ sys_session = 0;
+ via_data = 0;
+ via_clock = 0;
+ pll_ctrl = 0;
+ timer_ctrl = 0;
+ timer_counter = 0;
+ last_adb_time = m_maincpu->total_cycles();
+}
+
+void egret_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ onesec |= 0x40;
+
+ if (onesec & 0x10)
+ {
+ device_set_input_line(m_maincpu, M68HC05EG_INT_CPI, ASSERT_LINE);
+ }
+}
+
+// the 6805 program clears PRAM on startup (on h/w it's always running once a battery is inserted)
+// we deal with that by loading pram from disk to a secondary buffer and then slapping it into "live"
+// once the Egret reboots the 68k
+void egret_device::nvram_default()
+{
+ memset(pram, 0, 0x100);
+ memset(disk_pram, 0, 0x100);
+
+ // IIsi and IIvx both default PRAM to this, it seems a reasonable default for Egret systems
+ pram[0x1] = 0x80;
+ pram[0x2] = 0x4f;
+ pram[0x3] = 0x48;
+ pram[0x8] = 0x13;
+ pram[0x9] = 0x88;
+ pram[0xb] = 0x4c;
+ pram[0xc] = 0x4e;
+ pram[0xd] = 0x75;
+ pram[0xe] = 0x4d;
+ pram[0xf] = 0x63;
+ pram[0x10] = 0xa8;
+ pram[0x14] = 0xcc;
+ pram[0x15] = 0x0a;
+ pram[0x16] = 0xcc;
+ pram[0x17] = 0x0a;
+ pram[0x1d] = 0x02;
+ pram[0x1e] = 0x63;
+ pram[0x6f] = 0x28;
+ pram[0x70] = 0x83;
+ pram[0x71] = 0x26;
+ pram[0x77] = 0x01;
+ pram[0x78] = 0xff;
+ pram[0x79] = 0xff;
+ pram[0x7a] = 0xff;
+ pram[0x7b] = 0xdf;
+ pram[0x7d] = 0x09;
+ pram[0xf3] = 0x12;
+ pram[0xf9] = 0x01;
+ pram[0xf3] = 0x12;
+ pram[0xfb] = 0x8d;
+ pram_loaded = false;
+}
+
+void egret_device::nvram_read(emu_file &file)
+{
+ file.read(disk_pram, 0x100);
+ pram_loaded = false;
+}
+
+void egret_device::nvram_write(emu_file &file)
+{
+ file.write(pram, 0x100);
+}
diff --git a/src/mess/machine/egret.h b/src/mess/machine/egret.h
new file mode 100644
index 00000000000..0d5581e32db
--- /dev/null
+++ b/src/mess/machine/egret.h
@@ -0,0 +1,117 @@
+#pragma once
+
+#ifndef __EGRET_H__
+#define __EGRET_H__
+
+#include "emu.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define EGRET_TAG "egret"
+
+#define EGRET_341S0851 0x1100
+#define EGRET_341S0850 0x2200
+#define EGRET_344S0100 0x3300
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_EGRET_ADD(_type) \
+ MCFG_DEVICE_ADD(EGRET_TAG, EGRET, 0) \
+ MCFG_EGRET_TYPE(_type)
+
+#define MCFG_EGRET_REPLACE(_type) \
+ MCFG_DEVICE_REPLACE(EGRET_TAG, EGRET, 0) \
+ MCFG_EGRET_TYPE(_type)
+
+#define MCFG_EGRET_TYPE(_type) \
+ egret_device::static_set_type(*device, _type);
+
+#define MCFG_EGRET_REMOVE() \
+ MCFG_DEVICE_REMOVE(EGRET_TAG)
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> egret_device
+
+class egret_device : public device_t, public device_nvram_interface
+{
+public:
+ // construction/destruction
+ egret_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);
+
+ // device_config_nvram_interface overrides
+ virtual void nvram_default();
+ virtual void nvram_read(emu_file &file);
+ virtual void nvram_write(emu_file &file);
+
+ DECLARE_READ8_MEMBER( ddr_r );
+ DECLARE_WRITE8_MEMBER( ddr_w );
+ DECLARE_READ8_MEMBER( ports_r );
+ DECLARE_WRITE8_MEMBER( ports_w );
+ DECLARE_READ8_MEMBER( pll_r );
+ DECLARE_WRITE8_MEMBER( pll_w );
+ DECLARE_READ8_MEMBER( timer_ctrl_r );
+ DECLARE_WRITE8_MEMBER( timer_ctrl_w );
+ DECLARE_READ8_MEMBER( timer_counter_r );
+ DECLARE_WRITE8_MEMBER( timer_counter_w );
+ DECLARE_READ8_MEMBER( onesec_r );
+ DECLARE_WRITE8_MEMBER( onesec_w );
+ DECLARE_READ8_MEMBER( pram_r );
+ DECLARE_WRITE8_MEMBER( pram_w );
+
+ // interface routines
+ UINT8 get_xcvr_session() { return xcvr_session; }
+ void set_via_full(UINT8 val) { via_full = val; }
+ void set_sys_session(UINT8 val) { sys_session = val; }
+ UINT8 get_via_data() { return via_data; }
+ void set_via_data(UINT8 dat) { via_data = dat; }
+ UINT8 get_via_clock() { return via_clock; }
+
+ int rom_offset;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "egret"; }
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+
+ required_device<cpu_device> m_maincpu;
+
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+private:
+ UINT8 ddrs[3];
+ UINT8 ports[3];
+ UINT8 pll_ctrl;
+ UINT8 timer_ctrl;
+ UINT8 timer_counter;
+ UINT8 onesec;
+ UINT8 xcvr_session, via_full, sys_session, via_data, via_clock, last_adb;
+ UINT64 last_adb_time;
+ bool egret_controls_power;
+ bool adb_in;
+ int reset_line;
+ emu_timer *m_timer;
+ UINT8 pram[0x100], disk_pram[0x100];
+ bool pram_loaded;
+
+ void send_port(address_space &space, UINT8 offset, UINT8 data);
+};
+
+// device type definition
+extern const device_type EGRET;
+
+#endif
diff --git a/src/mess/machine/einstein.c b/src/mess/machine/einstein.c
new file mode 100644
index 00000000000..22f44ec0443
--- /dev/null
+++ b/src/mess/machine/einstein.c
@@ -0,0 +1,199 @@
+#include "emu.h"
+#include "includes/einstein.h"
+
+/****************************************************************
+ EINSTEIN NON-Z80 DEVICES DAISY CHAIN SUPPORT
+****************************************************************/
+
+
+const device_type EINSTEIN_KEYBOARD_DAISY = &device_creator<einstein_keyboard_daisy_device>;
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// z80ctc_device - constructor
+//-------------------------------------------------
+
+einstein_keyboard_daisy_device::einstein_keyboard_daisy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, EINSTEIN_KEYBOARD_DAISY, "Einstein keyboard daisy chain", tag, owner, clock),
+ device_z80daisy_interface(mconfig, *this)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void einstein_keyboard_daisy_device::device_start()
+{
+}
+
+//**************************************************************************
+// DAISY CHAIN INTERFACE
+//**************************************************************************
+
+//-------------------------------------------------
+// z80daisy_irq_state - return the overall IRQ
+// state for this device
+//-------------------------------------------------
+
+int einstein_keyboard_daisy_device::z80daisy_irq_state()
+{
+ einstein_state *einstein = device().machine().driver_data<einstein_state>();
+
+ if (einstein->m_interrupt & einstein->m_interrupt_mask & EINSTEIN_KEY_INT)
+ return Z80_DAISY_INT;
+
+ return 0;
+}
+
+
+//-------------------------------------------------
+// z80daisy_irq_ack - acknowledge an IRQ and
+// return the appropriate vector
+//-------------------------------------------------
+
+int einstein_keyboard_daisy_device::z80daisy_irq_ack()
+{
+ return 0xf7;
+}
+
+//-------------------------------------------------
+// z80daisy_irq_reti - clear the interrupt
+// pending state to allow other interrupts through
+//-------------------------------------------------
+
+void einstein_keyboard_daisy_device::z80daisy_irq_reti()
+{
+}
+
+const device_type EINSTEIN_ADC_DAISY = &device_creator<einstein_adc_daisy_device>;
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// z80ctc_device - constructor
+//-------------------------------------------------
+
+einstein_adc_daisy_device::einstein_adc_daisy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, EINSTEIN_ADC_DAISY, "Einstein ADC daisy chain", tag, owner, clock),
+ device_z80daisy_interface(mconfig, *this)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void einstein_adc_daisy_device::device_start()
+{
+}
+
+//**************************************************************************
+// DAISY CHAIN INTERFACE
+//**************************************************************************
+
+//-------------------------------------------------
+// z80daisy_irq_state - return the overall IRQ
+// state for this device
+//-------------------------------------------------
+
+int einstein_adc_daisy_device::z80daisy_irq_state()
+{
+ einstein_state *einstein = device().machine().driver_data<einstein_state>();
+
+ if (einstein->m_interrupt & einstein->m_interrupt_mask & EINSTEIN_ADC_INT)
+ return Z80_DAISY_INT;
+
+ return 0;
+}
+
+
+//-------------------------------------------------
+// z80daisy_irq_ack - acknowledge an IRQ and
+// return the appropriate vector
+//-------------------------------------------------
+
+int einstein_adc_daisy_device::z80daisy_irq_ack()
+{
+ return 0xfb;
+}
+
+//-------------------------------------------------
+// z80daisy_irq_reti - clear the interrupt
+// pending state to allow other interrupts through
+//-------------------------------------------------
+
+void einstein_adc_daisy_device::z80daisy_irq_reti()
+{
+}
+
+
+const device_type EINSTEIN_FIRE_DAISY = &device_creator<einstein_fire_daisy_device>;
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// z80ctc_device - constructor
+//-------------------------------------------------
+
+einstein_fire_daisy_device::einstein_fire_daisy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, EINSTEIN_FIRE_DAISY, "Einstein fire button daisy chain", tag, owner, clock),
+ device_z80daisy_interface(mconfig, *this)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void einstein_fire_daisy_device::device_start()
+{
+}
+
+//**************************************************************************
+// DAISY CHAIN INTERFACE
+//**************************************************************************
+
+//-------------------------------------------------
+// z80daisy_irq_state - return the overall IRQ
+// state for this device
+//-------------------------------------------------
+
+int einstein_fire_daisy_device::z80daisy_irq_state()
+{
+ einstein_state *einstein = device().machine().driver_data<einstein_state>();
+
+ if (einstein->m_interrupt & einstein->m_interrupt_mask & EINSTEIN_FIRE_INT)
+ return Z80_DAISY_INT;
+
+ return 0;
+}
+
+
+//-------------------------------------------------
+// z80daisy_irq_ack - acknowledge an IRQ and
+// return the appropriate vector
+//-------------------------------------------------
+
+int einstein_fire_daisy_device::z80daisy_irq_ack()
+{
+ return 0xfd;
+}
+
+//-------------------------------------------------
+// z80daisy_irq_reti - clear the interrupt
+// pending state to allow other interrupts through
+//-------------------------------------------------
+
+void einstein_fire_daisy_device::z80daisy_irq_reti()
+{
+}
diff --git a/src/mess/machine/electron.c b/src/mess/machine/electron.c
new file mode 100644
index 00000000000..57fbe164ea8
--- /dev/null
+++ b/src/mess/machine/electron.c
@@ -0,0 +1,354 @@
+/******************************************************************************
+ Acorn Electron driver
+
+ MESS Driver By:
+
+ Wilbert Pol
+
+******************************************************************************/
+
+#include "emu.h"
+#include "includes/electron.h"
+#include "sound/beep.h"
+#include "imagedev/cassette.h"
+
+
+static cassette_image_device *cassette_device_image( running_machine &machine )
+{
+ return machine.device<cassette_image_device>(CASSETTE_TAG);
+}
+
+void electron_state::electron_tape_start()
+{
+ if (m_ula.tape_running )
+ {
+ return;
+ }
+ m_ula.tape_steps = 0;
+ m_ula.tape_value = 0x80808080;
+ m_ula.high_tone_set = 0;
+ m_ula.bit_count = 0;
+ m_ula.tape_running = 1;
+ m_tape_timer->adjust(attotime::zero, 0, attotime::from_hz(4800));
+}
+
+void electron_state::electron_tape_stop()
+{
+ m_ula.tape_running = 0;
+ m_tape_timer->reset();
+}
+
+#define TAPE_LOW 0x00;
+#define TAPE_HIGH 0xFF;
+
+static TIMER_CALLBACK(electron_tape_timer_handler)
+{
+ electron_state *state = machine.driver_data<electron_state>();
+ if ( state->m_ula.cassette_motor_mode )
+ {
+ double tap_val;
+ tap_val = cassette_device_image(machine)->input();
+ if ( tap_val < -0.5 )
+ {
+ state->m_ula.tape_value = ( state->m_ula.tape_value << 8 ) | TAPE_LOW;
+ state->m_ula.tape_steps++;
+ }
+ else if ( tap_val > 0.5 )
+ {
+ state->m_ula.tape_value = ( state->m_ula.tape_value << 8 ) | TAPE_HIGH;
+ state->m_ula.tape_steps++;
+ }
+ else
+ {
+ state->m_ula.tape_steps = 0;
+ state->m_ula.bit_count = 0;
+ state->m_ula.high_tone_set = 0;
+ state->m_ula.tape_value = 0x80808080;
+ }
+ if ( state->m_ula.tape_steps > 2 && ( state->m_ula.tape_value == 0x0000FFFF || state->m_ula.tape_value == 0x00FF00FF ) )
+ {
+ state->m_ula.tape_steps = 0;
+ switch( state->m_ula.bit_count )
+ {
+ case 0: /* start bit */
+ state->m_ula.start_bit = ( ( state->m_ula.tape_value == 0x0000FFFF ) ? 0 : 1 );
+ //logerror( "++ Read start bit: %d\n", state->m_ula.start_bit );
+ if ( state->m_ula.start_bit )
+ {
+ if ( state->m_ula.high_tone_set )
+ {
+ state->m_ula.bit_count--;
+ }
+ }
+ else
+ {
+ state->m_ula.high_tone_set = 0;
+ }
+ break;
+ case 1: case 2: case 3: case 4:
+ case 5: case 6: case 7: case 8:
+ //logerror( "++ Read regular bit: %d\n", state->m_ula.tape_value == 0x0000FFFF ? 0 : 1 );
+ state->m_ula.tape_byte = ( state->m_ula.tape_byte >> 1 ) | ( state->m_ula.tape_value == 0x0000FFFF ? 0 : 0x80 );
+ break;
+ case 9: /* stop bit */
+ state->m_ula.stop_bit = ( ( state->m_ula.tape_value == 0x0000FFFF ) ? 0 : 1 );
+ //logerror( "++ Read stop bit: %d\n", state->m_ula.stop_bit );
+ if ( state->m_ula.start_bit && state->m_ula.stop_bit && state->m_ula.tape_byte == 0xFF && ! state->m_ula.high_tone_set )
+ {
+ electron_interrupt_handler( machine, INT_SET, INT_HIGH_TONE );
+ state->m_ula.high_tone_set = 1;
+ }
+ else if ( ! state->m_ula.start_bit && state->m_ula.stop_bit )
+ {
+ //logerror( "-- Byte read from tape: %02x\n", state->m_ula.tape_byte );
+ electron_interrupt_handler( machine, INT_SET, INT_RECEIVE_FULL );
+ }
+ else
+ {
+ logerror( "Invalid start/stop bit combination detected: %d,%d\n", state->m_ula.start_bit, state->m_ula.stop_bit );
+ }
+ break;
+ }
+ state->m_ula.bit_count = ( state->m_ula.bit_count + 1 ) % 10;
+ }
+ }
+}
+
+READ8_MEMBER(electron_state::electron_read_keyboard)
+{
+ UINT8 data = 0;
+ int i;
+ static const char *const keynames[] = {
+ "LINE0", "LINE1", "LINE2", "LINE3", "LINE4", "LINE5", "LINE6",
+ "LINE7", "LINE8", "LINE9", "LINE10", "LINE11", "LINE12", "LINE13"
+ };
+
+ //logerror( "PC=%04x: keyboard read from paged rom area, address: %04x", activecpu_get_pc(), offset );
+ for( i = 0; i < 14; i++ )
+ {
+ if( !(offset & 1) )
+ data |= ioport(keynames[i])->read() & 0x0f;
+
+ offset = offset >> 1;
+ }
+ //logerror( ", data: %02x\n", data );
+ return data;
+}
+
+READ8_MEMBER(electron_state::electron_jim_r)
+{
+ return 0xff;
+}
+
+WRITE8_MEMBER(electron_state::electron_jim_w)
+{
+}
+
+READ8_MEMBER(electron_state::electron_1mhz_r)
+{
+ return 0xff;
+}
+
+WRITE8_MEMBER(electron_state::electron_1mhz_w)
+{
+}
+
+READ8_MEMBER(electron_state::electron_ula_r)
+{
+ UINT8 data = ((UINT8 *)machine().root_device().memregion("user1")->base())[0x43E00 + offset];
+ switch ( offset & 0x0f )
+ {
+ case 0x00: /* Interrupt status */
+ data = m_ula.interrupt_status;
+ m_ula.interrupt_status &= ~0x02;
+ break;
+ case 0x01: /* Unknown */
+ break;
+ case 0x04: /* Casette data shift register */
+ electron_interrupt_handler(machine(), INT_CLEAR, INT_RECEIVE_FULL );
+ data = m_ula.tape_byte;
+ break;
+ }
+ logerror( "ULA: read offset %02x: %02x\n", offset, data );
+ return data;
+}
+
+static const int electron_palette_offset[4] = { 0, 4, 5, 1 };
+static const UINT16 electron_screen_base[8] = { 0x3000, 0x3000, 0x3000, 0x4000, 0x5800, 0x5800, 0x6000, 0x5800 };
+
+WRITE8_MEMBER(electron_state::electron_ula_w)
+{
+ device_t *speaker = machine().device(BEEPER_TAG);
+ int i = electron_palette_offset[(( offset >> 1 ) & 0x03)];
+ logerror( "ULA: write offset %02x <- %02x\n", offset & 0x0f, data );
+ switch( offset & 0x0f )
+ {
+ case 0x00: /* Interrupt control */
+ m_ula.interrupt_control = data;
+ break;
+ case 0x01: /* Unknown */
+ break;
+ case 0x02: /* Screen start address #1 */
+ m_ula.screen_start = ( m_ula.screen_start & 0x7e00 ) | ( ( data & 0xe0 ) << 1 );
+ logerror( "screen_start changed to %04x\n", m_ula.screen_start );
+ break;
+ case 0x03: /* Screen start addres #2 */
+ m_ula.screen_start = ( m_ula.screen_start & 0x1c0 ) | ( ( data & 0x3f ) << 9 );
+ logerror( "screen_start changed to %04x\n", m_ula.screen_start );
+ break;
+ case 0x04: /* Cassette data shift register */
+ break;
+ case 0x05: /* Interrupt clear and paging */
+ /* rom page requests are honoured when currently bank 0-7 or 12-15 is switched in,
+ * or when 8-11 is currently switched in only switching to bank 8-15 is allowed.
+ *
+ * Rompages 10 and 11 both select the Basic ROM.
+ * Rompages 8 and 9 both select the keyboard.
+ */
+ if ( ( ( m_ula.rompage & 0x0C ) != 0x08 ) || ( data & 0x08 ) )
+ {
+ m_ula.rompage = data & 0x0f;
+ if ( m_ula.rompage == 8 || m_ula.rompage == 9 )
+ {
+ m_ula.rompage = 8;
+ space.install_read_handler( 0x8000, 0xbfff, read8_delegate(FUNC(electron_state::electron_read_keyboard),this));
+ }
+ else
+ {
+ space.install_read_bank( 0x8000, 0xbfff, "bank2");
+ }
+ membank("bank2")->set_entry(m_ula.rompage);
+ }
+ if ( data & 0x10 )
+ {
+ electron_interrupt_handler( machine(), INT_CLEAR, INT_DISPLAY_END );
+ }
+ if ( data & 0x20 )
+ {
+ electron_interrupt_handler( machine(), INT_CLEAR, INT_RTC );
+ }
+ if ( data & 0x40 )
+ {
+ electron_interrupt_handler( machine(), INT_CLEAR, INT_HIGH_TONE );
+ }
+ if ( data & 0x80 )
+ {
+ }
+ break;
+ case 0x06: /* Counter divider */
+ if ( m_ula.communication_mode == 0x01)
+ {
+ beep_set_frequency( speaker, 1000000 / ( 16 * ( data + 1 ) ) );
+ }
+ break;
+ case 0x07: /* Misc. */
+ m_ula.communication_mode = ( data >> 1 ) & 0x03;
+ switch( m_ula.communication_mode )
+ {
+ case 0x00: /* cassette input */
+ beep_set_state( speaker, 0 );
+ electron_tape_start();
+ break;
+ case 0x01: /* sound generation */
+ beep_set_state( speaker, 1 );
+ electron_tape_stop();
+ break;
+ case 0x02: /* cassette output */
+ beep_set_state( speaker, 0 );
+ electron_tape_stop();
+ break;
+ case 0x03: /* not used */
+ beep_set_state( speaker, 0 );
+ electron_tape_stop();
+ break;
+ }
+ m_ula.screen_mode = ( data >> 3 ) & 0x07;
+ m_ula.screen_base = electron_screen_base[ m_ula.screen_mode ];
+ m_ula.screen_size = 0x8000 - m_ula.screen_base;
+ m_ula.vram = (UINT8 *)space.get_read_ptr(m_ula.screen_base );
+ logerror( "ULA: screen mode set to %d\n", m_ula.screen_mode );
+ m_ula.cassette_motor_mode = ( data >> 6 ) & 0x01;
+ cassette_device_image(machine())->change_state(m_ula.cassette_motor_mode ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED, CASSETTE_MOTOR_DISABLED );
+ m_ula.capslock_mode = ( data >> 7 ) & 0x01;
+ break;
+ case 0x08: case 0x0A: case 0x0C: case 0x0E:
+ // video_update
+ m_ula.current_pal[i+10] = (m_ula.current_pal[i+10] & 0x01) | (((data & 0x80) >> 5) | ((data & 0x08) >> 1));
+ m_ula.current_pal[i+8] = (m_ula.current_pal[i+8] & 0x01) | (((data & 0x40) >> 4) | ((data & 0x04) >> 1));
+ m_ula.current_pal[i+2] = (m_ula.current_pal[i+2] & 0x03) | ((data & 0x20) >> 3);
+ m_ula.current_pal[i] = (m_ula.current_pal[i] & 0x03) | ((data & 0x10) >> 2);
+ break;
+ case 0x09: case 0x0B: case 0x0D: case 0x0F:
+ // video_update
+ m_ula.current_pal[i+10] = (m_ula.current_pal[i+10] & 0x06) | ((data & 0x08) >> 3);
+ m_ula.current_pal[i+8] = (m_ula.current_pal[i+8] & 0x06) | ((data & 0x04) >> 2);
+ m_ula.current_pal[i+2] = (m_ula.current_pal[i+2] & 0x04) | (((data & 0x20) >> 4) | ((data & 0x02) >> 1));
+ m_ula.current_pal[i] = (m_ula.current_pal[i] & 0x04) | (((data & 0x10) >> 3) | ((data & 0x01)));
+ break;
+ }
+}
+
+void electron_interrupt_handler(running_machine &machine, int mode, int interrupt)
+{
+ electron_state *state = machine.driver_data<electron_state>();
+ if ( mode == INT_SET )
+ {
+ state->m_ula.interrupt_status |= interrupt;
+ }
+ else
+ {
+ state->m_ula.interrupt_status &= ~interrupt;
+ }
+ if ( state->m_ula.interrupt_status & state->m_ula.interrupt_control & ~0x83 )
+ {
+ state->m_ula.interrupt_status |= 0x01;
+ cputag_set_input_line(machine, "maincpu", 0, ASSERT_LINE );
+ }
+ else
+ {
+ state->m_ula.interrupt_status &= ~0x01;
+ cputag_set_input_line(machine, "maincpu", 0, CLEAR_LINE );
+ }
+}
+
+/**************************************
+ Machine Initialisation functions
+***************************************/
+
+static TIMER_CALLBACK(setup_beep)
+{
+ device_t *speaker = machine.device(BEEPER_TAG);
+ beep_set_state( speaker, 0 );
+ beep_set_frequency( speaker, 300 );
+}
+
+static void electron_reset(running_machine &machine)
+{
+ electron_state *state = machine.driver_data<electron_state>();
+ state->membank("bank2")->set_entry(0);
+
+ state->m_ula.communication_mode = 0x04;
+ state->m_ula.screen_mode = 0;
+ state->m_ula.cassette_motor_mode = 0;
+ state->m_ula.capslock_mode = 0;
+ state->m_ula.screen_mode = 0;
+ state->m_ula.screen_start = 0x3000;
+ state->m_ula.screen_base = 0x3000;
+ state->m_ula.screen_size = 0x8000 - 0x3000;
+ state->m_ula.screen_addr = 0;
+ state->m_ula.tape_running = 0;
+ state->m_ula.vram = (UINT8 *)machine.device("maincpu")->memory().space(AS_PROGRAM)->get_read_ptr(state->m_ula.screen_base);
+}
+
+MACHINE_START( electron )
+{
+ electron_state *state = machine.driver_data<electron_state>();
+ state->membank("bank2")->configure_entries(0, 16, state->memregion("user1")->base(), 0x4000);
+
+ state->m_ula.interrupt_status = 0x82;
+ state->m_ula.interrupt_control = 0x00;
+ machine.scheduler().timer_set(attotime::zero, FUNC(setup_beep));
+ state->m_tape_timer = machine.scheduler().timer_alloc(FUNC(electron_tape_timer_handler));
+ machine.add_notifier(MACHINE_NOTIFY_RESET, machine_notify_delegate(FUNC(electron_reset),&machine));
+}
+
diff --git a/src/mess/machine/er59256.c b/src/mess/machine/er59256.c
new file mode 100644
index 00000000000..040258f31af
--- /dev/null
+++ b/src/mess/machine/er59256.c
@@ -0,0 +1,252 @@
+/*********************************************************************
+
+ er59256.c
+
+ Microchip ER59256 serial eeprom.
+
+
+*********************************************************************/
+
+#include "emu.h"
+#include "er59256.h"
+
+/* LOGLEVEL 0=no logging, 1=just commands and data, 2=everything ! */
+
+#define LOGLEVEL 0
+
+#define LOG(level,...) if(LOGLEVEL>=level) logerror(__VA_ARGS__)
+#define LOG_BITS(bits) logerror("CS=%d CK=%d DI=%d DO=%d", (bits&CS_MASK) ? 1 : 0, (bits&CK_MASK) ? 1 : 0, (bits&DI_MASK) ? 1 : 0, (bits&DO_MASK) ? 1 : 0)
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _er59256_t er59256_t;
+struct _er59256_t
+{
+ /* The actual memory */
+ UINT16 eerom[EEROM_WORDS];
+
+ /* Bits as they appear on the io pins, current state */
+ UINT8 io_bits;
+
+ /* Bits as they appear on the io pins, previous state */
+ UINT8 old_io_bits;
+
+
+ /* the 16 bit shift in/out reg */
+ UINT16 in_shifter;
+ UINT32 out_shifter;
+
+ /* Count of bits received since last CS low->high */
+ UINT8 bitcount;
+
+ /* Command & addresss */
+ UINT8 command;
+
+ /* Write enable and write in progress flags */
+ UINT8 flags;
+};
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+************************************************************************/
+
+static void decode_command(er59256_t *er59256);
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+INLINE er59256_t *get_token(device_t *device)
+{
+ assert(device->type() == ER59256);
+ return (er59256_t *) downcast<legacy_device_base *>(device)->token();
+}
+
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+void er59256_preload_rom(device_t *device, const UINT16 *rom_data, int count)
+{
+ er59256_t *er59256 = get_token(device);
+ int WordNo;
+
+ logerror("Preloading %d words of data\n",count);
+
+ if(count>EEROM_WORDS)
+ memcpy(&er59256->eerom,rom_data,count*2);
+ else
+ memcpy(&er59256->eerom,rom_data,EEROM_WORDS*2);
+
+ for(WordNo=0;WordNo<EEROM_WORDS;WordNo++)
+ logerror("%04X ",er59256->eerom[WordNo]);
+
+ logerror("\n");
+}
+
+UINT8 er59256_data_loaded(device_t *device)
+{
+ er59256_t *er59256 = get_token(device);
+
+ return (er59256->flags & FLAG_DATA_LOADED) ? 1 : 0;
+}
+
+/*-------------------------------------------------
+ DEVICE_START( er59256 )
+-------------------------------------------------*/
+
+static DEVICE_START( er59256 )
+{
+ er59256_t *er59256 = get_token(device);
+
+ memset(er59256, 0x00, sizeof(er59256_t));
+
+ // Start with rom defaulted to erased
+ memset(&er59256->eerom, 0xFF, EEROM_WORDS*2);
+
+ er59256->command=CMD_INVALID;
+
+ er59256->flags&= ~FLAG_DATA_LOADED;
+}
+
+static DEVICE_STOP( er59256 )
+{
+ /* Save contents of eerom */
+}
+
+void er59256_set_iobits(device_t *device, UINT8 newbits)
+{
+ er59256_t *er59256 = get_token(device);
+ //UINT32 bit;
+
+ // Make sure we only apply valid bits
+ newbits&=ALL_MASK;
+
+ if(LOGLEVEL>1)
+ {
+ logerror("er59256:newbits=%02X : ",newbits);
+ LOG_BITS(newbits);
+ logerror(" io_bits=%02X : ",er59256->io_bits);
+ LOG_BITS(er59256->io_bits);
+ logerror(" old_io_bits=%02X : ",er59256->old_io_bits);
+ LOG_BITS(er59256->old_io_bits);
+ logerror(" bitcount=%d, in_shifter=%04X, out_shifter=%05X, flags=%02X\n",er59256->bitcount,er59256->in_shifter,er59256->out_shifter,er59256->flags);
+ }
+ // Only do anything if the inputs have changed
+ if((newbits&IN_MASK)!=(er59256->io_bits&IN_MASK))
+ {
+ // save the current state, then set the new one, remembering to preserve data out
+ er59256->old_io_bits=er59256->io_bits;
+ er59256->io_bits=(newbits & ~DO_MASK) | (er59256->old_io_bits&DO_MASK);
+
+ if(CS_RISE(er59256))
+ {
+ er59256->flags&=~FLAG_START_BIT;
+ er59256->command=CMD_INVALID;
+ }
+
+ if(LOGLEVEL>1)
+ {
+ if(CK_RISE(er59256)) logerror("er59256:CK rise\n");
+ if(CS_RISE(er59256)) logerror("er59256:CS rise\n");
+ if(CK_FALL(er59256)) logerror("er59256:CK fall\n");
+ if(CS_FALL(er59256)) logerror("er59256:CS fall\n");
+ }
+
+ if(CK_RISE(er59256) && CS_VALID(er59256))
+ {
+ if((STARTED(er59256)==0) && (GET_DI(er59256)==1))
+ {
+ er59256->bitcount=0;
+ er59256->flags|=FLAG_START_BIT;
+ }
+ else
+ {
+ SHIFT_IN(er59256);
+ er59256->bitcount++;
+
+ if(er59256->bitcount==CMD_BITLEN)
+ decode_command(er59256);
+
+ if((er59256->bitcount==WRITE_BITLEN) && ((er59256->command & CMD_MASK)==CMD_WRITE))
+ {
+ er59256->eerom[er59256->command & ADDR_MASK]=er59256->in_shifter;
+ LOG(1,"er59256:write[%02X]=%04X\n",(er59256->command & ADDR_MASK),er59256->in_shifter);
+ er59256->command=CMD_INVALID;
+ }
+ LOG(1,"out_shifter=%05X, io_bits=%02X\n",er59256->out_shifter,er59256->io_bits);
+ SHIFT_OUT(er59256);
+ }
+
+ LOG(2,"io_bits:out=%02X\n",er59256->io_bits);
+ }
+ }
+}
+
+UINT8 er59256_get_iobits(device_t *device)
+{
+ er59256_t *er59256 = get_token(device);
+
+ return er59256->io_bits;
+}
+
+
+static void decode_command(er59256_t *er59256)
+{
+ er59256->out_shifter=0x0000;
+ er59256->command=(er59256->in_shifter & (CMD_MASK | ADDR_MASK));
+
+ switch(er59256->command & CMD_MASK)
+ {
+ case CMD_READ : er59256->out_shifter=er59256->eerom[er59256->command & ADDR_MASK];
+ LOG(1,"er59256:read[%02X]=%04X\n",(er59256->command&ADDR_MASK),er59256->eerom[er59256->command & ADDR_MASK]);
+ break;
+ case CMD_WRITE : break;
+ case CMD_ERASE : if (WRITE_ENABLED(er59256)) er59256->eerom[er59256->command & ADDR_MASK]=0xFF;
+ LOG(1,"er59256:erase[%02X]\n",(er59256->command&ADDR_MASK));
+ break;
+ case CMD_EWEN : er59256->flags|=FLAG_WRITE_EN;
+ LOG(1,"er59256:erase/write enabled\n");
+ break;
+ case CMD_EWDS : er59256->flags&=~FLAG_WRITE_EN;
+ LOG(1,"er59256:erase/write disabled\n");
+ break;
+ case CMD_ERAL : if (WRITE_ENABLED(er59256)) memset(&er59256->eerom, 0xFF, EEROM_WORDS*2);
+ LOG(1,"er59256:erase all\n");
+ break;
+ }
+
+ if ((er59256->command & CMD_MASK)!=CMD_WRITE)
+ er59256->command=CMD_INVALID;
+}
+
+/*-------------------------------------------------
+ DEVICE_GET_INFO( er59256 )
+-------------------------------------------------*/
+
+DEVICE_GET_INFO( er59256 )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(er59256_t); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(er59256); break;
+ case DEVINFO_FCT_STOP: info->stop = DEVICE_STOP_NAME(er59256); break;
+ case DEVINFO_FCT_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "Microchip ER59256 serial eeprom."); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "Microchip ER59256 serial eeprom."); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: /* Nothing */ break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(ER59256, er59256);
diff --git a/src/mess/machine/er59256.h b/src/mess/machine/er59256.h
new file mode 100644
index 00000000000..4a81e6809ce
--- /dev/null
+++ b/src/mess/machine/er59256.h
@@ -0,0 +1,93 @@
+/*********************************************************************
+
+ er59256.h
+
+ Microchip ER59256 serial eeprom.
+
+
+*********************************************************************/
+
+#ifndef _ER59256_H_
+#define _ER59256_H_
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+DECLARE_LEGACY_DEVICE(ER59256, er59256);
+
+#define MCFG_ER59256_ADD(_tag) \
+ MCFG_DEVICE_ADD((_tag), ER59256, 0)
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define EEROM_WORDS 0x10
+
+#define CK_SHIFT 0x00
+#define DI_SHIFT 0x01
+#define DO_SHIFT 0x02
+#define CS_SHIFT 0x03
+
+#define CK_MASK (1<<CK_SHIFT)
+#define DI_MASK (1<<DI_SHIFT)
+#define DO_MASK (1<<DO_SHIFT)
+#define CS_MASK (1<<CS_SHIFT)
+
+#define ALL_MASK (CK_MASK | DI_MASK | DO_MASK | CS_MASK)
+#define IN_MASK (CK_MASK | DI_MASK | CS_MASK)
+
+#define GET_CK(eep) ((eep->io_bits & CK_MASK) >> CK_SHIFT)
+#define GET_DI(eep) ((eep->io_bits & DI_MASK) >> DI_SHIFT)
+#define GET_DO(eep) ((eep->io_bits & DO_MASK) >> DO_SHIFT)
+#define GET_CS(eep) ((eep->io_bits & CS_MASK) >> CS_SHIFT)
+
+#define SET_CK(eep,data) eep->io_bits=((eep->io_bits & ~CK_MASK) | ((data & 0x01) << CK_SHIFT))
+#define SET_DI(eep,data) eep->io_bits=((eep->io_bits & ~DI_MASK) | ((data & 0x01) << DI_SHIFT))
+#define SET_DO(eep,data) eep->io_bits=((eep->io_bits & ~DO_MASK) | ((data & 0x01) << DO_SHIFT))
+#define SET_CS(eep,data) eep->io_bits=((eep->io_bits & ~CS_MASK) | ((data & 0x01) << CS_SHIFT))
+
+#define CK_RISE(eep) ((eep->io_bits & CK_MASK) & ~(eep->old_io_bits & CK_MASK))
+#define CS_RISE(eep) ((eep->io_bits & CS_MASK) & ~(eep->old_io_bits & CS_MASK))
+#define CS_VALID(eep) ((eep->io_bits & CS_MASK) & (eep->old_io_bits & CS_MASK))
+
+#define CK_FALL(eep) (~(eep->io_bits & CK_MASK) & (eep->old_io_bits & CK_MASK))
+#define CS_FALL(eep) (~(eep->io_bits & CS_MASK) & (eep->old_io_bits & CS_MASK))
+
+
+#define SHIFT_IN(eep) eep->in_shifter=(eep->in_shifter<<1) | GET_DI(eep)
+#define SHIFT_OUT(eep) SET_DO(eep,(eep->out_shifter & 0x10000)>>16); eep->out_shifter=(eep->out_shifter<<1)
+
+#define CMD_READ 0x80
+#define CMD_WRITE 0x40
+#define CMD_ERASE 0xC0
+#define CMD_EWEN 0x30
+#define CMD_EWDS 0x00
+#define CMD_ERAL 0x20
+#define CMD_INVALID 0xF0
+
+#define CMD_MASK 0xF0
+#define ADDR_MASK 0x0F
+
+// CMD_BITLEN is 1 start bit plus 4 command bits plus 4 address bits
+#define CMD_BITLEN 8
+#define DATA_BITLEN 16
+#define WRITE_BITLEN CMD_BITLEN+DATA_BITLEN
+
+#define FLAG_WRITE_EN 0x01
+#define FLAG_START_BIT 0x02
+#define FLAG_DATA_LOADED 0x04
+
+#define WRITE_ENABLED(eep) ((eep->flags & FLAG_WRITE_EN) ? 1 : 0)
+#define STARTED(eep) ((eep->flags & FLAG_START_BIT) ? 1 : 0)
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+void er59256_set_iobits(device_t *device, UINT8 newbits);
+UINT8 er59256_get_iobits(device_t *device);
+void er59256_preload_rom(device_t *device, const UINT16 *rom_data, int count);
+UINT8 er59256_data_loaded(device_t *device);
+#endif
diff --git a/src/mess/machine/esqvfd.c b/src/mess/machine/esqvfd.c
new file mode 100644
index 00000000000..94139b10fd4
--- /dev/null
+++ b/src/mess/machine/esqvfd.c
@@ -0,0 +1,358 @@
+/*
+ Ensoniq Vacuum Flourescent Displays (VFDs)
+ Emulation by R. Belmont
+*/
+
+#include "esqvfd.h"
+#include "esq1by22.lh"
+#include "esq2by40.lh"
+
+const device_type ESQ1x22 = &device_creator<esq1x22_t>;
+const device_type ESQ2x40 = &device_creator<esq2x40_t>;
+const device_type ESQ2x40_SQ1 = &device_creator<esq2x40_sq1_t>;
+
+// adapted from bfm_bd1, rearranged to work with ASCII data used by the Ensoniq h/w
+static const UINT16 font[]=
+{ // FEDC BA98 7654 3210
+ 0x0000, // 0000 0000 0000 0000 (space)
+ 0x0000, // 0000 0000 0000 0000 ! (not defined)
+ 0x0009, // 0000 0000 0000 1001 ".
+ 0xC62A, // 1100 0110 0010 1010 #.
+ 0xC62D, // 1100 0110 0010 1101 $.
+ 0x0000, // 0000 0000 0000 0000 % (not defined)
+ 0x0000, // 0000 0000 0000 0000 & (not defined)
+ 0x0040, // 0000 0000 1000 0000 '.
+ 0x0880, // 0000 1000 1000 0000 (.
+ 0x0050, // 0000 0000 0101 0000 ).
+ 0xCCD8, // 1100 1100 1101 1000 *.
+ 0xC408, // 1100 0100 0000 1000 +.
+ 0x0000, // 0000 0000 0000 0000 , (not defined)
+ 0xC000, // 1100 0000 0000 0000 -.
+ 0x1000, // 0001 0000 0000 0000 .
+ 0x0090, // 0000 0000 1001 0000 /
+ 0x22B7, // 0010 0010 1011 0111 0.
+ 0x0408, // 0000 0100 0000 1000 1.
+ 0xE206, // 1110 0010 0000 0110 2.
+ 0x4226, // 0100 0010 0010 0110 3.
+ 0xC023, // 1100 0000 0010 0011 4.
+ 0xC225, // 1100 0010 0010 0101 5.
+ 0xE225, // 1110 0010 0010 0101 6.
+ 0x0026, // 0000 0000 0010 0110 7.
+ 0xE227, // 1110 0010 0010 0111 8.
+ 0xC227, // 1100 0010 0010 0111 9.
+ 0x0000, // 0000 0000 0000 0000 : (not defined)
+ 0x0000, // 0000 0000 0000 0000 ; (not defined)
+ 0x0290, // 0000 0010 1001 0000 <.
+ 0xC200, // 1100 0010 0000 0000 =.
+ 0x0A40, // 0000 1010 0100 0000 >.
+ 0x0000, // 0000 0000 0000 0000 ? (not defined)
+ 0xA626, // 1010 0110 0010 0110 @.
+ 0xE027, // 1110 0000 0010 0111 A.
+ 0x462E, // 0100 0110 0010 1110 B.
+ 0x2205, // 0010 0010 0000 0101 C.
+ 0x062E, // 0000 0110 0010 1110 D.
+ 0xA205, // 1010 0010 0000 0101 E.
+ 0xA005, // 1010 0000 0000 0101 F.
+ 0x6225, // 0110 0010 0010 0101 G.
+ 0xE023, // 1110 0000 0010 0011 H.
+ 0x060C, // 0000 0110 0000 1100 I.
+ 0x2222, // 0010 0010 0010 0010 J.
+ 0xA881, // 1010 1000 1000 0001 K.
+ 0x2201, // 0010 0010 0000 0001 L.
+ 0x20E3, // 0010 0000 1110 0011 M.
+ 0x2863, // 0010 1000 0110 0011 N.
+ 0x2227, // 0010 0010 0010 0111 O.
+ 0xE007, // 1110 0000 0000 0111 P.
+ 0x2A27, // 0010 1010 0010 0111 Q.
+ 0xE807, // 1110 1000 0000 0111 R.
+ 0xC225, // 1100 0010 0010 0101 S.
+ 0x040C, // 0000 0100 0000 1100 T.
+ 0x2223, // 0010 0010 0010 0011 U.
+ 0x2091, // 0010 0000 1001 0001 V.
+ 0x2833, // 0010 1000 0011 0011 W.
+ 0x08D0, // 0000 1000 1101 0000 X.
+ 0x04C0, // 0000 0100 1100 0000 Y.
+ 0x0294, // 0000 0010 1001 0100 Z.
+ 0x2205, // 0010 0010 0000 0101 [.
+ 0x0840, // 0000 1000 0100 0000 \.
+ 0x0226, // 0000 0010 0010 0110 ].
+ 0x0810, // 0000 1000 0001 0000 ^.
+ 0x0200, // 0000 0010 0000 0000 _
+ 0x0040, // 0000 0000 0100 0000 `
+ 0xE027, // 1110 0000 0010 0111 A.
+ 0x462E, // 0100 0110 0010 1110 B.
+ 0x2205, // 0010 0010 0000 0101 C.
+ 0x062E, // 0000 0110 0010 1110 D.
+ 0xA205, // 1010 0010 0000 0101 E.
+ 0xA005, // 1010 0000 0000 0101 F.
+ 0x6225, // 0110 0010 0010 0101 G.
+ 0xE023, // 1110 0000 0010 0011 H.
+ 0x060C, // 0000 0110 0000 1100 I.
+ 0x2222, // 0010 0010 0010 0010 J.
+ 0xA881, // 1010 1000 1000 0001 K.
+ 0x2201, // 0010 0010 0000 0001 L.
+ 0x20E3, // 0010 0000 1110 0011 M.
+ 0x2863, // 0010 1000 0110 0011 N.
+ 0x2227, // 0010 0010 0010 0111 O.
+ 0xE007, // 1110 0000 0000 0111 P.
+ 0x2A27, // 0010 1010 0010 0111 Q.
+ 0xE807, // 1110 1000 0000 0111 R.
+ 0xC225, // 1100 0010 0010 0101 S.
+ 0x040C, // 0000 0100 0000 1100 T.
+ 0x2223, // 0010 0010 0010 0011 U.
+ 0x2091, // 0010 0000 1001 0001 V.
+ 0x2833, // 0010 1000 0011 0011 W.
+ 0x08D0, // 0000 1000 1101 0000 X.
+ 0x04C0, // 0000 0100 1100 0000 Y.
+ 0x0294, // 0000 0010 1001 0100 Z.
+ 0x2205, // 0010 0010 0000 0101 [.
+ 0x0408, // 0000 0100 0000 1000 |
+ 0x0226, // 0000 0010 0010 0110 ].
+ 0x0810, // 0000 1000 0001 0000 ~.
+ 0x0000, // 0000 0000 0000 0000 (DEL)
+};
+
+esqvfd_t::esqvfd_t(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)
+{
+}
+
+void esqvfd_t::device_start()
+{
+}
+
+void esqvfd_t::device_reset()
+{
+ m_cursx = m_cursy = 0;
+ m_curattr = AT_NORMAL;
+ memset(m_chars, 0, sizeof(m_chars));
+ memset(m_attrs, 0, sizeof(m_attrs));
+ memset(m_dirty, 1, sizeof(m_attrs));
+}
+
+void esqvfd_t::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+}
+
+// why isn't the font just stored in this order?
+UINT32 esqvfd_t::conv_segments(UINT16 segin)
+{
+ UINT32 segout = 0;
+
+ if ( segin & 0x0004 ) segout |= 0x0001;
+ if ( segin & 0x0002 ) segout |= 0x0002;
+ if ( segin & 0x0020 ) segout |= 0x0004;
+ if ( segin & 0x0200 ) segout |= 0x0008;
+ if ( segin & 0x2000 ) segout |= 0x0010;
+ if ( segin & 0x0001 ) segout |= 0x0020;
+ if ( segin & 0x8000 ) segout |= 0x0040;
+ if ( segin & 0x4000 ) segout |= 0x0080;
+ if ( segin & 0x0008 ) segout |= 0x0100;
+ if ( segin & 0x0400 ) segout |= 0x0200;
+ if ( segin & 0x0010 ) segout |= 0x0400;
+ if ( segin & 0x0040 ) segout |= 0x0800;
+ if ( segin & 0x0080 ) segout |= 0x1000;
+ if ( segin & 0x0800 ) segout |= 0x2000;
+ if ( segin & 0x1000 ) segout |= 0x4000;
+
+ return segout;
+}
+
+// generic display update; can override from child classes if not good enough
+void esqvfd_t::update_display()
+{
+ for (int row = 0; row < m_rows; row++)
+ {
+ for (int col = 0; col < m_cols; col++)
+ {
+ if (m_dirty[row][col])
+ {
+ UINT32 segdata = conv_segments(font[m_chars[row][col]]);
+
+ output_set_indexed_value("vfd", (row*m_cols) + col, segdata);
+
+ m_dirty[row][col] = 0;
+ }
+ }
+ }
+}
+
+/* 2x40 VFD display used in the ESQ-1, VFX-SD, SD-1, and others */
+
+static MACHINE_CONFIG_FRAGMENT(esq2x40)
+ MCFG_DEFAULT_LAYOUT(layout_esq2by40)
+MACHINE_CONFIG_END
+
+machine_config_constructor esq2x40_t::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( esq2x40 );
+}
+
+void esq2x40_t::write_char(int data)
+{
+ if ((data >= 0x80) && (data < 0xd0))
+ {
+ m_cursy = ((data & 0x7f) >= 40) ? 1 : 0;
+ m_cursx = (data & 0x7f) % 40;
+ }
+ else if (data >= 0xd0)
+ {
+ switch (data)
+ {
+ case 0xd0: // blink start
+ m_curattr = AT_BLINK;
+ break;
+
+ case 0xd1: // blink stop
+ m_curattr &= ~AT_BLINK;
+ break;
+
+ case 0xd6: // clear screen
+ m_cursx = m_cursy = 0;
+ memset(m_chars, 0, sizeof(m_chars));
+ memset(m_attrs, 0, sizeof(m_attrs));
+ memset(m_dirty, 1, sizeof(m_dirty));
+ break;
+
+ default:
+// printf("Unknown control code %02x\n", data);
+ break;
+ }
+ }
+ else
+ {
+ if ((data >= 0x20) && (data <= 0x5f))
+ {
+ m_chars[m_cursy][m_cursx] = data - ' ';
+ m_attrs[m_cursy][m_cursx] = m_curattr;
+ m_dirty[m_cursy][m_cursx] = 1;
+ m_cursx++;
+
+ if (m_cursx >= 39)
+ {
+ m_cursx = 39;
+ }
+ }
+ }
+
+ update_display();
+}
+
+esq2x40_t::esq2x40_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : esqvfd_t(mconfig, ESQ2x40, "Ensoniq 2x40 VFD", tag, owner, clock)
+{
+ m_rows = 2;
+ m_cols = 40;
+}
+
+/* 1x22 display from the VFX (not right, but it'll do for now) */
+
+static MACHINE_CONFIG_FRAGMENT(esq1x22)
+ MCFG_DEFAULT_LAYOUT(layout_esq1by22)
+MACHINE_CONFIG_END
+
+machine_config_constructor esq1x22_t::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( esq1x22 );
+}
+
+void esq1x22_t::write_char(int data)
+{
+ if (data >= 0x60)
+ {
+ switch (data)
+ {
+ case 'f': // clear screen
+ m_cursx = m_cursy = 0;
+ memset(m_chars, 0, sizeof(m_chars));
+ memset(m_attrs, 0, sizeof(m_attrs));
+ memset(m_dirty, 1, sizeof(m_dirty));
+ break;
+
+ default:
+ printf("Unhandled control code %02x\n", data);
+ break;
+ }
+ }
+ else
+ {
+ if ((data >= 0x20) && (data <= 0x5f))
+ {
+ m_chars[0][m_cursx] = data - ' ';
+ m_dirty[0][m_cursx] = 1;
+ m_cursx++;
+
+ if (m_cursx >= 23)
+ {
+ m_cursx = 23;
+ }
+ }
+ }
+
+ update_display();
+}
+
+esq1x22_t::esq1x22_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : esqvfd_t(mconfig, ESQ1x22, "Ensoniq 1x22 VFD", tag, owner, clock)
+{
+ m_rows = 1;
+ m_cols = 22;
+}
+
+/* SQ-1 display, I think it's really an LCD but we'll deal with it for now */
+machine_config_constructor esq2x40_sq1_t::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( esq2x40 ); // we use the normal 2x40 layout
+}
+
+void esq2x40_sq1_t::write_char(int data)
+{
+ if (m_Wait87Shift)
+ {
+// printf("87Shift got %02x\n", data);
+ if (data == 0x00) // clear
+ {
+ m_cursx = m_cursy = 0;
+ memset(m_chars, 0, sizeof(m_chars));
+ memset(m_attrs, 0, sizeof(m_attrs));
+ memset(m_dirty, 1, sizeof(m_dirty));
+ }
+
+ m_Wait87Shift = false;
+ }
+ else if ((data >= 0x20) && (data <= 0x7f))
+ {
+ m_chars[m_cursy][m_cursx] = data - ' ';
+ m_attrs[m_cursy][m_cursx] = m_curattr;
+ m_dirty[m_cursy][m_cursx] = 1;
+ m_cursx++;
+
+ if (m_cursx >= 39)
+ {
+ m_cursx = 39;
+ }
+
+ update_display();
+ }
+ else if (data == 0x83)
+ {
+ m_cursx = m_cursy = 0;
+ memset(m_chars, 0, sizeof(m_chars));
+ memset(m_attrs, 0, sizeof(m_attrs));
+ memset(m_dirty, 1, sizeof(m_dirty));
+ }
+ else if (data == 0x87)
+ {
+ m_Wait87Shift = true;
+ }
+ else
+ {
+// printf("SQ-1 unhandled display char %02x\n", data);
+ }
+}
+
+esq2x40_sq1_t::esq2x40_sq1_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : esqvfd_t(mconfig, ESQ2x40_SQ1, "Ensoniq 2x40 VFD (SQ-1 variant)", tag, owner, clock)
+{
+ m_rows = 2;
+ m_cols = 40;
+ m_Wait87Shift = false;
+}
+
diff --git a/src/mess/machine/esqvfd.h b/src/mess/machine/esqvfd.h
new file mode 100644
index 00000000000..67f783be8dc
--- /dev/null
+++ b/src/mess/machine/esqvfd.h
@@ -0,0 +1,97 @@
+#ifndef ESQVFD_H
+#define ESQVFD_H
+
+#include "emu.h"
+
+#define MCFG_ESQ1x22_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, ESQ1x22, 60)
+
+#define MCFG_ESQ1x22_REMOVE(_tag) \
+ MCFG_DEVICE_REMOVE(_tag)
+
+#define MCFG_ESQ2x40_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, ESQ2x40, 60)
+
+#define MCFG_ESQ2x40_REMOVE(_tag) \
+ MCFG_DEVICE_REMOVE(_tag)
+
+#define MCFG_ESQ2x40_SQ1_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, ESQ2x40_SQ1, 60)
+
+#define MCFG_ESQ2x40_SQ1_REMOVE(_tag) \
+ MCFG_DEVICE_REMOVE(_tag)
+
+class esqvfd_t : public device_t {
+public:
+ typedef delegate<void (bool state)> line_cb;
+
+ esqvfd_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
+
+ DECLARE_WRITE8_MEMBER( write ) { write_char(data); }
+
+ virtual void write_char(int data) = 0;
+ virtual void update_display();
+
+ UINT32 conv_segments(UINT16 segin);
+
+protected:
+ static const UINT8 AT_NORMAL = 0x00;
+ static const UINT8 AT_BOLD = 0x01;
+ static const UINT8 AT_UNDERLINE = 0x02;
+ static const UINT8 AT_BLINK = 0x04;
+ static const UINT8 AT_BLINKED = 0x80; // set when character should be blinked off
+
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+ int m_cursx, m_cursy;
+ int m_rows, m_cols;
+ UINT8 m_curattr;
+ UINT8 m_chars[2][40];
+ UINT8 m_attrs[2][40];
+ UINT8 m_dirty[2][40];
+};
+
+class esq1x22_t : public esqvfd_t {
+public:
+ esq1x22_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ virtual void write_char(int data);
+
+protected:
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+private:
+};
+
+class esq2x40_t : public esqvfd_t {
+public:
+ esq2x40_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ virtual void write_char(int data);
+
+protected:
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+private:
+};
+
+class esq2x40_sq1_t : public esqvfd_t {
+public:
+ esq2x40_sq1_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ virtual void write_char(int data);
+
+protected:
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+private:
+ bool m_Wait87Shift;
+};
+
+extern const device_type ESQ1x22;
+extern const device_type ESQ2x40;
+extern const device_type ESQ2x40_SQ1;
+
+#endif
diff --git a/src/mess/machine/europc.c b/src/mess/machine/europc.c
new file mode 100644
index 00000000000..afe31335093
--- /dev/null
+++ b/src/mess/machine/europc.c
@@ -0,0 +1,365 @@
+#include "emu.h"
+#include "includes/europc.h"
+#include "includes/pc.h"
+#include "machine/pcshare.h"
+#include "machine/pit8253.h"
+#include "video/pc_aga.h"
+#include "coreutil.h"
+
+/*
+
+ */
+
+/*
+ europc
+ fe107 bios checksum test
+ memory test
+ fe145
+ irq vector init
+ fe156
+ fe169 fd774 // test of special europc registers 254 354
+ fe16c fe817
+ fe16f
+ fec08 // test of special europc registers 800a rtc time or date error, rtc corrected
+ fef66 0xf
+ fdb3e 0x8..0xc
+ fd7f8
+ fdb5f
+ fe172
+ fecc5 // 801a video setup error
+ fd6c9
+ copyright output
+ fe1b7
+ fe1be di bits set mean output text!!!,
+ (801a)
+ 0x8000 output
+ 1 rtc error
+ 2 rtc time or date error
+ 4 checksum error in setup
+ 8 rtc status corrected
+ 10 video setup error
+ 20 video ram bad
+ 40 monitor type not recogniced
+ 80 mouse port enabled
+ 100 joystick port enabled
+
+ fe1e2 fdc0c cpu speed is 4.77 MHz
+ fe1e5 ff9c0 keyboard processor error
+ fe1eb fc617 external lpt1 at 0x3bc
+ fe1ee fe8ee external coms at
+
+ routines:
+ fc92d output text at bp
+ fdb3e rtc read reg cl
+ fe8ee piep
+ fe95e rtc write reg cl
+ polls until jim 0xa is zero,
+ output cl at jim 0xa
+ write ah hinibble as lownibble into jim 0xa
+ write ah lownibble into jim 0xa
+ fef66 rtc read reg cl
+ polls until jim 0xa is zero,
+ output cl at jim 0xa
+ read low 4 nibble at jim 0xa
+ read low 4 nibble at jim 0xa
+ return first nibble<<4|second nibble in ah
+ ff046 seldom compares ret
+ ffe87 0 -> ds
+
+ 469:
+ bit 0: b0000 memory available
+ bit 1: b8000 memory available
+ 46a: 00 jim 250 01 jim 350
+ */
+
+static struct {
+ UINT8 data[16];
+ UINT8 state;
+ AGA_MODE mode;
+} europc_jim = { { 0 } } ;
+
+/*
+ 250..253 write only 00 be 00 10
+
+ 252 write 0 b0000 memory activ
+ 252 write 0x10 b8000 memory activ
+
+ jim 04: 0:4.77 0x40:7.16
+ pio 63: 11,19 4.77 51,59 7.16
+
+ 63 bit 6,7 clock select
+ 254 bit 6,7 clock select
+ 250 bit 0: mouse on
+ bit 1: joystick on
+ 254..257 r/w memory ? JIM asic? ram behaviour
+
+*/
+WRITE8_HANDLER ( europc_jim_w )
+{
+ switch (offset)
+ {
+ case 2:
+ if (!(data & 0x80))
+ {
+ switch (data)
+ {
+ case 0x1f:
+ case 0x0b: europc_jim.mode = AGA_MONO; break;
+ case 0xe: //80 columns?
+ case 0xd: //40 columns?
+ case 0x18:
+ case 0x1a: europc_jim.mode = AGA_COLOR; break;
+ default: europc_jim.mode = AGA_OFF; break;
+ }
+ }
+// mode= data&0x10?AGA_COLOR:AGA_MONO;
+// mode= data&0x10?AGA_COLOR:AGA_OFF;
+ pc_aga_set_mode(space->machine(), europc_jim.mode);
+ if (data & 0x80) europc_jim.state = 0;
+ break;
+ case 4:
+ switch(data & 0xc0)
+ {
+ case 0x00: space->machine().device("maincpu")->set_clock_scale(1.0 / 2); break;
+ case 0x40: space->machine().device("maincpu")->set_clock_scale(3.0 / 4); break;
+ default: space->machine().device("maincpu")->set_clock_scale(1); break;
+ }
+ break;
+ case 0xa:
+ europc_rtc_w(space, 0, data);
+ return;
+ }
+ logerror("jim write %.2x %.2x\n", offset, data);
+ europc_jim.data[offset] = data;
+}
+
+READ8_HANDLER ( europc_jim_r )
+{
+ int data = 0;
+ switch(offset)
+ {
+ case 4: case 5: case 6: case 7: data = europc_jim.data[offset]; break;
+ case 0: case 1: case 2: case 3: data = 0; break;
+ case 0xa: return europc_rtc_r(space, 0);
+ }
+ return data;
+}
+
+READ8_HANDLER ( europc_jim2_r )
+{
+ switch (europc_jim.state)
+ {
+ case 0: europc_jim.state++; return 0;
+ case 1: europc_jim.state++; return 0x80;
+ case 2:
+ europc_jim.state = 0;
+ switch (europc_jim.mode)
+ {
+ case AGA_COLOR: return 0x87; // for color;
+ case AGA_MONO: return 0x90; //for mono
+ case AGA_OFF: return 0x80; // for vram
+// return 0x97; //for error
+ }
+ }
+ return 0;
+}
+
+/* port 2e0 polling!? at fd6e1 */
+
+static struct {
+ int port61; // bit 0,1 must be 0 for startup; reset?
+} europc_pio= { 0 };
+
+WRITE8_HANDLER( europc_pio_w )
+{
+ switch (offset)
+ {
+ case 1:
+ europc_pio.port61=data;
+// if (data == 0x30) pc1640.port62 = (pc1640.port65 & 0x10) >> 4;
+// else if (data == 0x34) pc1640.port62 = pc1640.port65 & 0xf;
+ pit8253_gate2_w(space->machine().device("pit8253"), BIT(data, 0));
+ pc_speaker_set_spkrdata(space->machine(), BIT(data, 1));
+ pc_keyb_set_clock(BIT(data, 6));
+ break;
+ }
+
+ logerror("europc pio write %.2x %.2x\n", offset, data);
+}
+
+
+ READ8_HANDLER( europc_pio_r )
+{
+ int data = 0;
+ switch (offset)
+ {
+ case 0:
+ if (!(europc_pio.port61&0x80))
+ data = pc_keyb_read();
+ break;
+ case 1:
+ data = europc_pio.port61;
+ break;
+ case 2:
+ if (pit8253_get_output(space->machine().device("pit8253"), 2))
+ data |= 0x20;
+ break;
+ }
+ return data;
+}
+
+// realtime clock and nvram
+static struct {
+ /*
+ reg 0: seconds
+ reg 1: minutes
+ reg 2: hours
+ reg 3: day 1 based
+ reg 4: month 1 based
+ reg 5: year bcd (no century, values bigger 88? are handled as 1900, else 2000)
+ reg 6:
+ reg 7:
+ reg 8:
+ reg 9:
+ reg a:
+ reg b: 0x10 written
+ bit 0,1: 0 video startup mode: 0=specialadapter, 1=color40, 2=color80, 3=monochrom
+ bit 2: internal video on
+ bit 4: color
+ bit 6,7: clock
+ reg c:
+ bit 0,1: language/country
+ reg d: xor checksum
+ reg e:
+ reg 0f: 01 status ok, when not 01 written
+ */
+ UINT8 data[0x10];
+ int reg;
+ int state;
+ emu_timer *timer;
+} europc_rtc;
+
+void europc_rtc_set_time(running_machine &machine)
+{
+ system_time systime;
+
+ /* get the current date/time from the core */
+ machine.current_datetime(systime);
+
+ europc_rtc.data[0] = dec_2_bcd(systime.utc_time.second);
+ europc_rtc.data[1] = dec_2_bcd(systime.utc_time.minute);
+ europc_rtc.data[2] = dec_2_bcd(systime.utc_time.hour);
+
+ europc_rtc.data[3] = dec_2_bcd(systime.utc_time.mday);
+ europc_rtc.data[4] = dec_2_bcd(systime.utc_time.month + 1);
+ europc_rtc.data[5] = dec_2_bcd(systime.utc_time.year % 100);
+}
+
+static TIMER_CALLBACK(europc_rtc_timer)
+{
+ int month, year;
+ europc_rtc.data[0]=bcd_adjust(europc_rtc.data[0]+1);
+ if (europc_rtc.data[0]>=0x60)
+ {
+ europc_rtc.data[0]=0;
+ europc_rtc.data[1]=bcd_adjust(europc_rtc.data[1]+1);
+ if (europc_rtc.data[1]>=0x60)
+ {
+ europc_rtc.data[1]=0;
+ europc_rtc.data[2]=bcd_adjust(europc_rtc.data[2]+1);
+ if (europc_rtc.data[2]>=0x24)
+ {
+ europc_rtc.data[2]=0;
+ europc_rtc.data[3]=bcd_adjust(europc_rtc.data[3]+1);
+ month=bcd_2_dec(europc_rtc.data[4]);
+ year=bcd_2_dec(europc_rtc.data[5])+2000; // save for julian_days_in_month_calculation
+ if (europc_rtc.data[3]> gregorian_days_in_month(month, year))
+ {
+ europc_rtc.data[3]=1;
+ europc_rtc.data[4]=bcd_adjust(europc_rtc.data[4]+1);
+ if (europc_rtc.data[4]>0x12)
+ {
+ europc_rtc.data[4]=1;
+ europc_rtc.data[5]=bcd_adjust(europc_rtc.data[5]+1)&0xff;
+ }
+ }
+ }
+ }
+ }
+}
+
+void europc_rtc_init(running_machine &machine)
+{
+ memset(&europc_rtc,0,sizeof(europc_rtc));
+ europc_rtc.data[0xf]=1;
+
+ europc_rtc.timer = machine.scheduler().timer_alloc(FUNC(europc_rtc_timer));
+ europc_rtc.timer->adjust(attotime::zero, 0, attotime(1,0));
+}
+
+ READ8_HANDLER( europc_rtc_r )
+{
+ int data=0;
+ switch (europc_rtc.state)
+ {
+ case 1:
+ data=(europc_rtc.data[europc_rtc.reg]&0xf0)>>4;
+ europc_rtc.state++;
+ break;
+ case 2:
+ data=europc_rtc.data[europc_rtc.reg]&0xf;
+ europc_rtc.state=0;
+// logerror("rtc read %x %.2x\n",europc_rtc.reg, europc_rtc.data[europc_rtc.reg]);
+ break;
+ }
+ return data;
+}
+
+WRITE8_HANDLER( europc_rtc_w )
+{
+ switch (europc_rtc.state)
+ {
+ case 0:
+ europc_rtc.reg=data;
+ europc_rtc.state=1;
+ break;
+ case 1:
+ europc_rtc.data[europc_rtc.reg]=(europc_rtc.data[europc_rtc.reg]&~0xf0)|((data&0xf)<<4);
+ europc_rtc.state++;
+ break;
+ case 2:
+ europc_rtc.data[europc_rtc.reg]=(europc_rtc.data[europc_rtc.reg]&~0xf)|(data&0xf);
+ europc_rtc.state=0;
+// logerror("rtc written %x %.2x\n",europc_rtc.reg, europc_rtc.data[europc_rtc.reg]);
+ break;
+ }
+}
+
+static void europc_rtc_load_stream(emu_file *file)
+{
+ file->read(europc_rtc.data, sizeof(europc_rtc.data));
+}
+
+static void europc_rtc_save_stream(emu_file *file)
+{
+ file->write(europc_rtc.data, sizeof(europc_rtc.data));
+}
+
+NVRAM_HANDLER( europc_rtc )
+{
+ if (file == NULL)
+ {
+ /* init only */
+ /* europc_rtc_set_time(machine); */
+ }
+ else if (read_or_write)
+ {
+ europc_rtc_save_stream(file);
+ }
+ else
+ {
+ europc_rtc_load_stream(file);
+ europc_rtc_set_time(machine);
+ }
+}
+
diff --git a/src/mess/machine/fd2000.c b/src/mess/machine/fd2000.c
new file mode 100644
index 00000000000..80831949be4
--- /dev/null
+++ b/src/mess/machine/fd2000.c
@@ -0,0 +1,229 @@
+/**********************************************************************
+
+ CMD FD2000 disk drive emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "fd2000.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define M6502_TAG "m6502"
+#define M6522_TAG "m6522"
+#define DP8473_TAG "dp8473"
+#define PC8477AV1_TAG "pc8477av1"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type FD2000 = &device_creator<fd2000_device>;
+
+
+//-------------------------------------------------
+// ROM( fd2000 )
+//-------------------------------------------------
+
+ROM_START( fd2000 )
+ ROM_REGION( 0x8000, M6502_TAG, 0 )
+ ROM_LOAD( "cmd_fd-2000_dos_v1.40_cs_33cc6f.bin", 0x0000, 0x8000, CRC(4e6ca15c) SHA1(0c61ba58269baf2b8aadf3bbc4648c7a5a6d2128) )
+ROM_END
+
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *fd2000_device::device_rom_region() const
+{
+ return ROM_NAME( fd2000 );
+}
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( fd2000_mem )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( fd2000_mem, AS_PROGRAM, 8, fd2000_device )
+ AM_RANGE(0x0000, 0x7fff) AM_RAM
+ AM_RANGE(0x8000, 0xffff) AM_ROM AM_REGION(M6502_TAG, 0)
+ //AM_RANGE() AM_DEVREADWRITE(M6522_TAG, via6522_device, read, write)
+ //AM_RANGE() AM_DEVREAD_LEGACY(DP8473_TAG, upd765_status_r)
+ //AM_RANGE() AM_DEVREADWRITE_LEGACY(DP8473_TAG, upd765_data_r, upd765_data_w)
+ADDRESS_MAP_END
+
+
+//-------------------------------------------------
+// via6522_interface via1_intf
+//-------------------------------------------------
+
+static const via6522_interface via_intf =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// LEGACY_FLOPPY_OPTIONS( fd2000 )
+//-------------------------------------------------
+
+static LEGACY_FLOPPY_OPTIONS_START( fd2000 )
+ LEGACY_FLOPPY_OPTION( fd2000, "d81", "Commodore 1581 Disk Image", d81_dsk_identify, d81_dsk_construct, NULL, NULL )
+ //LEGACY_FLOPPY_OPTION( fd2000, "d2m", "CMD FD-2000 Disk Image", d2m_dsk_identify, d2m_dsk_construct, NULL, NULL )
+LEGACY_FLOPPY_OPTIONS_END
+
+
+//-------------------------------------------------
+// floppy_interface fd2000_floppy_interface
+//-------------------------------------------------
+
+static const floppy_interface fd2000_floppy_interface =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ FLOPPY_STANDARD_3_5_DSDD,
+ LEGACY_FLOPPY_OPTIONS_NAME(fd2000),
+ "floppy_3_5",
+ NULL
+};
+
+
+//-------------------------------------------------
+// upd765_interface fdc_intf
+//-------------------------------------------------
+
+static const struct upd765_interface fdc_intf =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ NULL,
+ UPD765_RDY_PIN_CONNECTED,
+ { FLOPPY_0, NULL, NULL, NULL }
+};
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( fd2000 )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( fd2000 )
+ MCFG_CPU_ADD(M6502_TAG, M65C02, 2000000)
+ MCFG_CPU_PROGRAM_MAP(fd2000_mem)
+
+ MCFG_VIA6522_ADD(M6522_TAG, 2000000, via_intf)
+ MCFG_UPD765A_ADD(DP8473_TAG, fdc_intf)
+
+ MCFG_LEGACY_FLOPPY_DRIVE_ADD(FLOPPY_0, fd2000_floppy_interface)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor fd2000_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( fd2000 );
+}
+
+
+
+//**************************************************************************
+// 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),
+ device_cbm_iec_interface(mconfig, *this),
+ m_maincpu(*this, M6502_TAG)
+{
+}
+
+
+//-------------------------------------------------
+// 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/mess/machine/fd2000.h b/src/mess/machine/fd2000.h
new file mode 100644
index 00000000000..736c972c87b
--- /dev/null
+++ b/src/mess/machine/fd2000.h
@@ -0,0 +1,74 @@
+/**********************************************************************
+
+ CMD FD2000 disk drive emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __FD2000__
+#define __FD2000__
+
+#define ADDRESS_MAP_MODERN
+
+#include "emu.h"
+#include "cpu/m6502/m6502.h"
+#include "imagedev/flopdrv.h"
+#include "formats/d81_dsk.h"
+#include "machine/6522via.h"
+#include "machine/cbmiec.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);
+
+ // 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();
+ virtual void device_config_complete() { m_shortname = "fd2000"; }
+
+ // 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<cpu_device> m_maincpu;
+};
+
+
+// device type definition
+extern const device_type FD2000;
+
+
+
+#endif
diff --git a/src/mess/machine/fm_scsi.c b/src/mess/machine/fm_scsi.c
new file mode 100644
index 00000000000..765d8884e43
--- /dev/null
+++ b/src/mess/machine/fm_scsi.c
@@ -0,0 +1,446 @@
+/*
+ *
+ * Implementation of Fujitsu FMR-50, FMR-60 and FM-Towns SCSI hardware
+ *
+ *
+
+ info from Toshiya Takeda's e-FMR50 source (the Towns uses the same controller?)
+ 0xc30 = Data register
+ 0xc32 = Status register (read)
+ bit 7 = REQ
+ bit 6 = I/O
+ bit 5 = MSG
+ bit 4 = C/D
+ bit 3 = BUSY
+ bit 1 = INT
+ bit 0 = PERR
+ 0xc32 = Control register (write)
+ bit 7 = WEN
+ bit 6 = IMSK
+ bit 4 = ATN
+ bit 2 = SEL
+ bit 1 = DMAE
+ bit 0 = RST
+*/
+#include "emu.h"
+#include "fm_scsi.h"
+#include "machine/devhelpr.h"
+#include "debugger.h"
+
+/*
+ * Device config
+ */
+
+const device_type FMSCSI = &device_creator<fmscsi_device>;
+
+void fmscsi_device::device_config_complete()
+{
+ // copy static configuration if present
+ const FMSCSIinterface *intf = reinterpret_cast<const FMSCSIinterface *>(static_config());
+ if (intf != NULL)
+ *static_cast<FMSCSIinterface *>(this) = *intf;
+
+ // otherwise, initialize it to defaults
+ else
+ {
+ scsidevs = NULL;
+ memset(&irq_callback,0,sizeof(irq_callback));
+ memset(&drq_callback,0,sizeof(drq_callback));
+ }
+}
+
+/*
+ * Device
+ */
+
+fmscsi_device::fmscsi_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, FMSCSI, "FM-SCSI", tag, owner, clock)
+{
+}
+
+void fmscsi_device::device_start()
+{
+ int x;
+
+ m_input_lines = 0;
+ m_output_lines = 0;
+ m_data = 0;
+ m_command_index = 0;
+ m_last_id = 0;
+ m_target = 0;
+ m_phase = SCSI_PHASE_BUS_FREE;
+
+ m_irq_func.resolve(irq_callback,*this);
+ m_drq_func.resolve(drq_callback,*this);
+
+ memset(m_SCSIdevices,0,sizeof(m_SCSIdevices));
+
+ // initialise SCSI devices, if any present
+ for(x=0;x<scsidevs->devs_present;x++)
+ {
+ m_SCSIdevices[scsidevs->devices[x].scsiID] = machine().device<scsidev_device>( scsidevs->devices[x].tag );
+ }
+
+ // allocate read timer
+ m_transfer_timer = timer_alloc(TIMER_TRANSFER);
+ m_phase_timer = timer_alloc(TIMER_PHASE);
+}
+
+void fmscsi_device::device_reset()
+{
+ m_input_lines = 0;
+ m_output_lines = 0;
+ m_data = 0;
+ m_command_index = 0;
+ m_last_id = 0;
+ m_target = 0;
+ m_result_length = 0;
+ m_result_index = 0;
+
+ m_phase = SCSI_PHASE_BUS_FREE;
+}
+
+// get the length of a SCSI command based on it's command byte type
+int fmscsi_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("fmscsi: Unknown SCSI command group %d", group);
+
+ return 6;
+}
+
+void fmscsi_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch(id)
+ {
+ case TIMER_TRANSFER:
+ set_input_line(FMSCSI_LINE_REQ,1);
+ //logerror("FMSCSI: timer triggered: %i/%i\n",m_result_index,m_result_length);
+ if(m_output_lines & FMSCSI_LINE_DMAE)
+ {
+ m_drq_func(1);
+ }
+ break;
+ case TIMER_PHASE:
+ set_phase(param);
+ break;
+ }
+}
+
+UINT8 fmscsi_device::fmscsi_data_r(void)
+{
+ // read from data bus
+ // ACK is automatic on accessing the data bus, so REQ will go low.
+ set_input_line(FMSCSI_LINE_REQ,0);
+
+ if(m_phase == SCSI_PHASE_DATAIN)
+ {
+ m_data = m_buffer[m_result_index % 512];
+ //logerror("FMSCSI: DATAIN phase read data %02x\n",m_data);
+ m_result_index++;
+ if(m_result_index % 512 == 0)
+ m_SCSIdevices[m_target]->ReadData(m_buffer,512); // read next sector
+
+ if(m_result_index >= m_result_length)
+ {
+ // end of data transfer
+ m_transfer_timer->adjust(attotime::never); // stop timer
+ m_phase_timer->adjust(attotime::from_usec(800),SCSI_PHASE_STATUS);
+ if(m_output_lines & FMSCSI_LINE_DMAE)
+ {
+ m_drq_func(0);
+ }
+ logerror("FMSCSI: Stopping transfer : (%i/%i)\n",m_result_index,m_result_length);
+ }
+ return m_data;
+ }
+
+ if(m_phase == SCSI_PHASE_MESSAGE_IN)
+ {
+ m_data = 0; // command complete message
+ m_phase_timer->adjust(attotime::from_usec(800),SCSI_PHASE_BUS_FREE);
+ m_command_index = 0;
+ return m_data;
+ }
+
+ if(m_phase == SCSI_PHASE_STATUS)
+ {
+ m_data = 0; // GOOD status
+ // no command complete message?
+ m_phase_timer->adjust(attotime::from_usec(800),SCSI_PHASE_MESSAGE_IN);
+ m_command_index = 0;
+ //set_input_line(FMSCSI_LINE_REQ,1); // raise REQ yet again
+ return m_data;
+ }
+
+ return m_data;
+}
+
+void fmscsi_device::fmscsi_data_w(UINT8 data)
+{
+ int phase;
+
+ // write to data bus
+ m_data = data;
+ //logerror("FMSCSI: data write %02x\n",data);
+
+ // ACK is automatic on accessing the data bus, so REQ will go low.
+ set_input_line(FMSCSI_LINE_REQ,0);
+
+ if(m_phase == SCSI_PHASE_BUS_FREE)
+ {
+ // select target
+ switch(data & 0x7f)
+ {
+ 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;
+ }
+ }
+ if(m_phase == SCSI_PHASE_DATAOUT)
+ {
+ m_buffer[m_result_index % 512] = m_data;
+ m_result_index++;
+ if(m_result_index % 512 == 0)
+ m_SCSIdevices[m_target]->WriteData(m_buffer,512); // write buffer to disc
+ if(m_result_index >= m_result_length)
+ {
+ // end of data transfer
+ m_transfer_timer->adjust(attotime::never); // stop timer
+ m_phase_timer->adjust(attotime::from_usec(800),SCSI_PHASE_STATUS);
+ if(m_output_lines & FMSCSI_LINE_DMAE)
+ {
+ m_drq_func(0);
+ }
+ logerror("FMSCSI: Stopping transfer : (%i/%i)\n",m_result_index,m_result_length);
+ }
+ }
+ if(m_phase == SCSI_PHASE_COMMAND)
+ {
+ m_command[m_command_index] = data;
+ logerror("FMSCSI: writing command byte %02x [%i]\n",data,m_command_index);
+ m_command_index++;
+ if(m_command_index >= get_scsi_cmd_len(m_command[0]))
+ {
+ // command complete
+ m_SCSIdevices[m_target]->SetCommand(m_command,m_command_index);
+ m_SCSIdevices[m_target]->ExecCommand(&m_result_length);
+ m_SCSIdevices[m_target]->GetPhase(&phase);
+ if(m_command[0] == 1) // rezero unit command - not implemented in SCSI code
+ m_phase_timer->adjust(attotime::from_usec(800),SCSI_PHASE_STATUS);
+ else
+ m_phase_timer->adjust(attotime::from_usec(800),phase);
+
+ logerror("FMSCSI: Command %02x sent, result length = %i\n",m_command[0],m_result_length);
+ }
+ else
+ {
+ m_phase_timer->adjust(attotime::from_usec(800),SCSI_PHASE_COMMAND);
+ }
+ }
+ if(m_phase == SCSI_PHASE_MESSAGE_OUT)
+ {
+ m_phase_timer->adjust(attotime::from_usec(800),SCSI_PHASE_STATUS);
+ }
+}
+
+void fmscsi_device::set_phase(int phase)
+{
+ m_phase = phase;
+ logerror("FMSCSI: phase set to %i\n",m_phase);
+ // set input lines accordingly
+ switch(phase)
+ {
+ case SCSI_PHASE_BUS_FREE:
+ set_input_line(FMSCSI_LINE_BSY,0);
+ set_input_line(FMSCSI_LINE_CD,0);
+ set_input_line(FMSCSI_LINE_MSG,0);
+ set_input_line(FMSCSI_LINE_IO,0);
+ //set_input_line(FMSCSI_LINE_REQ,0);
+ break;
+ case SCSI_PHASE_COMMAND:
+ set_input_line(FMSCSI_LINE_BSY,1);
+ set_input_line(FMSCSI_LINE_CD,1);
+ set_input_line(FMSCSI_LINE_MSG,0);
+ set_input_line(FMSCSI_LINE_IO,0);
+ set_input_line(FMSCSI_LINE_REQ,1);
+ break;
+ case SCSI_PHASE_STATUS:
+ set_input_line(FMSCSI_LINE_CD,1);
+ set_input_line(FMSCSI_LINE_MSG,0);
+ set_input_line(FMSCSI_LINE_IO,1);
+ set_input_line(FMSCSI_LINE_REQ,1);
+ break;
+ case SCSI_PHASE_DATAIN:
+ set_input_line(FMSCSI_LINE_CD,0);
+ set_input_line(FMSCSI_LINE_MSG,0);
+ set_input_line(FMSCSI_LINE_IO,1);
+ set_input_line(FMSCSI_LINE_REQ,1);
+ // start transfer timer
+ m_transfer_timer->adjust(attotime::zero,0,attotime::from_hz(3000000)); // arbitrary value for now
+ m_SCSIdevices[m_target]->ReadData(m_buffer,512);
+ m_result_index = 0;
+ logerror("FMSCSI: Starting transfer (%i)\n",m_result_length);
+ break;
+ case SCSI_PHASE_DATAOUT:
+ set_input_line(FMSCSI_LINE_CD,0);
+ set_input_line(FMSCSI_LINE_MSG,0);
+ set_input_line(FMSCSI_LINE_IO,0);
+ set_input_line(FMSCSI_LINE_REQ,1);
+ // start transfer timer
+ m_transfer_timer->adjust(attotime::zero,0,attotime::from_hz(3000000)); // arbitrary value for now
+ m_result_index = 0;
+ logerror("FMSCSI: Starting transfer (%i)\n",m_result_length);
+ break;
+ case SCSI_PHASE_MESSAGE_IN:
+ set_input_line(FMSCSI_LINE_CD,1);
+ set_input_line(FMSCSI_LINE_MSG,1);
+ set_input_line(FMSCSI_LINE_IO,1);
+ set_input_line(FMSCSI_LINE_REQ,1);
+ break;
+ case SCSI_PHASE_MESSAGE_OUT:
+ set_input_line(FMSCSI_LINE_CD,1);
+ set_input_line(FMSCSI_LINE_MSG,1);
+ set_input_line(FMSCSI_LINE_IO,0);
+ set_input_line(FMSCSI_LINE_REQ,1);
+ break;
+ }
+}
+
+int fmscsi_device::get_phase(void)
+{
+ return m_phase;
+}
+
+void fmscsi_device::set_input_line(UINT8 line, UINT8 state)
+{
+ if(line == FMSCSI_LINE_REQ)
+ {
+ if(state != 0 && !(m_input_lines & FMSCSI_LINE_REQ)) // low to high
+ {
+ if(m_output_lines & FMSCSI_LINE_IMSK && m_phase != SCSI_PHASE_DATAIN && m_phase != SCSI_PHASE_DATAOUT)
+ {
+ set_input_line(FMSCSI_LINE_INT,1);
+ m_irq_func(1);
+ logerror("FMSCSI: IRQ high\n");
+ }
+ }
+ if(state == 0 && (m_input_lines & FMSCSI_LINE_REQ)) // high to low
+ {
+ if(m_output_lines & FMSCSI_LINE_IMSK && m_phase != SCSI_PHASE_DATAIN && m_phase != SCSI_PHASE_DATAOUT)
+ {
+ set_input_line(FMSCSI_LINE_INT,0);
+ m_irq_func(0);
+ logerror("FMSCSI: IRQ low\n");
+ }
+ }
+ }
+ if(state != 0)
+ m_input_lines |= line;
+ else
+ m_input_lines &= ~line;
+// logerror("FMSCSI: input line %02x set to %i\n",line,state);
+}
+
+UINT8 fmscsi_device::get_input_line(UINT8 line)
+{
+ return m_input_lines & line;
+}
+
+void fmscsi_device::set_output_line(UINT8 line, UINT8 state)
+{
+ if(line == FMSCSI_LINE_RST && state != 0)
+ {
+ device_reset();
+ logerror("FMSCSI: reset\n");
+ }
+
+ if(line == FMSCSI_LINE_SEL)
+ {
+ if(state != 0 && !(m_output_lines & FMSCSI_LINE_SEL)) // low to high transition
+ {
+ void *image;
+ m_SCSIdevices[m_target]->GetDevice(&image);
+ if (image != NULL) // if device is mounted
+ {
+ m_phase_timer->adjust(attotime::from_usec(800),SCSI_PHASE_COMMAND);
+ m_data = 0x08;
+ }
+ }
+ }
+
+ if(line == FMSCSI_LINE_ATN)
+ {
+ if(state != 0)
+ m_phase_timer->adjust(attotime::from_usec(800),SCSI_PHASE_MESSAGE_OUT);
+ }
+
+ if(state != 0)
+ m_output_lines |= line;
+ else
+ m_output_lines &= ~line;
+// logerror("FMSCSI: output line %02x set to %i\n",line,state);
+}
+
+UINT8 fmscsi_device::get_output_line(UINT8 line)
+{
+ return m_output_lines & line;
+}
+
+UINT8 fmscsi_device::fmscsi_status_r(void)
+{
+ // status inputs
+ return m_input_lines;
+}
+
+void fmscsi_device::fmscsi_control_w(UINT8 data)
+{
+ // control outputs
+ set_output_line(FMSCSI_LINE_RST,data & FMSCSI_LINE_RST);
+ set_output_line(FMSCSI_LINE_DMAE,data & FMSCSI_LINE_DMAE);
+ set_output_line(FMSCSI_LINE_IMSK,data & FMSCSI_LINE_IMSK);
+ set_output_line(FMSCSI_LINE_ATN,data & FMSCSI_LINE_ATN);
+ set_output_line(FMSCSI_LINE_WEN,data & FMSCSI_LINE_WEN);
+ set_output_line(FMSCSI_LINE_SEL,data & FMSCSI_LINE_SEL);
+ logerror("FMSCSI: control write %02x\n",data);
+}
+
+READ8_MEMBER( fmscsi_device::fmscsi_r )
+{
+ switch(offset & 0x03)
+ {
+ case 0x00:
+ return fmscsi_data_r();
+ case 0x01:
+ return fmscsi_status_r();
+ case 0x02:
+ return 0x80; // Linux uses this port to detect the ability to do word transfers. We'll tell it that it doesn't for now.
+ default:
+ logerror("FMSCSI: Unknown read at offset %i\n",offset);
+ }
+ return 0;
+}
+
+WRITE8_MEMBER( fmscsi_device::fmscsi_w )
+{
+ switch(offset & 0x03)
+ {
+ case 0x00:
+ fmscsi_data_w(data);
+ break;
+ case 0x01:
+ fmscsi_control_w(data);
+ break;
+ default:
+ logerror("FMSCSI: Unknown write 0x%02x at offset %i\n",data,offset);
+ }
+}
diff --git a/src/mess/machine/fm_scsi.h b/src/mess/machine/fm_scsi.h
new file mode 100644
index 00000000000..1b8aaed981d
--- /dev/null
+++ b/src/mess/machine/fm_scsi.h
@@ -0,0 +1,107 @@
+/*
+ * fm_scsi.h
+ *
+ * SCSI controller used in Fujitsu FMR-50, FMR-60, and FM-Towns
+ *
+ */
+
+#ifndef FM_SCSI_H_
+#define FM_SCSI_H_
+
+#include "machine/scsi.h"
+#include "machine/scsidev.h"
+
+// SCSI input lines (from target)
+#define FMSCSI_LINE_REQ 0x80
+#define FMSCSI_LINE_IO 0x40
+#define FMSCSI_LINE_MSG 0x20
+#define FMSCSI_LINE_CD 0x10
+#define FMSCSI_LINE_BSY 0x08
+#define FMSCSI_LINE_EX 0x04
+#define FMSCSI_LINE_INT 0x02
+#define FMSCSI_LINE_PERR 0x01
+
+// SCSI output lines (to target)
+#define FMSCSI_LINE_WEN 0x80
+#define FMSCSI_LINE_IMSK 0x40
+#define FMSCSI_LINE_RMSK 0x20
+#define FMSCSI_LINE_ATN 0x10
+#define FMSCSI_LINE_WRD 0x08
+#define FMSCSI_LINE_SEL 0x04
+#define FMSCSI_LINE_DMAE 0x02
+#define FMSCSI_LINE_RST 0x01
+
+// these aren't defined in scsi.h
+#define SCSI_PHASE_BUS_FREE 8
+#define SCSI_PHASE_SELECT 9
+
+struct FMSCSIinterface
+{
+ const SCSIConfigTable *scsidevs; /* SCSI devices */
+ devcb_write_line irq_callback; /* irq callback */
+ devcb_write_line drq_callback; /* drq callback */
+};
+
+#define MCFG_FMSCSI_ADD(_tag, _intrf) \
+ MCFG_DEVICE_ADD(_tag, FMSCSI, 0) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+class fmscsi_device : public device_t,
+ public FMSCSIinterface
+{
+public:
+ // construction/destruction
+ fmscsi_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // any publically accessible interfaces needed for runtime
+ UINT8 fmscsi_data_r(void);
+ void fmscsi_data_w(UINT8 data);
+ UINT8 fmscsi_status_r(void);
+ void fmscsi_control_w(UINT8 data);
+ DECLARE_READ8_MEMBER( fmscsi_r );
+ DECLARE_WRITE8_MEMBER( fmscsi_w );
+
+ void set_phase(int phase);
+ int get_phase(void);
+ void set_input_line(UINT8 line, UINT8 state);
+ UINT8 get_input_line(UINT8 line);
+ void set_output_line(UINT8 line, UINT8 state);
+ UINT8 get_output_line(UINT8 line);
+
+protected:
+ // device-level overrides (none are required, but these are common)
+ 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();
+
+private:
+ // internal device state goes here
+ static const device_timer_id TIMER_TRANSFER = 0;
+ static const device_timer_id TIMER_PHASE = 1;
+
+ int get_scsi_cmd_len(UINT8 cbyte);
+
+ devcb_resolved_write_line m_irq_func;
+ devcb_resolved_write_line m_drq_func;
+
+ scsidev_device* m_SCSIdevices[8];
+ UINT8 m_command[32];
+ UINT8 m_result[32];
+ UINT8 m_command_index;
+ int m_result_length;
+ UINT32 m_result_index;
+ UINT8 m_input_lines;
+ UINT8 m_output_lines;
+ UINT8 m_data;
+ UINT8 m_last_id;
+ UINT8 m_phase;
+ UINT8 m_target;
+ UINT8 m_buffer[512];
+ emu_timer* m_transfer_timer;
+ emu_timer* m_phase_timer;
+};
+
+extern const device_type FMSCSI;
+
+#endif /* FM_SCSI_H_ */
diff --git a/src/mess/machine/galaxy.c b/src/mess/machine/galaxy.c
new file mode 100644
index 00000000000..57392644ec6
--- /dev/null
+++ b/src/mess/machine/galaxy.c
@@ -0,0 +1,214 @@
+/***************************************************************************
+
+ machine.c
+
+ Functions to emulate general aspects of the machine (RAM, ROM, interrupts,
+ I/O ports)
+
+***************************************************************************/
+
+#include "emu.h"
+#include "cpu/z80/z80.h"
+#include "includes/galaxy.h"
+#include "imagedev/cassette.h"
+#include "machine/ram.h"
+
+/***************************************************************************
+ I/O devices
+***************************************************************************/
+
+READ8_MEMBER(galaxy_state::galaxy_keyboard_r)
+{
+ static const char *const keynames[] = { "LINE0", "LINE1", "LINE2", "LINE3", "LINE4", "LINE5", "LINE6", "LINE7" };
+
+ if (offset == 0)
+ {
+ double level = (machine().device<cassette_image_device>(CASSETTE_TAG)->input());
+ return (level > 0) ? 0xfe : 0xff;
+ }
+ else
+ {
+ return ioport(keynames[(offset>>3) & 0x07])->read() & (0x01<<(offset & 0x07)) ? 0xfe : 0xff;
+ }
+}
+
+WRITE8_MEMBER(galaxy_state::galaxy_latch_w)
+{
+ double val = (((data >>6) & 1 ) + ((data >> 2) & 1) - 1) * 32000;
+ m_latch_value = data;
+ machine().device<cassette_image_device>(CASSETTE_TAG)->output(val);
+}
+
+
+
+/***************************************************************************
+ Interrupts
+***************************************************************************/
+
+INTERRUPT_GEN( galaxy_interrupt )
+{
+ device_set_input_line(device, 0, HOLD_LINE);
+}
+
+static IRQ_CALLBACK ( galaxy_irq_callback )
+{
+ galaxy_state *state = device->machine().driver_data<galaxy_state>();
+ galaxy_set_timer(device->machine());
+ state->m_interrupts_enabled = TRUE;
+ return 0xff;
+}
+
+/***************************************************************************
+ Snapshot files (GAL)
+***************************************************************************/
+
+#define GALAXY_SNAPSHOT_V1_SIZE 8268
+#define GALAXY_SNAPSHOT_V2_SIZE 8244
+
+static void galaxy_setup_snapshot (running_machine &machine, const UINT8 * data, UINT32 size)
+{
+ device_t *cpu = machine.device("maincpu");
+
+ switch (size)
+ {
+ case GALAXY_SNAPSHOT_V1_SIZE:
+ cpu_set_reg(cpu, Z80_AF, data[0x00] | data[0x01] << 8);
+ cpu_set_reg(cpu, Z80_BC, data[0x04] | data[0x05] << 8);
+ cpu_set_reg(cpu, Z80_DE, data[0x08] | data[0x09] << 8);
+ cpu_set_reg(cpu, Z80_HL, data[0x0c] | data[0x0d] << 8);
+ cpu_set_reg(cpu, Z80_IX, data[0x10] | data[0x11] << 8);
+ cpu_set_reg(cpu, Z80_IY, data[0x14] | data[0x15] << 8);
+ cpu_set_reg(cpu, Z80_PC, data[0x18] | data[0x19] << 8);
+ cpu_set_reg(cpu, Z80_SP, data[0x1c] | data[0x1d] << 8);
+ cpu_set_reg(cpu, Z80_AF2, data[0x20] | data[0x21] << 8);
+ cpu_set_reg(cpu, Z80_BC2, data[0x24] | data[0x25] << 8);
+ cpu_set_reg(cpu, Z80_DE2, data[0x28] | data[0x29] << 8);
+ cpu_set_reg(cpu, Z80_HL2, data[0x2c] | data[0x2d] << 8);
+ cpu_set_reg(cpu, Z80_IFF1, data[0x30]);
+ cpu_set_reg(cpu, Z80_IFF2, data[0x34]);
+ cpu_set_reg(cpu, Z80_HALT, data[0x38]);
+ cpu_set_reg(cpu, Z80_IM, data[0x3c]);
+ cpu_set_reg(cpu, Z80_I, data[0x40]);
+ cpu_set_reg(cpu, Z80_R, (data[0x44] & 0x7f) | (data[0x48] & 0x80));
+
+ memcpy (machine.device<ram_device>(RAM_TAG)->pointer(), data + 0x084c, (machine.device<ram_device>(RAM_TAG)->size() < 0x1800) ? machine.device<ram_device>(RAM_TAG)->size() : 0x1800);
+
+ break;
+ case GALAXY_SNAPSHOT_V2_SIZE:
+ cpu_set_reg(cpu, Z80_AF, data[0x00] | data[0x01] << 8);
+ cpu_set_reg(cpu, Z80_BC, data[0x02] | data[0x03] << 8);
+ cpu_set_reg(cpu, Z80_DE, data[0x04] | data[0x05] << 8);
+ cpu_set_reg(cpu, Z80_HL, data[0x06] | data[0x07] << 8);
+ cpu_set_reg(cpu, Z80_IX, data[0x08] | data[0x09] << 8);
+ cpu_set_reg(cpu, Z80_IY, data[0x0a] | data[0x0b] << 8);
+ cpu_set_reg(cpu, Z80_PC, data[0x0c] | data[0x0d] << 8);
+ cpu_set_reg(cpu, Z80_SP, data[0x0e] | data[0x0f] << 8);
+ cpu_set_reg(cpu, Z80_AF2, data[0x10] | data[0x11] << 8);
+ cpu_set_reg(cpu, Z80_BC2, data[0x12] | data[0x13] << 8);
+ cpu_set_reg(cpu, Z80_DE2, data[0x14] | data[0x15] << 8);
+ cpu_set_reg(cpu, Z80_HL2, data[0x16] | data[0x17] << 8);
+
+ cpu_set_reg(cpu, Z80_IFF1, data[0x18] & 0x01);
+ cpu_set_reg(cpu, Z80_IFF2, (UINT64)0);
+
+ cpu_set_reg(cpu, Z80_HALT, (UINT64)0);
+
+ cpu_set_reg(cpu, Z80_IM, (data[0x18] >> 1) & 0x03);
+
+ cpu_set_reg(cpu, Z80_I, data[0x19]);
+ cpu_set_reg(cpu, Z80_R, data[0x1a]);
+
+ memcpy (machine.device<ram_device>(RAM_TAG)->pointer(), data + 0x0834, (machine.device<ram_device>(RAM_TAG)->size() < 0x1800) ? machine.device<ram_device>(RAM_TAG)->size() : 0x1800);
+
+ break;
+ }
+
+ device_set_input_line(cpu, INPUT_LINE_NMI, CLEAR_LINE);
+ device_set_input_line(cpu, INPUT_LINE_IRQ0, CLEAR_LINE);
+}
+
+SNAPSHOT_LOAD( galaxy )
+{
+ UINT8* snapshot_data;
+
+ switch (snapshot_size)
+ {
+ case GALAXY_SNAPSHOT_V1_SIZE:
+ case GALAXY_SNAPSHOT_V2_SIZE:
+ snapshot_data = auto_alloc_array(image.device().machine(), UINT8, snapshot_size);
+ break;
+ default:
+ return IMAGE_INIT_FAIL;
+ }
+
+ image.fread( snapshot_data, snapshot_size);
+
+ galaxy_setup_snapshot(image.device().machine(), snapshot_data, snapshot_size);
+
+ return IMAGE_INIT_PASS;
+}
+
+
+/***************************************************************************
+ Driver Initialization
+***************************************************************************/
+
+DRIVER_INIT_MEMBER(galaxy_state,galaxy)
+{
+ address_space *space = machine().device("maincpu")->memory().space(AS_PROGRAM);
+ space->install_readwrite_bank( 0x2800, 0x2800 + machine().device<ram_device>(RAM_TAG)->size() - 1, "bank1");
+ membank("bank1")->set_base(machine().device<ram_device>(RAM_TAG)->pointer());
+
+ if (machine().device<ram_device>(RAM_TAG)->size() < (6 + 48) * 1024)
+ {
+ space->nop_readwrite( 0x2800 + machine().device<ram_device>(RAM_TAG)->size(), 0xffff);
+ }
+}
+
+/***************************************************************************
+ Machine Initialization
+***************************************************************************/
+
+MACHINE_RESET( galaxy )
+{
+ galaxy_state *state = machine.driver_data<galaxy_state>();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ /* ROM 2 enable/disable */
+ if (machine.root_device().ioport("ROM2")->read()) {
+ space->install_read_bank(0x1000, 0x1fff, "bank10");
+ } else {
+ space->nop_read(0x1000, 0x1fff);
+ }
+ space->nop_write(0x1000, 0x1fff);
+
+ if (machine.root_device().ioport("ROM2")->read())
+ state->membank("bank10")->set_base(machine.root_device().memregion("maincpu")->base() + 0x1000);
+
+ device_set_irq_callback(machine.device("maincpu"), galaxy_irq_callback);
+ state->m_interrupts_enabled = TRUE;
+}
+
+DRIVER_INIT_MEMBER(galaxy_state,galaxyp)
+{
+ DRIVER_INIT_CALL(galaxy);
+}
+
+MACHINE_RESET( galaxyp )
+{
+ galaxy_state *state = machine.driver_data<galaxy_state>();
+ UINT8 *ROM = machine.root_device().memregion("maincpu")->base();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ device_set_irq_callback(machine.device("maincpu"), galaxy_irq_callback);
+
+ ROM[0x0037] = 0x29;
+ ROM[0x03f9] = 0xcd;
+ ROM[0x03fa] = 0x00;
+ ROM[0x03fb] = 0xe0;
+
+ space->install_read_bank(0xe000, 0xefff, "bank11");
+ space->nop_write(0xe000, 0xefff);
+ state->membank("bank11")->set_base(state->memregion("maincpu")->base() + 0xe000);
+ state->m_interrupts_enabled = TRUE;
+}
diff --git a/src/mess/machine/gamecom.c b/src/mess/machine/gamecom.c
new file mode 100644
index 00000000000..49a278029c8
--- /dev/null
+++ b/src/mess/machine/gamecom.c
@@ -0,0 +1,637 @@
+
+#include "includes/gamecom.h"
+
+
+
+static const int gamecom_timer_limit[8] = { 2, 1024, 2048, 4096, 8192, 16384, 32768, 65536 };
+
+static TIMER_CALLBACK(gamecom_clock_timer_callback)
+{
+ UINT8 * RAM = machine.root_device().memregion("maincpu")->base();
+ UINT8 val = ( ( RAM[SM8521_CLKT] & 0x3F ) + 1 ) & 0x3F;
+ RAM[SM8521_CLKT] = ( RAM[SM8521_CLKT] & 0xC0 ) | val;
+ cputag_set_input_line(machine, "maincpu", CK_INT, ASSERT_LINE );
+}
+
+MACHINE_RESET( gamecom )
+{
+ gamecom_state *state = machine.driver_data<gamecom_state>();
+ UINT8 *rom = state->memregion("kernel")->base();
+ state->membank( "bank1" )->set_base( rom );
+ state->membank( "bank2" )->set_base( rom );
+ state->membank( "bank3" )->set_base( rom );
+ state->membank( "bank4" )->set_base( rom );
+
+ state->m_cartridge = NULL;
+}
+
+void gamecom_state::gamecom_set_mmu(UINT8 mmu, UINT8 data )
+{
+ char bank[8];
+ sprintf(bank,"bank%d",mmu);
+ if (data < 0x20)
+ {
+ /* select internal ROM bank */
+ membank( bank )->set_base( memregion("kernel")->base() + (data << 13) );
+ }
+ else
+ {
+ /* select cartridge bank */
+ if ( m_cartridge )
+ membank( bank )->set_base( m_cartridge + ( data << 13 ) );
+ }
+}
+
+void gamecom_state::handle_stylus_press( int column )
+{
+ static const UINT16 row_data[17] = { 0x3FE, 0x3FD, 0x3FB, 0x3F7, 0x3EF, 0x3DF, 0x3BF, 0x37F, 0x2FF, 0x1FF };
+
+ if ( column == 0 )
+ {
+ if ( !BIT( ioport("IN2")->read(), 2) )
+ {
+ m_stylus_x = ioport("STYX")->read() >> 4;
+ m_stylus_y = ioport("STYY")->read() >> 4;
+ }
+ else
+ {
+ m_stylus_x = 16;
+ m_stylus_y = 16;
+ }
+ }
+
+ if ( m_stylus_x == column )
+ {
+ m_p_ram[SM8521_P0] = row_data[m_stylus_y];
+ m_p_ram[SM8521_P1] = ( m_p_ram[SM8521_P1] & 0xFC ) | ( ( row_data[m_stylus_y] >> 8 ) & 3 );
+ }
+ else
+ {
+ m_p_ram[SM8521_P0] = 0xFF;
+ m_p_ram[SM8521_P1] = ( m_p_ram[SM8521_P1] & 0xFC ) | 3;
+ }
+}
+
+WRITE8_MEMBER( gamecom_state::gamecom_pio_w )
+{
+ offset += 0x14;
+ m_p_ram[offset] = data;
+ switch( offset )
+ {
+ case SM8521_P2: switch( ( m_p_ram[SM8521_P1] << 8 ) | data )
+ {
+ case 0xFBFF: /* column #0 */
+ /* P0 bit 0 cleared => 01 */
+ /* P0 bit 1 cleared => 0E */
+ /* P0 bit 2 cleared => 1B */
+ /* P0 bit 3 cleared => etc */
+ /* P0 bit 4 cleared => */
+ /* P0 bit 5 cleared => */
+ /* P0 bit 6 cleared => */
+ /* P0 bit 7 cleared => */
+ /* P1 bit 0 cleared => */
+ /* P1 bit 1 cleared => */
+ handle_stylus_press(0);
+ break;
+ case 0xF7FF: /* column #1 */
+ handle_stylus_press(1);
+ break;
+ case 0xEFFF: /* column #2 */
+ handle_stylus_press(2);
+ break;
+ case 0xDFFF: /* column #3 */
+ handle_stylus_press(3);
+ break;
+ case 0xBFFF: /* column #4 */
+ handle_stylus_press(4);
+ break;
+ case 0x7FFF: /* column #5 */
+ handle_stylus_press(5);
+ break;
+ case 0xFFFE: /* column #6 */
+ handle_stylus_press(6);
+ break;
+ case 0xFFFD: /* column #7 */
+ handle_stylus_press(7);
+ break;
+ case 0xFFFB: /* column #8 */
+ handle_stylus_press(8);
+ break;
+ case 0xFFF7: /* column #9 */
+ handle_stylus_press(9);
+ break;
+ case 0xFFEF: /* column #10 */
+ handle_stylus_press(10);
+ break;
+ case 0xFFDF: /* column #11 */
+ handle_stylus_press(11);
+ break;
+ case 0xFFBF: /* column #12 */
+ handle_stylus_press(12);
+ break;
+ case 0xFF7F: /* keys #1 */
+ /* P0 bit 0 cleared => 83 (up) */
+ /* P0 bit 1 cleared => 84 (down) */
+ /* P0 bit 2 cleared => 85 (left) */
+ /* P0 bit 3 cleared => 86 (right) */
+ /* P0 bit 4 cleared => 87 (menu) */
+ /* P0 bit 5 cleared => 8A (pause) */
+ /* P0 bit 6 cleared => 89 (sound) */
+ /* P0 bit 7 cleared => 8B (button A) */
+ /* P1 bit 0 cleared => 8C (button B) */
+ /* P1 bit 1 cleared => 8D (button C) */
+ m_p_ram[SM8521_P0] = ioport("IN0")->read();
+ m_p_ram[SM8521_P1] = (m_p_ram[SM8521_P1] & 0xFC) | ( ioport("IN1")->read() & 3 );
+ break;
+ case 0xFFFF: /* keys #2 */
+ /* P0 bit 0 cleared => 88 (power) */
+ /* P0 bit 1 cleared => 8E (button D) */
+ /* P0 bit 2 cleared => A0 */
+ /* P0 bit 3 cleared => A0 */
+ /* P0 bit 4 cleared => A0 */
+ /* P0 bit 5 cleared => A0 */
+ /* P0 bit 6 cleared => A0 */
+ /* P0 bit 7 cleared => A0 */
+ /* P1 bit 0 cleared => A0 */
+ /* P1 bit 1 cleared => A0 */
+ m_p_ram[SM8521_P0] = (m_p_ram[SM8521_P0] & 0xFC) | ( ioport("IN2")->read() & 3 );
+ m_p_ram[SM8521_P1] = 0xFF;
+ break;
+ }
+ return;
+ case SM8521_P3:
+ /* P3 bit7 clear, bit6 set -> enable cartridge port #0? */
+ /* P3 bit6 clear, bit7 set -> enable cartridge port #1? */
+ switch( data & 0xc0 )
+ {
+ case 0x40: m_cartridge = m_cartridge1; break;
+ case 0x80: m_cartridge = m_cartridge2; break;
+ default: m_cartridge = NULL; break;
+ }
+ return;
+ }
+}
+
+READ8_MEMBER( gamecom_state::gamecom_pio_r )
+{
+ return m_p_ram[offset + 0x14];
+}
+
+READ8_MEMBER( gamecom_state::gamecom_internal_r )
+{
+ return m_p_ram[offset + 0x20];
+}
+
+WRITE8_MEMBER( gamecom_state::gamecom_internal_w )
+{
+ offset += 0x20;
+ switch( offset )
+ {
+ case SM8521_MMU0: /* disable bootstrap ROM? most likely not written to on game.com */
+ logerror( "Write to MMU0\n" );
+ break;
+ case SM8521_MMU1:
+ gamecom_set_mmu(1, data);
+ break;
+ case SM8521_MMU2:
+ gamecom_set_mmu(2, data);
+ break;
+ case SM8521_MMU3:
+ gamecom_set_mmu(3, data);
+ break;
+ case SM8521_MMU4:
+ gamecom_set_mmu(4, data);
+ break;
+
+ /* Video hardware and DMA */
+ case SM8521_DMBR:
+ data &= 0x7f;
+ break;
+ case SM8521_TM0D:
+ m_timer[0].check_value = data;
+ return;
+ case SM8521_TM0C:
+ m_timer[0].enabled = data & 0x80;
+ m_timer[0].state_limit = gamecom_timer_limit[data & 0x07];
+ m_timer[0].state_count = 0;
+ m_p_ram[SM8521_TM0D] = 0;
+ break;
+ case SM8521_TM1D:
+ m_timer[1].check_value = data;
+ return;
+ case SM8521_TM1C:
+ m_timer[1].enabled = data & 0x80;
+ m_timer[1].state_limit = gamecom_timer_limit[data & 0x07];
+ m_timer[1].state_count = 0;
+ m_p_ram[SM8521_TM1D] = 0;
+ break;
+ case SM8521_CLKT: /* bit 6-7 */
+ if ( data & 0x80 )
+ {
+ /* timer run */
+ if ( data & 0x40 )
+ {
+ /* timer resolution 1 minute */
+ m_clock_timer->adjust(attotime::from_seconds(1), 0, attotime::from_seconds(60));
+ }
+ else
+ {
+ /* TImer resolution 1 second */
+ m_clock_timer->adjust(attotime::from_seconds(1), 0, attotime::from_seconds(1));
+ }
+ }
+ else
+ {
+ /* disable timer reset */
+ m_clock_timer->enable( 0 );
+ data &= 0xC0;
+ }
+ break;
+
+ /* Sound */
+ case SM8521_SGC:
+ m_sound.sgc = data;
+ break;
+ case SM8521_SG0L:
+ m_sound.sg0l = data;
+ break;
+ case SM8521_SG1L:
+ m_sound.sg1l = data;
+ break;
+ case SM8521_SG0TH:
+ m_sound.sg0t = ( m_sound.sg0t & 0xFF ) | ( data << 8 );
+ break;
+ case SM8521_SG0TL:
+ m_sound.sg0t = ( m_sound.sg0t & 0xFF00 ) | data;
+ break;
+ case SM8521_SG1TH:
+ m_sound.sg1t = ( m_sound.sg1t & 0xFF ) | ( data << 8 );
+ break;
+ case SM8521_SG1TL:
+ m_sound.sg1t = ( m_sound.sg1t & 0xFF00 ) | data;
+ break;
+ case SM8521_SG2L:
+ m_sound.sg2l = data;
+ break;
+ case SM8521_SG2TH:
+ m_sound.sg2t = ( m_sound.sg2t & 0xFF ) | ( data << 8 );
+ break;
+ case SM8521_SG2TL:
+ m_sound.sg2t = ( m_sound.sg2t & 0xFF00 ) | data;
+ break;
+ case SM8521_SGDA:
+ m_sound.sgda = data;
+ break;
+
+ case SM8521_SG0W0:
+ case SM8521_SG0W1:
+ case SM8521_SG0W2:
+ case SM8521_SG0W3:
+ case SM8521_SG0W4:
+ case SM8521_SG0W5:
+ case SM8521_SG0W6:
+ case SM8521_SG0W7:
+ case SM8521_SG0W8:
+ case SM8521_SG0W9:
+ case SM8521_SG0W10:
+ case SM8521_SG0W11:
+ case SM8521_SG0W12:
+ case SM8521_SG0W13:
+ case SM8521_SG0W14:
+ case SM8521_SG0W15:
+ m_sound.sg0w[offset - SM8521_SG0W0] = data;
+ break;
+ case SM8521_SG1W0:
+ case SM8521_SG1W1:
+ case SM8521_SG1W2:
+ case SM8521_SG1W3:
+ case SM8521_SG1W4:
+ case SM8521_SG1W5:
+ case SM8521_SG1W6:
+ case SM8521_SG1W7:
+ case SM8521_SG1W8:
+ case SM8521_SG1W9:
+ case SM8521_SG1W10:
+ case SM8521_SG1W11:
+ case SM8521_SG1W12:
+ case SM8521_SG1W13:
+ case SM8521_SG1W14:
+ case SM8521_SG1W15:
+ m_sound.sg1w[offset - SM8521_SG1W0] = data;
+ break;
+
+ /* Reserved addresses */
+ case SM8521_18: case SM8521_1B:
+ case SM8521_29: case SM8521_2A: case SM8521_2F:
+ case SM8521_33: case SM8521_3E: case SM8521_3F:
+ case SM8521_41: case SM8521_43: case SM8521_45: case SM8521_4B:
+ case SM8521_4F:
+ case SM8521_55: case SM8521_56: case SM8521_57: case SM8521_58:
+ case SM8521_59: case SM8521_5A: case SM8521_5B: case SM8521_5C:
+ case SM8521_5D:
+ logerror( "%X: Write to reserved address (0x%02X). Value written: 0x%02X\n", cpu_get_pc(m_maincpu), offset, data );
+ break;
+ }
+ m_p_ram[offset] = data;
+}
+
+
+/* The manual is not conclusive as to which bit of the DMVP register (offset 0x3D) determines
+ which page for source or destination is used */
+/* For now the increment/decrement-x and increment/decrement-y parts are NOT supported.
+ Their usage is also not explained properly in the manuals. Guess we'll have to wait
+ for them to show up in some rom images...
+ */
+void gamecom_handle_dma( device_t *device, int cycles )
+{
+ gamecom_state *state = device->machine().driver_data<gamecom_state>();
+ UINT8 * RAM = state->memregion("maincpu")->base();
+ UINT8 data = RAM[SM8521_DMC];
+ state->m_dma.overwrite_mode = data & 0x01;
+ state->m_dma.transfer_mode = data & 0x06;
+ state->m_dma.decrement_x = data & 0x08;
+ state->m_dma.decrement_y = data & 0x10;
+ state->m_dma.enabled = data & 0x80;
+ if ( !state->m_dma.enabled ) return;
+
+
+ if ( state->m_dma.decrement_x || state->m_dma.decrement_y )
+ logerror( "TODO: Decrement-x and decrement-y are not supported yet\n" );
+
+ state->m_dma.width_x = RAM[SM8521_DMDX];
+ state->m_dma.width_x_count = 0;
+ state->m_dma.width_y = RAM[SM8521_DMDY];
+ state->m_dma.width_y_count = 0;
+ state->m_dma.source_x = RAM[SM8521_DMX1];
+ state->m_dma.source_x_current = state->m_dma.source_x;
+ state->m_dma.source_y = RAM[SM8521_DMY1];
+ state->m_dma.source_width = ( RAM[SM8521_LCH] & 0x20 ) ? 50 : 40;
+ state->m_dma.dest_x = RAM[SM8521_DMX2];
+ state->m_dma.dest_x_current = state->m_dma.dest_x;
+ state->m_dma.dest_y = RAM[SM8521_DMY2];
+ state->m_dma.dest_width = ( RAM[SM8521_LCH] & 0x20 ) ? 50 : 40;
+ state->m_dma.palette[0] = RAM[SM8521_DMPL] & 0x03;
+ state->m_dma.palette[1] = ( RAM[SM8521_DMPL] >> 2 ) & 3;
+ state->m_dma.palette[2] = ( RAM[SM8521_DMPL] >> 4 ) & 3;
+ state->m_dma.palette[3] = RAM[SM8521_DMPL] >> 6;
+ state->m_dma.source_mask = 0x1FFF;
+ state->m_dma.dest_mask = 0x1FFF;
+// logerror("DMA: width %Xx%X, source (%X,%X), dest (%X,%X), transfer_mode %X, banks %X \n", state->m_dma.width_x, state->m_dma.width_y, state->m_dma.source_x, state->m_dma.source_y, state->m_dma.dest_x, state->m_dma.dest_y, state->m_dma.transfer_mode, RAM[SM8521_DMVP] );
+// logerror( " Palette: %d, %d, %d, %d\n", state->m_dma.palette[0], state->m_dma.palette[1], state->m_dma.palette[2], state->m_dma.palette[3] );
+ switch( state->m_dma.transfer_mode )
+ {
+ case 0x00:
+ /* VRAM->VRAM */
+ state->m_dma.source_bank = &state->m_p_videoram[(RAM[SM8521_DMVP] & 0x01) ? 0x2000 : 0x0000];
+ state->m_dma.dest_bank = &state->m_p_videoram[(RAM[SM8521_DMVP] & 0x02) ? 0x2000 : 0x0000];
+ break;
+ case 0x02:
+ /* ROM->VRAM */
+// logerror( "DMA DMBR = %X\n", RAM[SM8521_DMBR] );
+ state->m_dma.source_width = 64;
+ state->m_dma.source_mask = 0x3FFF;
+ if ( RAM[SM8521_DMBR] < 16 )
+ state->m_dma.source_bank = state->memregion("kernel")->base() + (RAM[SM8521_DMBR] << 14);
+ else
+ if (state->m_cartridge)
+ state->m_dma.source_bank = state->m_cartridge + (RAM[SM8521_DMBR] << 14);
+
+ state->m_dma.dest_bank = &state->m_p_videoram[(RAM[SM8521_DMVP] & 0x02) ? 0x2000 : 0x0000];
+ break;
+ case 0x04:
+ /* Extend RAM->VRAM */
+ state->m_dma.source_width = 64;
+ state->m_dma.source_bank = &state->m_p_nvram[0x0000];
+ state->m_dma.dest_bank = &state->m_p_videoram[(RAM[SM8521_DMVP] & 0x02) ? 0x2000 : 0x0000];
+ break;
+ case 0x06:
+ /* VRAM->Extend RAM */
+ state->m_dma.source_bank = &state->m_p_videoram[(RAM[SM8521_DMVP] & 0x01) ? 0x2000 : 0x0000];
+ state->m_dma.dest_width = 64;
+ state->m_dma.dest_bank = &state->m_p_nvram[0x0000];
+ break;
+ }
+ state->m_dma.source_current = state->m_dma.source_width * state->m_dma.source_y;
+ state->m_dma.source_current += state->m_dma.source_x >> 2;
+ state->m_dma.dest_current = state->m_dma.dest_width * state->m_dma.dest_y;
+ state->m_dma.dest_current += state->m_dma.dest_x >> 2;
+ state->m_dma.source_line = state->m_dma.source_current;
+ state->m_dma.dest_line = state->m_dma.dest_current;
+ state->m_dma.state_count = 0;
+
+ unsigned y_count, x_count;
+
+ for( y_count = 0; y_count <= state->m_dma.width_y; y_count++ )
+ {
+ for( x_count = 0; x_count <= state->m_dma.width_x; x_count++ )
+ {
+ int source_pixel = 0;
+ int dest_pixel = 0;
+ int src_addr = state->m_dma.source_current & state->m_dma.source_mask;
+ int dest_addr = state->m_dma.dest_current & state->m_dma.dest_mask;
+ /* handle DMA for 1 pixel */
+ /* Read pixel data */
+ switch ( state->m_dma.source_x_current & 0x03 )
+ {
+ case 0x00: source_pixel = state->m_dma.source_bank[src_addr] >> 6; break;
+ case 0x01: source_pixel = ( state->m_dma.source_bank[src_addr] >> 4 ) & 3; break;
+ case 0x02: source_pixel = ( state->m_dma.source_bank[src_addr] >> 2 ) & 3; break;
+ case 0x03: source_pixel = state->m_dma.source_bank[src_addr] & 3; break;
+ }
+
+ if ( !state->m_dma.overwrite_mode && source_pixel == 0 )
+ {
+ switch ( state->m_dma.dest_x_current & 0x03 )
+ {
+ case 0x00: dest_pixel = state->m_dma.dest_bank[dest_addr] >> 6; break;
+ case 0x01: dest_pixel = ( state->m_dma.dest_bank[dest_addr] >> 4 ) & 3; break;
+ case 0x02: dest_pixel = ( state->m_dma.dest_bank[dest_addr] >> 2 ) & 3; break;
+ case 0x03: dest_pixel = state->m_dma.dest_bank[dest_addr] & 3; break;
+ }
+ source_pixel = dest_pixel;
+ }
+
+ /* Translate pixel data using DMA palette. */
+ /* Not sure if this should be done before the compound stuff - WP */
+ source_pixel = state->m_dma.palette[ source_pixel ];
+ /* Write pixel data */
+ switch( state->m_dma.dest_x_current & 0x03 )
+ {
+ case 0x00:
+ state->m_dma.dest_bank[dest_addr] = ( state->m_dma.dest_bank[dest_addr] & 0x3F ) | ( source_pixel << 6 );
+ break;
+ case 0x01:
+ state->m_dma.dest_bank[dest_addr] = ( state->m_dma.dest_bank[dest_addr] & 0xCF ) | ( source_pixel << 4 );
+ break;
+ case 0x02:
+ state->m_dma.dest_bank[dest_addr] = ( state->m_dma.dest_bank[dest_addr] & 0xF3 ) | ( source_pixel << 2 );
+ break;
+ case 0x03:
+ state->m_dma.dest_bank[dest_addr] = ( state->m_dma.dest_bank[dest_addr] & 0xFC ) | source_pixel;
+ break;
+ }
+
+ /* Advance a pixel */
+ if ( state->m_dma.decrement_x )
+ {
+ state->m_dma.source_x_current--;
+ if ( ( state->m_dma.source_x_current & 0x03 ) == 0x03 )
+ state->m_dma.source_current--;
+ }
+ else
+ {
+ state->m_dma.source_x_current++;
+ if ( ( state->m_dma.source_x_current & 0x03 ) == 0x00 )
+ state->m_dma.source_current++;
+ }
+ state->m_dma.dest_x_current++;
+ if ( ( state->m_dma.dest_x_current & 0x03 ) == 0x00 )
+ state->m_dma.dest_current++;
+ }
+
+ /* Advance a line */
+ state->m_dma.source_x_current = state->m_dma.source_x;
+ state->m_dma.dest_x_current = state->m_dma.dest_x;
+ state->m_dma.source_line += state->m_dma.source_width;
+ state->m_dma.source_current = state->m_dma.source_line;
+ state->m_dma.dest_line += state->m_dma.dest_width;
+ state->m_dma.dest_current = state->m_dma.dest_line;
+ }
+ state->m_dma.enabled = 0;
+ cputag_set_input_line(device->machine(), "maincpu", DMA_INT, ASSERT_LINE );
+}
+
+void gamecom_update_timers( device_t *device, int cycles )
+{
+ gamecom_state *state = device->machine().driver_data<gamecom_state>();
+ UINT8 * RAM = state->memregion("maincpu")->base();
+ if ( state->m_timer[0].enabled )
+ {
+ state->m_timer[0].state_count += cycles;
+ while ( state->m_timer[0].state_count >= state->m_timer[0].state_limit )
+ {
+ state->m_timer[0].state_count -= state->m_timer[0].state_limit;
+ RAM[SM8521_TM0D]++;
+ if ( RAM[SM8521_TM0D] >= state->m_timer[0].check_value )
+ {
+ RAM[SM8521_TM0D] = 0;
+ cputag_set_input_line(device->machine(), "maincpu", TIM0_INT, ASSERT_LINE );
+ }
+ }
+ }
+ if ( state->m_timer[1].enabled )
+ {
+ state->m_timer[1].state_count += cycles;
+ while ( state->m_timer[1].state_count >= state->m_timer[1].state_limit )
+ {
+ state->m_timer[1].state_count -= state->m_timer[1].state_limit;
+ RAM[SM8521_TM1D]++;
+ if ( RAM[SM8521_TM1D] >= state->m_timer[1].check_value )
+ {
+ RAM[SM8521_TM1D] = 0;
+ cputag_set_input_line(device->machine(), "maincpu", TIM1_INT, ASSERT_LINE );
+ }
+ }
+ }
+}
+
+DRIVER_INIT_MEMBER(gamecom_state,gamecom)
+{
+ m_clock_timer = machine().scheduler().timer_alloc(FUNC(gamecom_clock_timer_callback));
+ m_p_ram = memregion("maincpu")->base(); // required here because pio_w gets called before machine_reset
+}
+
+DEVICE_IMAGE_LOAD( gamecom_cart1 )
+{
+ gamecom_state *state = image.device().machine().driver_data<gamecom_state>();
+ UINT32 filesize;
+ UINT32 load_offset = 0;
+
+ state->m_cartridge1 = state->memregion("cart1")->base();
+
+ if (image.software_entry() == NULL)
+ filesize = image.length();
+ else
+ filesize = image.get_software_region_length("rom");
+
+ switch(filesize)
+ {
+ case 0x008000: load_offset = 0; break; /* 32 KB */
+ case 0x040000: load_offset = 0; break; /* 256KB */
+ case 0x080000: load_offset = 0; break; /* 512KB */
+ case 0x100000: load_offset = 0; break; /* 1 MB */
+ case 0x1c0000: load_offset = 0x040000; break; /* 1.8MB */
+ case 0x200000: load_offset = 0; break; /* 2 MB */
+ default: /* otherwise */
+ logerror("Error loading cartridge: Invalid file size 0x%X\n", filesize);
+ image.seterror(IMAGE_ERROR_UNSPECIFIED, "Unhandled cart size");
+ return IMAGE_INIT_FAIL;
+ }
+
+ if (image.software_entry() == NULL)
+ {
+ if (image.fread( state->m_cartridge1 + load_offset, filesize) != filesize)
+ {
+ image.seterror(IMAGE_ERROR_UNSPECIFIED, "Unable to load all of the cart");
+ return IMAGE_INIT_FAIL;
+ }
+ }
+ else
+ memcpy(state->m_cartridge1 + load_offset, image.get_software_region("rom"), filesize);
+
+ if (filesize < 0x010000) { memcpy(state->m_cartridge1 + 0x008000, state->m_cartridge1, 0x008000); } /* ->64KB */
+ if (filesize < 0x020000) { memcpy(state->m_cartridge1 + 0x010000, state->m_cartridge1, 0x010000); } /* ->128KB */
+ if (filesize < 0x040000) { memcpy(state->m_cartridge1 + 0x020000, state->m_cartridge1, 0x020000); } /* ->256KB */
+ if (filesize < 0x080000) { memcpy(state->m_cartridge1 + 0x040000, state->m_cartridge1, 0x040000); } /* ->512KB */
+ if (filesize < 0x100000) { memcpy(state->m_cartridge1 + 0x080000, state->m_cartridge1, 0x080000); } /* ->1MB */
+ if (filesize < 0x1c0000) { memcpy(state->m_cartridge1 + 0x100000, state->m_cartridge1, 0x100000); } /* -> >=1.8MB */
+ return IMAGE_INIT_PASS;
+}
+
+DEVICE_IMAGE_LOAD( gamecom_cart2 )
+{
+ gamecom_state *state = image.device().machine().driver_data<gamecom_state>();
+ UINT32 filesize;
+ UINT32 load_offset = 0;
+
+ state->m_cartridge2 = state->memregion("cart2")->base();
+
+// if (image.software_entry() == NULL)
+ filesize = image.length();
+// else
+// filesize = image.get_software_region_length("rom");
+
+ switch(filesize)
+ {
+ case 0x008000: load_offset = 0; break; /* 32 KB */
+ case 0x040000: load_offset = 0; break; /* 256KB */
+ case 0x080000: load_offset = 0; break; /* 512KB */
+ case 0x100000: load_offset = 0; break; /* 1 MB */
+ case 0x1c0000: load_offset = 0x040000; break; /* 1.8MB */
+ case 0x200000: load_offset = 0; break; /* 2 MB */
+ default: /* otherwise */
+ logerror("Error loading cartridge: Invalid file size 0x%X\n", filesize);
+ image.seterror(IMAGE_ERROR_UNSPECIFIED, "Unhandled cart size");
+ return IMAGE_INIT_FAIL;
+ }
+
+// if (image.software_entry() == NULL)
+ {
+ if (image.fread( state->m_cartridge2 + load_offset, filesize) != filesize)
+ {
+ image.seterror(IMAGE_ERROR_UNSPECIFIED, "Unable to load all of the cart");
+ return IMAGE_INIT_FAIL;
+ }
+ }
+// else
+// memcpy(state->m_cartridge2 + load_offset, image.get_software_region("rom"), filesize);
+
+ if (filesize < 0x010000) { memcpy(state->m_cartridge2 + 0x008000, state->m_cartridge2, 0x008000); } /* ->64KB */
+ if (filesize < 0x020000) { memcpy(state->m_cartridge2 + 0x010000, state->m_cartridge2, 0x010000); } /* ->128KB */
+ if (filesize < 0x040000) { memcpy(state->m_cartridge2 + 0x020000, state->m_cartridge2, 0x020000); } /* ->256KB */
+ if (filesize < 0x080000) { memcpy(state->m_cartridge2 + 0x040000, state->m_cartridge2, 0x040000); } /* ->512KB */
+ if (filesize < 0x100000) { memcpy(state->m_cartridge2 + 0x080000, state->m_cartridge2, 0x080000); } /* ->1MB */
+ if (filesize < 0x1c0000) { memcpy(state->m_cartridge2 + 0x100000, state->m_cartridge2, 0x100000); } /* -> >=1.8MB */
+ return IMAGE_INIT_PASS;
+}
+
diff --git a/src/mess/machine/gamepock.c b/src/mess/machine/gamepock.c
new file mode 100644
index 00000000000..5d39d6d59b1
--- /dev/null
+++ b/src/mess/machine/gamepock.c
@@ -0,0 +1,226 @@
+#include "emu.h"
+#include "sound/speaker.h"
+#include "cpu/upd7810/upd7810.h"
+#include "includes/gamepock.h"
+
+
+void gamepock_state::hd44102ch_w( int which, int c_d, UINT8 data )
+{
+ if ( c_d )
+ {
+ UINT8 y;
+ /* Data */
+ m_hd44102ch[which].ram[ m_hd44102ch[which].address ] = data;
+
+ /* Increment/decrement Y counter */
+ y = ( m_hd44102ch[which].address & 0x3F ) + m_hd44102ch[which].y_inc;
+ if ( y == 0xFF )
+ {
+ y = 49;
+ }
+ if ( y == 50 )
+ {
+ y = 0;
+ }
+ m_hd44102ch[which].address = ( m_hd44102ch[which].address & 0xC0 ) | y;
+ }
+ else
+ {
+ /* Command */
+ switch ( data )
+ {
+ case 0x38: /* Display off */
+ m_hd44102ch[which].enabled = 0;
+ break;
+ case 0x39: /* Display on */
+ m_hd44102ch[which].enabled = 1;
+ break;
+ case 0x3A: /* Y decrement mode */
+ m_hd44102ch[which].y_inc = 0xFF;
+ break;
+ case 0x3B: /* Y increment mode */
+ m_hd44102ch[which].y_inc = 0x01;
+ break;
+ case 0x3E: /* Display start page #0 */
+ case 0x7E: /* Display start page #1 */
+ case 0xBE: /* Display start page #2 */
+ case 0xFE: /* Display start page #3 */
+ m_hd44102ch[which].start_page = data & 0xC0;
+ break;
+ default:
+ if ( ( data & 0x3F ) < 50 )
+ {
+ m_hd44102ch[which].address = data;
+ }
+ break;
+ }
+ }
+}
+
+
+void gamepock_state::hd44102ch_init( int which )
+{
+ memset( &m_hd44102ch[which], 0, sizeof( HD44102CH ) );
+ m_hd44102ch[which].y_inc = 0x01;
+}
+
+
+void gamepock_state::lcd_update()
+{
+ /* Check whether HD44102CH #1 is enabled */
+ if ( m_port_a & 0x08 )
+ {
+ hd44102ch_w( 0, m_port_a & 0x04, m_port_b );
+ }
+
+ /* Check whether HD44102CH #2 is enabled */
+ if ( m_port_a & 0x10 )
+ {
+ hd44102ch_w( 1, m_port_a & 0x04, m_port_b );
+ }
+
+ /* Check whether HD44102CH #3 is enabled */
+ if ( m_port_a & 0x20 )
+ {
+ hd44102ch_w( 2, m_port_a & 0x04, m_port_b );
+ }
+}
+
+
+WRITE8_MEMBER( gamepock_state::port_a_w )
+{
+ UINT8 old_port_a = m_port_a;
+
+ m_port_a = data;
+
+ if ( ! ( old_port_a & 0x02 ) && ( m_port_a & 0x02 ) )
+ {
+ lcd_update();
+ }
+}
+
+
+WRITE8_MEMBER( gamepock_state::port_b_w )
+{
+ m_port_b = data;
+}
+
+
+READ8_MEMBER( gamepock_state::port_b_r )
+{
+ logerror("gamepock_port_b_r: not implemented\n");
+ return 0xFF;
+}
+
+
+READ8_MEMBER( gamepock_state::port_c_r )
+{
+ UINT8 data = 0xFF;
+
+ if ( m_port_a & 0x80 )
+ {
+ data &= ioport("IN0")->read();
+ }
+
+ if ( m_port_a & 0x40 )
+ {
+ data &= ioport("IN1")->read();
+ }
+
+ return data;
+}
+
+
+void gamepock_state::machine_reset()
+{
+ hd44102ch_init( 0 );
+ hd44102ch_init( 1 );
+ hd44102ch_init( 2 );
+}
+
+SCREEN_UPDATE_IND16( gamepock )
+{
+ gamepock_state *state = screen.machine().driver_data<gamepock_state>();
+ UINT8 ad;
+ int i,j;
+
+ /* Handle HD44102CH #0 */
+ ad = state->m_hd44102ch[0].start_page;
+ for ( i = 0; i < 4; i++ )
+ {
+ for ( j = 0; j < 50; j++ )
+ {
+ bitmap.pix16(i * 8 + 0, 49 - j ) = ( state->m_hd44102ch[0].ram[ad+j] & 0x01 ) ? 0 : 1;
+ bitmap.pix16(i * 8 + 1, 49 - j ) = ( state->m_hd44102ch[0].ram[ad+j] & 0x02 ) ? 0 : 1;
+ bitmap.pix16(i * 8 + 2, 49 - j ) = ( state->m_hd44102ch[0].ram[ad+j] & 0x04 ) ? 0 : 1;
+ bitmap.pix16(i * 8 + 3, 49 - j ) = ( state->m_hd44102ch[0].ram[ad+j] & 0x08 ) ? 0 : 1;
+ bitmap.pix16(i * 8 + 4, 49 - j ) = ( state->m_hd44102ch[0].ram[ad+j] & 0x10 ) ? 0 : 1;
+ bitmap.pix16(i * 8 + 5, 49 - j ) = ( state->m_hd44102ch[0].ram[ad+j] & 0x20 ) ? 0 : 1;
+ bitmap.pix16(i * 8 + 6, 49 - j ) = ( state->m_hd44102ch[0].ram[ad+j] & 0x40 ) ? 0 : 1;
+ bitmap.pix16(i * 8 + 7, 49 - j ) = ( state->m_hd44102ch[0].ram[ad+j] & 0x80 ) ? 0 : 1;
+ }
+ ad += 0x40;
+ }
+
+ /* Handle HD44102CH #1 */
+ ad = state->m_hd44102ch[1].start_page;
+ for ( i = 4; i < 8; i++ )
+ {
+ for ( j = 0; j < 50; j++ )
+ {
+ bitmap.pix16(i * 8 + 0, j ) = ( state->m_hd44102ch[1].ram[ad+j] & 0x01 ) ? 0 : 1;
+ bitmap.pix16(i * 8 + 1, j ) = ( state->m_hd44102ch[1].ram[ad+j] & 0x02 ) ? 0 : 1;
+ bitmap.pix16(i * 8 + 2, j ) = ( state->m_hd44102ch[1].ram[ad+j] & 0x04 ) ? 0 : 1;
+ bitmap.pix16(i * 8 + 3, j ) = ( state->m_hd44102ch[1].ram[ad+j] & 0x08 ) ? 0 : 1;
+ bitmap.pix16(i * 8 + 4, j ) = ( state->m_hd44102ch[1].ram[ad+j] & 0x10 ) ? 0 : 1;
+ bitmap.pix16(i * 8 + 5, j ) = ( state->m_hd44102ch[1].ram[ad+j] & 0x20 ) ? 0 : 1;
+ bitmap.pix16(i * 8 + 6, j ) = ( state->m_hd44102ch[1].ram[ad+j] & 0x40 ) ? 0 : 1;
+ bitmap.pix16(i * 8 + 7, j ) = ( state->m_hd44102ch[1].ram[ad+j] & 0x80 ) ? 0 : 1;
+ }
+ ad += 0x40;
+ }
+
+ /* Handle HD44102CH #2 */
+ ad = state->m_hd44102ch[2].start_page;
+ for ( i = 0; i < 4; i++ )
+ {
+ for ( j = 0; j < 25; j++ )
+ {
+ bitmap.pix16(i * 8 + 0, 50 + j ) = ( state->m_hd44102ch[2].ram[ad+j] & 0x01 ) ? 0 : 1;
+ bitmap.pix16(i * 8 + 1, 50 + j ) = ( state->m_hd44102ch[2].ram[ad+j] & 0x02 ) ? 0 : 1;
+ bitmap.pix16(i * 8 + 2, 50 + j ) = ( state->m_hd44102ch[2].ram[ad+j] & 0x04 ) ? 0 : 1;
+ bitmap.pix16(i * 8 + 3, 50 + j ) = ( state->m_hd44102ch[2].ram[ad+j] & 0x08 ) ? 0 : 1;
+ bitmap.pix16(i * 8 + 4, 50 + j ) = ( state->m_hd44102ch[2].ram[ad+j] & 0x10 ) ? 0 : 1;
+ bitmap.pix16(i * 8 + 5, 50 + j ) = ( state->m_hd44102ch[2].ram[ad+j] & 0x20 ) ? 0 : 1;
+ bitmap.pix16(i * 8 + 6, 50 + j ) = ( state->m_hd44102ch[2].ram[ad+j] & 0x40 ) ? 0 : 1;
+ bitmap.pix16(i * 8 + 7, 50 + j ) = ( state->m_hd44102ch[2].ram[ad+j] & 0x80 ) ? 0 : 1;
+ }
+ for ( j = 25; j < 50; j++ )
+ {
+ bitmap.pix16(32 + i * 8 + 0, 25 + j ) = ( state->m_hd44102ch[2].ram[ad+j] & 0x01 ) ? 0 : 1;
+ bitmap.pix16(32 + i * 8 + 1, 25 + j ) = ( state->m_hd44102ch[2].ram[ad+j] & 0x02 ) ? 0 : 1;
+ bitmap.pix16(32 + i * 8 + 2, 25 + j ) = ( state->m_hd44102ch[2].ram[ad+j] & 0x04 ) ? 0 : 1;
+ bitmap.pix16(32 + i * 8 + 3, 25 + j ) = ( state->m_hd44102ch[2].ram[ad+j] & 0x08 ) ? 0 : 1;
+ bitmap.pix16(32 + i * 8 + 4, 25 + j ) = ( state->m_hd44102ch[2].ram[ad+j] & 0x10 ) ? 0 : 1;
+ bitmap.pix16(32 + i * 8 + 5, 25 + j ) = ( state->m_hd44102ch[2].ram[ad+j] & 0x20 ) ? 0 : 1;
+ bitmap.pix16(32 + i * 8 + 6, 25 + j ) = ( state->m_hd44102ch[2].ram[ad+j] & 0x40 ) ? 0 : 1;
+ bitmap.pix16(32 + i * 8 + 7, 25 + j ) = ( state->m_hd44102ch[2].ram[ad+j] & 0x80 ) ? 0 : 1;
+ }
+ ad += 0x40;
+ }
+
+ return 0;
+}
+
+/* This is called whenever the T0 pin switches state */
+int gamepock_io_callback( device_t *device, int ioline, int state )
+{
+ device_t *speaker = device->machine().device(SPEAKER_TAG);
+ if ( ioline == UPD7810_TO )
+ {
+ speaker_level_w(speaker, state & 1 );
+ }
+ return 0;
+}
+
+
diff --git a/src/mess/machine/gb.c b/src/mess/machine/gb.c
new file mode 100644
index 00000000000..7e2e403db02
--- /dev/null
+++ b/src/mess/machine/gb.c
@@ -0,0 +1,2237 @@
+/***************************************************************************
+
+ gb.c
+
+ Machine file to handle emulation of the Nintendo Game Boy.
+
+ Changes:
+
+ 13/2/2002 AK - MBC2 and MBC3 support and added NVRAM support.
+ 23/2/2002 AK - MBC5 support, and MBC2 RAM support.
+ 13/3/2002 AK - Tidied up the MBC code, window layer now has it's
+ own palette. Tidied init code.
+ 15/3/2002 AK - More init code tidying with a slight hack to stop
+ sound when the machine starts.
+ 19/3/2002 AK - Changed NVRAM code to the new battery_* functions.
+ 24/3/2002 AK - Added MBC1 mode switching, and partial MBC3 RTC support.
+ 28/3/2002 AK - Improved LCD status timing and interrupts.
+ Free memory when we shutdown instead of leaking.
+ 31/3/2002 AK - Handle IO memory reading so we return 0xFF for registers
+ that are unsupported.
+ 7/4/2002 AK - Free memory from battery load/save. General tidying.
+ 13/4/2002 AK - Ok, don't free memory when we shutdown as that causes
+ a crash on reset.
+ 28/4/2002 AK - General code tidying.
+ Fixed MBC3's RAM/RTC banking.
+ Added support for games with more than 128 ROM banks.
+ 12/6/2002 AK - Rewrote the way bg and sprite palettes are handled.
+ The window layer no longer has it's own palette.
+ Added Super Game Boy support.
+ 13/6/2002 AK - Added Game Boy Color support.
+
+ 17/5/2004 WP - Added Megaduck/Cougar Boy support.
+ 13/6/2005 WP - Added support for bootstrap rom banking.
+
+***************************************************************************/
+#define __MACHINE_GB_C
+
+#include "emu.h"
+#include "cpu/lr35902/lr35902.h"
+#include "imagedev/cartslot.h"
+#include "machine/ram.h"
+#include "audio/gb.h"
+#include "includes/gb.h"
+
+/* Memory bank controller types */
+enum {
+ MBC_NONE=0, /* 32KB ROM - No memory bank controller */
+ MBC_MBC1, /* ~2MB ROM, 8KB RAM -or- 512KB ROM, 32KB RAM */
+ MBC_MBC2, /* 256KB ROM, 32KB RAM */
+ MBC_MMM01, /* ?? ROM, ?? RAM */
+ MBC_MBC3, /* 2MB ROM, 32KB RAM, RTC */
+ MBC_MBC4, /* ?? ROM, ?? RAM */
+ MBC_MBC5, /* 8MB ROM, 128KB RAM (32KB w/ Rumble) */
+ MBC_TAMA5, /* ?? ROM ?? RAM - What is this? */
+ MBC_HUC1, /* ?? ROM, ?? RAM - Hudson Soft Controller */
+ MBC_HUC3, /* ?? ROM, ?? RAM - Hudson Soft Controller */
+ MBC_MBC6, /* ?? ROM, 32KB SRAM */
+ MBC_MBC7, /* ?? ROM, ?? RAM */
+ MBC_WISDOM, /* ?? ROM, ?? RAM - Wisdom tree controller */
+ MBC_MBC1_KOR, /* 1MB ROM, ?? RAM - Korean MBC1 variant */
+ MBC_MEGADUCK, /* MEGADUCK style banking */
+ MBC_UNKNOWN, /* Unknown mapper */
+};
+
+/* machine.device<ram_device>(RAM_TAG)->pointer() layout defines */
+#define CGB_START_VRAM_BANKS 0x0000
+#define CGB_START_RAM_BANKS ( 2 * 8 * 1024 )
+
+#define JOYPAD m_gb_io[0x00] /* Joystick: 1.1.P15.P14.P13.P12.P11.P10 */
+#define SIODATA m_gb_io[0x01] /* Serial IO data buffer */
+#define SIOCONT m_gb_io[0x02] /* Serial IO control register */
+#define DIVREG m_gb_io[0x04] /* Divider register (???) */
+#define TIMECNT m_gb_io[0x05] /* Timer counter. Gen. int. when it overflows */
+#define TIMEMOD m_gb_io[0x06] /* New value of TimeCount after it overflows */
+#define TIMEFRQ m_gb_io[0x07] /* Timer frequency and start/stop switch */
+
+
+
+/*
+ Prototypes
+*/
+
+static TIMER_CALLBACK(gb_serial_timer_proc);
+static void gb_machine_stop(running_machine &machine);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+static void gb_timer_increment( running_machine &machine );
+
+#ifdef MAME_DEBUG
+/* #define V_GENERAL*/ /* Display general debug information */
+/* #define V_BANK*/ /* Display bank switching debug information */
+#endif
+
+static void gb_init_regs(running_machine &machine)
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ /* Initialize the registers */
+ state->SIODATA = 0x00;
+ state->SIOCONT = 0x7E;
+
+ state->gb_io_w( *machine.device("maincpu")->memory().space(AS_PROGRAM ), 0x05, 0x00 ); /* TIMECNT */
+ state->gb_io_w( *machine.device("maincpu")->memory().space(AS_PROGRAM ), 0x06, 0x00 ); /* TIMEMOD */
+}
+
+static void gb_rom16_0000( running_machine &machine, UINT8 *addr )
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ state->membank( "bank5" )->set_base( addr );
+ state->membank( "bank10" )->set_base( addr + 0x0100 );
+ state->membank( "bank6" )->set_base( addr + 0x0200 );
+ state->membank( "bank11" )->set_base( addr + 0x0900 );
+}
+
+static void gb_rom16_4000( running_machine &machine, UINT8 *addr )
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ state->membank( "bank1" )->set_base( addr );
+ state->membank( "bank4" )->set_base( addr + 0x2000 );
+}
+
+static void gb_rom8_4000( running_machine &machine, UINT8 *addr )
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ state->membank( "bank1" )->set_base( addr );
+}
+
+static void gb_rom8_6000( running_machine &machine, UINT8 *addr )
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ state->membank( "bank4" )->set_base( addr );
+}
+
+static void gb_init(running_machine &machine)
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ address_space *space = machine.device( "maincpu")->memory().space( AS_PROGRAM );
+
+ /* Initialize the memory banks */
+ state->m_MBC1Mode = 0;
+ state->m_MBC3RTCBank = 0;
+ state->m_ROMBank = state->m_ROMBank00 + 1;
+ state->m_RAMBank = 0;
+
+ if (state->m_gb_cart)
+ {
+ if ( state->m_MBCType != MBC_MEGADUCK )
+ {
+ gb_rom16_4000( machine, state->m_ROMMap[state->m_ROMBank] );
+ state->membank ("bank2")->set_base (state->m_RAMMap[state->m_RAMBank] ? state->m_RAMMap[state->m_RAMBank] : state->m_gb_dummy_ram_bank);
+ }
+ else
+ {
+ state->membank( "bank1" )->set_base( state->m_ROMMap[state->m_ROMBank] );
+ state->membank( "bank10" )->set_base( state->m_ROMMap[0] );
+ }
+ }
+
+ /* Set handlers based on the Memory Bank Controller in the cart */
+ switch( state->m_MBCType )
+ {
+ case MBC_NONE:
+ break;
+ case MBC_MMM01:
+ space->install_write_handler( 0x0000, 0x1fff, write8_delegate(FUNC(gb_state::gb_rom_bank_mmm01_0000_w),state) );
+ space->install_write_handler( 0x2000, 0x3fff, write8_delegate(FUNC(gb_state::gb_rom_bank_mmm01_2000_w),state));
+ space->install_write_handler( 0x4000, 0x5fff, write8_delegate(FUNC(gb_state::gb_rom_bank_mmm01_4000_w),state));
+ space->install_write_handler( 0x6000, 0x7fff, write8_delegate(FUNC(gb_state::gb_rom_bank_mmm01_6000_w),state));
+ break;
+ case MBC_MBC1:
+ space->install_write_handler( 0x0000, 0x1fff, write8_delegate(FUNC(gb_state::gb_ram_enable),state) ); /* We don't emulate RAM enable yet */
+ space->install_write_handler( 0x2000, 0x3fff, write8_delegate(FUNC(gb_state::gb_rom_bank_select_mbc1),state) );
+ space->install_write_handler( 0x4000, 0x5fff, write8_delegate(FUNC(gb_state::gb_ram_bank_select_mbc1),state) );
+ space->install_write_handler( 0x6000, 0x7fff, write8_delegate(FUNC(gb_state::gb_mem_mode_select_mbc1),state) );
+ break;
+ case MBC_MBC2:
+ space->install_write_handler( 0x2000, 0x3fff, write8_delegate(FUNC(gb_state::gb_rom_bank_select_mbc2),state) );
+ break;
+ case MBC_MBC3:
+ case MBC_HUC1: /* Possibly wrong */
+ case MBC_HUC3: /* Possibly wrong */
+ space->install_write_handler( 0x0000, 0x1fff, write8_delegate(FUNC(gb_state::gb_ram_enable),state) ); /* We don't emulate RAM enable yet */
+ space->install_write_handler( 0x2000, 0x3fff, write8_delegate(FUNC(gb_state::gb_rom_bank_select_mbc3),state) );
+ space->install_write_handler( 0x4000, 0x5fff, write8_delegate(FUNC(gb_state::gb_ram_bank_select_mbc3),state) );
+ space->install_write_handler( 0x6000, 0x7fff, write8_delegate(FUNC(gb_state::gb_mem_mode_select_mbc3),state) );
+ break;
+ case MBC_MBC5:
+ space->install_write_handler( 0x0000, 0x1fff, write8_delegate(FUNC(gb_state::gb_ram_enable),state) );
+ space->install_write_handler( 0x2000, 0x3fff, write8_delegate(FUNC(gb_state::gb_rom_bank_select_mbc5),state) );
+ space->install_write_handler( 0x4000, 0x5fff, write8_delegate(FUNC(gb_state::gb_ram_bank_select_mbc5),state) );
+ break;
+ case MBC_MBC6:
+ space->install_write_handler( 0x0000, 0x1fff, write8_delegate(FUNC(gb_state::gb_ram_bank_select_mbc6),state) );
+ space->install_write_handler( 0x2000, 0x2fff, write8_delegate(FUNC(gb_state::gb_rom_bank_select_mbc6_1),state) );
+ space->install_write_handler( 0x3000, 0x3fff, write8_delegate(FUNC(gb_state::gb_rom_bank_select_mbc6_2),state) );
+ break;
+ case MBC_MBC7:
+ space->install_write_handler( 0x0000, 0x1fff, write8_delegate(FUNC(gb_state::gb_ram_enable),state) );
+ space->install_write_handler( 0x2000, 0x2fff, write8_delegate(FUNC(gb_state::gb_rom_bank_select_mbc7),state) );
+ space->install_write_handler( 0x3000, 0x7fff, write8_delegate(FUNC(gb_state::gb_rom_bank_unknown_mbc7),state) );
+ break;
+ case MBC_TAMA5:
+ space->install_write_handler( 0xA000, 0xBFFF, write8_delegate(FUNC(gb_state::gb_ram_tama5),state) );
+ break;
+ case MBC_WISDOM:
+ space->install_write_handler( 0x0000, 0x3fff, write8_delegate(FUNC(gb_state::gb_rom_bank_select_wisdom),state) );
+ break;
+ case MBC_MBC1_KOR:
+ space->install_write_handler( 0x0000, 0x1fff, write8_delegate(FUNC(gb_state::gb_ram_enable),state) ); /* We don't emulate RAM enable yet */
+ space->install_write_handler( 0x2000, 0x3fff, write8_delegate(FUNC(gb_state::gb_rom_bank_select_mbc1_kor),state) );
+ space->install_write_handler( 0x4000, 0x5fff, write8_delegate(FUNC(gb_state::gb_ram_bank_select_mbc1_kor),state) );
+ space->install_write_handler( 0x6000, 0x7fff, write8_delegate(FUNC(gb_state::gb_mem_mode_select_mbc1_kor),state) );
+ break;
+
+ case MBC_MEGADUCK:
+ space->install_write_handler( 0x0001, 0x0001, write8_delegate(FUNC(gb_state::megaduck_rom_bank_select_type1),state) );
+ space->install_write_handler( 0xB000, 0xB000, write8_delegate(FUNC(gb_state::megaduck_rom_bank_select_type2),state) );
+ break;
+ }
+
+ gb_sound_w(space->machine().device("custom"), 0x16, 0x00 ); /* Initialize sound hardware */
+
+ state->m_divcount = 0;
+ state->m_triggering_irq = 0;
+ state->m_gb_io[0x07] = 0xF8; /* Upper bits of TIMEFRQ register are set to 1 */
+}
+
+MACHINE_START( gb )
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(gb_machine_stop),&machine));
+
+ /* Allocate the serial timer, and disable it */
+ state->m_gb_serial_timer = machine.scheduler().timer_alloc(FUNC(gb_serial_timer_proc));
+ state->m_gb_serial_timer->enable( 0 );
+
+ MACHINE_START_CALL( gb_video );
+}
+
+MACHINE_START( gbc )
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(gb_machine_stop),&machine));
+
+ /* Allocate the serial timer, and disable it */
+ state->m_gb_serial_timer = machine.scheduler().timer_alloc(FUNC(gb_serial_timer_proc));
+ state->m_gb_serial_timer->enable( 0 );
+
+ MACHINE_START_CALL( gbc_video );
+}
+
+MACHINE_RESET( gb )
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ gb_init(machine);
+
+ gb_video_reset( machine, GB_VIDEO_DMG );
+
+ gb_rom16_0000( machine, state->m_ROMMap[state->m_ROMBank00] );
+
+ /* Enable BIOS rom */
+ state->membank("bank5")->set_base(state->memregion("maincpu")->base() );
+
+ state->m_divcount = 0x0004;
+}
+
+
+MACHINE_START( sgb )
+{
+ gb_state *state = machine.driver_data<gb_state>();
+
+ state->m_sgb_packets = -1;
+ state->m_sgb_tile_data = auto_alloc_array_clear(machine, UINT8, 0x2000 );
+
+ machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(gb_machine_stop),&machine));
+
+ /* Allocate the serial timer, and disable it */
+ state->m_gb_serial_timer = machine.scheduler().timer_alloc(FUNC(gb_serial_timer_proc));
+ state->m_gb_serial_timer->enable( 0 );
+
+ MACHINE_START_CALL( gb_video );
+}
+
+MACHINE_RESET( sgb )
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ gb_init(machine);
+
+ gb_video_reset( machine, GB_VIDEO_SGB );
+
+ gb_init_regs(machine);
+
+ gb_rom16_0000( machine, state->m_ROMMap[state->m_ROMBank00] ? state->m_ROMMap[state->m_ROMBank00] : state->m_gb_dummy_rom_bank );
+
+ /* Enable BIOS rom */
+ state->membank("bank5")->set_base(state->memregion("maincpu")->base() );
+
+ memset( state->m_sgb_tile_data, 0, 0x2000 );
+
+ state->m_sgb_window_mask = 0;
+ memset( state->m_sgb_pal_map, 0, sizeof(state->m_sgb_pal_map) );
+ memset( state->m_sgb_atf_data, 0, sizeof(state->m_sgb_atf_data) );
+
+ /* HACKS for Donkey Kong Land 2 + 3.
+ For some reason that I haven't figured out, they store the tile
+ data differently. Hacks will go once I figure it out */
+ state->m_sgb_hack = 0;
+
+ if (state->m_gb_cart) // make sure cart is in
+ {
+ if( strncmp( (const char*)(state->m_gb_cart + 0x134), "DONKEYKONGLAND 2", 16 ) == 0 ||
+ strncmp( (const char*)(state->m_gb_cart + 0x134), "DONKEYKONGLAND 3", 16 ) == 0 )
+ state->m_sgb_hack = 1;
+ }
+
+ state->m_divcount = 0x0004;
+}
+
+MACHINE_RESET( gbpocket )
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ gb_init(machine);
+
+ gb_video_reset( machine, GB_VIDEO_MGB );
+
+ gb_init_regs(machine);
+
+ /* Initialize the Sound registers */
+ gb_sound_w(machine.device("custom"), 0x16,0x80);
+ gb_sound_w(machine.device("custom"), 0x15,0xF3);
+ gb_sound_w(machine.device("custom"), 0x14,0x77);
+
+ /* Enable BIOS rom if we have one */
+ gb_rom16_0000( machine, state->m_ROMMap[state->m_ROMBank00] ? state->m_ROMMap[state->m_ROMBank00] : state->m_gb_dummy_rom_bank );
+
+ state->m_divcount = 0xABC8;
+}
+
+MACHINE_RESET( gbc )
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ int ii;
+
+ gb_init(machine);
+
+ gb_video_reset( machine, GB_VIDEO_CGB );
+
+ gb_init_regs(machine);
+
+ gb_rom16_0000( machine, state->m_ROMMap[state->m_ROMBank00] ? state->m_ROMMap[state->m_ROMBank00] : state->m_gb_dummy_rom_bank );
+
+ /* Enable BIOS rom */
+ state->membank("bank5")->set_base(machine.root_device().memregion("maincpu")->base() );
+ state->membank("bank6")->set_base(state->memregion("maincpu")->base() + 0x100 );
+
+ /* Allocate memory for internal ram */
+ for( ii = 0; ii < 8; ii++ )
+ {
+ state->m_GBC_RAMMap[ii] = machine.device<ram_device>(RAM_TAG)->pointer() + CGB_START_RAM_BANKS + ii * 0x1000;
+ memset (state->m_GBC_RAMMap[ii], 0, 0x1000);
+ }
+}
+
+static void gb_machine_stop(running_machine &machine)
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ /* Don't save if there was no battery */
+ if(!(state->m_CartType & BATTERY) || !state->m_RAMBanks)
+ return;
+
+ /* NOTE: The reason we save the carts RAM this way instead of using MAME's
+ built in macros is because they force the filename to be the name of
+ the machine. We need to have a separate name for each game. */
+ device_image_interface *image = dynamic_cast<device_image_interface *>(machine.device("cart"));
+ image->battery_save(state->m_gb_cart_ram, state->m_RAMBanks * 0x2000);
+}
+
+static void gb_set_mbc1_banks( running_machine &machine )
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ gb_rom16_4000( machine, state->m_ROMMap[ state->m_ROMBank ] );
+ state->membank( "bank2" )->set_base( state->m_RAMMap[ state->m_MBC1Mode ? ( state->m_ROMBank >> 5 ) : 0 ] );
+}
+
+WRITE8_MEMBER(gb_state::gb_rom_bank_select_mbc1)
+{
+ data &= 0x1F; /* Only uses lower 5 bits */
+ /* Selecting bank 0 == selecting bank 1 */
+ if( data == 0 )
+ data = 1;
+
+ m_ROMBank = ( m_ROMBank & 0x01E0 ) | data;
+ /* Switch banks */
+ gb_set_mbc1_banks(machine());
+}
+
+WRITE8_MEMBER(gb_state::gb_rom_bank_select_mbc2)
+{
+ data &= 0x0F; /* Only uses lower 4 bits */
+ /* Selecting bank 0 == selecting bank 1 */
+ if( data == 0 )
+ data = 1;
+
+ /* The least significant bit of the upper address byte must be 1 */
+ if( offset & 0x0100 )
+ m_ROMBank = ( m_ROMBank & 0x100 ) | data;
+ /* Switch banks */
+ gb_rom16_4000( machine(), m_ROMMap[m_ROMBank] );
+}
+
+WRITE8_MEMBER(gb_state::gb_rom_bank_select_mbc3)
+{
+ logerror( "0x%04X: write to mbc3 rom bank select register 0x%04X <- 0x%02X\n", cpu_get_pc( &space.device() ), offset, data );
+ data &= 0x7F; /* Only uses lower 7 bits */
+ /* Selecting bank 0 == selecting bank 1 */
+ if( data == 0 )
+ data = 1;
+
+ m_ROMBank = ( m_ROMBank & 0x0100 ) | data;
+ /* Switch banks */
+ gb_rom16_4000( machine(), m_ROMMap[m_ROMBank] );
+}
+
+WRITE8_MEMBER(gb_state::gb_rom_bank_select_mbc5)
+{
+ /* MBC5 has a 9 bit bank select
+ Writing into 2000-2FFF sets the lower 8 bits
+ Writing into 3000-3FFF sets the 9th bit
+ */
+ logerror( "0x%04X: MBC5 ROM Bank select write 0x%04X <- 0x%02X\n", cpu_get_pc( &space.device() ), offset, data );
+ if( offset & 0x1000 )
+ {
+ m_ROMBank = (m_ROMBank & 0xFF ) | ( ( data & 0x01 ) << 8 );
+ }
+ else
+ {
+ m_ROMBank = (m_ROMBank & 0x100 ) | data;
+ }
+ /* Switch banks */
+ gb_rom16_4000( machine(), m_ROMMap[m_ROMBank] );
+}
+
+WRITE8_MEMBER(gb_state::gb_ram_bank_select_mbc6)
+{
+ logerror( "0x%04X: write to mbc6 ram enable area: %04X <- 0x%02X\n", cpu_get_pc( &space.device() ), offset, data );
+}
+
+WRITE8_MEMBER(gb_state::gb_rom_bank_select_mbc6_1)
+{
+ logerror( "0x%04X: write to mbc6 rom area: 0x%04X <- 0x%02X\n", cpu_get_pc( &space.device() ), 0x2000 + offset, data );
+ if ( offset & 0x0800 )
+ {
+ if ( data == 0x00 )
+ {
+ gb_rom8_4000( machine(), m_ROMMap[m_ROMBank>>1] + ( ( m_ROMBank & 0x01 ) ? 0x2000 : 0x0000 ) );
+ }
+ }
+ else
+ {
+ m_ROMBank = data;
+ }
+}
+
+WRITE8_MEMBER(gb_state::gb_rom_bank_select_mbc6_2)
+{
+ logerror( "0x%04X: write to mbc6 rom area: 0x%04X <- 0x%02X\n", cpu_get_pc( &space.device() ), 0x3000 + offset, data );
+ if ( offset & 0x0800 )
+ {
+ if ( data == 0x00 )
+ {
+ gb_rom8_6000( machine(), m_ROMMap[m_ROMBank00>>1] + ( ( m_ROMBank00 & 0x01 ) ? 0x2000 : 0x0000 ) );
+ }
+ }
+ else
+ {
+ m_ROMBank00 = data;
+ }
+}
+
+WRITE8_MEMBER(gb_state::gb_rom_bank_select_mbc7)
+{
+ logerror( "0x%04X: write to mbc7 rom select register: 0x%04X <- 0x%02X\n", cpu_get_pc( &space.device() ), 0x2000 + offset, data );
+ /* Bit 12 must be set for writing to the mbc register */
+ if ( offset & 0x0100 )
+ {
+ m_ROMBank = data;
+ gb_rom16_4000( machine(), m_ROMMap[m_ROMBank] );
+ }
+}
+
+WRITE8_MEMBER(gb_state::gb_rom_bank_unknown_mbc7)
+{
+ logerror( "0x%04X: write to mbc7 rom area: 0x%04X <- 0x%02X\n", cpu_get_pc( &space.device() ), 0x3000 + offset, data );
+ /* Bit 12 must be set for writing to the mbc register */
+ if ( offset & 0x0100 )
+ {
+ switch( offset & 0x7000 )
+ {
+ case 0x0000: /* 0x3000-0x3fff */
+ case 0x1000: /* 0x4000-0x4fff */
+ case 0x2000: /* 0x5000-0x5fff */
+ case 0x3000: /* 0x6000-0x6fff */
+ case 0x4000: /* 0x7000-0x7fff */
+ break;
+ }
+ }
+}
+
+WRITE8_MEMBER(gb_state::gb_rom_bank_select_wisdom)
+{
+ logerror( "0x%04X: wisdom tree mapper write to address 0x%04X\n", cpu_get_pc( &space.device() ), offset );
+ /* The address determines the bank to select */
+ m_ROMBank = ( offset << 1 ) & 0x1FF;
+ membank( "bank5" )->set_base( m_ROMMap[ m_ROMBank ] );
+ membank( "bank10" )->set_base( m_ROMMap[ m_ROMBank ] + 0x0100 );
+ gb_rom16_4000( machine(), m_ROMMap[ m_ROMBank + 1 ] );
+}
+
+WRITE8_MEMBER(gb_state::gb_ram_bank_select_mbc1)
+{
+ data &= 0x3; /* Only uses the lower 2 bits */
+
+ /* Select the upper bits of the ROMMask */
+ m_ROMBank = ( m_ROMBank & 0x1F ) | ( data << 5 );
+
+ /* Switch banks */
+ gb_set_mbc1_banks(machine());
+}
+
+WRITE8_MEMBER(gb_state::gb_ram_bank_select_mbc3)
+{
+ logerror( "0x%04X: write mbc3 ram bank select register 0x%04X <- 0x%02X\n", cpu_get_pc( &space.device() ), offset, data );
+ if( data & 0x8 )
+ { /* RTC banks */
+ if ( m_CartType & TIMER )
+ {
+ m_MBC3RTCBank = data & 0x07;
+ if ( data < 5 )
+ {
+ memset( m_MBC3RTCData, m_MBC3RTCMap[m_MBC3RTCBank], 0x2000 );
+ membank( "bank2" )->set_base( m_MBC3RTCData );
+ }
+ }
+ }
+ else
+ { /* RAM banks */
+ m_RAMBank = data & 0x3;
+ m_MBC3RTCBank = 0xFF;
+ /* Switch banks */
+ membank( "bank2" )->set_base( m_RAMMap[m_RAMBank] );
+ }
+}
+
+WRITE8_MEMBER(gb_state::gb_ram_bank_select_mbc5)
+{
+ logerror( "0x%04X: MBC5 RAM Bank select write 0x%04X <- 0x%02X\n", cpu_get_pc( &space.device() ), offset, data );
+ data &= 0x0F;
+ if( m_CartType & RUMBLE )
+ {
+ data &= 0x7;
+ }
+ m_RAMBank = data;
+ /* Switch banks */
+ membank ("bank2")->set_base (m_RAMMap[m_RAMBank] );
+}
+
+WRITE8_MEMBER(gb_state::gb_ram_enable)
+{
+ /* FIXME: Currently we don't handle this, but a value of 0xA will enable
+ * writing to the cart's RAM banks */
+ logerror( "0x%04X: Write to ram enable register 0x%04X <- 0x%02X\n", cpu_get_pc( &space.device() ), offset, data );
+}
+
+WRITE8_MEMBER(gb_state::gb_mem_mode_select_mbc1)
+{
+ m_MBC1Mode = data & 0x1;
+ gb_set_mbc1_banks(machine());
+}
+
+WRITE8_MEMBER(gb_state::gb_mem_mode_select_mbc3)
+{
+ logerror( "0x%04X: Write to mbc3 mem mode select register 0x%04X <- 0x%02X\n", cpu_get_pc( &space.device() ), offset, data );
+ if( m_CartType & TIMER )
+ {
+ /* FIXME: RTC Latch goes here */
+ m_MBC3RTCMap[0] = 50; /* Seconds */
+ m_MBC3RTCMap[1] = 40; /* Minutes */
+ m_MBC3RTCMap[2] = 15; /* Hours */
+ m_MBC3RTCMap[3] = 25; /* Day counter lowest 8 bits */
+ m_MBC3RTCMap[4] = 0x01; /* Day counter upper bit, timer off, no day overflow occurred (bit7) */
+ }
+}
+
+WRITE8_MEMBER(gb_state::gb_ram_tama5)
+{
+ logerror( "0x%04X: TAMA5 write 0x%04X <- 0x%02X\n", cpu_get_pc( &space.device() ), 0xA000 + offset, data );
+ switch( offset & 0x0001 )
+ {
+ case 0x0000: /* Write to data register */
+ switch( m_gbLastTama5Command )
+ {
+ case 0x00: /* Bits 0-3 for rom bank selection */
+ m_ROMBank = ( m_ROMBank & 0xF0 ) | ( data & 0x0F );
+ gb_rom16_4000( machine(), m_ROMMap[m_ROMBank] );
+ break;
+ case 0x01: /* Bit 4(-7?) for rom bank selection */
+ m_ROMBank = ( m_ROMBank & 0x0F ) | ( ( data & 0x0F ) << 4 );
+ gb_rom16_4000( machine(), m_ROMMap[m_ROMBank] );
+ break;
+ case 0x04: /* Data to write lo */
+ m_gbTama5Byte = ( m_gbTama5Byte & 0xF0 ) | ( data & 0x0F );
+ break;
+ case 0x05: /* Data to write hi */
+ m_gbTama5Byte = ( m_gbTama5Byte & 0x0F ) | ( ( data & 0x0F ) << 4 );
+ break;
+ case 0x06: /* Address selection hi */
+ m_gbTama5Address = ( m_gbTama5Address & 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_gbTama5Address = ( m_gbTama5Address & 0xF0 ) | ( data & 0x0F );
+ switch ( m_gbTama5Address & 0xE0 )
+ {
+ case 0x00: /* Write memory */
+ logerror( "Write tama5 memory 0x%02X <- 0x%02X\n", m_gbTama5Address & 0x1F, m_gbTama5Byte );
+ m_gbTama5Memory[ m_gbTama5Address & 0x1F ] = m_gbTama5Byte;
+ break;
+ case 0x20: /* Read memory */
+ logerror( "Read tama5 memory 0x%02X\n", m_gbTama5Address & 0x1F );
+ m_gbTama5Byte = m_gbTama5Memory[ m_gbTama5Address & 0x1F ];
+ break;
+ case 0x40: /* Unknown, some kind of read */
+ if ( ( m_gbTama5Address & 0x1F ) == 0x12 )
+ {
+ m_gbTama5Byte = 0xFF;
+ }
+ case 0x80: /* Unknown, some kind of read (when 07=01)/write (when 07=00/02) */
+ default:
+ logerror( "0x%04X: Unknown addressing mode\n", cpu_get_pc( &space.device() ) );
+ 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_MBC3RTCData[0] = 0x01;
+ membank( "bank2" )->set_base( m_MBC3RTCData );
+ break;
+ case 0x0C: /* Data read register lo */
+ m_MBC3RTCData[0] = m_gbTama5Byte & 0x0F;
+ break;
+ case 0x0D: /* Data read register hi */
+ m_MBC3RTCData[0] = ( m_gbTama5Byte & 0xF0 ) >> 4;
+ break;
+ default:
+ logerror( "0x%04X: Unknown tama5 command 0x%02X\n", cpu_get_pc( &space.device() ), data );
+ break;
+ }
+ m_gbLastTama5Command = data;
+ break;
+ }
+}
+
+/* This mmm01 implementation is mostly guess work, no clue how correct it all is */
+
+
+WRITE8_MEMBER(gb_state::gb_rom_bank_mmm01_0000_w)
+{
+ logerror( "0x%04X: write 0x%02X to 0x%04X\n", cpu_get_pc( &space.device() ), data, offset+0x000 );
+ if ( data & 0x40 )
+ {
+ m_mmm01_bank_offset = m_mmm01_reg1;
+ membank( "bank5" )->set_base( m_ROMMap[ m_mmm01_bank_offset ] );
+ membank( "bank10" )->set_base( m_ROMMap[ m_mmm01_bank_offset ] + 0x0100 );
+ gb_rom16_4000( machine(), m_ROMMap[ m_mmm01_bank_offset + m_mmm01_bank ] );
+ }
+}
+
+WRITE8_MEMBER(gb_state::gb_rom_bank_mmm01_2000_w)
+{
+ logerror( "0x%04X: write 0x%02X to 0x%04X\n", cpu_get_pc( &space.device() ), data, offset+0x2000 );
+
+ m_mmm01_reg1 = data & m_ROMMask;
+ m_mmm01_bank = m_mmm01_reg1 & m_mmm01_bank_mask;
+ if ( m_mmm01_bank == 0 )
+ {
+ m_mmm01_bank = 1;
+ }
+ gb_rom16_4000( machine(), m_ROMMap[ m_mmm01_bank_offset + m_mmm01_bank ] );
+}
+
+WRITE8_MEMBER(gb_state::gb_rom_bank_mmm01_4000_w)
+{
+ logerror( "0x%04X: write 0x%02X to 0x%04X\n", cpu_get_pc( &space.device() ), data, offset+0x4000 );
+}
+
+WRITE8_MEMBER(gb_state::gb_rom_bank_mmm01_6000_w)
+{
+ logerror( "0x%04X: write 0x%02X to 0x%04X\n", cpu_get_pc( &space.device() ), data, offset+0x6000 );
+ /* 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_mmm01_bank_mask = 0x07; break;
+ case 0x38: m_mmm01_bank_mask = 0x03; break;
+ default: m_mmm01_bank_mask = 0xFF; break;
+ }
+}
+
+/* Korean MBC1 variant mapping */
+
+static void gb_set_mbc1_kor_banks( running_machine &machine )
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ if ( state->m_ROMBank & 0x30 )
+ {
+ gb_rom16_0000( machine, state->m_ROMMap[ state->m_ROMBank & 0x30 ] );
+ }
+ gb_rom16_4000( machine, state->m_ROMMap[ state->m_ROMBank ] );
+ state->membank( "bank2" )->set_base( state->m_RAMMap[ state->m_MBC1Mode ? ( state->m_ROMBank >> 5 ) : 0 ] );
+}
+
+WRITE8_MEMBER(gb_state::gb_rom_bank_select_mbc1_kor)
+{
+ data &= 0x0F; /* Only uses lower 5 bits */
+ /* Selecting bank 0 == selecting bank 1 */
+ if( data == 0 )
+ data = 1;
+
+ m_ROMBank = ( m_ROMBank & 0x01F0 ) | data;
+ /* Switch banks */
+ gb_set_mbc1_kor_banks(machine());
+}
+
+WRITE8_MEMBER(gb_state::gb_ram_bank_select_mbc1_kor)
+{
+ data &= 0x3; /* Only uses the lower 2 bits */
+
+ /* Select the upper bits of the ROMMask */
+ m_ROMBank = ( m_ROMBank & 0x0F ) | ( data << 4 );
+
+ /* Switch banks */
+ gb_set_mbc1_kor_banks(machine());
+}
+
+WRITE8_MEMBER(gb_state::gb_mem_mode_select_mbc1_kor)
+{
+ m_MBC1Mode = data & 0x1;
+ gb_set_mbc1_kor_banks(machine());
+}
+
+WRITE8_MEMBER(gb_state::gb_io_w)
+{
+ static const UINT8 timer_shifts[4] = {10, 4, 6, 8};
+
+ switch (offset)
+ {
+ case 0x00: /* JOYP - Joypad */
+ JOYPAD = 0xCF | data;
+ if (!(data & 0x20))
+ JOYPAD &= (ioport("INPUTS")->read() >> 4) | 0xF0;
+ if (!(data & 0x10))
+ JOYPAD &= ioport("INPUTS")->read() | 0xF0;
+ return;
+ case 0x01: /* SB - Serial transfer data */
+ break;
+ case 0x02: /* SC - SIO control */
+ switch( data & 0x81 )
+ {
+ case 0x00:
+ case 0x01:
+ case 0x80: /* enabled & external clock */
+ m_SIOCount = 0;
+ break;
+ case 0x81: /* enabled & internal clock */
+ SIODATA = 0xFF;
+ m_SIOCount = 8;
+ m_gb_serial_timer->adjust(machine().device<cpu_device>("maincpu")->cycles_to_attotime(512), 0, machine().device<cpu_device>("maincpu")->cycles_to_attotime(512));
+ m_gb_serial_timer->enable( 1 );
+ break;
+ }
+ break;
+ case 0x04: /* DIV - Divider register */
+ /* Force increment of TIMECNT register */
+ if ( m_divcount >= 16 )
+ gb_timer_increment(machine());
+ m_divcount = 0;
+ return;
+ case 0x05: /* TIMA - Timer counter */
+ /* Check if the counter is being reloaded in this cycle */
+ if ( m_reloading && ( m_divcount & ( m_shift_cycles - 1 ) ) == 4 )
+ {
+ data = TIMECNT;
+ }
+ break;
+ case 0x06: /* TMA - Timer module */
+ /* Check if the counter is being reloaded in this cycle */
+ if ( m_reloading && ( m_divcount & ( m_shift_cycles - 1 ) ) == 4 )
+ {
+ TIMECNT = data;
+ }
+ break;
+ case 0x07: /* TAC - Timer control */
+ data |= 0xF8;
+ /* Check if timer is just disabled or the timer frequency is changing */
+ if ( ( ! ( data & 0x04 ) && ( TIMEFRQ & 0x04 ) ) || ( ( data & 0x04 ) && ( TIMEFRQ & 0x04 ) && ( data & 0x03 ) != ( TIMEFRQ & 0x03 ) ) )
+ {
+ /* Check if TIMECNT should be incremented */
+ if ( ( m_divcount & ( m_shift_cycles - 1 ) ) >= ( m_shift_cycles >> 1 ) )
+ {
+ gb_timer_increment(machine());
+ }
+ }
+ m_shift = timer_shifts[data & 0x03];
+ m_shift_cycles = 1 << m_shift;
+ break;
+ case 0x0F: /* IF - Interrupt flag */
+ data &= 0x1F;
+ machine().device<lr35902_cpu_device>(":maincpu")->set_if( data );
+ break;
+ }
+
+ m_gb_io[offset] = data;
+}
+
+WRITE8_MEMBER(gb_state::gb_io2_w)
+{
+ if ( offset == 0x10 )
+ {
+ /* disable BIOS ROM */
+ gb_rom16_0000( machine(), m_ROMMap[m_ROMBank00] );
+ }
+ else
+ {
+ gb_video_w( space, offset, data );
+ }
+}
+
+#ifdef MAME_DEBUG
+static const char *const sgbcmds[26] =
+{
+ "PAL01 ",
+ "PAL23 ",
+ "PAL03 ",
+ "PAL12 ",
+ "ATTR_BLK",
+ "ATTR_LIN",
+ "ATTR_DIV",
+ "ATTR_CHR",
+ "SOUND ",
+ "SOU_TRN ",
+ "PAL_SET ",
+ "PAL_TRN ",
+ "ATRC_EN ",
+ "TEST_EN ",
+ "ICON_EN ",
+ "DATA_SND",
+ "DATA_TRN",
+ "MLT_REG ",
+ "JUMP ",
+ "CHR_TRN ",
+ "PCT_TRN ",
+ "ATTR_TRN",
+ "ATTR_SET",
+ "MASK_EN ",
+ "OBJ_TRN ",
+ "????????",
+};
+#endif
+
+WRITE8_MEMBER(gb_state::sgb_io_w)
+{
+ UINT8 *sgb_data = m_sgb_data;
+
+ switch( offset )
+ {
+ case 0x00:
+ switch (data & 0x30)
+ {
+ case 0x00: /* start condition */
+ if (m_sgb_start)
+ logerror("SGB: Start condition before end of transfer ??\n");
+ m_sgb_bitcount = 0;
+ m_sgb_start = 1;
+ m_sgb_rest = 0;
+ JOYPAD = 0x0F & ((ioport("INPUTS")->read() >> 4) | ioport("INPUTS")->read() | 0xF0);
+ break;
+ case 0x10: /* data true */
+ if (m_sgb_rest)
+ {
+ /* We should test for this case , but the code below won't
+ work with the current setup */
+#if 0
+ if (m_sgb_bytecount == 16)
+ {
+ logerror("SGB: end of block is not zero!");
+ m_sgb_start = 0;
+ }
+#endif
+ sgb_data[m_sgb_bytecount] >>= 1;
+ sgb_data[m_sgb_bytecount] |= 0x80;
+ m_sgb_bitcount++;
+ if (m_sgb_bitcount == 8)
+ {
+ m_sgb_bitcount = 0;
+ m_sgb_bytecount++;
+ }
+ m_sgb_rest = 0;
+ }
+ JOYPAD = 0x1F & ((ioport("INPUTS")->read() >> 4) | 0xF0);
+ break;
+ case 0x20: /* data false */
+ if (m_sgb_rest)
+ {
+ if( m_sgb_bytecount == 16 && m_sgb_packets == -1 )
+ {
+#ifdef MAME_DEBUG
+ logerror("SGB: %s (%02X) pkts: %d data: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n",
+ sgbcmds[sgb_data[0] >> 3],sgb_data[0] >> 3, sgb_data[0] & 0x07, sgb_data[1], sgb_data[2], sgb_data[3],
+ sgb_data[4], sgb_data[5], sgb_data[6], sgb_data[7],
+ sgb_data[8], sgb_data[9], sgb_data[10], sgb_data[11],
+ sgb_data[12], sgb_data[13], sgb_data[14], sgb_data[15]);
+#endif
+ m_sgb_packets = sgb_data[0] & 0x07;
+ m_sgb_start = 0;
+ }
+ if (m_sgb_bytecount == (m_sgb_packets << 4) )
+ {
+ switch( sgb_data[0] >> 3 )
+ {
+ case 0x00: /* PAL01 */
+ m_sgb_pal[0*4 + 0] = sgb_data[1] | (sgb_data[2] << 8);
+ m_sgb_pal[0*4 + 1] = sgb_data[3] | (sgb_data[4] << 8);
+ m_sgb_pal[0*4 + 2] = sgb_data[5] | (sgb_data[6] << 8);
+ m_sgb_pal[0*4 + 3] = sgb_data[7] | (sgb_data[8] << 8);
+ m_sgb_pal[1*4 + 0] = sgb_data[1] | (sgb_data[2] << 8);
+ m_sgb_pal[1*4 + 1] = sgb_data[9] | (sgb_data[10] << 8);
+ m_sgb_pal[1*4 + 2] = sgb_data[11] | (sgb_data[12] << 8);
+ m_sgb_pal[1*4 + 3] = sgb_data[13] | (sgb_data[14] << 8);
+ break;
+ case 0x01: /* PAL23 */
+ m_sgb_pal[2*4 + 0] = sgb_data[1] | (sgb_data[2] << 8);
+ m_sgb_pal[2*4 + 1] = sgb_data[3] | (sgb_data[4] << 8);
+ m_sgb_pal[2*4 + 2] = sgb_data[5] | (sgb_data[6] << 8);
+ m_sgb_pal[2*4 + 3] = sgb_data[7] | (sgb_data[8] << 8);
+ m_sgb_pal[3*4 + 0] = sgb_data[1] | (sgb_data[2] << 8);
+ m_sgb_pal[3*4 + 1] = sgb_data[9] | (sgb_data[10] << 8);
+ m_sgb_pal[3*4 + 2] = sgb_data[11] | (sgb_data[12] << 8);
+ m_sgb_pal[3*4 + 3] = sgb_data[13] | (sgb_data[14] << 8);
+ break;
+ case 0x02: /* PAL03 */
+ m_sgb_pal[0*4 + 0] = sgb_data[1] | (sgb_data[2] << 8);
+ m_sgb_pal[0*4 + 1] = sgb_data[3] | (sgb_data[4] << 8);
+ m_sgb_pal[0*4 + 2] = sgb_data[5] | (sgb_data[6] << 8);
+ m_sgb_pal[0*4 + 3] = sgb_data[7] | (sgb_data[8] << 8);
+ m_sgb_pal[3*4 + 0] = sgb_data[1] | (sgb_data[2] << 8);
+ m_sgb_pal[3*4 + 1] = sgb_data[9] | (sgb_data[10] << 8);
+ m_sgb_pal[3*4 + 2] = sgb_data[11] | (sgb_data[12] << 8);
+ m_sgb_pal[3*4 + 3] = sgb_data[13] | (sgb_data[14] << 8);
+ break;
+ case 0x03: /* PAL12 */
+ m_sgb_pal[1*4 + 0] = sgb_data[1] | (sgb_data[2] << 8);
+ m_sgb_pal[1*4 + 1] = sgb_data[3] | (sgb_data[4] << 8);
+ m_sgb_pal[1*4 + 2] = sgb_data[5] | (sgb_data[6] << 8);
+ m_sgb_pal[1*4 + 3] = sgb_data[7] | (sgb_data[8] << 8);
+ m_sgb_pal[2*4 + 0] = sgb_data[1] | (sgb_data[2] << 8);
+ m_sgb_pal[2*4 + 1] = sgb_data[9] | (sgb_data[10] << 8);
+ m_sgb_pal[2*4 + 2] = sgb_data[11] | (sgb_data[12] << 8);
+ m_sgb_pal[2*4 + 3] = sgb_data[13] | (sgb_data[14] << 8);
+ break;
+ case 0x04: /* ATTR_BLK */
+ {
+ UINT8 I, J, K, o;
+ for( K = 0; K < sgb_data[1]; K++ )
+ {
+ o = K * 6;
+ if( sgb_data[o + 2] & 0x1 )
+ {
+ for( I = sgb_data[ o + 4]; I <= sgb_data[o + 6]; I++ )
+ {
+ for( J = sgb_data[o + 5]; J <= sgb_data[o + 7]; J++ )
+ {
+ m_sgb_pal_map[I][J] = sgb_data[o + 3] & 0x3;
+ }
+ }
+ }
+ }
+ }
+ break;
+ case 0x05: /* ATTR_LIN */
+ {
+ UINT8 J, K;
+ if( sgb_data[1] > 15 )
+ sgb_data[1] = 15;
+ for( K = 0; K < sgb_data[1]; K++ )
+ {
+ if( sgb_data[K + 1] & 0x80 )
+ {
+ for( J = 0; J < 20; J++ )
+ {
+ m_sgb_pal_map[J][sgb_data[K + 1] & 0x1f] = (sgb_data[K + 1] & 0x60) >> 5;
+ }
+ }
+ else
+ {
+ for( J = 0; J < 18; J++ )
+ {
+ m_sgb_pal_map[sgb_data[K + 1] & 0x1f][J] = (sgb_data[K + 1] & 0x60) >> 5;
+ }
+ }
+ }
+ }
+ break;
+ case 0x06: /* ATTR_DIV */
+ {
+ UINT8 I, J;
+ if( sgb_data[1] & 0x40 ) /* Vertical */
+ {
+ for( I = 0; I < sgb_data[2]; I++ )
+ {
+ for( J = 0; J < 20; J++ )
+ {
+ m_sgb_pal_map[J][I] = (sgb_data[1] & 0xC) >> 2;
+ }
+ }
+ for( J = 0; J < 20; J++ )
+ {
+ m_sgb_pal_map[J][sgb_data[2]] = (sgb_data[1] & 0x30) >> 4;
+ }
+ for( I = sgb_data[2] + 1; I < 18; I++ )
+ {
+ for( J = 0; J < 20; J++ )
+ {
+ m_sgb_pal_map[J][I] = sgb_data[1] & 0x3;
+ }
+ }
+ }
+ else /* Horizontal */
+ {
+ for( I = 0; I < sgb_data[2]; I++ )
+ {
+ for( J = 0; J < 18; J++ )
+ {
+ m_sgb_pal_map[I][J] = (sgb_data[1] & 0xC) >> 2;
+ }
+ }
+ for( J = 0; J < 18; J++ )
+ {
+ m_sgb_pal_map[sgb_data[2]][J] = (sgb_data[1] & 0x30) >> 4;
+ }
+ for( I = sgb_data[2] + 1; I < 20; I++ )
+ {
+ for( J = 0; J < 18; J++ )
+ {
+ m_sgb_pal_map[I][J] = sgb_data[1] & 0x3;
+ }
+ }
+ }
+ }
+ break;
+ case 0x07: /* ATTR_CHR */
+ {
+ UINT16 I, sets;
+ UINT8 x, y;
+ sets = (sgb_data[3] | (sgb_data[4] << 8) );
+ if( sets > 360 )
+ sets = 360;
+ sets >>= 2;
+ sets += 6;
+ x = sgb_data[1];
+ y = sgb_data[2];
+ if( sgb_data[5] ) /* Vertical */
+ {
+ for( I = 6; I < sets; I++ )
+ {
+ m_sgb_pal_map[x][y++] = (sgb_data[I] & 0xC0) >> 6;
+ if( y > 17 )
+ {
+ y = 0;
+ x++;
+ if( x > 19 )
+ x = 0;
+ }
+
+ m_sgb_pal_map[x][y++] = (sgb_data[I] & 0x30) >> 4;
+ if( y > 17 )
+ {
+ y = 0;
+ x++;
+ if( x > 19 )
+ x = 0;
+ }
+
+ m_sgb_pal_map[x][y++] = (sgb_data[I] & 0xC) >> 2;
+ if( y > 17 )
+ {
+ y = 0;
+ x++;
+ if( x > 19 )
+ x = 0;
+ }
+
+ m_sgb_pal_map[x][y++] = sgb_data[I] & 0x3;
+ if( y > 17 )
+ {
+ y = 0;
+ x++;
+ if( x > 19 )
+ x = 0;
+ }
+ }
+ }
+ else /* horizontal */
+ {
+ for( I = 6; I < sets; I++ )
+ {
+ m_sgb_pal_map[x++][y] = (sgb_data[I] & 0xC0) >> 6;
+ if( x > 19 )
+ {
+ x = 0;
+ y++;
+ if( y > 17 )
+ y = 0;
+ }
+
+ m_sgb_pal_map[x++][y] = (sgb_data[I] & 0x30) >> 4;
+ if( x > 19 )
+ {
+ x = 0;
+ y++;
+ if( y > 17 )
+ y = 0;
+ }
+
+ m_sgb_pal_map[x++][y] = (sgb_data[I] & 0xC) >> 2;
+ if( x > 19 )
+ {
+ x = 0;
+ y++;
+ if( y > 17 )
+ y = 0;
+ }
+
+ m_sgb_pal_map[x++][y] = sgb_data[I] & 0x3;
+ if( x > 19 )
+ {
+ x = 0;
+ y++;
+ if( y > 17 )
+ y = 0;
+ }
+ }
+ }
+ }
+ break;
+ case 0x08: /* SOUND */
+ /* This command enables internal sound effects */
+ /* Not Implemented */
+ break;
+ case 0x09: /* SOU_TRN */
+ /* This command sends data to the SNES sound processor.
+ We'll need to emulate that for this to be used */
+ /* Not Implemented */
+ break;
+ case 0x0A: /* PAL_SET */
+ {
+ UINT16 index_, J, I;
+
+ /* Palette 0 */
+ index_ = (UINT16)(sgb_data[1] | (sgb_data[2] << 8)) * 4;
+ m_sgb_pal[0] = m_sgb_pal_data[index_];
+ m_sgb_pal[1] = m_sgb_pal_data[index_ + 1];
+ m_sgb_pal[2] = m_sgb_pal_data[index_ + 2];
+ m_sgb_pal[3] = m_sgb_pal_data[index_ + 3];
+ /* Palette 1 */
+ index_ = (UINT16)(sgb_data[3] | (sgb_data[4] << 8)) * 4;
+ m_sgb_pal[4] = m_sgb_pal_data[index_];
+ m_sgb_pal[5] = m_sgb_pal_data[index_ + 1];
+ m_sgb_pal[6] = m_sgb_pal_data[index_ + 2];
+ m_sgb_pal[7] = m_sgb_pal_data[index_ + 3];
+ /* Palette 2 */
+ index_ = (UINT16)(sgb_data[5] | (sgb_data[6] << 8)) * 4;
+ m_sgb_pal[8] = m_sgb_pal_data[index_];
+ m_sgb_pal[9] = m_sgb_pal_data[index_ + 1];
+ m_sgb_pal[10] = m_sgb_pal_data[index_ + 2];
+ m_sgb_pal[11] = m_sgb_pal_data[index_ + 3];
+ /* Palette 3 */
+ index_ = (UINT16)(sgb_data[7] | (sgb_data[8] << 8)) * 4;
+ m_sgb_pal[12] = m_sgb_pal_data[index_];
+ m_sgb_pal[13] = m_sgb_pal_data[index_ + 1];
+ m_sgb_pal[14] = m_sgb_pal_data[index_ + 2];
+ m_sgb_pal[15] = m_sgb_pal_data[index_ + 3];
+ /* Attribute File */
+ if( sgb_data[9] & 0x40 )
+ m_sgb_window_mask = 0;
+ m_sgb_atf = (sgb_data[9] & 0x3f) * (18 * 5);
+ if( sgb_data[9] & 0x80 )
+ {
+ for( J = 0; J < 18; J++ )
+ {
+ for( I = 0; I < 5; I++ )
+ {
+ m_sgb_pal_map[I * 4][J] = (m_sgb_atf_data[(J * 5) + m_sgb_atf + I] & 0xC0) >> 6;
+ m_sgb_pal_map[(I * 4) + 1][J] = (m_sgb_atf_data[(J * 5) + m_sgb_atf + I] & 0x30) >> 4;
+ m_sgb_pal_map[(I * 4) + 2][J] = (m_sgb_atf_data[(J * 5) + m_sgb_atf + I] & 0xC) >> 2;
+ m_sgb_pal_map[(I * 4) + 3][J] = m_sgb_atf_data[(J * 5) + m_sgb_atf + I] & 0x3;
+ }
+ }
+ }
+ }
+ break;
+ case 0x0B: /* PAL_TRN */
+ {
+ UINT8 *gb_vram = gb_get_vram_ptr(machine());
+ UINT16 I, col;
+
+ for( I = 0; I < 2048; I++ )
+ {
+ col = ( gb_vram[ 0x0800 + (I*2) + 1 ] << 8 ) | gb_vram[ 0x0800 + (I*2) ];
+ m_sgb_pal_data[I] = col;
+ }
+ }
+ break;
+ case 0x0C: /* ATRC_EN */
+ /* Not Implemented */
+ break;
+ case 0x0D: /* TEST_EN */
+ /* Not Implemented */
+ break;
+ case 0x0E: /* ICON_EN */
+ /* Not Implemented */
+ break;
+ case 0x0F: /* DATA_SND */
+ /* Not Implemented */
+ break;
+ case 0x10: /* DATA_TRN */
+ /* Not Implemented */
+ break;
+ case 0x11: /* MLT_REQ - Multi controller request */
+ if (sgb_data[1] == 0x00)
+ m_sgb_controller_mode = 0;
+ else if (sgb_data[1] == 0x01)
+ m_sgb_controller_mode = 2;
+ break;
+ case 0x12: /* JUMP */
+ /* Not Implemented */
+ break;
+ case 0x13: /* CHR_TRN */
+ if( sgb_data[1] & 0x1 )
+ memcpy( m_sgb_tile_data + 4096, gb_get_vram_ptr(machine()) + 0x0800, 4096 );
+ else
+ memcpy( m_sgb_tile_data, gb_get_vram_ptr(machine()) + 0x0800, 4096 );
+ break;
+ case 0x14: /* PCT_TRN */
+ {
+ int I;
+ UINT16 col;
+ UINT8 *gb_vram = gb_get_vram_ptr(machine());
+ if( m_sgb_hack )
+ {
+ memcpy( m_sgb_tile_map, gb_vram + 0x1000, 2048 );
+ for( I = 0; I < 64; I++ )
+ {
+ col = ( gb_vram[ 0x0800 + (I*2) + 1 ] << 8 ) | gb_vram[ 0x0800 + (I*2) ];
+ m_sgb_pal[SGB_BORDER_PAL_OFFSET + I] = col;
+ }
+ }
+ else /* Do things normally */
+ {
+ memcpy( m_sgb_tile_map, gb_vram + 0x0800, 2048 );
+ for( I = 0; I < 64; I++ )
+ {
+ col = ( gb_vram[ 0x1000 + (I*2) + 1 ] << 8 ) | gb_vram[ 0x1000 + (I*2) ];
+ m_sgb_pal[SGB_BORDER_PAL_OFFSET + I] = col;
+ }
+ }
+ }
+ break;
+ case 0x15: /* ATTR_TRN */
+ memcpy( m_sgb_atf_data, gb_get_vram_ptr(machine()) + 0x0800, 4050 );
+ break;
+ case 0x16: /* ATTR_SET */
+ {
+ UINT8 J, I;
+
+ /* Attribute File */
+ if( sgb_data[1] & 0x40 )
+ m_sgb_window_mask = 0;
+ m_sgb_atf = (sgb_data[1] & 0x3f) * (18 * 5);
+ for( J = 0; J < 18; J++ )
+ {
+ for( I = 0; I < 5; I++ )
+ {
+ m_sgb_pal_map[I * 4][J] = (m_sgb_atf_data[(J * 5) + m_sgb_atf + I] & 0xC0) >> 6;
+ m_sgb_pal_map[(I * 4) + 1][J] = (m_sgb_atf_data[(J * 5) + m_sgb_atf + I] & 0x30) >> 4;
+ m_sgb_pal_map[(I * 4) + 2][J] = (m_sgb_atf_data[(J * 5) + m_sgb_atf + I] & 0xC) >> 2;
+ m_sgb_pal_map[(I * 4) + 3][J] = m_sgb_atf_data[(J * 5) + m_sgb_atf + I] & 0x3;
+ }
+ }
+ }
+ break;
+ case 0x17: /* MASK_EN */
+ m_sgb_window_mask = sgb_data[1];
+ break;
+ case 0x18: /* OBJ_TRN */
+ /* Not Implemnted */
+ break;
+ case 0x19: /* ? */
+ /* Called by: dkl,dkl2,dkl3,zeldadx
+ But I don't know what it is for. */
+ /* Not Implemented */
+ break;
+ case 0x1E: /* Used by bootrom to transfer the gb cart header */
+ break;
+ case 0x1F: /* Used by bootrom to transfer the gb cart header */
+ break;
+ default:
+ logerror( "SGB: Unknown Command 0x%02x!\n", sgb_data[0] >> 3 );
+ }
+
+ m_sgb_start = 0;
+ m_sgb_bytecount = 0;
+ m_sgb_packets = -1;
+ }
+ if( m_sgb_start )
+ {
+ sgb_data[m_sgb_bytecount] >>= 1;
+ m_sgb_bitcount++;
+ if (m_sgb_bitcount == 8)
+ {
+ m_sgb_bitcount = 0;
+ m_sgb_bytecount++;
+ }
+ }
+ m_sgb_rest = 0;
+ }
+ JOYPAD = 0x2F & (ioport("INPUTS")->read() | 0xF0);
+ break;
+ case 0x30: /* rest condition */
+ if (m_sgb_start)
+ m_sgb_rest = 1;
+ if (m_sgb_controller_mode)
+ {
+ m_sgb_controller_no++;
+ if (m_sgb_controller_no == m_sgb_controller_mode)
+ m_sgb_controller_no = 0;
+ JOYPAD = 0x3F - m_sgb_controller_no;
+ }
+ else
+ JOYPAD = 0x3F;
+
+ /* Hack to let cartridge know it's running on an SGB */
+ if ( (sgb_data[0] >> 3) == 0x1F )
+ JOYPAD = 0x3E;
+ break;
+ }
+ return;
+ default:
+ /* we didn't handle the write, so pass it to the GB handler */
+ gb_io_w( space, offset, data );
+ return;
+ }
+
+ m_gb_io[offset] = data;
+}
+
+/* Interrupt Enable register */
+READ8_MEMBER(gb_state::gb_ie_r)
+{
+ return machine().device<lr35902_cpu_device>(":maincpu")->get_ie();
+}
+
+WRITE8_MEMBER(gb_state::gb_ie_w)
+{
+ machine().device<lr35902_cpu_device>(":maincpu")->set_ie( data & 0x1F );
+}
+
+/* IO read */
+READ8_MEMBER(gb_state::gb_io_r)
+{
+ switch(offset)
+ {
+ case 0x04:
+ return ( m_divcount >> 8 ) & 0xFF;
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ return m_gb_io[offset];
+ case 0x0F:
+ /* Make sure the internal states are up to date */
+ return 0xE0 | machine().device<lr35902_cpu_device>(":maincpu")->get_if();
+ default:
+ /* It seems unsupported registers return 0xFF */
+ return 0xFF;
+ }
+}
+
+DEVICE_START(gb_cart)
+{
+ gb_state *state = device->machine().driver_data<gb_state>();
+ int I;
+
+ state->m_gb_dummy_rom_bank = auto_alloc_array(device->machine(), UINT8, 0x4000);
+ memset(state->m_gb_dummy_rom_bank, 0xff, 0x4000);
+
+ state->m_gb_dummy_ram_bank = auto_alloc_array(device->machine(), UINT8, 0x2000);
+ memset(state->m_gb_dummy_ram_bank, 0xff, 0x2000 );
+
+ for(I = 0; I < MAX_ROMBANK; I++)
+ {
+ state->m_ROMMap[I] = state->m_gb_dummy_rom_bank;
+ }
+ for(I = 0; I < MAX_RAMBANK; I++)
+ {
+ state->m_RAMMap[I] = state->m_gb_dummy_ram_bank;
+ }
+ state->m_ROMBank00 = 0;
+ state->m_ROMBanks = 0;
+ state->m_RAMBanks = 0;
+ state->m_MBCType = MBC_NONE;
+ state->m_CartType = 0;
+ state->m_ROMMask = 0;
+ state->m_RAMMask = 0;
+}
+
+DEVICE_IMAGE_LOAD(gb_cart)
+{
+ gb_state *state = image.device().machine().driver_data<gb_state>();
+ static const char *const CartTypes[] =
+ {
+ "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"
+ };
+
+/*** Following are some known manufacturer 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}
+ };
+
+ int Checksum, I, J, filesize, load_start = 0;
+ UINT16 reported_rom_banks;
+ UINT8 *gb_header;
+ static const int rambanks[8] = {0, 1, 1, 4, 16, 8, 0, 0};
+
+ if (image.software_entry() == NULL)
+ filesize = image.length();
+ else
+ filesize = image.get_software_region_length("rom");
+
+ /* Check for presence of a header, and skip that header */
+ J = filesize % 0x4000;
+ if (J == 512)
+ {
+ logerror("Rom-header found, skipping\n");
+ load_start = 512;
+ filesize -= 512;
+ }
+
+ /* Verify that the file contains 16kb blocks */
+ if ((filesize == 0) || ((filesize % 0x4000) != 0))
+ {
+ image.seterror(IMAGE_ERROR_UNSPECIFIED, "Invalid rom file size");
+ return IMAGE_INIT_FAIL;
+ }
+
+ /* Claim memory */
+ state->m_gb_cart = auto_alloc_array(image.device().machine(), UINT8, filesize);
+
+ if (image.software_entry() == NULL)
+ {
+ /* Actually skip the header */
+ image.fseek(load_start, SEEK_SET);
+
+ /* Read cartridge */
+ if (image.fread( state->m_gb_cart, filesize) != filesize)
+ {
+ image.seterror(IMAGE_ERROR_UNSPECIFIED, "Unable to fully read from file");
+ return IMAGE_INIT_FAIL;
+ }
+ }
+ else
+ memcpy(state->m_gb_cart, image.get_software_region("rom") + load_start, filesize);
+
+ gb_header = state->m_gb_cart;
+ state->m_ROMBank00 = 0;
+
+ /* Check for presence of MMM01 mapper */
+ if (filesize >= 0x8000)
+ {
+ 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;
+ gb_header = state->m_gb_cart + filesize - 0x8000;
+ for (I = 0; I < 0x18; I++)
+ {
+ if (gb_header[0x0104 + I] == nintendo_logo[I])
+ {
+ bytes_matched++;
+ }
+ }
+
+ if (bytes_matched == 0x18 && gb_header[0x0147] >= 0x0B && gb_header[0x0147] <= 0x0D)
+ {
+ state->m_ROMBank00 = (filesize / 0x4000) - 2;
+ state->m_mmm01_bank_offset = state->m_ROMBank00;
+ }
+ else
+ {
+ gb_header = state->m_gb_cart;
+ }
+ }
+
+ /* Fill in our cart details */
+ switch(gb_header[0x0147])
+ {
+ case 0x00: state->m_MBCType = MBC_NONE; state->m_CartType = 0; break;
+ case 0x01: state->m_MBCType = MBC_MBC1; state->m_CartType = 0; break;
+ case 0x02: state->m_MBCType = MBC_MBC1; state->m_CartType = CART_RAM; break;
+ case 0x03: state->m_MBCType = MBC_MBC1; state->m_CartType = CART_RAM | BATTERY; break;
+ case 0x05: state->m_MBCType = MBC_MBC2; state->m_CartType = 0; break;
+ case 0x06: state->m_MBCType = MBC_MBC2; state->m_CartType = BATTERY; break;
+ case 0x08: state->m_MBCType = MBC_NONE; state->m_CartType = CART_RAM; break;
+ case 0x09: state->m_MBCType = MBC_NONE; state->m_CartType = CART_RAM | BATTERY; break;
+ case 0x0B: state->m_MBCType = MBC_MMM01; state->m_CartType = 0; break;
+ case 0x0C: state->m_MBCType = MBC_MMM01; state->m_CartType = CART_RAM; break;
+ case 0x0D: state->m_MBCType = MBC_MMM01; state->m_CartType = CART_RAM | BATTERY; break;
+ case 0x0F: state->m_MBCType = MBC_MBC3; state->m_CartType = TIMER | BATTERY; break;
+ case 0x10: state->m_MBCType = MBC_MBC3; state->m_CartType = TIMER | CART_RAM | BATTERY; break;
+ case 0x11: state->m_MBCType = MBC_MBC3; state->m_CartType = 0; break;
+ case 0x12: state->m_MBCType = MBC_MBC3; state->m_CartType = CART_RAM; break;
+ case 0x13: state->m_MBCType = MBC_MBC3; state->m_CartType = CART_RAM | BATTERY; break;
+ case 0x15: state->m_MBCType = MBC_MBC4; state->m_CartType = 0; break;
+ case 0x16: state->m_MBCType = MBC_MBC4; state->m_CartType = CART_RAM; break;
+ case 0x17: state->m_MBCType = MBC_MBC4; state->m_CartType = CART_RAM | BATTERY; break;
+ case 0x19: state->m_MBCType = MBC_MBC5; state->m_CartType = 0; break;
+ case 0x1A: state->m_MBCType = MBC_MBC5; state->m_CartType = CART_RAM; break;
+ case 0x1B: state->m_MBCType = MBC_MBC5; state->m_CartType = CART_RAM | BATTERY; break;
+ case 0x1C: state->m_MBCType = MBC_MBC5; state->m_CartType = RUMBLE; break;
+ case 0x1D: state->m_MBCType = MBC_MBC5; state->m_CartType = RUMBLE | SRAM; break;
+ case 0x1E: state->m_MBCType = MBC_MBC5; state->m_CartType = RUMBLE | SRAM | BATTERY; break;
+ case 0x20: state->m_MBCType = MBC_MBC6; state->m_CartType = SRAM; break;
+ case 0x22: state->m_MBCType = MBC_MBC7; state->m_CartType = SRAM | BATTERY; break;
+ case 0xBE: state->m_MBCType = MBC_NONE; state->m_CartType = 0; break; /* used in Flash2Advance GB Bridge boot program */
+ case 0xFD: state->m_MBCType = MBC_TAMA5; state->m_CartType = 0 /*RTC | BATTERY?*/; break;
+ case 0xFE: state->m_MBCType = MBC_HUC3; state->m_CartType = 0; break;
+ case 0xFF: state->m_MBCType = MBC_HUC1; state->m_CartType = 0; break;
+ default: state->m_MBCType = MBC_UNKNOWN; state->m_CartType = UNKNOWN; break;
+ }
+
+ /* Check whether we're dealing with a (possible) Wisdom Tree game here */
+ if (gb_header[0x0147] == 0x00)
+ {
+ int count = 0;
+ for (I = 0x0134; I <= 0x014C; I++)
+ {
+ count += gb_header[I];
+ }
+ if (count == 0)
+ {
+ state->m_MBCType = MBC_WISDOM;
+ }
+ }
+
+ /* Check if we're dealing with a Korean variant of the MBC1 mapper */
+ if (state->m_MBCType == MBC_MBC1)
+ {
+ if (gb_header[0x13F] == 0x42 && gb_header[0x140] == 0x32 && gb_header[0x141] == 0x43 && gb_header[0x142] == 0x4B)
+ {
+ state->m_MBCType = MBC_MBC1_KOR;
+ }
+ }
+ if (state->m_MBCType == MBC_UNKNOWN)
+ {
+ image.seterror(IMAGE_ERROR_UNSUPPORTED, "Unknown mapper type");
+ return IMAGE_INIT_FAIL;
+ }
+ if (state->m_MBCType == MBC_MMM01)
+ {
+// image.seterror(IMAGE_ERROR_UNSUPPORTED, "Mapper MMM01 is not supported yet");
+// return IMAGE_INIT_FAIL;
+ }
+ if (state->m_MBCType == MBC_MBC4)
+ {
+ image.seterror(IMAGE_ERROR_UNSUPPORTED, "Mapper MBC4 is not supported yet");
+ return IMAGE_INIT_FAIL;
+ }
+ /* MBC7 support is still work-in-progress, so only enable it for debug builds */
+#ifndef MAME_DEBUG
+ if (state->m_MBCType == MBC_MBC7)
+ {
+ image.seterror(IMAGE_ERROR_UNSUPPORTED, "Mapper MBC7 is not supported yet");
+ return IMAGE_INIT_FAIL;
+ }
+#endif
+
+ state->m_ROMBanks = filesize / 0x4000;
+ switch (gb_header[0x0148])
+ {
+ case 0x52:
+ reported_rom_banks = 72;
+ break;
+ case 0x53:
+ reported_rom_banks = 80;
+ break;
+ case 0x54:
+ reported_rom_banks = 96;
+ break;
+ case 0x00: case 0x01: case 0x02: case 0x03:
+ case 0x04: case 0x05: case 0x06: case 0x07:
+ reported_rom_banks = 2 << gb_header[0x0148];
+ break;
+ default:
+ logerror("Warning loading cartridge: Unknown ROM size in header.\n");
+ reported_rom_banks = 256;
+ break;
+ }
+ if (state->m_ROMBanks != reported_rom_banks && state->m_MBCType != MBC_WISDOM)
+ {
+ logerror("Warning loading cartridge: Filesize and reported ROM banks don't match.\n");
+ }
+
+ state->m_RAMBanks = rambanks[gb_header[0x0149] & 7];
+
+ /* Calculate and check checksum */
+ Checksum = ((UINT16) gb_header[0x014E] << 8) + gb_header[0x014F];
+ Checksum += gb_header[0x014E] + gb_header[0x014F];
+ for (I = 0; I < filesize; I++)
+ {
+ Checksum -= state->m_gb_cart[I];
+ }
+ if (Checksum & 0xFFFF)
+ {
+ logerror("Warning loading cartridge: Checksum is wrong.");
+ }
+
+ /* Initialize ROMMap pointers */
+ for (I = 0; I < state->m_ROMBanks; I++)
+ {
+ state->m_ROMMap[I] = state->m_gb_cart + (I * 0x4000);
+ }
+
+ /*
+ Handle odd-sized cartridges (72,80,96 banks)
+ ROMBanks ROMMask
+ 72 (1001000) 1000111 (71)
+ 80 (1010000) 1001111 (79)
+ 96 (1100000) 1011111 (95)
+ */
+ state->m_ROMMask = I - 1;
+ if ((state->m_ROMBanks & state->m_ROMMask) != 0)
+ {
+ for( ; I & state->m_ROMBanks; I++)
+ {
+ state->m_ROMMap[I] = state->m_ROMMap[I & state->m_ROMMask];
+ }
+ state->m_ROMMask = I - 1;
+ }
+
+ /* Fill out the remaining rom bank pointers, if any. */
+ for ( ; I < MAX_ROMBANK; I++)
+ {
+ state->m_ROMMap[I] = state->m_ROMMap[I & state->m_ROMMask];
+ }
+
+ /* Log cart information */
+ {
+ const char *P;
+ char S[50];
+ static const int ramsize[8] = { 0, 2, 8, 32, 128, 64, 0, 0 };
+
+
+ strncpy (S, (char *)&gb_header[0x0134], 16);
+ S[16] = '\0';
+ logerror("Cart Information\n");
+ logerror("\tName: %s\n", S);
+ logerror("\tType: %s [0x%2X]\n", CartTypes[gb_header[0x0147]], gb_header[0x0147] );
+ logerror("\tGame Boy: %s\n", (gb_header[0x0143] == 0xc0) ? "No" : "Yes" );
+ logerror("\tSuper GB: %s [0x%2X]\n", (gb_header[0x0146] == 0x03) ? "Yes" : "No", gb_header[0x0146] );
+ logerror("\tColor GB: %s [0x%2X]\n", (gb_header[0x0143] == 0x80 || gb_header[0x0143] == 0xc0) ? "Yes" : "No", state->m_gb_cart[0x0143] );
+ logerror("\tROM Size: %d 16kB Banks [0x%2X]\n", state->m_ROMBanks, gb_header[0x0148]);
+ logerror("\tRAM Size: %d kB [0x%2X]\n", ramsize[ gb_header[0x0149] & 0x07 ], gb_header[0x0149]);
+ logerror("\tLicense code: 0x%2X%2X\n", gb_header[0x0145], gb_header[0x0144] );
+ J = ((UINT16) gb_header[0x014B] << 8) + gb_header[0x014A];
+ for (I = 0, P = NULL; !P && Companies[I].Name; I++)
+ if (J == Companies[I].Code)
+ P = Companies[I].Name;
+ logerror("\tManufacturer ID: 0x%2X", J);
+ logerror(" [%s]\n", P ? P : "?");
+ logerror("\tVersion Number: 0x%2X\n", gb_header[0x014C]);
+ logerror("\tComplement Check: 0x%2X\n", gb_header[0x014D]);
+ logerror("\tChecksum: 0x%2X\n", ( ( gb_header[0x014E] << 8 ) + gb_header[0x014F] ) );
+ J = ((UINT16) gb_header[0x0103] << 8) + gb_header[0x0102];
+ logerror("\tStart Address: 0x%2X\n", J);
+ }
+
+ /* MBC2 has 512 * 4bits (8kb) internal RAM */
+ if(state->m_MBCType == MBC_MBC2)
+ state->m_RAMBanks = 1;
+ /* MBC7 has 512 bytes(?) of internal RAM */
+ if (state->m_MBCType == MBC_MBC7)
+ {
+ state->m_RAMBanks = 1;
+ }
+
+ if (state->m_RAMBanks && state->m_MBCType)
+ {
+ /* Claim memory */
+ state->m_gb_cart_ram = auto_alloc_array(image.device().machine(), UINT8, state->m_RAMBanks * 0x2000);
+ memset(state->m_gb_cart_ram, 0xFF, state->m_RAMBank * 0x2000);
+
+ for (I = 0; I < state->m_RAMBanks; I++)
+ {
+ state->m_RAMMap[I] = state->m_gb_cart_ram + (I * 0x2000);
+ }
+
+ /* Set up rest of the (mirrored) RAM pages */
+ state->m_RAMMask = I - 1;
+ for ( ; I < MAX_RAMBANK; I++)
+ {
+ state->m_RAMMap[I] = state->m_RAMMap[I & state->m_RAMMask];
+ }
+ }
+ else
+ {
+ state->m_RAMMask = 0;
+ }
+
+ /* If there's an RTC claim memory to store the RTC contents */
+ if (state->m_CartType & TIMER)
+ {
+ state->m_MBC3RTCData = auto_alloc_array(image.device().machine(), UINT8, 0x2000);
+ }
+
+ if (state->m_MBCType == MBC_TAMA5)
+ {
+ state->m_MBC3RTCData = auto_alloc_array(image.device().machine(), UINT8, 0x2000);
+ memset(state->m_gbTama5Memory, 0xff, sizeof(state->m_gbTama5Memory));
+ }
+
+ /* Load the saved RAM if this cart has a battery */
+ if (state->m_CartType & BATTERY && state->m_RAMBanks)
+ {
+ image.battery_load(state->m_gb_cart_ram, state->m_RAMBanks * 0x2000, 0x00);
+ }
+
+ return IMAGE_INIT_PASS;
+}
+
+INTERRUPT_GEN( gb_scanline_interrupt )
+{
+}
+
+static TIMER_CALLBACK(gb_serial_timer_proc)
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ /* Shift in a received bit */
+ state->SIODATA = (state->SIODATA << 1) | 0x01;
+ /* Decrement number of handled bits */
+ state->m_SIOCount--;
+ /* If all bits done, stop timer and trigger interrupt */
+ if ( ! state->m_SIOCount )
+ {
+ state->SIOCONT &= 0x7F;
+ state->m_gb_serial_timer->enable( 0 );
+ cputag_set_input_line(machine, "maincpu", SIO_INT, ASSERT_LINE);
+ }
+}
+
+INLINE void gb_timer_check_irq( running_machine &machine )
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ state->m_reloading = 0;
+ if ( state->m_triggering_irq )
+ {
+ state->m_triggering_irq = 0;
+ if ( state->TIMECNT == 0 )
+ {
+ state->TIMECNT = state->TIMEMOD;
+ cputag_set_input_line(machine, "maincpu", TIM_INT, ASSERT_LINE );
+ state->m_reloading = 1;
+ }
+ }
+}
+
+static void gb_timer_increment( running_machine &machine )
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ gb_timer_check_irq(machine);
+
+ state->TIMECNT += 1;
+ if ( state->TIMECNT == 0 )
+ {
+ state->m_triggering_irq = 1;
+ }
+}
+
+void gb_timer_callback(lr35902_cpu_device *device, int cycles)
+{
+ gb_state *state = device->machine().driver_data<gb_state>();
+ UINT16 old_gb_divcount = state->m_divcount;
+ state->m_divcount += cycles;
+
+ gb_timer_check_irq(device->machine());
+
+ if ( state->TIMEFRQ & 0x04 )
+ {
+ UINT16 old_count = old_gb_divcount >> state->m_shift;
+ UINT16 new_count = state->m_divcount >> state->m_shift;
+ if ( cycles > state->m_shift_cycles )
+ {
+ gb_timer_increment(device->machine());
+ old_count++;
+ }
+ if ( new_count != old_count )
+ {
+ gb_timer_increment(device->machine());
+ }
+ if ( new_count << state->m_shift < state->m_divcount )
+ {
+ gb_timer_check_irq(device->machine());
+ }
+ }
+}
+
+WRITE8_MEMBER(gb_state::gbc_io2_w)
+{
+ switch( offset )
+ {
+ case 0x0D: /* KEY1 - Prepare speed switch */
+ machine().device<lr35902_cpu_device>(":maincpu")->set_speed( data );
+ return;
+ case 0x10: /* BFF - Bios disable */
+ gb_rom16_0000( machine(), m_ROMMap[m_ROMBank00] );
+ return;
+ case 0x16: /* RP - Infrared port */
+ break;
+ case 0x30: /* SVBK - RAM bank select */
+ m_GBC_RAMBank = data & 0x7;
+ if ( ! m_GBC_RAMBank )
+ m_GBC_RAMBank = 1;
+ membank ("bank3")->set_base (m_GBC_RAMMap[m_GBC_RAMBank]);
+ break;
+ default:
+ break;
+ }
+ gbc_video_w( space, offset, data );
+}
+
+READ8_MEMBER(gb_state::gbc_io2_r)
+{
+ switch( offset )
+ {
+ case 0x0D: /* KEY1 */
+ machine().device<lr35902_cpu_device>(":maincpu")->get_speed();
+ case 0x16: /* RP - Infrared port */
+ break;
+ case 0x30: /* SVBK - RAM bank select */
+ return m_GBC_RAMBank;
+ default:
+ break;
+ }
+ return gbc_video_r( space, offset );
+}
+
+/****************************************************************************
+
+ Megaduck routines
+
+ ****************************************************************************/
+
+MACHINE_START( megaduck )
+{
+ gb_state *state = machine.driver_data<gb_state>();
+ /* Allocate the serial timer, and disable it */
+ state->m_gb_serial_timer = machine.scheduler().timer_alloc(FUNC(gb_serial_timer_proc));
+ state->m_gb_serial_timer->enable( 0 );
+
+ MACHINE_START_CALL( gb_video );
+}
+
+MACHINE_RESET( megaduck )
+{
+ /* We may have to add some more stuff here, if not then it can be merged back into gb */
+ gb_init(machine);
+
+ gb_video_reset( machine, GB_VIDEO_DMG );
+}
+
+/*
+ Map megaduck video related area on to regular Game Boy video area
+
+ Different locations of the video registers:
+ Register Game Boy MegaDuck
+ LCDC FF40 FF10 (See different bit order below)
+ STAT FF41 FF11
+ SCY FF42 FF12
+ SCX FF43 FF13
+ LY FF44 FF18
+ LYC FF45 FF19
+ DMA FF46 FF1A
+ BGP FF47 FF1B
+ OBP0 FF48 FF14
+ OBP1 FF49 FF15
+ WY FF4A FF16
+ WX FF4B FF17
+ Unused FF4C FF4C (?)
+ Unused FF4D FF4D (?)
+ Unused FF4E FF4E (?)
+ Unused FF4F FF4F (?)
+
+ Different LCDC register
+
+ Game Boy MegaDuck
+ 0 6 - BG & Window Display : 0 - Off, 1 - On
+ 1 0 - OBJ Display: 0 - Off, 1 - On
+ 2 1 - OBJ Size: 0 - 8x8, 1 - 8x16
+ 3 2 - BG Tile Map Display: 0 - 9800, 1 - 9C00
+ 4 4 - BG & Window Tile Data Select: 0 - 8800, 1 - 8000
+ 5 5 - Window Display: 0 - Off, 1 - On
+ 6 3 - Window Tile Map Display Select: 0 - 9800, 1 - 9C00
+ 7 7 - LCD Operation
+
+ **************/
+
+READ8_MEMBER(gb_state::megaduck_video_r)
+{
+ UINT8 data;
+
+ if ( (offset & 0x0C) && ((offset & 0x0C) ^ 0x0C) )
+ {
+ offset ^= 0x0C;
+ }
+ data = gb_video_r( space, offset );
+ if ( offset )
+ return data;
+ return BITSWAP8(data,7,0,5,4,6,3,2,1);
+}
+
+WRITE8_MEMBER(gb_state::megaduck_video_w)
+{
+ if ( !offset )
+ {
+ data = BITSWAP8(data,7,3,5,4,2,1,0,6);
+ }
+ if ( (offset & 0x0C) && ((offset & 0x0C) ^ 0x0C) )
+ {
+ offset ^= 0x0C;
+ }
+ gb_video_w(space, offset, data );
+}
+
+/* Map megaduck audio offset to game boy audio offsets */
+
+static const UINT8 megaduck_sound_offsets[16] = { 0, 2, 1, 3, 4, 6, 5, 7, 8, 9, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
+
+WRITE8_MEMBER(gb_state::megaduck_sound_w1)
+{
+ gb_sound_w(machine().device("custom"), megaduck_sound_offsets[offset], data );
+}
+
+READ8_MEMBER(gb_state::megaduck_sound_r1)
+{
+ return gb_sound_r( machine().device("custom"), megaduck_sound_offsets[offset] );
+}
+
+WRITE8_MEMBER(gb_state::megaduck_sound_w2)
+{
+ switch(offset)
+ {
+ case 0x00: gb_sound_w(machine().device("custom"), 0x10, data ); break;
+ case 0x01: gb_sound_w(machine().device("custom"), 0x12, data ); break;
+ case 0x02: gb_sound_w(machine().device("custom"), 0x11, data ); break;
+ case 0x03: gb_sound_w(machine().device("custom"), 0x13, data ); break;
+ case 0x04: gb_sound_w(machine().device("custom"), 0x14, data ); break;
+ case 0x05: gb_sound_w(machine().device("custom"), 0x16, data ); break;
+ case 0x06: gb_sound_w(machine().device("custom"), 0x15, data ); break;
+ case 0x07:
+ case 0x08:
+ case 0x09:
+ case 0x0A:
+ case 0x0B:
+ case 0x0C:
+ case 0x0D:
+ case 0x0E:
+ case 0x0F:
+ break;
+ }
+}
+
+READ8_MEMBER(gb_state::megaduck_sound_r2)
+{
+ return gb_sound_r(machine().device("custom"), 0x10 + megaduck_sound_offsets[offset]);
+}
+
+WRITE8_MEMBER(gb_state::megaduck_rom_bank_select_type1)
+{
+ if( m_ROMMask )
+ {
+ m_ROMBank = data & m_ROMMask;
+
+ /* Switch banks */
+ membank ("bank1")->set_base (m_ROMMap[m_ROMBank]);
+ }
+}
+
+WRITE8_MEMBER(gb_state::megaduck_rom_bank_select_type2)
+{
+ if( m_ROMMask )
+ {
+ m_ROMBank = (data << 1) & m_ROMMask;
+
+ /* Switch banks */
+ membank( "bank10" )->set_base( m_ROMMap[m_ROMBank]);
+ membank( "bank1" )->set_base( m_ROMMap[m_ROMBank + 1]);
+ }
+}
+
+DEVICE_IMAGE_LOAD(megaduck_cart)
+{
+ gb_state *state = image.device().machine().driver_data<gb_state>();
+ int I;
+ UINT32 filesize;
+
+ for (I = 0; I < MAX_ROMBANK; I++)
+ state->m_ROMMap[I] = NULL;
+ for (I = 0; I < MAX_RAMBANK; I++)
+ state->m_RAMMap[I] = NULL;
+
+ if (image.software_entry() == NULL)
+ filesize = image.length();
+ else
+ filesize = image.get_software_region_length("rom");
+
+ if ((filesize == 0) || ((filesize % 0x4000) != 0))
+ {
+ image.seterror(IMAGE_ERROR_UNSPECIFIED, "Invalid rom file size");
+ return IMAGE_INIT_FAIL;
+ }
+
+ state->m_ROMBanks = filesize / 0x4000;
+
+ /* Claim memory */
+ state->m_gb_cart = auto_alloc_array(image.device().machine(), UINT8, filesize);
+
+ /* Read cartridge */
+ if (image.software_entry() == NULL)
+ {
+ if (image.fread( state->m_gb_cart, filesize) != filesize)
+ {
+ image.seterror(IMAGE_ERROR_UNSPECIFIED, "Unable to fully read from file");
+ return IMAGE_INIT_FAIL;
+ }
+ }
+ else
+ {
+ memcpy(state->m_gb_cart, image.get_software_region("rom"), filesize);
+ }
+
+ /* Log cart information */
+ {
+ logerror("Cart Information\n");
+ logerror("\tRom Banks: %d\n", state->m_ROMBanks);
+ }
+
+ for (I = 0; I < state->m_ROMBanks; I++)
+ {
+ state->m_ROMMap[I] = state->m_gb_cart + (I * 0x4000);
+ }
+
+ /* Build rom bank Mask */
+ if (state->m_ROMBanks < 3)
+ state->m_ROMMask = 0;
+ else
+ {
+ for (I = 1; I < state->m_ROMBanks; I <<= 1)
+ {
+ }
+ state->m_ROMMask = I - 1;
+ }
+
+ state->m_MBCType = MBC_MEGADUCK;
+
+ return IMAGE_INIT_PASS;
+}
diff --git a/src/mess/machine/genpc.c b/src/mess/machine/genpc.c
new file mode 100644
index 00000000000..ec9f708f30a
--- /dev/null
+++ b/src/mess/machine/genpc.c
@@ -0,0 +1,861 @@
+/***************************************************************************
+
+ machine/genpc.c
+
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/genpc.h"
+
+#include "machine/i8255.h"
+#include "machine/pic8259.h"
+#include "machine/pit8253.h"
+#include "sound/speaker.h"
+#include "machine/ram.h"
+#include "imagedev/cassette.h"
+
+#define VERBOSE_PIO 0 /* PIO (keyboard controller) */
+
+#define PIO_LOG(N,M,A) \
+ do { \
+ if(VERBOSE_PIO>=N) \
+ { \
+ if( M ) \
+ logerror("%11.6f: %-24s",machine().time().as_double(),(char*)M ); \
+ logerror A; \
+ } \
+ } while (0)
+
+
+/*************************************************************************
+ *
+ * PC DMA stuff
+ *
+ *************************************************************************/
+
+READ8_DEVICE_HANDLER(pc_page_r)
+{
+ return 0xFF;
+}
+
+
+WRITE8_DEVICE_HANDLER(pc_page_w)
+{
+ ibm5160_mb_device *board = downcast<ibm5160_mb_device *>(device);
+ switch(offset % 4)
+ {
+ case 1:
+ board->m_dma_offset[2] = data;
+ break;
+ case 2:
+ board->m_dma_offset[3] = data;
+ break;
+ case 3:
+ board->m_dma_offset[0] = board->m_dma_offset[1] = data;
+ break;
+ }
+}
+
+
+WRITE_LINE_MEMBER( ibm5160_mb_device::pc_dma_hrq_changed )
+{
+ device_set_input_line(m_maincpu, INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE);
+
+ /* Assert HLDA */
+ m_dma8237->hack_w(state);
+}
+
+
+READ8_MEMBER( ibm5160_mb_device::pc_dma_read_byte )
+{
+ address_space *spaceio = m_maincpu->space(AS_PROGRAM);
+ offs_t page_offset = (((offs_t) m_dma_offset[m_dma_channel]) << 16) & 0x0F0000;
+ return spaceio->read_byte( page_offset + offset);
+}
+
+
+WRITE8_MEMBER( ibm5160_mb_device::pc_dma_write_byte )
+{
+ address_space *spaceio = m_maincpu->space(AS_PROGRAM);
+ offs_t page_offset = (((offs_t) m_dma_offset[m_dma_channel]) << 16) & 0x0F0000;
+
+ spaceio->write_byte( page_offset + offset, data);
+}
+
+
+READ8_MEMBER( ibm5160_mb_device::pc_dma8237_1_dack_r )
+{
+ return m_isabus->dack_r(1);
+}
+
+READ8_MEMBER( ibm5160_mb_device::pc_dma8237_2_dack_r )
+{
+ return m_isabus->dack_r(2);
+}
+
+
+READ8_MEMBER( ibm5160_mb_device::pc_dma8237_3_dack_r )
+{
+ return m_isabus->dack_r(3);
+}
+
+
+WRITE8_MEMBER( ibm5160_mb_device::pc_dma8237_1_dack_w )
+{
+ m_isabus->dack_w(1,data);
+}
+
+WRITE8_MEMBER( ibm5160_mb_device::pc_dma8237_2_dack_w )
+{
+ m_isabus->dack_w(2,data);
+}
+
+
+WRITE8_MEMBER( ibm5160_mb_device::pc_dma8237_3_dack_w )
+{
+ m_isabus->dack_w(3,data);
+}
+
+
+WRITE8_MEMBER( ibm5160_mb_device::pc_dma8237_0_dack_w )
+{
+ m_u73_q2 = 0;
+ m_dma8237->dreq0_w( m_u73_q2 );
+}
+
+
+WRITE_LINE_MEMBER( ibm5160_mb_device::pc_dma8237_out_eop )
+{
+ return m_isabus->eop_w(state == ASSERT_LINE ? 0 : 1 );
+}
+
+WRITE_LINE_MEMBER( ibm5160_mb_device::pc_dack0_w ) { if (!state) m_dma_channel = 0; }
+WRITE_LINE_MEMBER( ibm5160_mb_device::pc_dack1_w ) { if (!state) m_dma_channel = 1; }
+WRITE_LINE_MEMBER( ibm5160_mb_device::pc_dack2_w ) { if (!state) m_dma_channel = 2; }
+WRITE_LINE_MEMBER( ibm5160_mb_device::pc_dack3_w ) { if (!state) m_dma_channel = 3; }
+
+I8237_INTERFACE( pc_dma8237_config )
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ibm5160_mb_device, pc_dma_hrq_changed),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ibm5160_mb_device, pc_dma8237_out_eop),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ibm5160_mb_device, pc_dma_read_byte),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ibm5160_mb_device, pc_dma_write_byte),
+
+ { DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ibm5160_mb_device, pc_dma8237_1_dack_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ibm5160_mb_device, pc_dma8237_2_dack_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ibm5160_mb_device, pc_dma8237_3_dack_r) },
+
+
+ { DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ibm5160_mb_device, pc_dma8237_0_dack_w),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ibm5160_mb_device, pc_dma8237_1_dack_w),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ibm5160_mb_device, pc_dma8237_2_dack_w),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ibm5160_mb_device, pc_dma8237_3_dack_w) },
+
+ // DACK's
+ { DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ibm5160_mb_device, pc_dack0_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ibm5160_mb_device, pc_dack1_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ibm5160_mb_device, pc_dack2_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ibm5160_mb_device, pc_dack3_w) }
+};
+
+
+/*************************************************************
+ *
+ * pic8259 configuration
+ *
+ *************************************************************/
+WRITE_LINE_MEMBER(ibm5160_mb_device::pc_cpu_line)
+{
+ m_maincpu->set_input_line(INPUT_LINE_IRQ0, state);
+}
+
+const struct pic8259_interface pc_pic8259_config =
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ibm5160_mb_device, pc_cpu_line),
+ DEVCB_LINE_VCC,
+ DEVCB_NULL
+};
+
+
+WRITE_LINE_MEMBER(ibm5160_mb_device::pc_speaker_set_spkrdata)
+{
+ m_pc_spkrdata = state ? 1 : 0;
+ speaker_level_w( m_speaker, m_pc_spkrdata & m_pc_input );
+}
+
+
+/*************************************************************
+ *
+ * pit8253 configuration
+ *
+ *************************************************************/
+
+WRITE_LINE_MEMBER( ibm5160_mb_device::pc_pit8253_out1_changed )
+{
+ /* Trigger DMA channel #0 */
+ if ( m_out1 == 0 && state == 1 && m_u73_q2 == 0 )
+ {
+ m_u73_q2 = 1;
+ m_dma8237->dreq0_w( m_u73_q2 );
+ }
+ m_out1 = state;
+}
+
+
+WRITE_LINE_MEMBER( ibm5160_mb_device::pc_pit8253_out2_changed )
+{
+ m_pc_input = state ? 1 : 0;
+ speaker_level_w( m_speaker, m_pc_spkrdata & m_pc_input );
+}
+
+
+const struct pit8253_config pc_pit8253_config =
+{
+ {
+ {
+ XTAL_14_31818MHz/12, /* heartbeat IRQ */
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE("pic8259", pic8259_ir0_w)
+ }, {
+ XTAL_14_31818MHz/12, /* dram refresh */
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ibm5160_mb_device, pc_pit8253_out1_changed)
+ }, {
+ XTAL_14_31818MHz/12, /* pio port c pin 4, and speaker polling enough */
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ibm5160_mb_device, pc_pit8253_out2_changed)
+ }
+ }
+};
+
+/**********************************************************
+ *
+ * PPI8255 interface
+ *
+ *
+ * PORT A (input)
+ *
+ * Directly attached to shift register which stores data
+ * received from the keyboard.
+ *
+ * PORT B (output)
+ * 0 - PB0 - TIM2GATESPK - Enable/disable counting on timer 2 of the 8253
+ * 1 - PB1 - SPKRDATA - Speaker data
+ * 2 - PB2 - - Enable receiving data from the keyboard when keyboard is not locked.
+ * 3 - PB3 - - Dipsswitch set selector
+ * 4 - PB4 - ENBRAMPCK - Enable ram parity check
+ * 5 - PB5 - ENABLEI/OCK - Enable expansion I/O check
+ * 6 - PB6 - - Connected to keyboard clock signal
+ * 0 = ignore keyboard signals
+ * 1 = accept keyboard signals
+ * 7 - PB7 - - Clear/disable shift register and IRQ1 line
+ * 0 = normal operation
+ * 1 = clear and disable shift register and clear IRQ1 flip flop
+ *
+ * PORT C
+ * 0 - PC0 - - Dipswitch 0/4 SW1
+ * 1 - PC1 - - Dipswitch 1/5 SW1
+ * 2 - PC2 - - Dipswitch 2/6 SW1
+ * 3 - PC3 - - Dipswitch 3/7 SW1
+ * 4 - PC4 - SPK - Speaker/cassette data
+ * 5 - PC5 - I/OCHCK - Expansion I/O check result
+ * 6 - PC6 - T/C2OUT - Output of 8253 timer 2
+ * 7 - PC7 - PCK - Parity check result
+ *
+ * IBM5150 SW1:
+ * 0 - OFF - One or more floppy drives
+ * ON - Diskless operation
+ * 1 - OFF - 8087 present
+ * ON - No 8087 present
+ * 2+3 - Used to determine on board memory configuration
+ * OFF OFF - 64KB
+ * ON OFF - 48KB
+ * OFF ON - 32KB
+ * ON ON - 16KB
+ * 4+5 - Used to select display
+ * OFF OFF - Monochrome
+ * ON OFF - CGA, 80 column
+ * OFF ON - CGA, 40 column
+ * ON ON - EGA/VGA display
+ * 6+7 - Used to select number of disk drives
+ * OFF OFF - four disk drives
+ * ON OFF - three disk drives
+ * OFF ON - two disk drives
+ * ON ON - one disk drive
+ *
+ **********************************************************/
+WRITE_LINE_MEMBER( ibm5160_mb_device::keyboard_clock_w )
+{
+ if ( m_ppi_clock_signal != state )
+ {
+ if ( m_ppi_keyb_clock && m_ppi_shift_enable )
+ {
+ m_ppi_clock_signal = state;
+ if ( ! m_ppi_keyboard_clear )
+ {
+ /* Data is clocked in on a high->low transition */
+ if ( ! state )
+ {
+ UINT8 trigger_irq = m_ppi_shift_register & 0x01;
+
+ m_ppi_shift_register = ( m_ppi_shift_register >> 1 ) | ( m_ppi_data_signal << 7 );
+ if ( trigger_irq )
+ {
+ pic8259_ir1_w(m_pic8259, 1);
+ m_ppi_shift_enable = 0;
+ m_ppi_clock_signal = 0;
+ m_pc_kbdc->clock_write_from_mb(m_ppi_clock_signal);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+WRITE_LINE_MEMBER( ibm5160_mb_device::keyboard_data_w )
+{
+ m_ppi_data_signal = state;
+}
+
+READ8_MEMBER (ibm5160_mb_device::pc_ppi_porta_r)
+{
+ int data = 0xFF;
+ /* KB port A */
+ if (m_ppi_keyboard_clear)
+ {
+ /* 0 0 - no floppy drives
+ * 1 Not used
+ * 2-3 The number of memory banks on the system board
+ * 4-5 Display mode
+ * 11 = monochrome
+ * 10 - color 80x25
+ * 01 - color 40x25
+ * 6-7 The number of floppy disk drives
+ */
+ data = ioport("DSW0")->read();
+ }
+ else
+ {
+ data = m_ppi_shift_register;
+ }
+ PIO_LOG(1,"PIO_A_r",("$%02x\n", data));
+ return data;
+}
+
+
+READ8_MEMBER ( ibm5160_mb_device::pc_ppi_portc_r )
+{
+ int timer2_output = pit8253_get_output( m_pit8253, 2 );
+ int data=0xff;
+
+ data&=~0x80; // no parity error
+ data&=~0x40; // no error on expansion board
+ /* KB port C: equipment flags */
+ if (m_ppi_portc_switch_high)
+ {
+ /* read hi nibble of S2 */
+ data = (data & 0xf0) | ((ioport("DSW0")->read() >> 4) & 0x0f);
+ PIO_LOG(1,"PIO_C_r (hi)",("$%02x\n", data));
+ }
+ else
+ {
+ /* read lo nibble of S2 */
+ data = (data & 0xf0) | (ioport("DSW0")->read() & 0x0f);
+ PIO_LOG(1,"PIO_C_r (lo)",("$%02x\n", data));
+ }
+
+ if ( m_ppi_portb & 0x01 )
+ {
+ data = ( data & ~0x10 ) | ( timer2_output ? 0x10 : 0x00 );
+ }
+ data = ( data & ~0x20 ) | ( timer2_output ? 0x20 : 0x00 );
+
+ return data;
+}
+
+
+WRITE8_MEMBER( ibm5160_mb_device::pc_ppi_portb_w )
+{
+ /* PPI controller port B*/
+ m_ppi_portb = data;
+ m_ppi_portc_switch_high = data & 0x08;
+ m_ppi_keyboard_clear = data & 0x80;
+ m_ppi_keyb_clock = data & 0x40;
+ pit8253_gate2_w(m_pit8253, BIT(data, 0));
+ pc_speaker_set_spkrdata( data & 0x02 );
+
+ m_ppi_clock_signal = ( m_ppi_keyb_clock ) ? 1 : 0;
+ m_pc_kbdc->clock_write_from_mb(m_ppi_clock_signal);
+
+ /* If PB7 is set clear the shift register and reset the IRQ line */
+ if ( m_ppi_keyboard_clear )
+ {
+ pic8259_ir1_w(m_pic8259, 0);
+ m_ppi_shift_register = 0;
+ m_ppi_shift_enable = 1;
+ }
+}
+
+
+I8255A_INTERFACE( pc_ppi8255_interface )
+{
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ibm5160_mb_device, pc_ppi_porta_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ibm5160_mb_device, pc_ppi_portb_w),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ibm5160_mb_device, pc_ppi_portc_r),
+ DEVCB_NULL
+};
+
+static const isa8bus_interface isabus_intf =
+{
+ // interrupts
+ DEVCB_DEVICE_LINE("pic8259", pic8259_ir2_w),
+ DEVCB_DEVICE_LINE("pic8259", pic8259_ir3_w),
+ DEVCB_DEVICE_LINE("pic8259", pic8259_ir4_w),
+ DEVCB_DEVICE_LINE("pic8259", pic8259_ir5_w),
+ DEVCB_DEVICE_LINE("pic8259", pic8259_ir6_w),
+ DEVCB_DEVICE_LINE("pic8259", pic8259_ir7_w),
+
+ // dma request
+ DEVCB_DEVICE_LINE_MEMBER("dma8237", am9517a_device, dreq1_w),
+ DEVCB_DEVICE_LINE_MEMBER("dma8237", am9517a_device, dreq2_w),
+ DEVCB_DEVICE_LINE_MEMBER("dma8237", am9517a_device, dreq3_w)
+};
+
+static const pc_kbdc_interface pc_kbdc_intf =
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ibm5160_mb_device, keyboard_clock_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ibm5160_mb_device, keyboard_data_w)
+};
+
+/**********************************************************
+ *
+ * NMI handling
+ *
+ **********************************************************/
+
+static WRITE8_DEVICE_HANDLER( nmi_enable_w )
+{
+ ibm5160_mb_device *board = downcast<ibm5160_mb_device *>(device);
+
+ board->m_nmi_enabled = BIT(data,7);
+ board->m_isabus->set_nmi_state(board->m_nmi_enabled);
+
+}
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type IBM5160_MOTHERBOARD = &device_creator<ibm5160_mb_device>;
+
+//**************************************************************************
+// DEVICE CONFIGURATION
+//**************************************************************************
+
+static MACHINE_CONFIG_FRAGMENT( ibm5160_mb_config )
+ MCFG_PIT8253_ADD( "pit8253", pc_pit8253_config )
+
+ MCFG_I8237_ADD( "dma8237", XTAL_14_31818MHz/3, pc_dma8237_config )
+
+ MCFG_PIC8259_ADD( "pic8259", pc_pic8259_config )
+
+ MCFG_I8255A_ADD( "ppi8255", pc_ppi8255_interface )
+
+ MCFG_ISA8_BUS_ADD("isa", "maincpu", isabus_intf)
+
+ MCFG_PC_KBDC_ADD("pc_kbdc", pc_kbdc_intf)
+
+ /* sound hardware */
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+ MCFG_SOUND_ADD(SPEAKER_TAG, SPEAKER_SOUND, 0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor ibm5160_mb_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( ibm5160_mb_config );
+}
+
+
+static INPUT_PORTS_START( ibm5160_mb )
+ PORT_START("DSW0") /* IN1 */
+ PORT_DIPNAME( 0xc0, 0x40, "Number of floppy drives")
+ PORT_DIPSETTING( 0x00, "1" )
+ PORT_DIPSETTING( 0x40, "2" )
+ PORT_DIPSETTING( 0x80, "3" )
+ PORT_DIPSETTING( 0xc0, "4" )
+ PORT_DIPNAME( 0x30, 0x30, "Graphics adapter")
+ PORT_DIPSETTING( 0x00, "EGA/VGA" )
+ PORT_DIPSETTING( 0x10, "Color 40x25" )
+ PORT_DIPSETTING( 0x20, "Color 80x25" )
+ PORT_DIPSETTING( 0x30, "Monochrome" )
+ PORT_DIPNAME( 0x0c, 0x0c, "RAM banks")
+ PORT_DIPSETTING( 0x00, "1 - 16/ 64/256K" )
+ PORT_DIPSETTING( 0x04, "2 - 32/128/512K" )
+ PORT_DIPSETTING( 0x08, "3 - 48/192/576K" )
+ PORT_DIPSETTING( 0x0c, "4 - 64/256/640K" )
+ PORT_DIPNAME( 0x02, 0x00, "8087 installed")
+ PORT_DIPSETTING( 0x00, DEF_STR(No) )
+ PORT_DIPSETTING( 0x02, DEF_STR(Yes) )
+ PORT_DIPNAME( 0x01, 0x01, "Any floppy drive installed")
+ PORT_DIPSETTING( 0x00, DEF_STR(No) )
+ PORT_DIPSETTING( 0x01, DEF_STR(Yes) )
+INPUT_PORTS_END
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+ioport_constructor ibm5160_mb_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( ibm5160_mb );
+}
+
+
+void ibm5160_mb_device::static_set_cputag(device_t &device, const char *tag)
+{
+ ibm5160_mb_device &board = downcast<ibm5160_mb_device &>(device);
+ board.m_cputag = tag;
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// ibm5160_mb_device - constructor
+//-------------------------------------------------
+
+ibm5160_mb_device::ibm5160_mb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, IBM5160_MOTHERBOARD, "IBM5160_MOTHERBOARD", tag, owner, clock),
+ m_maincpu(*owner, "maincpu"),
+ m_pic8259(*this, "pic8259"),
+ m_dma8237(*this, "dma8237"),
+ m_pit8253(*this, "pit8253"),
+ m_ppi8255(*this, "ppi8255"),
+ m_speaker(*this, SPEAKER_TAG),
+ m_isabus(*this, "isa"),
+ m_pc_kbdc(*this, "pc_kbdc")
+{
+}
+
+void ibm5160_mb_device::install_device(device_t *dev, offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_device_func rhandler, const char* rhandler_name, write8_device_func whandler, const char *whandler_name)
+{
+ int buswidth = machine().firstcpu->memory().space_config(AS_IO)->m_databus_width;
+ switch(buswidth)
+ {
+ case 8:
+ m_maincpu->memory().space(AS_IO)->install_legacy_readwrite_handler(*dev, start, end, mask, mirror, rhandler, rhandler_name, whandler, whandler_name, 0);
+ break;
+ case 16:
+ m_maincpu->memory().space(AS_IO)->install_legacy_readwrite_handler(*dev, start, end, mask, mirror, rhandler, rhandler_name, whandler, whandler_name,0xffff);
+ break;
+ default:
+ fatalerror("IBM5160_MOTHERBOARD: Bus width %d not supported", buswidth);
+ break;
+ }
+}
+
+void ibm5160_mb_device::install_device_write(device_t *dev, offs_t start, offs_t end, offs_t mask, offs_t mirror, write8_device_func whandler, const char *whandler_name)
+{
+ int buswidth = machine().firstcpu->memory().space_config(AS_IO)->m_databus_width;
+ switch(buswidth)
+ {
+ case 8:
+ m_maincpu->memory().space(AS_IO)->install_legacy_write_handler(*dev, start, end, mask, mirror, whandler, whandler_name,0);
+ break;
+ case 16:
+ m_maincpu->memory().space(AS_IO)->install_legacy_write_handler(*dev, start, end, mask, mirror, whandler, whandler_name, 0xffff);
+ break;
+ default:
+ fatalerror("IBM5160_MOTHERBOARD: Bus width %d not supported", buswidth);
+ break;
+ }
+}
+
+void ibm5160_mb_device::install_device(offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_delegate rhandler, write8_delegate whandler)
+{
+ int buswidth = m_maincpu->memory().space_config(AS_IO)->m_databus_width;
+ switch(buswidth)
+ {
+ case 8:
+ m_maincpu->memory().space(AS_IO)->install_readwrite_handler(start, end, mask, mirror, rhandler, whandler, 0);
+ break;
+ case 16:
+ m_maincpu->memory().space(AS_IO)->install_readwrite_handler(start, end, mask, mirror, rhandler, whandler, 0xffff);
+ break;
+ default:
+ fatalerror("IBM5160_MOTHERBOARD: Bus width %d not supported", buswidth);
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void ibm5160_mb_device::device_start()
+{
+ install_device(0x0000, 0x000f, 0, 0, read8_delegate(FUNC(am9517a_device::read), (am9517a_device*)m_dma8237), write8_delegate(FUNC(am9517a_device::write), (am9517a_device*)m_dma8237) );
+ install_device(m_pic8259, 0x0020, 0x0021, 0, 0, FUNC(pic8259_r), FUNC(pic8259_w) );
+ install_device(m_pit8253, 0x0040, 0x0043, 0, 0, FUNC(pit8253_r), FUNC(pit8253_w) );
+
+ // install_device(m_ppi8255, 0x0060, 0x0063, 0, 0, FUNC(i8255a_r), FUNC(i8255a_w) );
+ int buswidth = machine().firstcpu->memory().space_config(AS_IO)->m_databus_width;
+ switch(buswidth)
+ {
+ case 8:
+ m_maincpu->memory().space(AS_IO)->install_readwrite_handler(0x0060, 0x0063, 0, 0, read8_delegate(FUNC(i8255_device::read), (i8255_device*)m_ppi8255), write8_delegate(FUNC(i8255_device::write), (i8255_device*)m_ppi8255), 0);
+ break;
+ case 16:
+ m_maincpu->memory().space(AS_IO)->install_readwrite_handler(0x0060, 0x0063, 0, 0, read8_delegate(FUNC(i8255_device::read), (i8255_device*)m_ppi8255), write8_delegate(FUNC(i8255_device::write), (i8255_device*)m_ppi8255), 0xffff);
+ break;
+ default:
+ fatalerror("IBM5160_MOTHERBOARD: Bus width %d not supported", buswidth);
+ break;
+ }
+
+ install_device(this, 0x0080, 0x0087, 0, 0, FUNC(pc_page_r), FUNC(pc_page_w) );
+ install_device_write(this, 0x00a0, 0x00a1, 0, 0, FUNC(nmi_enable_w));
+ /* MESS managed RAM */
+ if ( machine().device<ram_device>(RAM_TAG)->pointer() )
+ membank( "bank10" )->set_base( machine().device<ram_device>(RAM_TAG)->pointer() );
+}
+
+IRQ_CALLBACK(ibm5160_mb_device::pc_irq_callback)
+{
+ device_t *pic = device->machine().device("mb:pic8259");
+ return pic8259_acknowledge( pic );
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void ibm5160_mb_device::device_reset()
+{
+ device_set_irq_callback(m_maincpu, pc_irq_callback);
+
+ m_u73_q2 = 0;
+ m_out1 = 2; // initial state of pit output is undefined
+ m_pc_spkrdata = 0;
+ m_pc_input = 0;
+ m_dma_channel = 0;
+ memset(m_dma_offset,0,sizeof(m_dma_offset));
+ m_ppi_portc_switch_high = 0;
+ m_ppi_speaker = 0;
+ m_ppi_keyboard_clear = 0;
+ m_ppi_keyb_clock = 0;
+ m_ppi_portb = 0;
+ m_ppi_clock_signal = 0;
+ m_ppi_data_signal = 0;
+ m_ppi_shift_register = 0;
+ m_ppi_shift_enable = 0;
+ m_nmi_enabled = 0;
+ speaker_level_w( m_speaker, 0 );
+}
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type IBM5150_MOTHERBOARD = &device_creator<ibm5150_mb_device>;
+
+//**************************************************************************
+// DEVICE CONFIGURATION
+//**************************************************************************
+static const cassette_interface ibm5150_cassette_interface =
+{
+ cassette_default_formats,
+ NULL,
+ (cassette_state)(CASSETTE_PLAY | CASSETTE_MOTOR_DISABLED | CASSETTE_SPEAKER_ENABLED),
+ NULL,
+ NULL
+};
+
+static MACHINE_CONFIG_FRAGMENT( ibm5150_mb_config )
+ MCFG_FRAGMENT_ADD(ibm5160_mb_config)
+
+ MCFG_CASSETTE_ADD( CASSETTE_TAG, ibm5150_cassette_interface )
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor ibm5150_mb_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( ibm5150_mb_config );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// ibm5150_mb_device - constructor
+//-------------------------------------------------
+
+ibm5150_mb_device::ibm5150_mb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : ibm5160_mb_device(mconfig, tag, owner, clock),
+ m_cassette(*this, CASSETTE_TAG)
+{
+}
+
+void ibm5150_mb_device::device_start()
+{
+ ibm5160_mb_device::device_start();
+}
+void ibm5150_mb_device::device_reset()
+{
+ ibm5160_mb_device::device_reset();
+}
+
+READ8_MEMBER (ibm5150_mb_device::pc_ppi_porta_r)
+{
+ int data = 0xFF;
+ /* KB port A */
+ if (m_ppi_keyboard_clear)
+ {
+ /* 0 0 - no floppy drives
+ * 1 Not used
+ * 2-3 The number of memory banks on the system board
+ * 4-5 Display mode
+ * 11 = monochrome
+ * 10 - color 80x25
+ * 01 - color 40x25
+ * 6-7 The number of floppy disk drives
+ */
+ data = ioport("DSW0")->read() & 0xF3;
+ switch ( machine().device<ram_device>(RAM_TAG)->size() )
+ {
+ case 16 * 1024:
+ data |= 0x00;
+ break;
+ case 32 * 1024: /* Need to verify if this is correct */
+ data |= 0x04;
+ break;
+ case 48 * 1024: /* Need to verify if this is correct */
+ data |= 0x08;
+ break;
+ default:
+ data |= 0x0C;
+ break;
+ }
+ }
+ else
+ {
+ data = m_ppi_shift_register;
+ }
+ PIO_LOG(1,"PIO_A_r",("$%02x\n", data));
+ return data;
+}
+
+
+READ8_MEMBER ( ibm5150_mb_device::pc_ppi_portc_r )
+{
+ int timer2_output = pit8253_get_output( m_pit8253, 2 );
+ int data=0xff;
+
+ data&=~0x80; // no parity error
+ data&=~0x40; // no error on expansion board
+ /* KB port C: equipment flags */
+ if (m_ppi_portc_switch_high)
+ {
+ /* read hi nibble of SW2 */
+ data = data & 0xf0;
+
+ switch ( machine().device<ram_device>(RAM_TAG)->size() - 64 * 1024 )
+ {
+ case 64 * 1024: data |= 0x00; break;
+ case 128 * 1024: data |= 0x02; break;
+ case 192 * 1024: data |= 0x04; break;
+ case 256 * 1024: data |= 0x06; break;
+ case 320 * 1024: data |= 0x08; break;
+ case 384 * 1024: data |= 0x0A; break;
+ case 448 * 1024: data |= 0x0C; break;
+ case 512 * 1024: data |= 0x0E; break;
+ case 576 * 1024: data |= 0x01; break;
+ case 640 * 1024: data |= 0x03; break;
+ case 704 * 1024: data |= 0x05; break;
+ case 768 * 1024: data |= 0x07; break;
+ case 832 * 1024: data |= 0x09; break;
+ case 896 * 1024: data |= 0x0B; break;
+ case 960 * 1024: data |= 0x0D; break;
+ }
+ if ( machine().device<ram_device>(RAM_TAG)->size() > 960 * 1024 )
+ data |= 0x0D;
+
+ PIO_LOG(1,"PIO_C_r (hi)",("$%02x\n", data));
+ }
+ else
+ {
+ /* read lo nibble of S2 */
+ data = (data & 0xf0) | (ioport("DSW0")->read() & 0x0f);
+ PIO_LOG(1,"PIO_C_r (lo)",("$%02x\n", data));
+ }
+
+ if ( ! ( m_ppi_portb & 0x08 ) )
+ {
+ double tap_val = m_cassette->input();
+
+ if ( tap_val < 0 )
+ {
+ data &= ~0x10;
+ }
+ else
+ {
+ data |= 0x10;
+ }
+ }
+ else
+ {
+ if ( m_ppi_portb & 0x01 )
+ {
+ data = ( data & ~0x10 ) | ( timer2_output ? 0x10 : 0x00 );
+ }
+ }
+ data = ( data & ~0x20 ) | ( timer2_output ? 0x20 : 0x00 );
+
+ return data;
+}
+
+
+WRITE8_MEMBER( ibm5150_mb_device::pc_ppi_portb_w )
+{
+ /* KB controller port B */
+ m_ppi_portb = data;
+ m_ppi_portc_switch_high = data & 0x08;
+ m_ppi_keyboard_clear = data & 0x80;
+ m_ppi_keyb_clock = data & 0x40;
+ pit8253_gate2_w(m_pit8253, BIT(data, 0));
+ pc_speaker_set_spkrdata( data & 0x02 );
+
+ m_cassette->change_state(( data & 0x08 ) ? CASSETTE_MOTOR_DISABLED : CASSETTE_MOTOR_ENABLED,CASSETTE_MASK_MOTOR);
+
+ m_ppi_clock_signal = ( m_ppi_keyb_clock ) ? 1 : 0;
+ m_pc_kbdc->clock_write_from_mb(m_ppi_clock_signal);
+
+
+ /* If PB7 is set clear the shift register and reset the IRQ line */
+ if ( m_ppi_keyboard_clear )
+ {
+ pic8259_ir1_w(m_pic8259, 0);
+ m_ppi_shift_register = 0;
+ m_ppi_shift_enable = 1;
+ }
+}
diff --git a/src/mess/machine/hd63450.c b/src/mess/machine/hd63450.c
new file mode 100644
index 00000000000..b82d7cdc889
--- /dev/null
+++ b/src/mess/machine/hd63450.c
@@ -0,0 +1,488 @@
+/*
+ Hitachi HD63450 DMA Controller
+
+ Largely based on documentation of the Sharp X68000
+*/
+
+#include "hd63450.h"
+
+typedef struct _hd63450_regs hd63450_regs;
+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)
+};
+
+typedef struct _hd63450_t hd63450_t;
+struct _hd63450_t
+{
+ hd63450_regs reg[4];
+ emu_timer* timer[4]; // for timing data reading/writing each channel
+ attotime clock[4];
+ attotime burst_clock[4];
+ int in_progress[4]; // if a channel is in use
+ int transfer_size[4];
+ int halted[4]; // non-zero if a channel has been halted, and can be continued later.
+ const hd63450_intf* intf;
+};
+
+static TIMER_CALLBACK(dma_transfer_timer);
+static void dma_transfer_abort(device_t* device, int channel);
+static void dma_transfer_halt(device_t* device, int channel);
+static void dma_transfer_continue(device_t* device, int channel);
+static void dma_transfer_start(device_t* device, int channel, int dir);
+
+INLINE hd63450_t *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == HD63450);
+
+ return (hd63450_t *)downcast<legacy_device_base *>(device)->token();
+}
+
+static DEVICE_START(hd63450)
+{
+ hd63450_t* dmac = get_safe_token(device);
+ int x;
+
+ dmac->intf = (const hd63450_intf*)device->static_config();
+
+ // Initialise timers and registers
+ for(x=0;x<4;x++)
+ {
+ dmac->timer[x] = device->machine().scheduler().timer_alloc(FUNC(dma_transfer_timer), (void*)device);
+ dmac->reg[x].niv = 0x0f; // defaults?
+ dmac->reg[x].eiv = 0x0f;
+ dmac->clock[x] = dmac->intf->clock[x];
+ dmac->burst_clock[x] = dmac->intf->burst_clock[x];
+ }
+}
+
+int hd63450_read(device_t* device, int offset, UINT16 mem_mask)
+{
+ int channel,reg;
+ hd63450_t* dmac = get_safe_token(device);
+
+ channel = (offset & 0x60) >> 5;
+ reg = offset & 0x1f;
+
+ switch(reg)
+ {
+ case 0x00: // CSR / CER
+ return (dmac->reg[channel].csr << 8) | dmac->reg[channel].cer;
+ case 0x02: // DCR / OCR
+ return (dmac->reg[channel].dcr << 8) | dmac->reg[channel].ocr;
+ case 0x03: // SCR / CCR
+ return (dmac->reg[channel].scr << 8) | dmac->reg[channel].ccr;
+ case 0x05: // MTC
+ return dmac->reg[channel].mtc;
+ case 0x06: // MAR (high)
+ return (dmac->reg[channel].mar & 0xffff0000) >> 16;
+ case 0x07: // MAR (low)
+ return (dmac->reg[channel].mar & 0x0000ffff);
+ case 0x0a: // DAR (high)
+ return (dmac->reg[channel].dar & 0xffff0000) >> 16;
+ case 0x0b: // DAR (low)
+ return (dmac->reg[channel].dar & 0x0000ffff);
+ case 0x0d: // BTC
+ return dmac->reg[channel].btc;
+ case 0x0e: // BAR (high)
+ return (dmac->reg[channel].bar & 0xffff0000) >> 16;
+ case 0x0f: // BAR (low)
+ return (dmac->reg[channel].bar & 0x0000ffff);
+ case 0x12: // NIV
+ return dmac->reg[channel].niv;
+ case 0x13: // EIV
+ return dmac->reg[channel].eiv;
+ case 0x14: // MFC
+ return dmac->reg[channel].mfc;
+ case 0x16: // CPR
+ return dmac->reg[channel].cpr;
+ case 0x18: // DFC
+ return dmac->reg[channel].dfc;
+ case 0x1c: // BFC
+ return dmac->reg[channel].bfc;
+ case 0x1f: // GCR
+ return dmac->reg[channel].gcr;
+ }
+ return 0xff;
+}
+
+void hd63450_write(device_t* device, int offset, int data, UINT16 mem_mask)
+{
+ int channel,reg;
+
+ hd63450_t* dmac = get_safe_token(device);
+
+ channel = (offset & 0x60) >> 5;
+ reg = offset & 0x1f;
+ switch(reg)
+ {
+ case 0x00: // CSR / CER
+ if(ACCESSING_BITS_8_15)
+ {
+// dmac->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)
+ {
+ dmac->reg[channel].dcr = (data & 0xff00) >> 8;
+ logerror("DMA#%i: Device Control write : %02x\n",channel,dmac->reg[channel].dcr);
+ }
+ if(ACCESSING_BITS_0_7)
+ {
+ dmac->reg[channel].ocr = data & 0x00ff;
+ logerror("DMA#%i: Operation Control write : %02x\n",channel,dmac->reg[channel].ocr);
+ }
+ break;
+ case 0x03: // SCR / CCR
+ if(ACCESSING_BITS_8_15)
+ {
+ dmac->reg[channel].scr = (data & 0xff00) >> 8;
+ logerror("DMA#%i: Sequence Control write : %02x\n",channel,dmac->reg[channel].scr);
+ }
+ if(ACCESSING_BITS_0_7)
+ {
+ dmac->reg[channel].ccr = data & 0x00ff;
+ if((data & 0x0080))// && !dmac->intf->dma_read[channel] && !dmac->intf->dma_write[channel])
+ dma_transfer_start(device, channel,0);
+ if(data & 0x0010) // software abort
+ dma_transfer_abort(device,channel);
+ if(data & 0x0020) // halt operation
+ dma_transfer_halt(device,channel);
+ if(data & 0x0040) // continure operation
+ dma_transfer_continue(device,channel);
+ logerror("DMA#%i: Channel Control write : %02x\n",channel,dmac->reg[channel].ccr);
+ }
+ break;
+ case 0x05: // MTC
+ dmac->reg[channel].mtc = data;
+ logerror("DMA#%i: Memory Transfer Counter write : %04x\n",channel,dmac->reg[channel].mtc);
+ break;
+ case 0x06: // MAR (high)
+ dmac->reg[channel].mar = (dmac->reg[channel].mar & 0x0000ffff) | (data << 16);
+ logerror("DMA#%i: Memory Address write : %08lx\n",channel,dmac->reg[channel].mar);
+ break;
+ case 0x07: // MAR (low)
+ dmac->reg[channel].mar = (dmac->reg[channel].mar & 0xffff0000) | (data & 0x0000ffff);
+ logerror("DMA#%i: Memory Address write : %08lx\n",channel,dmac->reg[channel].mar);
+ break;
+ case 0x0a: // DAR (high)
+ dmac->reg[channel].dar = (dmac->reg[channel].dar & 0x0000ffff) | (data << 16);
+ logerror("DMA#%i: Device Address write : %08lx\n",channel,dmac->reg[channel].dar);
+ break;
+ case 0x0b: // DAR (low)
+ dmac->reg[channel].dar = (dmac->reg[channel].dar & 0xffff0000) | (data & 0x0000ffff);
+ logerror("DMA#%i: Device Address write : %08lx\n",channel,dmac->reg[channel].dar);
+ break;
+ case 0x0d: // BTC
+ dmac->reg[channel].btc = data;
+ logerror("DMA#%i: Base Transfer Counter write : %04x\n",channel,dmac->reg[channel].btc);
+ break;
+ case 0x0e: // BAR (high)
+ dmac->reg[channel].bar = (dmac->reg[channel].bar & 0x0000ffff) | (data << 16);
+ logerror("DMA#%i: Base Address write : %08lx\n",channel,dmac->reg[channel].bar);
+ break;
+ case 0x0f: // BAR (low)
+ dmac->reg[channel].bar = (dmac->reg[channel].bar & 0xffff0000) | (data & 0x0000ffff);
+ logerror("DMA#%i: Base Address write : %08lx\n",channel,dmac->reg[channel].bar);
+ break;
+ case 0x12: // NIV
+ dmac->reg[channel].niv = data & 0xff;
+ logerror("DMA#%i: Normal IRQ Vector write : %02x\n",channel,dmac->reg[channel].niv);
+ break;
+ case 0x13: // EIV
+ dmac->reg[channel].eiv = data & 0xff;
+ logerror("DMA#%i: Error IRQ Vector write : %02x\n",channel,dmac->reg[channel].eiv);
+ break;
+ case 0x14: // MFC
+ dmac->reg[channel].mfc = data & 0xff;
+ logerror("DMA#%i: Memory Function Code write : %02x\n",channel,dmac->reg[channel].mfc);
+ break;
+ case 0x16: // CPR
+ dmac->reg[channel].cpr = data & 0xff;
+ logerror("DMA#%i: Channel Priority write : %02x\n",channel,dmac->reg[channel].cpr);
+ break;
+ case 0x18: // DFC
+ dmac->reg[channel].dfc = data & 0xff;
+ logerror("DMA#%i: Device Function Code write : %02x\n",channel,dmac->reg[channel].dfc);
+ break;
+ case 0x1c: // BFC
+ dmac->reg[channel].bfc = data & 0xff;
+ logerror("DMA#%i: Base Function Code write : %02x\n",channel,dmac->reg[channel].bfc);
+ break;
+ case 0x1f:
+ dmac->reg[channel].gcr = data & 0xff;
+ logerror("DMA#%i: General Control write : %02x\n",channel,dmac->reg[channel].gcr);
+ break;
+ }
+}
+
+static void dma_transfer_start(device_t* device, int channel, int dir)
+{
+ address_space *space = device->machine().firstcpu->memory().space(AS_PROGRAM);
+ hd63450_t* dmac = get_safe_token(device);
+ dmac->in_progress[channel] = 1;
+ dmac->reg[channel].csr &= ~0xe0;
+ dmac->reg[channel].csr |= 0x08; // Channel active
+ dmac->reg[channel].csr &= ~0x30; // Reset Error and Normal termination bits
+ if((dmac->reg[channel].ocr & 0x0c) != 0x00) // Array chain or Link array chain
+ {
+ dmac->reg[channel].mar = space->read_word(dmac->reg[channel].bar) << 16;
+ dmac->reg[channel].mar |= space->read_word(dmac->reg[channel].bar+2);
+ dmac->reg[channel].mtc = space->read_word(dmac->reg[channel].bar+4);
+ if(dmac->reg[channel].btc > 0)
+ dmac->reg[channel].btc--;
+ }
+
+ // Burst transfers will halt the CPU until the transfer is complete
+ if((dmac->reg[channel].dcr & 0xc0) == 0x00) // Burst transfer
+ {
+ device_t *cpu = device->machine().device(dmac->intf->cpu_tag);
+ device_set_input_line(cpu, INPUT_LINE_HALT, ASSERT_LINE);
+ dmac->timer[channel]->adjust(attotime::zero, channel, dmac->burst_clock[channel]);
+ }
+ else
+ dmac->timer[channel]->adjust(attotime::from_usec(500), channel, dmac->clock[channel]);
+
+ dmac->transfer_size[channel] = dmac->reg[channel].mtc;
+
+ logerror("DMA: Transfer begins: size=0x%08x\n",dmac->transfer_size[channel]);
+}
+
+void hd63450_set_timer(device_t* device, int channel, attotime tm)
+{
+ hd63450_t* dmac = get_safe_token(device);
+
+ dmac->clock[channel] = tm;
+ if(dmac->in_progress[channel] != 0)
+ dmac->timer[channel]->adjust(attotime::zero, channel, dmac->clock[channel]);
+}
+
+static TIMER_CALLBACK(dma_transfer_timer)
+{
+ hd63450_single_transfer((device_t*)ptr, param);
+}
+
+static void dma_transfer_abort(device_t* device, int channel)
+{
+ hd63450_t* dmac = get_safe_token(device);
+
+ logerror("DMA#%i: Transfer aborted\n",channel);
+ dmac->timer[channel]->adjust(attotime::zero);
+ dmac->in_progress[channel] = 0;
+ dmac->reg[channel].mtc = dmac->transfer_size[channel];
+ dmac->reg[channel].csr |= 0xe0; // channel operation complete, block transfer complete
+ dmac->reg[channel].csr &= ~0x08; // channel no longer active
+}
+
+static void dma_transfer_halt(device_t* device, int channel)
+{
+ hd63450_t* dmac = get_safe_token(device);
+
+ dmac->halted[channel] = 1;
+ dmac->timer[channel]->adjust(attotime::zero);
+}
+
+static void dma_transfer_continue(device_t* device, int channel)
+{
+ hd63450_t* dmac = get_safe_token(device);
+
+ if(dmac->halted[channel] != 0)
+ {
+ dmac->halted[channel] = 0;
+ dmac->timer[channel]->adjust(attotime::zero, channel, dmac->clock[channel]);
+ }
+}
+
+void hd63450_single_transfer(device_t* device, int x)
+{
+ address_space *space = device->machine().firstcpu->memory().space(AS_PROGRAM);
+ int data;
+ int datasize = 1;
+ hd63450_t* dmac = get_safe_token(device);
+
+ if(dmac->in_progress[x] != 0) // DMA in progress in channel x
+ {
+ if(dmac->reg[x].ocr & 0x80) // direction: 1 = device -> memory
+ {
+ if(dmac->intf->dma_read[x])
+ {
+ data = dmac->intf->dma_read[x](device->machine(),dmac->reg[x].mar);
+ if(data == -1)
+ return; // not ready to receive data
+ space->write_byte(dmac->reg[x].mar,data);
+ datasize = 1;
+ }
+ else
+ {
+ switch(dmac->reg[x].ocr & 0x30) // operation size
+ {
+ case 0x00: // 8 bit
+ data = space->read_byte(dmac->reg[x].dar); // read from device address
+ space->write_byte(dmac->reg[x].mar, data); // write to memory address
+ datasize = 1;
+ break;
+ case 0x10: // 16 bit
+ data = space->read_word(dmac->reg[x].dar); // read from device address
+ space->write_word(dmac->reg[x].mar, data); // write to memory address
+ datasize = 2;
+ break;
+ case 0x20: // 32 bit
+ data = space->read_word(dmac->reg[x].dar) << 16; // read from device address
+ data |= space->read_word(dmac->reg[x].dar+2);
+ space->write_word(dmac->reg[x].mar, (data & 0xffff0000) >> 16); // write to memory address
+ space->write_word(dmac->reg[x].mar+2, data & 0x0000ffff);
+ datasize = 4;
+ break;
+ case 0x30: // 8 bit packed (?)
+ data = space->read_byte(dmac->reg[x].dar); // read from device address
+ space->write_byte(dmac->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(dmac->intf->dma_write[x])
+ {
+ data = space->read_byte(dmac->reg[x].mar);
+ dmac->intf->dma_write[x](device->machine(), dmac->reg[x].mar,data);
+ datasize = 1;
+ }
+ else
+ {
+ switch(dmac->reg[x].ocr & 0x30) // operation size
+ {
+ case 0x00: // 8 bit
+ data = space->read_byte(dmac->reg[x].mar); // read from memory address
+ space->write_byte(dmac->reg[x].dar, data); // write to device address
+ datasize = 1;
+ break;
+ case 0x10: // 16 bit
+ data = space->read_word(dmac->reg[x].mar); // read from memory address
+ space->write_word(dmac->reg[x].dar, data); // write to device address
+ datasize = 2;
+ break;
+ case 0x20: // 32 bit
+ data = space->read_word(dmac->reg[x].mar) << 16; // read from memory address
+ data |= space->read_word(dmac->reg[x].mar+2); // read from memory address
+ space->write_word(dmac->reg[x].dar, (data & 0xffff0000) >> 16); // write to device address
+ space->write_word(dmac->reg[x].dar+2, data & 0x0000ffff); // write to device address
+ datasize = 4;
+ break;
+ case 0x30: // 8 bit packed (?)
+ data = space->read_byte(dmac->reg[x].mar); // read from memory address
+ space->write_byte(dmac->reg[x].dar, data); // write to device address
+ datasize = 1;
+ break;
+ }
+ }
+// logerror("DMA#%i: byte transfer %08lx -> %08lx\n",x,dmac->reg[x].mar,dmac->reg[x].dar);
+ }
+
+
+ // decrease memory transfer counter
+ if(dmac->reg[x].mtc > 0)
+ dmac->reg[x].mtc--;
+
+ // handle change of memory and device addresses
+ if((dmac->reg[x].scr & 0x03) == 0x01)
+ dmac->reg[x].dar+=datasize;
+ else if((dmac->reg[x].scr & 0x03) == 0x02)
+ dmac->reg[x].dar-=datasize;
+
+ if((dmac->reg[x].scr & 0x0c) == 0x04)
+ dmac->reg[x].mar+=datasize;
+ else if((dmac->reg[x].scr & 0x0c) == 0x08)
+ dmac->reg[x].mar-=datasize;
+
+ if(dmac->reg[x].mtc <= 0)
+ {
+ // End of transfer
+ logerror("DMA#%i: End of transfer\n",x);
+ if((dmac->reg[x].ocr & 0x0c) != 0 && dmac->reg[x].btc > 0)
+ {
+ dmac->reg[x].btc--;
+ dmac->reg[x].bar+=6;
+ dmac->reg[x].mar = space->read_word(dmac->reg[x].bar) << 16;
+ dmac->reg[x].mar |= space->read_word(dmac->reg[x].bar+2);
+ dmac->reg[x].mtc = space->read_word(dmac->reg[x].bar+4);
+ return;
+ }
+ dmac->timer[x]->adjust(attotime::zero);
+ dmac->in_progress[x] = 0;
+ dmac->reg[x].csr |= 0xe0; // channel operation complete, block transfer complete
+ dmac->reg[x].csr &= ~0x08; // channel no longer active
+
+ // Burst transfer
+ if((dmac->reg[x].dcr & 0xc0) == 0x00)
+ {
+ device_t *cpu = device->machine().device(dmac->intf->cpu_tag);
+ device_set_input_line(cpu, INPUT_LINE_HALT, CLEAR_LINE);
+ }
+
+ if(dmac->intf->dma_end)
+ dmac->intf->dma_end(device->machine(),x,dmac->reg[x].ccr & 0x08);
+ }
+ }
+}
+
+int hd63450_get_vector(device_t* device, int channel)
+{
+ hd63450_t* dmac = get_safe_token(device);
+ return dmac->reg[channel].niv;
+}
+
+int hd63450_get_error_vector(device_t* device, int channel)
+{
+ hd63450_t* dmac = get_safe_token(device);
+ return dmac->reg[channel].eiv;
+}
+
+DEVICE_GET_INFO(hd63450)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(hd63450_t); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(hd63450); break;
+ case DEVINFO_FCT_STOP: /* Nothing */ break;
+ case DEVINFO_FCT_RESET: /*info->reset = DEVICE_RESET_NAME(hd63450);*/ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "Hitachi HD63450"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "DMA Controller"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright the MESS Team"); break;
+ }
+}
+
+READ16_DEVICE_HANDLER(hd63450_r) { return hd63450_read(device,offset,mem_mask); }
+WRITE16_DEVICE_HANDLER(hd63450_w) { hd63450_write(device,offset,data,mem_mask); }
+
+DEFINE_LEGACY_DEVICE(HD63450, hd63450);
diff --git a/src/mess/machine/hd63450.h b/src/mess/machine/hd63450.h
new file mode 100644
index 00000000000..c5fba6a9ad8
--- /dev/null
+++ b/src/mess/machine/hd63450.h
@@ -0,0 +1,34 @@
+/*
+ Hitachi HD63450 DMA Controller
+*/
+
+#include "emu.h"
+
+typedef struct _hd63450_interface hd63450_intf;
+struct _hd63450_interface
+{
+ const char *cpu_tag;
+ attotime clock[4];
+ attotime burst_clock[4];
+ void (*dma_end)(running_machine &machine,int channel,int irq); // called when the DMA transfer ends
+ void (*dma_error)(running_machine &machine,int channel, int irq); // called when a DMA transfer error occurs
+ int (*dma_read[4])(running_machine &machine,int addr); // special read / write handlers for each channel
+ void (*dma_write[4])(running_machine &machine,int addr,int data);
+};
+
+int hd63450_read(device_t* device, int offset, UINT16 mem_mask);
+void hd63450_write(device_t* device,int offset, int data, UINT16 mem_mask);
+void hd63450_single_transfer(device_t* device, int x);
+void hd63450_set_timer(device_t* device, int channel, attotime tm);
+
+int hd63450_get_vector(device_t* device, int channel);
+int hd63450_get_error_vector(device_t* device, int channel);
+
+DECLARE_LEGACY_DEVICE(HD63450, hd63450);
+
+#define MCFG_HD63450_ADD(_tag, _config) \
+ MCFG_DEVICE_ADD(_tag, HD63450, 0) \
+ MCFG_DEVICE_CONFIG(_config)
+
+READ16_DEVICE_HANDLER( hd63450_r );
+WRITE16_DEVICE_HANDLER( hd63450_w );
diff --git a/src/mess/machine/hd64610.c b/src/mess/machine/hd64610.c
new file mode 100644
index 00000000000..cf6278174e2
--- /dev/null
+++ b/src/mess/machine/hd64610.c
@@ -0,0 +1,375 @@
+/**********************************************************************
+
+ 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<hd64610_device>;
+
+
+//**************************************************************************
+// 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_func(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),
+ device_rtc_interface(mconfig, *this),
+ device_nvram_interface(mconfig, *this),
+ m_hline_state(1),
+ m_irq_out(1)
+{
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void hd64610_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const hd64610_interface *intf = reinterpret_cast<const hd64610_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<hd64610_interface *>(this) = *intf;
+ }
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_irq_cb, 0, sizeof(m_out_irq_cb));
+ }
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void hd64610_device::device_start()
+{
+ // resolve callbacks
+ m_out_irq_func.resolve(m_out_irq_cb, *this);
+ m_out_1hz_func.resolve(m_out_1hz_cb, *this);
+
+ // 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_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_func(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/mess/machine/hd64610.h b/src/mess/machine/hd64610.h
new file mode 100644
index 00000000000..97d77815aa9
--- /dev/null
+++ b/src/mess/machine/hd64610.h
@@ -0,0 +1,114 @@
+/**********************************************************************
+
+ 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_ADD(_tag, _clock, _config) \
+ MCFG_DEVICE_ADD((_tag), HD64610, _clock) \
+ MCFG_DEVICE_CONFIG(_config)
+
+
+#define HD64610_INTERFACE(name) \
+ const hd64610_interface (name) =
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> hd64610_interface
+
+struct hd64610_interface
+{
+ devcb_write_line m_out_irq_cb;
+ devcb_write_line m_out_1hz_cb;
+};
+
+
+
+// ======================> hd64610_device
+
+class hd64610_device : public device_t,
+ public device_rtc_interface,
+ public device_nvram_interface,
+ public hd64610_interface
+{
+public:
+ // construction/destruction
+ hd64610_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ 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_config_complete();
+ 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);
+
+ // 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_resolved_write_line m_out_irq_func;
+ devcb_resolved_write_line m_out_1hz_func;
+
+ 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/mess/machine/hec2hrp.c b/src/mess/machine/hec2hrp.c
new file mode 100644
index 00000000000..02a9d195fa0
--- /dev/null
+++ b/src/mess/machine/hec2hrp.c
@@ -0,0 +1,899 @@
+/////////////////////////////////////////////////////////////////////////
+// HEC2HRP.C in machine
+/* Hector 2HR+
+ Victor
+ Hector 2HR
+ Hector HRX
+ Hector MX40c
+ Hector MX80c
+ Hector 1
+ Interact
+
+ 12/05/2009 Skeleton driver - Micko : mmicko@gmail.com
+ 31/06/2009 Video - Robbbert
+
+ 29/10/2009 Update skeleton to functional machine
+ by yo_fr (jj.stac @ aliceadsl.fr)
+
+ => add Keyboard,
+ => add color,
+ => add cassette,
+ => add sn76477 sound and 1bit sound,
+ => add joysticks (stick, pot, fire)
+ => add BR/HR switching
+ => add bank switch for HRX
+ => add device MX80c and bank switching for the ROM
+ 03/01/2010 Update and clean prog by yo_fr (jj.stac @ aliceadsl.fr)
+ => add the port mapping for keyboard
+ 28/09/2010 add the DISK II support by yo_fr (jj.stac @ aliceadsl.fr)
+ => Note that actually the DISK II boot (loading CPM : OK) but do not run (don't run the CPM...).
+ 20/11/2010 : synchronization between uPD765 and Z80 are now OK, CP/M runnig! JJStacino
+ 11/11/2011 : add the minidisque support -3 pouces 1/2 driver- JJStacino (jj.stac @ aliceadsl.fr)
+ 19/02/2012 : few adjustment for the hrp and hr machine - JJStacino
+
+ don't forget to keep some information about these machines, see DChector project : http://dchector.free.fr/ made by DanielCoulom
+ (and thank's to Daniel!) and Yves site : http://hectorvictor.free.fr/ (thank's too Yves!)
+
+ TODO : Add the cartridge function,
+ Adjust the one shot and A/D timing (sn76477)
+*/
+
+#include "emu.h"
+#include "imagedev/cassette.h"
+#include "imagedev/printer.h"
+#include "sound/sn76477.h" /* for sn sound*/
+#include "sound/wave.h" /* for K7 sound*/
+#include "sound/discrete.h" /* for 1 Bit sound*/
+#include "machine/upd765.h" /* for floppy disc controller */
+#include "formats/basicdsk.h"
+
+#include "formats/hect_tap.h"
+#include "includes/hec2hrp.h"
+
+#ifndef DEBUG_TRACE_COM_HECTOR
+//#define DEBUG_TRACE_COM_HECTOR 1
+#endif
+
+static void Mise_A_Jour_Etat(running_machine &machine, int Adresse, int Value );
+static void Update_Sound(address_space *space, UINT8 data);
+
+static cassette_image_device *cassette_device_image(running_machine &machine);
+
+/* machine List
+hec2hrp
+victor
+hec2hr
+hec2hrx
+hec2mdhrx
+hec2mx80
+hec2mx40
+*/
+
+/* Helper function*/
+static int isHectorWithDisc2(running_machine &machine)
+{
+return ((strncmp(machine.system().name , "hec2hrx" , 7)==0) ||
+ (strncmp(machine.system().name , "hec2mx40" , 8)==0) ||
+ (strncmp(machine.system().name , "hec2mx80" , 8)==0));
+}
+
+static int isHectorWithMiniDisc(running_machine &machine)
+{
+return ((strncmp(machine.system().name , "hec2mdhrx", 9)==0));
+}
+
+static int isHectorHR(running_machine &machine)
+{
+return ((strncmp(machine.system().name , "hec2hr" , 6)==0) || //Aviable for hr & hrp
+ (strncmp(machine.system().name , "hec2mdhrx", 9)==0) ||
+ (strncmp(machine.system().name , "victor" , 6)==0) ||
+ (strncmp(machine.system().name , "hec2mx40" , 8)==0) ||
+ (strncmp(machine.system().name , "hec2mx80" , 8)==0));
+}
+
+static int isHectoreXtend(running_machine &machine)
+{
+return ((strncmp(machine.system().name , "hec2mdhrx", 9)==0) ||
+ (strncmp(machine.system().name , "hec2hrx" , 7)==0) ||
+ (strncmp(machine.system().name , "hec2mx40" , 8)==0) ||
+ (strncmp(machine.system().name , "hec2mx80" , 8)==0));
+}
+
+/* Cassette timer*/
+static TIMER_CALLBACK( Callback_CK )
+{
+ hec2hrp_state *state = machine.driver_data<hec2hrp_state>();
+/* To generate the CK signal (K7)*/
+ state->m_CK_signal++;
+}
+
+void hector_minidisc_init(running_machine &machine)
+{
+ device_t *fdc = machine.device("wd179x");
+ //set density
+ wd17xx_dden_w(fdc, 1);// density select => always 1 (0 ?a plante !)
+
+ /* FDC Motor Control - Bit 0/1 defines the state of the FDD 0/1 motor */
+ floppy_mon_w(floppy_get_device(machine, 0), 0); // Moteur floppy A:
+ //floppy_mon_w(floppy_get_device(space->machine(), 1), BIT(data, 7)); // Moteur floppy B:, not implanted on the real machine
+
+ //Set the drive ready !
+ floppy_drive_set_ready_state(floppy_get_device(machine, 0), FLOPPY_DRIVE_READY, 0);// Disc 0 ready !
+
+}
+
+READ8_MEMBER(hec2hrp_state::hector_179x_register_r)
+{
+int data=0;
+device_t *fdc = machine().device("wd179x");
+
+ switch (offset & 0x0ff)
+ {
+ /* minidisc floppy disc interface */
+ case 0x04:
+ data = wd17xx_status_r(fdc, 0);
+ break;
+ case 0x05:
+ data = wd17xx_track_r(fdc, 0);
+ break;
+ case 0x06:
+ data = wd17xx_sector_r(fdc, 0);
+ break;
+ case 0x07:
+ data = wd17xx_data_r(fdc, 0);
+ break;
+ default:
+ break;
+ }
+
+ return data;
+}
+WRITE8_MEMBER(hec2hrp_state::hector_179x_register_w)
+{
+device_t *fdc = machine().device("wd179x");
+switch (offset)
+ {
+ /* minidisc floppy disc interface */
+ case 0x04:
+ wd17xx_command_w(fdc, 0, data);
+ break;
+ case 0x05:
+ wd17xx_track_w(fdc, 0, data);
+ break;
+ case 0x06:
+ wd17xx_sector_w(fdc, 0, data);
+ break;
+ case 0x07:
+ /*write into command register*/
+ wd17xx_data_w(fdc, 0, data);
+ break;
+ case 0x08:
+ /*General purpose port (0x08) for the minidisk I/O */
+ {
+ // Rom page bank switching
+ membank("bank2")->set_entry(BIT(data, 5) ? HECTOR_BANK_BASE : HECTOR_BANK_DISC );
+
+ // Set drive number
+ if (BIT(data, 6)) wd17xx_set_drive(fdc, 0); // Set the correct drive number 0
+ //if (BIT(data, 7)) wd17xx_set_drive(fdc, 1);// Set the correct drive number 1,never here
+
+ // Set side
+ wd17xx_set_side(fdc,BIT(data, 4) ? 1 : 0);// side select
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+WRITE8_MEMBER(hec2hrp_state::hector_switch_bank_w)
+{
+ if (offset==0x00) { /* 0x800 et 0x000=> video page, HR*/
+ if (isHectoreXtend(machine()))
+ membank("bank1")->set_entry(HECTOR_BANK_VIDEO);
+ if (m_flag_clk ==1)
+ {
+ m_flag_clk=0;
+ machine().device("maincpu")->set_unscaled_clock(XTAL_5MHz); /* increase CPU*/
+ }
+ }
+ if (offset==0x04) { /* 0x804 => video page, BR*/
+ m_hector_flag_hr=0;
+ if (isHectoreXtend(machine()))
+ membank("bank1")->set_entry(HECTOR_BANK_VIDEO);
+ if (m_flag_clk ==0)
+ {
+ m_flag_clk=1;
+ machine().device("maincpu")->set_unscaled_clock(XTAL_1_75MHz); /* slowdown CPU*/
+ }
+ }
+ if (offset==0x08) { /* 0x808 => base page, HR*/
+ if (isHectoreXtend(machine()))
+ membank("bank1")->set_entry(HECTOR_BANK_PROG);
+ if (m_flag_clk ==1)
+ {
+ m_flag_clk=0;
+ machine().device("maincpu")->set_unscaled_clock(XTAL_5MHz); /* increase CPU*/
+ }
+
+ }
+ if (offset==0x0c) { /* 0x80c => base page, BR*/
+ m_hector_flag_hr=0;
+ if (isHectoreXtend(machine()))
+ membank("bank1")->set_entry(HECTOR_BANK_PROG);
+ if (m_flag_clk ==0)
+ {
+ m_flag_clk=1;
+ machine().device("maincpu")->set_unscaled_clock(XTAL_1_75MHz); /* slowdown CPU*/
+ }
+ }
+}
+
+WRITE8_MEMBER(hec2hrp_state::hector_keyboard_w)
+{
+ /*nothing to do => read function manage the value*/
+}
+
+READ8_MEMBER(hec2hrp_state::hector_keyboard_r)
+{
+ UINT8 data = 0xff;
+ static const char *const keynames[] = { "KEY0", "KEY1", "KEY2", "KEY3", "KEY4", "KEY5", "KEY6", "KEY7", "KEY8" };
+
+ if (offset ==7) /* Only when joy reading*/
+ {
+ /* Read special key for analog joystick emulation only (button and pot are analog signal!) and the reset */
+ data=ioport(keynames[8])->read();
+
+ if (data & 0x01) /* Reset machine ! (on ESC key)*/
+ {
+ cputag_set_input_line(machine(), "maincpu", INPUT_LINE_RESET, PULSE_LINE);
+ if (isHectorHR(machine())) /* aviable for HR and up */
+ {
+ m_hector_flag_hr=1;
+ if (isHectoreXtend(machine()))
+ {
+ membank("bank1")->set_entry(HECTOR_BANK_PROG);
+ membank("bank2")->set_entry(HECTORMX_BANK_PAGE0);
+ }
+ //RESET DISC II unit
+ if (isHectorWithDisc2(machine()) )
+ hector_disc2_reset(machine());
+
+ /* floppy md master reset */
+ if (isHectorWithMiniDisc(machine()))
+ wd17xx_mr_w(machine().device("wd179x"), 1);
+
+ }
+
+ else /* aviable for BR machines */
+ m_hector_flag_hr=0;
+
+
+ /*Common flag*/
+ m_hector_flag_80c = 0;
+ m_flag_clk = 0;
+ }
+
+ m_actions = 0;
+ if (data & 0x02) /* Fire(0)*/
+ m_actions += 1;
+
+ if (data & 0x04) /* Fire(1)*/
+ m_actions += 2;
+
+ if (data & 0x08) /* Pot(0)+*/
+ m_pot0 += 1;
+ if (m_pot0>128) m_pot0 = 128;
+
+ if (data & 0x10) /* Pot(0)-*/
+ m_pot0 -= 1;
+
+ if (m_pot0>250) m_pot0 = 0;
+
+ if (data & 0x20) /* Pot(1)+*/
+ m_pot1 += 1;
+ if (m_pot1>128) m_pot1 = 128;
+
+ if (data & 0x40) /* Pot(1)-*/
+ m_pot1 -= 1;
+
+ if (m_pot1>250) m_pot1 = 0;
+ }
+
+ /* in all case return the request value*/
+ return ioport(keynames[offset])->read();
+}
+
+WRITE8_MEMBER(hec2hrp_state::hector_sn_2000_w)
+{
+ Mise_A_Jour_Etat(machine(), 0x2000+ offset, data);
+ Update_Sound(&space, data);
+}
+WRITE8_MEMBER(hec2hrp_state::hector_sn_2800_w)
+{
+ Mise_A_Jour_Etat(machine(), 0x2800+ offset, data);
+ Update_Sound(&space, data);
+}
+READ8_MEMBER(hec2hrp_state::hector_cassette_r)
+{
+ double level;
+ UINT8 value=0;
+
+ if ((m_state3000 & 0x38) != 0x38 ) /* Selon Sb choix cassette ou timer (74153)*/
+ {
+ m_Data_K7 = 0x00; /* No cassette => clear bit*/
+ switch (m_state3000 & 0x38 )
+ {
+ case 0x08: value = (m_actions & 1) ? 0x80 : 0; break;
+ case 0x10: value = m_pot0; break;
+ case 0x20: value = (m_actions & 2) ? 0x80 : 0; break;
+ case 0x28: value = m_pot1; break;
+ default: value = 0; break;
+ }
+ }
+ else
+ {
+ if (m_write_cassette == 0)
+ {
+ /* Accee a la cassette*/
+ level = (cassette_device_image(machine())->input());
+
+ /* Travail du 741 en trigger*/
+ if (level < -0.08)
+ m_cassette_bit = 0x00;
+ if (level > +0.08)
+ m_cassette_bit = 0x01;
+ }
+ /* Programme du sn7474 (bascule) : Changement ??tat bit Data K7 ?? chaque front montant de m_cassette_bit*/
+ if ((m_cassette_bit != m_cassette_bit_mem) && (m_cassette_bit !=0))
+ {
+ if (m_Data_K7 == 0x00)
+ m_Data_K7 = 0x80;/* En poids fort*/
+ else
+ m_Data_K7 = 0x00;
+ }
+ value = ( m_CK_signal & 0x7F ) + m_Data_K7;
+ m_cassette_bit_mem = m_cassette_bit; /* Memorisation etat bit cassette*/
+ }
+ return value;
+}
+WRITE8_MEMBER(hec2hrp_state::hector_sn_3000_w)
+{
+ m_state3000 = data & 0xf8; /* except bit 0 to 2*/
+ if ((data & 7) != m_oldstate3000 )
+ {
+ /* Update sn76477 only when necessary!*/
+ Mise_A_Jour_Etat( machine(), 0x3000, data & 7 );
+ Update_Sound(&space, data & 7);
+ }
+ m_oldstate3000 = data & 7;
+}
+
+/* Color Interface */
+WRITE8_MEMBER(hec2hrp_state::hector_color_a_w)
+{
+
+ if (data & 0x40)
+ {
+ /* Bit 6 => motor ON/OFF => for cassette state!*/
+ if (m_write_cassette==0)
+ {
+ cassette_device_image(machine())->change_state(
+ CASSETTE_MOTOR_ENABLED ,
+ CASSETTE_MASK_MOTOR);
+ // cassette_device_image(machine())->set_state((cassette_state)(CASSETTE_PLAY | CASSETTE_SPEAKER_ENABLED | CASSETTE_MOTOR_ENABLED ));
+ }
+ }
+ else
+ { /* stop motor*/
+ cassette_device_image(machine())->set_state(CASSETTE_STOPPED);
+ m_write_cassette=0;
+ m_counter_write =0;
+ }
+ if (((data & 0x80) != (m_oldstate1000 & 0x80)) && ((m_oldstate1000 & 7)==(data & 7)) ) /* Bit7 had change but not the color statement*/
+ {
+ /* Bit 7 => Write bit for cassette!*/
+ m_counter_write +=1;
+
+ if (m_counter_write > 5)
+ {
+ /* Wait several cycle before lauch the record to prevent somes bugs*/
+ m_counter_write = 6;
+ if (m_write_cassette==0)
+ { /* C'est la 1er fois => record*/
+ cassette_device_image(machine())->change_state(
+ CASSETTE_MOTOR_ENABLED ,
+ CASSETTE_MASK_MOTOR);
+ cassette_device_image(machine())->set_state(CASSETTE_RECORD);
+ m_write_cassette=1;
+ }
+ }
+ /* cassette data */
+ cassette_device_image(machine())->output(((data & 0x80) == 0x80) ? -1.0 : +1.0);
+ }
+
+ /* Other bit : color definition*/
+ m_hector_color[0] = data & 0x07 ;
+ m_hector_color[2] = ((data >> 3) & 0x07) | (m_hector_color[2] & 0x40);
+
+ m_oldstate1000=data; /* For next step*/
+}
+
+WRITE8_MEMBER(hec2hrp_state::hector_color_b_w)
+{
+ device_t *discrete = machine().device("discrete");
+ m_hector_color[1] = data & 0x07;
+ m_hector_color[3] = (data >> 3) & 0x07;
+
+ /* Half light on color 2 only on HR machines:*/
+ if (data & 0x40) m_hector_color[2] |= 8; else m_hector_color[2] &= 7;
+
+ /* Play bit*/
+ discrete_sound_w(discrete, NODE_01, (data & 0x80) ? 0:1 );
+}
+
+
+/******************************************************************************
+ Cassette Handling
+******************************************************************************/
+
+static cassette_image_device *cassette_device_image(running_machine &machine)
+{
+ return machine.device<cassette_image_device>(CASSETTE_TAG);
+}
+
+
+/********************************************************************************
+ Port Handling
+********************************************************************************/
+
+/******************* READ PIO 8255 *******************/
+READ8_MEMBER(hec2hrp_state::hector_io_8255_r)
+{
+
+ /* 8255 in mode 0 */
+ UINT8 data =0;
+ UINT8 data_l=0;
+ UINT8 data_h=0;
+
+
+ if ((offset & 0x3) == 0x0) /* Port A */
+ data = m_hector_port_a;
+
+ if ((offset & 0x3) == 0x1) /* Port B */
+ {
+ data = m_hector_port_b;
+ #ifdef DEBUG_TRACE_COM_HECTOR
+ printf("\nLecture data par Hector %x (portB)",data);
+ #endif
+ }
+
+ if ((offset & 0x3) == 0x2) /* Port C */
+ {
+ data_l = (m_hector_port_c_l & 0x0f);
+ data_h = (m_hector_port_c_h & 0xf0);
+
+ if (BIT(m_hector_port_cmd, 0)) /* Quartet inf en entree ?*/
+ data_l = (m_hector_port_c_l & 0x0f); /*no change*/
+
+ if (BIT(m_hector_port_cmd, 3)) /* Quartet sup en entree ?*/
+ {
+ m_hector_port_c_h = (m_hector_port_c_h & 0x0c0); /* Clear bits 4 & 5*/
+
+ if (m_hector_disc2_data_w_ready != 0x00)
+ m_hector_port_c_h = m_hector_port_c_h + 0x010; // PC4 (data write ready from Disc II to Hector)
+
+ if (m_hector_disc2_data_r_ready != 0x00)
+ m_hector_port_c_h = m_hector_port_c_h + 0x020; // PC5 (data read ready from Hector to Disc2)
+
+ m_hector_port_c_h = m_hector_port_c_h & 0x07F; // PC7 (printer busy=0)
+ data_h = m_hector_port_c_h;
+ }
+ data= data_l + data_h;
+ }
+ return data; // Return the value!
+}
+
+/******************* WRITE PIO 8255 *******************/
+
+WRITE8_MEMBER(hec2hrp_state::hector_io_8255_w)
+{
+ /* 8255 in mode 0 */
+ if ((offset & 0x3) == 0x0) /* Port A => to printer or Disc II*/
+ {
+ m_hector_port_a = data;
+ /* Port A => to printer*/
+ /* Caution : The strobe connection to the printer seems not be used
+ So, all what is send to the Disc2 unit will be printed too! */
+
+ if (BIT(m_hector_port_c_l, 0)) { // PC0 (bit X0)= strobe printer !
+ printer_image_device *printer = machine().device<printer_image_device>("printer");
+ printer->output(m_hector_port_a);
+ }
+
+#ifdef DEBUG_TRACE_COM_HECTOR
+ printf("\nEcriture data par Hector %x (dans portA)",data);
+#endif
+ }
+
+ if ((offset & 0x3) == 0x1) /* Port B */
+ m_hector_port_b = data;
+
+
+ if ((offset & 0x3) == 0x2) /* Port C => depending cmd word */
+ {
+ if (!BIT(m_hector_port_cmd, 0)) /* cmd -> Quartet inf en sortie ?*/
+ {
+ m_hector_port_c_l = data & 0x0f;
+ // Utilizing bits port C : PC0 for the printer : strobe!
+ if (BIT(m_hector_port_c_l , 0)) // PC0 (bit X0)= true
+ {
+ /* Port A => to printer*/
+ //printer_output(machine().device("printer"), m_hector_port_a);
+ }
+ // Utilizing bits port C : PC1 // PC2 for the communication with disc2
+ if (!BIT(m_hector_port_c_l , 1)) // PC1 (bit X1)= true
+ {
+ // Lecture effectuee => RAZ memoire donnee m_hector_disc2_data_write dispo
+ m_hector_port_b = m_hector_disc2_data_write; // Mep sur port B si 2eme 74374 existant !
+ m_hector_disc2_data_w_ready = 0x00;
+ #ifdef DEBUG_TRACE_COM_HECTOR
+ printf("\nEcriture port B vers m_hector_disc2_data_write suite a PC1");
+ #endif
+ }
+ if (!BIT(m_hector_port_c_l, 2)) // PC2 (bit X2)= true
+ {
+ m_hector_disc2_data_read = m_hector_port_a; /* mise en place de l'info presente sur le port A */
+ m_hector_disc2_data_r_ready = 0x08; /* memorisation de l'info */
+ #ifdef DEBUG_TRACE_COM_HECTOR
+ printf("\nEcriture port A pour m_hector_disc2_data_read suite a PC2");
+ #endif
+ }
+ }
+ if (!BIT(m_hector_port_cmd, 3)) /* cmd -> Quartet sup en sortie ?*/
+ m_hector_port_c_h = (data & 0xf0);
+ }
+
+ if ((offset & 0x3) == 0x3) /* Port commande */
+ {
+ m_hector_port_cmd = data;
+ }
+}
+/* End of 8255 managing */
+
+
+/******************* Ecriture PIO specifique machine MX40 *******************/
+WRITE8_MEMBER(hec2hrp_state::hector_mx40_io_port_w)
+{
+/* Bank switching on several address */
+ if ((offset &0x0ff) == 0x40) /* Port page 0*/
+ membank("bank2")->set_entry(HECTORMX_BANK_PAGE0);
+ if ((offset &0x0ff) == 0x41) /* Port page 1*/
+ {
+ membank("bank2")->set_entry(HECTORMX_BANK_PAGE1);
+ m_hector_flag_80c=0;
+ }
+ if ((offset &0x0ff) == 0x44) /* Port page 2 => 42 pour MX80*/
+ membank("bank2")->set_entry(HECTORMX_BANK_PAGE2);
+ if ((offset &0x0ff) == 0x49) /* Port screen resolution*/
+ m_hector_flag_80c=0;/* No 80c in 40c !*/
+}
+
+/******************* Ecriture PIO specifique machine MX80 *******************/
+WRITE8_MEMBER(hec2hrp_state::hector_mx80_io_port_w)
+{
+ if ((offset &0x0ff) == 0x40) /* Port page 0*/
+ membank("bank2")->set_entry(HECTORMX_BANK_PAGE0);
+ if ((offset &0x0ff) == 0x41) /* Port page 1*/
+ {
+ membank("bank2")->set_entry(HECTORMX_BANK_PAGE1);
+ m_hector_flag_80c=0;
+ }
+ if ((offset &0x0ff) == 0x42) /* Port page 2 => port different du MX40*/
+ membank("bank2")->set_entry(HECTORMX_BANK_PAGE2);
+ if ((offset &0x0ff) == 0x49) /* Port screen resolution*/
+ m_hector_flag_80c=1;
+}
+
+/********************************************************************************
+ sound managment
+********************************************************************************/
+
+static void Mise_A_Jour_Etat(running_machine &machine, int Adresse, int Value )
+{
+ hec2hrp_state *state = machine.driver_data<hec2hrp_state>();
+/* Adjust value depending on I/O main CPU request*/
+switch(Adresse )
+{
+ case 0x2000:
+ /* Modification AU0 / AU8*/
+ { /* AU0*/
+ state->m_AU[ 0] = ((Value & 0x080 )==0) ? 0 : 1 ;
+ /* AU8 : 0*/
+ state->m_AU[ 8] = ((Value & 0x040 )==0) ? 0 : 1 ;
+ break;
+ }
+ case 0x2001:
+ /* Modification AU1 / AU9*/
+ { /* AU1*/
+ state->m_AU[ 1] = ((Value & 0x080 )==0) ? 0 : 1 ;
+ /* AU9*/
+ state->m_AU[ 9] = ((Value & 0x040 )==0) ? 0 : 1 ;
+ break;
+ }
+ case 0x2002:
+ /* Modification AU2 / AU10*/
+ { /* AU2*/
+ state->m_AU[ 2] = ((Value & 0x080 )==0) ? 0 : 1 ;
+ /* AU10*/
+ state->m_AU[10] = ((Value & 0x040 )==0) ? 0 : 1 ;
+ break;
+ }
+ case 0x2003:
+ /* Modification AU3 / AU11*/
+ { /* AU3*/
+ state->m_AU[ 3] = ((Value & 0x080 )==0) ? 0 : 1 ;
+ /* AU11*/
+ state->m_AU[11] = ((Value & 0x040 )==0) ? 0 : 1 ;
+ break;
+ }
+ case 0x2800:
+ /* Modification AU4 / AU12*/
+ { /* AU4*/
+ state->m_AU[ 4] = ((Value & 0x080 )==0) ? 0 : 1 ;
+ /* AU8*/
+ state->m_AU[12] = ((Value & 0x040 )==0) ? 0 : 1 ;
+ break;
+ }
+ case 0x2801:
+ /* Modification AU5 / AU13*/
+ { /* AU5*/
+ state->m_AU[ 5] = ((Value & 0x080 )==0) ? 0 : 1 ;
+ /* AU13*/
+ state->m_AU[13] = ((Value & 0x040 )==0) ? 0 : 1 ;
+ break;
+ }
+ case 0x2802:
+ { /* Modification AU6 / AU14*/
+ /* AU6*/
+ state->m_AU[ 6] = ((Value & 0x080 )==0) ? 0 : 1 ;
+ /* AU14*/
+ state->m_AU[14] = ((Value & 0x040 )==0) ? 0 : 1 ;
+ break;
+ }
+ case 0x2803:
+ /* Modification AU7 / AU15*/
+ { /* AU7*/
+ state->m_AU[ 7] = ((Value & 0x080 )==0) ? 0 : 1 ;
+ /* AU15*/
+ state->m_AU[15] = ((Value & 0x040 )==0) ? 0 : 1 ;
+ break;
+ }
+ case 0x3000:
+ /* Mixer modification*/
+ {
+ state->m_ValMixer = (Value & 7) ;
+ break;
+ }
+ default: break;
+} /*switch*/
+}
+
+
+static void Init_Value_SN76477_Hector(running_machine &machine)
+{
+ hec2hrp_state *state = machine.driver_data<hec2hrp_state>();
+ /* Remplissage des valeurs de resistance et capacite d'Hector*/
+
+ /* Decay R*/
+ state->m_Pin_Value[7][1] = RES_K(680.0); /*680K */
+ state->m_Pin_Value[7][0] = RES_K(252.325); /* 142.325 (680 // 180KOhm)*/
+
+ /* Capa A/D*/
+ state->m_Pin_Value[8][0] = CAP_U(0.47); /* 0.47uf*/
+ state->m_Pin_Value[8][1] = CAP_U(1.47); /* 1.47*/
+
+ /* ATTACK R*/
+ state->m_Pin_Value[10][1]= RES_K(180.0); /* 180*/
+ state->m_Pin_Value[10][0]= RES_K(32.054); /* 32.054 (180 // 39 KOhm)*/
+
+ /* Version 3 : Ajuste pour les frequences mesurees :
+ // 4 0 SOUND 255 Hz => ajuste a l'oreille
+ // 4 4 SOUND 65 Hz => ajuste a l'oreille
+ // 4 8 SOUND 17 Hz => ajuste a l'oreille
+ // 4 12 SOUND 4,3 Hz => ajuste a l'oreille*/
+ /* SLF C Version 3*/
+ state->m_Pin_Value[21][0]= CAP_U(0.1); /*CAPU(0.1) */
+ state->m_Pin_Value[21][1]= CAP_U(1.1); /*1.1*/
+
+ /*SLF R Version 3*/
+ state->m_Pin_Value[20][1]= RES_K(180); //180 vu
+ state->m_Pin_Value[20][0]= RES_K(37.268); //37.268 (47//180 KOhms)
+
+ /* Capa VCO*/
+ /* Version 3 : Ajust?? pour les frequences mesur??es :
+ // 0 0 SOUND 5,5KHz => 5,1KHz
+ // 0 16 SOUND 1,3KHz => 1,2KHz
+ // 0 32 SOUND 580Hz => 570Hz
+ // 0 48 SOUND 132Hz => 120Hz*/
+ state->m_Pin_Value[17][0] = CAP_N(47.0) ; /*47,0 mesure ok */
+ state->m_Pin_Value[17][1] = CAP_N(580.0) ; /*580 mesure ok */
+ /* R VCO Version 3*/
+ state->m_Pin_Value[18][1] = RES_K(1400.0 );/*1300 mesure ok // au lieu de 1Mohm*/
+ state->m_Pin_Value[18][0] = RES_K( 203.548 );/*223 mesure ok // au lieu de 193.548 (1000 // 240KOhm)*/
+
+ /* VCO Controle*/
+ state->m_Pin_Value[16][0] = 0.0; /* Volts */
+ state->m_Pin_Value[16][1] = 1.41; /* 2 = 10/15eme de 5V*/
+
+ /* Pitch*/
+ state->m_Pin_Value[19][0] = 0.0; /*Volts */
+ state->m_Pin_Value[19][1] = 1.41;
+
+ state->m_Pin_Value[22][0] = 0; /* TOR */
+ state->m_Pin_Value[22][1] = 1;
+
+ /* R OneShot*/
+ state->m_Pin_Value[24][1] = RES_K(100);
+ state->m_Pin_Value[24][0] = RES_K(1000); /*RES_M(1) infini sur Hector car non connectee*/
+
+ /* Capa OneShot*/
+ state->m_Pin_Value[23][0] = 1.0;
+ state->m_Pin_Value[23][1] = 0.0; /* Valeur Bidon sur Hector car mise au 5Volts sans capa*/
+
+ /* Enabled*/
+ state->m_Pin_Value[9][0] = 0;
+ state->m_Pin_Value[9][1] = 1;
+
+ /* Volume*/
+ state->m_Pin_Value[11][0] = 128; /* Rapport 50% et 100% 128*/
+ state->m_Pin_Value[11][1] = 255; /* 255*/
+
+ /* Noise filter*/
+ state->m_Pin_Value[6][0] = CAP_U(0.390); /* 0.390*/
+ state->m_Pin_Value[6][1] = CAP_U(08.60); /* 0.48*/
+
+ /* Valeur corrige par rapport au schema :*/
+ state->m_Pin_Value[5][1] = RES_K(3.30 ) ; /* 330Kohm*/
+ state->m_Pin_Value[5][0] = RES_K(1.76 ) ; /* 76 Kohm*/
+
+ /* Noise pas commande par le bus audio !*/
+ /* Seule la valeur [0] est documentee !*/
+ state->m_Pin_Value[4][0] = RES_K(47) ; /* 47 K ohm*/
+ state->m_Pin_Value[12][0] = RES_K(100); /* 100K ohm*/
+ state->m_Pin_Value[3][0] = 0 ; /* NC*/
+
+ /* Gestion du type d'enveloppe*/
+ state->m_Pin_Value[ 1][0] = 0;
+ state->m_Pin_Value[ 1][1] = 1;
+
+ state->m_Pin_Value[28][0] = 0;
+ state->m_Pin_Value[28][1] = 1;
+
+ /* Initialisation a 0 des pin du SN*/
+ state->m_AU[0]=0;
+ state->m_AU[1]=0;
+ state->m_AU[2]=0;
+ state->m_AU[3]=0;
+ state->m_AU[4]=0;
+ state->m_AU[5]=0;
+ state->m_AU[6]=0;
+ state->m_AU[7]=0;
+ state->m_AU[8]=0;
+ state->m_AU[9]=0;
+ state->m_AU[10]=0;
+ state->m_AU[11]=0;
+ state->m_AU[12]=0;
+ state->m_AU[13]=0;
+ state->m_AU[14]=0;
+ state->m_AU[15]=0;
+ state->m_ValMixer = 0;
+}
+
+static void Update_Sound(address_space *space, UINT8 data)
+{
+ hec2hrp_state *state = space->machine().driver_data<hec2hrp_state>();
+ /* keep device*/
+ device_t *sn76477 = space->machine().device("sn76477");
+
+ /* MIXER*/
+ sn76477_mixer_a_w(sn76477, ((state->m_ValMixer & 0x04)==4) ? 1 : 0);
+ sn76477_mixer_b_w(sn76477, ((state->m_ValMixer & 0x01)==1) ? 1 : 0);
+ sn76477_mixer_c_w(sn76477, ((state->m_ValMixer & 0x02)==2) ? 1 : 0);/* Revu selon mesure electronique sur HRX*/
+
+ /* VCO oscillateur*/
+ if (state->m_AU[12]==1)
+ sn76477_vco_res_w( sn76477, state->m_Pin_Value[18][state->m_AU[10]]/12.0); /* en non AU11*/
+ else
+ sn76477_vco_res_w( sn76477, state->m_Pin_Value[18][state->m_AU[10]]); /* en non AU11*/
+
+ sn76477_vco_cap_w( sn76477, state->m_Pin_Value[17][state->m_AU[2 ]]);
+ sn76477_pitch_voltage_w(sn76477, state->m_Pin_Value[19][state->m_AU[15]]);
+ sn76477_vco_voltage_w( sn76477, state->m_Pin_Value[16][state->m_AU[15]]);
+ sn76477_vco_w( sn76477, state->m_Pin_Value[22][state->m_AU[12]]); /* VCO Select Ext/SLF*/
+
+ /* SLF*/
+ sn76477_slf_res_w( sn76477, state->m_Pin_Value[20][state->m_AU[ 9]]);/*AU10*/
+ sn76477_slf_cap_w( sn76477, state->m_Pin_Value[21][state->m_AU[1 ]]);
+
+ /* One Shot*/
+ sn76477_one_shot_res_w(sn76477, state->m_Pin_Value[24][ 0]); /* NC*/
+ sn76477_one_shot_cap_w(sn76477, state->m_Pin_Value[23][state->m_AU[13]]);
+
+ /* Ampli value*/
+ sn76477_amplitude_res_w(sn76477, state->m_Pin_Value[11][state->m_AU[5]]);
+
+ /* Attack / Decay*/
+ sn76477_attack_res_w(sn76477, state->m_Pin_Value[10][state->m_AU[ 8]]);
+ sn76477_decay_res_w( sn76477, state->m_Pin_Value[7 ][state->m_AU[11]]);/*AU9*/
+ sn76477_attack_decay_cap_w(sn76477, state->m_Pin_Value[8][state->m_AU[0]]);
+
+ /* Filtre*/
+ sn76477_noise_filter_res_w(sn76477, state->m_Pin_Value[5][state->m_AU[4]]);
+ sn76477_noise_filter_cap_w(sn76477, state->m_Pin_Value[6][state->m_AU[3]]);
+
+ /* Clock Extern Noise*/
+ sn76477_noise_clock_res_w(sn76477, state->m_Pin_Value[4][0]); /* fix*/
+ sn76477_feedback_res_w(sn76477, state->m_Pin_Value[12][0]); /*fix*/
+
+ /* Envelope*/
+ sn76477_envelope_1_w(sn76477, state->m_Pin_Value[1 ][state->m_AU[6]]);
+ sn76477_envelope_2_w(sn76477, state->m_Pin_Value[28][state->m_AU[7]]);
+
+ /* En dernier on lance (ou pas !)*/
+ sn76477_enable_w(sn76477, state->m_Pin_Value[9][state->m_AU[14]]);
+}
+
+const sn76477_interface hector_sn76477_interface =
+{
+ RES_K(47), /* 4 noise_res*/
+ RES_K(330), /* 5 filter_res*/
+ CAP_P(390), /* 6 filter_cap*/
+ RES_K(680), /* 7 decay_res*/
+ CAP_U(47), /* 8 attack_decay_cap*/
+ RES_K(180), /* 10 attack_res*/
+ RES_K(33), /* 11 amplitude_res*/
+ RES_K(100), /* 12 feedback_res*/
+ 2, /* 16 vco_voltage*/
+ CAP_N(47) , /* 17 vco_cap*/
+ RES_K(1000), /* 18 vco_res*/
+ 2, /* 19 pitch_voltage*/
+ RES_K(180), /* 20 slf_res*/
+ CAP_U(0.1), /* 21 slf_cap*/
+ CAP_U(1.00001), /* 23 oneshot_cap*/
+ RES_K(10000) /* 24 oneshot_res*/
+};
+
+void hector_reset(running_machine &machine, int hr, int with_D2 )
+{
+ hec2hrp_state *state = machine.driver_data<hec2hrp_state>();
+ // Initialization Hector
+ state->m_hector_flag_hr = hr;
+ state->m_flag_clk = 0;
+ state->m_write_cassette = 0;
+ cputag_set_input_line(machine, "maincpu" , INPUT_LINE_RESET, PULSE_LINE);
+
+ // Initialization Disc II
+ if (with_D2==1)
+
+ {
+ cputag_set_input_line(machine, "disc2cpu", INPUT_LINE_RESET, PULSE_LINE);
+ device_t *fdc = machine.device("upd765");
+ cputag_set_input_line(machine, "disc2cpu", INPUT_LINE_RESET, PULSE_LINE);
+ upd765_reset(fdc, 1);
+ upd765_reset_w(fdc, 1);
+ }
+}
+
+void hector_init(running_machine &machine)
+{
+ hec2hrp_state *state = machine.driver_data<hec2hrp_state>();
+ state->m_pot0 = state->m_pot1 = 0x40;
+
+ /* For Cassette synchro*/
+ state->m_Cassette_timer = machine.scheduler().timer_alloc(FUNC(Callback_CK));
+ state->m_Cassette_timer->adjust(attotime::from_msec(100), 0, attotime::from_usec(64));/* => real synchro scan speed for 15,624Khz*/
+
+ /* Sound sn76477*/
+ Init_Value_SN76477_Hector(machine); /*init R/C value*/
+}
diff --git a/src/mess/machine/hecdisk2.c b/src/mess/machine/hecdisk2.c
new file mode 100644
index 00000000000..7d13a8612cb
--- /dev/null
+++ b/src/mess/machine/hecdisk2.c
@@ -0,0 +1,327 @@
+/*******************************************************/
+/************ HECDISK2.C in machine ******************/
+/*******************************************************/
+
+/* Lecteur de disquette DISK II pour les machines :
+ Hector HRX
+ Hector MX40c
+ Hector MX80c
+
+ JJStacino jj.stacino@aliceadsl.fr
+
+ 15/02/2010 : Start of the disc2 project! JJStacino
+ 26/09/2010 : first sending with bug2 (the first "dir" command finih with a crash of the Z80 disc II proc) JJStacino
+ 01/11/2010 : first time ending boot sequence, probleme on the CP/M lauch JJStacino
+ 20/11/2010 : synchronization between uPD765 and Z80 are now OK, CP/M runnig! JJStacino
+ 28/11/2010 : Found at Bratislava that the disk writing with TRANS X: is NOT WORKING (the exchange Hector=>Disc2 ok)
+*/
+
+#include "emu.h"
+
+#include "sound/sn76477.h" /* for sn sound*/
+#include "sound/wave.h" /* for K7 sound*/
+#include "sound/discrete.h" /* for 1 Bit sound*/
+#include "machine/upd765.h" /* for floppy disc controller */
+#include "formats/hect_dsk.h"
+#include "cpu/z80/z80.h"
+
+#include "includes/hec2hrp.h"
+
+/* Disquette timer*/
+static TIMER_CALLBACK( Callback_DMA_irq );
+static TIMER_CALLBACK( Callback_INT_irq );
+
+/* Callback uPD request */
+//UPD765_DMA_REQUEST( hector_disc2_fdc_dma_irq );
+static WRITE_LINE_DEVICE_HANDLER( disc2_fdc_interrupt );
+static WRITE_LINE_DEVICE_HANDLER( hector_disc2_fdc_dma_irq );
+
+/* How uPD765 works:
+ * First we send at uPD the string of command (p.e. 9 bytes for read starting by 0x46) on port 60h
+ between each byte, check the authorization of the uPD by reading the status register
+ * When the command is finish, the data arrive with DMA interrupt, then:
+ If read: in port 70 to retrieve the data,
+ If write: in port 70 send the data
+ * When all data had been send the uPD launch an INT
+ * The Z80 Disc2 writes in FF12 a flag
+ * if the flag is set, end of DMA function,
+ * At this point the Z80 can read the RESULT in port 61h
+*/
+
+// Define the hardware of the disk
+ const floppy_interface hector_disc2_floppy_interface =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ FLOPPY_STANDARD_5_25_DSHD,
+ LEGACY_FLOPPY_OPTIONS_NAME(hector_disc2),
+ NULL,
+ NULL
+};
+
+/*****************************************************************************/
+/****** Management of the uPD765 for interface with floppy images************/
+/*****************************************************************************/
+/* Hector Disc II uPD765 interface use interrupts and DMA! */
+const upd765_interface hector_disc2_upd765_interface =
+{
+ DEVCB_LINE(disc2_fdc_interrupt),
+ DEVCB_LINE(hector_disc2_fdc_dma_irq),
+ NULL,
+ UPD765_RDY_PIN_NOT_CONNECTED,
+ {FLOPPY_0,FLOPPY_1, NULL, NULL}
+};
+
+/*****************************************************************************/
+/**** Management of the interrupts (NMI and INT)between uPD765 and Z80 ******/
+/*****************************************************************************/
+static void valid_interrupt( running_machine &machine)
+{
+ hec2hrp_state *state = machine.driver_data<hec2hrp_state>();
+ /* Called at each rising state of NMI or RNMI ! */
+
+ /* Take NMI only if RNMI ok*/
+ if ((state->m_hector_disc2_RNMI==1) && (state->m_NMI_current_state==1))
+ {
+ cputag_set_input_line(machine, "disc2cpu", INPUT_LINE_NMI, CLEAR_LINE); // Clear NMI...
+ state->m_DMA_timer->adjust(attotime::from_usec(6) );//a little time to let the Z80 terminate he's previous job !
+ state->m_NMI_current_state=0;
+ }
+}
+
+void hector_disc2_init( running_machine &machine)
+{
+ hec2hrp_state *state = machine.driver_data<hec2hrp_state>();
+ state->m_DMA_timer = machine.scheduler().timer_alloc(FUNC(Callback_DMA_irq));
+ state->m_INT_timer = machine.scheduler().timer_alloc(FUNC(Callback_INT_irq));
+}
+
+static TIMER_CALLBACK( Callback_DMA_irq )
+{
+ hec2hrp_state *state = machine.driver_data<hec2hrp_state>();
+ /* To generate the NMI signal (late) when uPD DMA request*/
+ cputag_set_input_line(machine, "disc2cpu", INPUT_LINE_NMI, ASSERT_LINE); //NMI...
+ state->m_hector_nb_cde =0; // clear the cde length
+}
+
+static TIMER_CALLBACK( Callback_INT_irq )
+{
+ /* To generate the INT signal (late) when uPD DMA request*/
+ cputag_set_input_line(/*device->*/machine, "disc2cpu", INPUT_LINE_IRQ0, ASSERT_LINE);
+}
+
+/* upd765 INT is connected to interrupt of Z80 within a RNMI hardware authorization*/
+static WRITE_LINE_DEVICE_HANDLER( disc2_fdc_interrupt )
+{
+ hec2hrp_state *drvstate = device->machine().driver_data<hec2hrp_state>();
+ cputag_set_input_line(device->machine(), "disc2cpu", INPUT_LINE_IRQ0, CLEAR_LINE);
+ if (state)
+ drvstate->m_INT_timer->adjust(attotime::from_usec(500) );//a little time to let the Z80 terminate he's previous job !
+}
+
+static WRITE_LINE_DEVICE_HANDLER( hector_disc2_fdc_dma_irq )
+{
+ hec2hrp_state *drvstate = device->machine().driver_data<hec2hrp_state>();
+ /* upd765 DRQ is connected to NMI of Z80 within a RNMI hardware authorization*/
+ /* Here the most difficult on this machine :
+ The DMA request come with the uPD765 "soft" immediately,
+ against the true hard uPD765. In the real life, the uPD had
+ to seach for the sector before !
+ So, we had to memorize the signal (the DMA is a pulse)
+ until disc2's Z80 is ready to take the NMI interupt (when
+ he had set the RNMI authorization) ! */
+
+ if (state==1)
+ drvstate->m_NMI_current_state = state;
+ valid_interrupt(device->machine());
+}
+
+// RESET the disc2 Unit !
+void hector_disc2_reset(running_machine &machine)
+{
+ hec2hrp_state *state = machine.driver_data<hec2hrp_state>();
+ // Initialization Disc2 unit
+ cputag_set_input_line(machine, "disc2cpu" , INPUT_LINE_RESET, PULSE_LINE);
+ //switch ON and OFF the reset line uPD
+ upd765_reset_w(machine.device("upd765"), 1);
+ upd765_reset_w(machine.device("upd765"), 0);
+ // Select ROM memory to cold restart
+ state->membank("bank3")->set_entry(DISCII_BANK_ROM);
+
+ // Clear the Hardware's buffers
+ state->m_hector_disc2_data_r_ready=0x0; /* =ff when PC2 = true and data in read buffer (state->m_hector_disc2_data_read) */
+ state->m_hector_disc2_data_w_ready=0x0; /* =ff when Disc 2 Port 40 had send a data in write buffer (state->m_hector_disc2_data_write) */
+ state->m_hector_disc2_data_read=0; /* Data send by Hector to Disc 2 when PC2=true */
+ state->m_hector_disc2_data_write=0; /* Data send by Disc 2 to Hector when Write Port I/O 40 */
+ state->m_hector_disc2_RNMI = 0; /* State of I/O 50 D5 = authorization for INT / NMI */
+ state->m_NMI_current_state=0; /* Clear the DMA active request */
+}
+
+/*****************************************************************************/
+/******************** Port handling of the Z80 Disc II unit *****************/
+/*****************************************************************************/
+READ8_HANDLER( hector_disc2_io00_port_r)
+{
+ hec2hrp_state *state = space->machine().driver_data<hec2hrp_state>();
+ /* Switch Disc 2 to RAM to let full RAM acces */
+ state->membank("bank3")->set_entry(DISCII_BANK_RAM);
+ return 0;
+}
+WRITE8_HANDLER( hector_disc2_io00_port_w)
+{
+ hec2hrp_state *state = space->machine().driver_data<hec2hrp_state>();
+ /* Switch Disc 2 to RAM to let full RAM acces */
+ state->membank("bank3")->set_entry(DISCII_BANK_RAM);
+}
+READ8_HANDLER( hector_disc2_io20_port_r)
+{
+ // You can implemente the 8251 chip communication here !
+ return 0;
+}
+WRITE8_HANDLER( hector_disc2_io20_port_w)
+{
+ // You can implemente the 8251 chip communication here !
+}
+READ8_HANDLER( hector_disc2_io30_port_r)
+{
+ hec2hrp_state *state = space->machine().driver_data<hec2hrp_state>();
+ return state->m_hector_disc2_data_r_ready;
+}
+WRITE8_HANDLER( hector_disc2_io30_port_w)
+{
+ // Nothing here !
+}
+
+READ8_HANDLER( hector_disc2_io40_port_r)
+{
+ hec2hrp_state *state = space->machine().driver_data<hec2hrp_state>();
+ /* Read data send by Hector, by Disc2*/
+ state->m_hector_disc2_data_r_ready = 0x00; /* Clear memory info read ready*/
+ return state->m_hector_disc2_data_read; /* send the data !*/
+}
+
+WRITE8_HANDLER( hector_disc2_io40_port_w) /* Write data send by Disc2, to Hector*/
+{
+ hec2hrp_state *state = space->machine().driver_data<hec2hrp_state>();
+ state->m_hector_disc2_data_write = data; /* Memorization data*/
+ state->m_hector_disc2_data_w_ready = 0x80; /* Memorization data write ready in D7*/
+}
+
+READ8_HANDLER( hector_disc2_io50_port_r) /*Read memory info write ready*/
+{
+ hec2hrp_state *state = space->machine().driver_data<hec2hrp_state>();
+ return state->m_hector_disc2_data_w_ready;
+}
+
+WRITE8_HANDLER( hector_disc2_io50_port_w) /* I/O Port to the stuff of Disc2*/
+{
+ hec2hrp_state *state = space->machine().driver_data<hec2hrp_state>();
+ device_t *fdc = space->machine().device("upd765");
+
+ /* FDC Motor Control - Bit 0/1 defines the state of the FDD 0/1 motor */
+ floppy_mon_w(floppy_get_device(space->machine(), 0), BIT(data, 0)); // Moteur floppy A:
+ floppy_mon_w(floppy_get_device(space->machine(), 1), BIT(data, 1)); // Moteur floppy B:
+ floppy_drive_set_ready_state(floppy_get_device(space->machine(), 0), FLOPPY_DRIVE_READY,!BIT(data, 0));
+ floppy_drive_set_ready_state(floppy_get_device(space->machine(), 1), FLOPPY_DRIVE_READY,!BIT(data, 1));
+
+ /* Write bit TC uPD765 on D4 of port I/O 50 */
+ upd765_tc_w(fdc, BIT(data, 4)); // Seems not used...
+
+
+ /* Authorization interrupt and NMI with RNMI signal*/
+ state->m_hector_disc2_RNMI = BIT(data, 5);
+
+ /* if RNMI is OK, try to lauch an NMI*/
+ if (state->m_hector_disc2_RNMI)
+ valid_interrupt(space->machine());
+}
+
+//Here we must take the exchange with uPD against AM_DEVREADWRITE
+// Because we had to add D6 = 1 when write is done with 0x28 in ST0 back
+
+// AM_RANGE(0x061,0x061) AM_DEVREADWRITE("upd765",upd765_data_r,upd765_data_w)
+READ8_HANDLER( hector_disc2_io61_port_r)
+{
+ hec2hrp_state *state = space->machine().driver_data<hec2hrp_state>();
+ UINT8 data;
+ device_t *fdc = space->machine().device("upd765");
+ data = upd765_data_r(fdc,0); //Get the result
+
+// if ST0 == 0x28 (drive A:) or 0x29 (drive B:) => add 0x40
+// and correct the ST1 and ST2 (patch)
+ if ((state->m_hector_flag_result == 3) & ((data==0x28) | (data==0x29)) ) // are we in the problem?
+ {
+ data=data + 0x40;
+ state->m_hector_flag_result--;
+ }
+ // Nothing to do in over case!
+ if (state->m_hector_flag_result == 3)
+ state->m_hector_flag_result = 0;
+
+ if ((state->m_hector_flag_result == 2) & (data==0x00) )
+ {
+ data=/*data +*/ 0x04;
+ state->m_hector_flag_result--;
+ }
+ if ((state->m_hector_flag_result == 1) & (data==0x00) )
+ {
+ data=/*data + */0x10;
+ state->m_hector_flag_result=0; // End !
+ }
+ #ifdef hector_trace
+ if (state->m_print==1)
+ printf(" _%x",data);
+ #endif
+ state->m_hector_nb_cde =0; // clear the cde length
+ return data;
+}
+WRITE8_HANDLER( hector_disc2_io61_port_w)
+{
+ hec2hrp_state *state = space->machine().driver_data<hec2hrp_state>();
+ /* Data useful to patch the RESULT in case of write command */
+ state->m_hector_cmd[9]=state->m_hector_cmd[8]; //hector_cmd_8 = Cde number when state->m_hector_nb_cde = 9
+ state->m_hector_cmd[8]=state->m_hector_cmd[7]; //hector_cmd_7 = Drive
+ state->m_hector_cmd[7]=state->m_hector_cmd[6]; //hector_cmd_6 = C
+ state->m_hector_cmd[6]=state->m_hector_cmd[5]; //hector_cmd_5 = H
+ state->m_hector_cmd[5]=state->m_hector_cmd[4]; //hector_cmd_4 = R
+ state->m_hector_cmd[4]=state->m_hector_cmd[3]; //hector_cmd_3 = N
+ state->m_hector_cmd[3]=state->m_hector_cmd[2]; //hector_cmd_2 = EOT
+ state->m_hector_cmd[2]=state->m_hector_cmd[1]; //hector_cmd_1 = GPL
+ state->m_hector_cmd[1]=state->m_hector_cmd[0]; //hector_cmd_0 = DTL
+ state->m_hector_cmd[0] = data;
+ // Increase the length cde!
+ state->m_hector_nb_cde++;
+
+ // check if current commande is write cmde.
+ if (((state->m_hector_cmd[8] & 0x1f)== 0x05) & (state->m_hector_nb_cde==9) ) /*Detect wrtie commande*/
+ state->m_hector_flag_result = 3; // here we are!
+#ifdef hector_trace
+ if (state->m_hector_nb_cde==6 ) /*Detect 1 octet command*/
+ {
+ printf("\n commande = %x, %x, %x, %x, %x, %x Result = ", state->m_hector_cmd[5], state->m_hector_cmd[4], state->m_hector_cmd[3], state->m_hector_cmd[2], state->m_hector_cmd[1], data );
+ state->m_print=1;
+ }
+ else
+ state->m_print=0;
+#endif
+
+ device_t *fdc = space->machine().device("upd765");
+ upd765_data_w(fdc,0, data);
+}
+
+// AM_RANGE(0x070,0x07f) AM_DEVREADWRITE("upd765",upd765_dack_r,upd765_dack_w)
+READ8_HANDLER( hector_disc2_io70_port_r) // Gestion du DMA
+{
+ UINT8 data;
+ device_t *fdc = space->machine().device("upd765");
+ data = upd765_dack_r(fdc,0);
+ return data;
+}
+WRITE8_HANDLER( hector_disc2_io70_port_w)
+{
+ device_t *fdc = space->machine().device("upd765");
+ upd765_dack_w(fdc,0, data);
+}
diff --git a/src/mess/machine/hp48.c b/src/mess/machine/hp48.c
new file mode 100644
index 00000000000..371002ea203
--- /dev/null
+++ b/src/mess/machine/hp48.c
@@ -0,0 +1,1238 @@
+/**********************************************************************
+
+ Copyright (C) Antoine Mine' 2008
+
+ Hewlett Packard HP48 S/SX & G/GX/G+
+
+**********************************************************************/
+
+#include "emu.h"
+#include "sound/dac.h"
+#include "cpu/saturn/saturn.h"
+
+#include "machine/nvram.h"
+
+#include "includes/hp48.h"
+
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+
+#define VERBOSE 0
+#define VERBOSE_SERIAL 0
+
+#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
+#define LOG_SERIAL(x) do { if (VERBOSE_SERIAL) logerror x; } while (0)
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* state field in hp48_module */
+#define HP48_MODULE_UNCONFIGURED 0
+#define HP48_MODULE_MASK_KNOWN 1
+#define HP48_MODULE_CONFIGURED 2
+
+/***************************************************************************
+ GLOBAL VARIABLES & CONSTANTS
+***************************************************************************/
+
+/* current HP48 model */
+
+#define HP48_G_SERIES ((state->m_model==HP48_G) || (state->m_model==HP48_GX) || (state->m_model==HP48_GP))
+#define HP48_S_SERIES ((state->m_model==HP48_S) || (state->m_model==HP48_SX))
+#define HP48_X_SERIES ((state->m_model==HP48_SX) || (state->m_model==HP48_GX))
+#define HP48_GX_MODEL ((state->m_model==HP48_GX) || (state->m_model==HP48_GP))
+
+/* OUT register from SATURN (actually 12-bit) */
+
+/* keyboard interrupt */
+
+/* from highest to lowest priority: HDW, NCE2, CE1, CE2, NCE3, NCE1 */
+
+static const char *const hp48_module_names[6] =
+{ "HDW (I/O)", "NCE2 (RAM)", "CE1", "CE2", "NCE3", "NCE1 (ROM)" };
+
+/* values returned by C=ID */
+static const UINT8 hp48_module_mask_id[6] = { 0x00, 0x03, 0x05, 0x07, 0x01, 0x00 };
+static const UINT8 hp48_module_addr_id[6] = { 0x19, 0xf4, 0xf6, 0xf8, 0xf2, 0x00 };
+
+/* RAM/ROM extensions, GX/SX only (each UINT8 stores one nibble)
+ port1: SX/GX: 32/128 KB
+ port2: SX:32/128KB, GX:128/512/4096 KB
+ */
+
+
+/* CRC state */
+
+/* timers state */
+
+#ifdef CHARDEV
+#include "devices/chardev.h"
+#endif
+
+
+/***************************************************************************
+ FUNCTIONS
+***************************************************************************/
+
+static void hp48_apply_modules(hp48_state *state);
+
+
+static void hp48_pulse_irq( running_machine &machine, int irq_line)
+{
+ cputag_set_input_line(machine, "maincpu", irq_line, ASSERT_LINE );
+ cputag_set_input_line(machine, "maincpu", irq_line, CLEAR_LINE );
+}
+
+
+/* ---------------- serial --------------------- */
+
+#define RS232_DELAY attotime::from_usec( 300 )
+
+/* end of receive event */
+static TIMER_CALLBACK( hp48_rs232_byte_recv_cb )
+{
+ hp48_state *state = machine.driver_data<hp48_state>();
+ LOG_SERIAL(( "%f hp48_rs232_byte_recv_cb: end of receive, data=%02x\n",
+ machine.time().as_double(), param ));
+
+ state->m_io[0x14] = param & 0xf; /* receive zone */
+ state->m_io[0x15] = param >> 4;
+ state->m_io[0x11] &= ~2; /* clear byte receiving */
+ state->m_io[0x11] |= 1; /* set byte received */
+
+ /* interrupt */
+ if ( state->m_io[0x10] & 2 )
+ {
+ hp48_pulse_irq( machine, SATURN_IRQ_LINE );
+ }
+}
+
+/* outside world initiates a receive event */
+void hp48_rs232_start_recv_byte( running_machine &machine, UINT8 data )
+{
+ hp48_state *state = machine.driver_data<hp48_state>();
+ LOG_SERIAL(( "%f hp48_rs232_start_recv_byte: start receiving, data=%02x\n",
+ machine.time().as_double(), data ));
+
+ state->m_io[0x11] |= 2; /* set byte receiving */
+
+ /* interrupt */
+ if ( state->m_io[0x10] & 1 )
+ {
+ hp48_pulse_irq( machine, SATURN_IRQ_LINE );
+ }
+
+ /* schedule end of reception */
+ machine.scheduler().timer_set( RS232_DELAY, FUNC(hp48_rs232_byte_recv_cb), data);
+}
+
+
+/* end of send event */
+static TIMER_CALLBACK( hp48_rs232_byte_sent_cb )
+{
+ hp48_state *state = machine.driver_data<hp48_state>();
+ //device_image_interface *xmodem = dynamic_cast<device_image_interface *>(machine.device("rs232_x"));
+ //device_image_interface *kermit = dynamic_cast<device_image_interface *>(machine.device("rs232_k"));
+
+ LOG_SERIAL(( "%f hp48_rs232_byte_sent_cb: end of send, data=%02x\n",
+ machine.time().as_double(), param ));
+
+ state->m_io[0x12] &= ~3; /* clear byte sending and buffer full */
+
+ /* interrupt */
+ if ( state->m_io[0x10] & 4 )
+ {
+ hp48_pulse_irq( machine, SATURN_IRQ_LINE );
+ }
+
+ /* protocol action */
+ //if ( xmodem && xmodem->exists() ) xmodem_receive_byte( &xmodem->device(), param );
+ //else if ( kermit && kermit->exists() ) kermit_receive_byte( &kermit->device(), param );
+//#ifdef CHARDEV
+// else chardev_out( state->m_chardev, param );
+//#endif
+}
+
+/* CPU initiates a send event */
+static void hp48_rs232_send_byte( running_machine &machine )
+{
+ hp48_state *state = machine.driver_data<hp48_state>();
+ UINT8 data = HP48_IO_8(0x16); /* byte to send */
+
+ LOG_SERIAL(( "%05x %f hp48_rs232_send_byte: start sending, data=%02x\n",
+ cpu_get_previouspc(machine.device("maincpu")), machine.time().as_double(), data ));
+
+ /* set byte sending and send buffer full */
+ state->m_io[0x12] |= 3;
+
+ /* schedule transmission */
+ machine.scheduler().timer_set( RS232_DELAY, FUNC(hp48_rs232_byte_sent_cb), data);
+}
+
+
+#ifdef CHARDEV
+
+static TIMER_CALLBACK( hp48_chardev_byte_recv_cb )
+{
+ hp48_state *state = machine.driver_data<hp48_state>();
+ UINT8 data = chardev_in( state->m_chardev );
+
+ LOG_SERIAL(( "%f hp48_chardev_byte_recv_cb: end of receive, data=%02x\n",
+ machine.time().as_double(), data ));
+
+ state->m_io[0x14] = data & 0xf; /* receive zone */
+ state->m_io[0x15] = data >> 4;
+ state->m_io[0x11] &= ~2; /* clear byte receiving */
+ state->m_io[0x11] |= 1; /* set byte received */
+
+ /* interrupt */
+ if ( state->m_io[0x10] & 2 )
+ {
+ hp48_pulse_irq( machine, SATURN_IRQ_LINE );
+ }
+}
+
+static void hp48_chardev_start_recv_byte( running_machine &machine, chardev_err status )
+{
+ hp48_state *state = machine.driver_data<hp48_state>();
+ if ( status != CHARDEV_OK ) return;
+
+ LOG_SERIAL(( "%f hp48_chardev_start_recv_byte: start receiving\n",
+ machine.time().as_double() ));
+
+ state->m_io[0x11] |= 2; /* set byte receiving */
+
+ /* interrupt */
+ if ( state->m_io[0x10] & 1 )
+ {
+ hp48_pulse_irq( machine, SATURN_IRQ_LINE );
+ }
+
+ /* schedule end of reception */
+ machine.scheduler().timer_set( RS232_DELAY, FUNC(hp48_chardev_byte_recv_cb));
+}
+
+static void hp48_chardev_ready_to_send( running_machine &machine )
+{
+ hp48_state *state = machine.driver_data<hp48_state>();
+ state->m_io[0x12] &= ~3;
+
+ /* interrupt */
+ if ( state->m_io[0x10] & 4 )
+ {
+ hp48_pulse_irq( machine, SATURN_IRQ_LINE );
+ }
+}
+
+static const chardev_interface hp48_chardev_iface =
+{ hp48_chardev_start_recv_byte, hp48_chardev_ready_to_send };
+
+#endif
+
+
+/* ------ Saturn's IN / OUT registers ---------- */
+
+
+/* CPU sets OUT register (keyboard + beeper) */
+void hp48_reg_out( device_t *device, int out )
+{
+ hp48_state *state = device->machine().driver_data<hp48_state>();
+ LOG(( "%05x %f hp48_reg_out: %03x\n",
+ cpu_get_previouspc(device->machine().device("maincpu")), device->machine().time().as_double(), out ));
+
+ /* bits 0-8: keyboard lines */
+ state->m_out = out & 0x1ff;
+
+ /* bits 9-10: unused */
+
+ /* bit 11: beeper */
+ device->machine().device<dac_device>("dac")->write_unsigned8((out & 0x800) ? 0x80 : 00 );
+}
+
+static int hp48_get_in( running_machine &machine )
+{
+ hp48_state *state = machine.driver_data<hp48_state>();
+ int in = 0;
+
+ /* regular keys */
+ if ( (state->m_out >> 0) & 1 ) in |= machine.root_device().ioport( "LINE0" )->read();
+ if ( (state->m_out >> 1) & 1 ) in |= machine.root_device().ioport( "LINE1" )->read();
+ if ( (state->m_out >> 2) & 1 ) in |= machine.root_device().ioport( "LINE2" )->read();
+ if ( (state->m_out >> 3) & 1 ) in |= machine.root_device().ioport( "LINE3" )->read();
+ if ( (state->m_out >> 4) & 1 ) in |= machine.root_device().ioport( "LINE4" )->read();
+ if ( (state->m_out >> 5) & 1 ) in |= machine.root_device().ioport( "LINE5" )->read();
+ if ( (state->m_out >> 6) & 1 ) in |= machine.root_device().ioport( "LINE6" )->read();
+ if ( (state->m_out >> 7) & 1 ) in |= machine.root_device().ioport( "LINE7" )->read();
+ if ( (state->m_out >> 8) & 1 ) in |= machine.root_device().ioport( "LINE8" )->read();
+
+ /* on key */
+ in |= machine.root_device().ioport( "ON" )->read();
+
+ return in;
+}
+
+/* CPU reads IN register (keyboard) */
+int hp48_reg_in( device_t *device )
+{
+ int in = hp48_get_in(device->machine());
+ LOG(( "%05x %f hp48_reg_in: %04x\n",
+ cpu_get_previouspc(device->machine().device("maincpu")), device->machine().time().as_double(), in ));
+ return in;
+}
+
+/* key detect */
+static void hp48_update_kdn( running_machine &machine )
+{
+ hp48_state *state = machine.driver_data<hp48_state>();
+ int in = hp48_get_in( machine );
+
+ /* interrupt on raising edge */
+ if ( in && !state->m_kdn )
+ {
+ LOG(( "%f hp48_update_kdn: interrupt\n", machine.time().as_double() ));
+ state->m_io[0x19] |= 8; /* service request */
+ hp48_pulse_irq( machine, SATURN_WAKEUP_LINE );
+ hp48_pulse_irq( machine, SATURN_IRQ_LINE );
+ }
+
+ state->m_kdn = (in!=0);
+}
+
+/* periodic keyboard polling, generates an interrupt */
+static TIMER_CALLBACK( hp48_kbd_cb )
+{
+ hp48_state *state = machine.driver_data<hp48_state>();
+ /* NMI for ON key */
+ if ( machine.root_device().ioport( "ON" )->read() )
+ {
+ LOG(( "%f hp48_kbd_cb: keyboard interrupt, on key\n",
+ machine.time().as_double() ));
+ state->m_io[0x19] |= 8; /* set service request */
+ hp48_pulse_irq( machine, SATURN_WAKEUP_LINE );
+ hp48_pulse_irq( machine, SATURN_NMI_LINE );
+ return;
+ }
+
+ /* regular keys */
+ hp48_update_kdn( machine );
+}
+
+/* RSI opcode */
+void hp48_rsi( device_t *device )
+{
+ hp48_state *state = device->machine().driver_data<hp48_state>();
+ LOG(( "%05x %f hp48_rsi\n", cpu_get_previouspc(device->machine().device("maincpu")), device->machine().time().as_double() ));
+
+ /* enables interrupts on key repeat
+ (normally, there is only one interrupt, when the key is pressed)
+ */
+ state->m_kdn = 0;
+}
+
+
+/* ------------- annonciators ------------ */
+
+static void hp48_update_annunciators(hp48_state *state)
+{
+ /* bit 0: left shift
+ bit 1: right shift
+ bit 2: alpha
+ bit 3: alert
+ bit 4: busy
+ bit 5: transmit
+ bit 7: master enable
+ */
+ int markers = HP48_IO_8(0xb);
+ output_set_value( "lshift0", (markers & 0x81) == 0x81 );
+ output_set_value( "rshift0", (markers & 0x82) == 0x82 );
+ output_set_value( "alpha0", (markers & 0x84) == 0x84 );
+ output_set_value( "alert0", (markers & 0x88) == 0x88 );
+ output_set_value( "busy0", (markers & 0x90) == 0x90 );
+ output_set_value( "transmit0", (markers & 0xb0) == 0xb0 );
+}
+
+
+/* ------------- I/O registers ----------- */
+
+/* Some part of the I/O registers are simple r/w registers. We store them in hp48_io.
+ Special cases are registers that:
+ - have a different meaning on read and write
+ - perform some action on read / write
+ */
+
+static WRITE8_HANDLER ( hp48_io_w )
+{
+ hp48_state *state = space->machine().driver_data<hp48_state>();
+ LOG(( "%05x %f hp48_io_w: off=%02x data=%x\n",
+ cpu_get_previouspc(&space->device()), space->machine().time().as_double(), offset, data ));
+
+ switch( offset )
+ {
+
+ /* CRC register */
+ case 0x04: state->m_crc = (state->m_crc & 0xfff0) | data; break;
+ case 0x05: state->m_crc = (state->m_crc & 0xff0f) | (data << 4); break;
+ case 0x06: state->m_crc = (state->m_crc & 0xf0ff) | (data << 8); break;
+ case 0x07: state->m_crc = (state->m_crc & 0x0fff) | (data << 12); break;
+
+ /* annunciators */
+ case 0x0b:
+ case 0x0c:
+ state->m_io[offset] = data;
+ hp48_update_annunciators(state);
+ break;
+
+ /* cntrl ROM */
+ case 0x29:
+ {
+ int old_cntrl = state->m_io[offset] & 8;
+ state->m_io[offset] = data;
+ if ( old_cntrl != (data & 8) )
+ {
+ hp48_apply_modules(state);
+ }
+ break;
+ }
+
+ /* timers */
+ case 0x37: state->m_timer1 = data; break;
+ case 0x38: state->m_timer2 = (state->m_timer2 & 0xfffffff0) | data; break;
+ case 0x39: state->m_timer2 = (state->m_timer2 & 0xffffff0f) | (data << 4); break;
+ case 0x3a: state->m_timer2 = (state->m_timer2 & 0xfffff0ff) | (data << 8); break;
+ case 0x3b: state->m_timer2 = (state->m_timer2 & 0xffff0fff) | (data << 12); break;
+ case 0x3c: state->m_timer2 = (state->m_timer2 & 0xfff0ffff) | (data << 16); break;
+ case 0x3d: state->m_timer2 = (state->m_timer2 & 0xff0fffff) | (data << 20); break;
+ case 0x3e: state->m_timer2 = (state->m_timer2 & 0xf0ffffff) | (data << 24); break;
+ case 0x3f: state->m_timer2 = (state->m_timer2 & 0x0fffffff) | (data << 28); break;
+
+ /* cards */
+ case 0x0e:
+ LOG(( "%05x: card control write %02x\n", cpu_get_previouspc(&space->device()), data ));
+
+ /* bit 0: software interrupt */
+ if ( data & 1 )
+ {
+ LOG(( "%f hp48_io_w: software interrupt requested\n",
+ space->machine().time().as_double() ));
+ hp48_pulse_irq( space->machine(), SATURN_IRQ_LINE );
+ data &= ~1;
+ }
+
+ /* XXX not implemented
+ bit 1: card test?
+ */
+
+ state->m_io[0x0e] = data;
+ break;
+
+ case 0x0f:
+ LOG(( "%05x: card info write %02x\n", cpu_get_previouspc(&space->device()), data ));
+ state->m_io[0x0f] = data;
+ break;
+
+ /* serial */
+ case 0x13:
+ state->m_io[0x11] &= ~4; /* clear error status */
+ break;
+ case 0x16:
+ /* first nibble of sent data */
+ state->m_io[offset] = data;
+ break;
+ case 0x17:
+ /* second nibble of sent data */
+ state->m_io[offset] = data;
+ hp48_rs232_send_byte(space->machine());
+ break;
+
+ /* XXX not implemented:
+
+ - 0x0d: RS232c speed:
+ bits 0-2: speed
+ 000 = 1200 bauds
+ 010 = 2400 bauds
+ 100 = 4800 bauds
+ 110 = 9600 bauds
+ bit 3: ?
+
+ - 0x1a: I/R input
+ bit 0: irq
+ bit 1: irq enable
+ bit 2: 1=RS232c mode 0=direct mode
+ bit 3: receiving
+
+ - 0x1c: I/R output control
+ bit 0: buffer full
+ bit 1: transmitting
+ bit 2: irq enable on buffer empty
+ bit 3: led on (direct mode)
+
+ - 0x1d: I/R output buffer
+ */
+
+ default: state->m_io[offset] = data;
+ }
+
+}
+
+
+static READ8_HANDLER ( hp48_io_r )
+{
+ hp48_state *state = space->machine().driver_data<hp48_state>();
+ UINT8 data = 0;
+
+ switch( offset )
+ {
+
+ /* CRC register */
+ case 0x04: data = state->m_crc & 0xf; break;
+ case 0x05: data = (state->m_crc >> 4) & 0xf; break;
+ case 0x06: data = (state->m_crc >> 8) & 0xf; break;
+ case 0x07: data = (state->m_crc >> 12) & 0xf; break;
+
+ /* battery test */
+ case 0x08:
+ data = 0;
+ if ( state->m_io[0x9] & 8 ) /* test enable */
+ {
+ /* XXX not implemented:
+ bit 3: battery in port 2
+ bit 2: battery in port 1
+ */
+ switch ( state->ioport( "BATTERY" )->read() )
+ {
+ case 1: data = 2; break; /* low */
+ case 2: data = 3; break; /* low | critical */
+ }
+ }
+ break;
+
+ /* remaining lines in main bitmap */
+ case 0x28:
+ case 0x29:
+ {
+ int last_line = HP48_IO_8(0x28) & 0x3f; /* last line of main bitmap before menu */
+ int cur_line = space->machine().primary_screen->vpos();
+ if ( last_line <= 1 ) last_line = 0x3f;
+ data = ( cur_line >= 0 && cur_line <= last_line ) ? last_line - cur_line : 0;
+ if ( offset == 0x29 )
+ {
+ data >>= 4;
+ data |= HP48_IO_4(0x29) & 0xc;
+ }
+ else
+ {
+ data &= 0xf;
+ }
+ break;
+ }
+
+ /* timers */
+ case 0x37: data = state->m_timer1; break;
+ case 0x38: data = state->m_timer2 & 0xf; break;
+ case 0x39: data = (state->m_timer2 >> 4) & 0xf; break;
+ case 0x3a: data = (state->m_timer2 >> 8) & 0xf; break;
+ case 0x3b: data = (state->m_timer2 >> 12) & 0xf; break;
+ case 0x3c: data = (state->m_timer2 >> 16) & 0xf; break;
+ case 0x3d: data = (state->m_timer2 >> 20) & 0xf; break;
+ case 0x3e: data = (state->m_timer2 >> 24) & 0xf; break;
+ case 0x3f: data = (state->m_timer2 >> 28) & 0xf; break;
+
+ /* serial */
+ case 0x15:
+ {
+ /* second nibble of received data */
+
+ //device_image_interface *xmodem = dynamic_cast<device_image_interface *>(space->machine().device("rs232_x"));
+ //device_image_interface *kermit = dynamic_cast<device_image_interface *>(space->machine().device("rs232_k"));
+
+ state->m_io[0x11] &= ~1; /* clear byte received */
+ data = state->m_io[offset];
+
+ /* protocol action */
+ //if ( xmodem && xmodem->exists() ) xmodem_byte_transmitted( &xmodem->device() );
+ //else if ( kermit && kermit->exists() ) kermit_byte_transmitted( &kermit->device() );
+ break;
+ }
+
+ /* cards */
+ case 0x0e: /* detection */
+ data = state->m_io[0x0e];
+ LOG(( "%05x: card control read %02x\n", cpu_get_previouspc(&space->device()), data ));
+ break;
+ case 0x0f: /* card info */
+ data = 0;
+ if ( HP48_G_SERIES )
+ {
+ if ( state->m_port_size[1] ) data |= 1;
+ if ( state->m_port_size[0] ) data |= 2;
+ if ( state->m_port_size[1] && state->m_port_write[1] ) data |= 4;
+ if ( state->m_port_size[0] && state->m_port_write[0] ) data |= 8;
+ }
+ else
+ {
+ if ( state->m_port_size[0] ) data |= 1;
+ if ( state->m_port_size[1] ) data |= 2;
+ if ( state->m_port_size[0] && state->m_port_write[0] ) data |= 4;
+ if ( state->m_port_size[1] && state->m_port_write[1] ) data |= 8;
+ }
+ LOG(( "%05x: card info read %02x\n", cpu_get_previouspc(&space->device()), data ));
+ break;
+
+
+ default: data = state->m_io[offset];
+ }
+
+ LOG(( "%05x %f hp48_io_r: off=%02x data=%x\n",
+ cpu_get_previouspc(&space->device()), space->machine().time().as_double(), offset, data ));
+ return data;
+}
+
+
+/* ---------- GX's bank switcher --------- */
+
+static READ8_HANDLER ( hp48_bank_r )
+{
+ hp48_state *state = space->machine().driver_data<hp48_state>();
+ /* bit 0: ignored, bits 2-5: bank number, bit 6: enable */
+ offset &= 0x7e;
+ if ( state->m_bank_switch != offset )
+ {
+ LOG(( "%05x %f hp48_bank_r: off=%03x\n", cpu_get_previouspc(&space->device()), space->machine().time().as_double(), offset ));
+ state->m_bank_switch = offset;
+ hp48_apply_modules(state);
+ }
+ return 0;
+}
+
+
+/* ---------------- timers --------------- */
+
+static TIMER_CALLBACK( hp48_timer1_cb )
+{
+ hp48_state *state = machine.driver_data<hp48_state>();
+ if ( !(state->m_io[0x2f] & 1) ) return; /* timer enable */
+
+ state->m_timer1 = (state->m_timer1 - 1) & 0xf;
+
+ /* wake-up on carry */
+ if ( (state->m_io[0x2e] & 4) && (state->m_timer1 == 0xf) )
+ {
+ LOG(( "wake-up on timer1\n" ));
+ state->m_io[0x2e] |= 8; /* set service request */
+ state->m_io[0x18] |= 4; /* set service request */
+ hp48_pulse_irq( machine, SATURN_WAKEUP_LINE );
+ }
+ /* interrupt on carry */
+ if ( (state->m_io[0x2e] & 2) && (state->m_timer1 == 0xf) )
+ {
+ LOG(( "generate timer1 interrupt\n" ));
+ state->m_io[0x2e] |= 8; /* set service request */
+ state->m_io[0x18] |= 4; /* set service request */
+ hp48_pulse_irq( machine, SATURN_NMI_LINE );
+ }
+}
+
+static TIMER_CALLBACK( hp48_timer2_cb )
+{
+ hp48_state *state = machine.driver_data<hp48_state>();
+ if ( !(state->m_io[0x2f] & 1) ) return; /* timer enable */
+
+ state->m_timer2 = (state->m_timer2 - 1) & 0xffffffff;
+
+ /* wake-up on carry */
+ if ( (state->m_io[0x2f] & 4) && (state->m_timer2 == 0xffffffff) )
+ {
+ LOG(( "wake-up on timer2\n" ));
+ state->m_io[0x2f] |= 8; /* set service request */
+ state->m_io[0x18] |= 4; /* set service request */
+ hp48_pulse_irq( machine, SATURN_WAKEUP_LINE );
+ }
+ /* interrupt on carry */
+ if ( (state->m_io[0x2f] & 2) && (state->m_timer2 == 0xffffffff) )
+ {
+ LOG(( "generate timer2 interrupt\n" ));
+ state->m_io[0x2f] |= 8; /* set service request */
+ state->m_io[0x18] |= 4; /* set service request */
+ hp48_pulse_irq( machine, SATURN_NMI_LINE );
+ }
+}
+
+
+
+
+/* --------- memory controller ----------- */
+
+/*
+ Clark (S series) and York (G series) CPUs have 6 daisy-chained modules
+
+
+ <-- highest --------- priority ------------- lowest -->
+
+ CPU ---------------------------------------------------
+ | | | | | |
+ HDW NCE2 CE1 CE2 NCE3 NCE1
+
+
+ However, controller usage is different in both series:
+
+
+ controller S series G series
+ (Clark CPU) (York CPU)
+
+ HDW I/O RAM I/O RAM
+ NCE2 RAM RAM
+ CE1 port1 bank switcher
+ CE2 port2 port1
+ NCE3 unused port2
+ NCE1 ROM ROM
+
+
+ - NCE1 (ROM) cannot be configured, it is always visible at addresses
+ 00000-7ffff not covered by higher priority modules.
+
+ - only the address of HDW (I/O) can be configured, its size is constant
+ (64 nibbles)
+
+ - other modules can have their address & size set
+
+ */
+
+
+/* remap all modules according to hp48_modules */
+static void hp48_apply_modules(hp48_state *state)
+{
+ int i;
+ int nce2_enable = 1;
+ address_space* space = state->machine().device("maincpu")->memory().space(AS_PROGRAM);
+
+ state->m_io_addr = 0x100000;
+
+ if ( HP48_G_SERIES )
+ {
+ /* port 2 bank switch */
+ if ( state->m_port_size[1] > 0 )
+ {
+ int off = (state->m_bank_switch << 16) % state->m_port_size[1];
+ state->m_modules[4].data = state->m_port_data[1] + off;
+ }
+
+ /* ROM A19 (hi 256 KB) / NCE2 (port 2) control switch */
+ if ( state->m_io[0x29] & 8 )
+ {
+ /* A19 */
+ state->m_modules[5].off_mask = 0xfffff;
+ nce2_enable = 0;
+ }
+ else
+ {
+ /* NCE2 */
+ state->m_modules[5].off_mask = 0x7ffff;
+ nce2_enable = state->m_bank_switch >> 6;
+ }
+ }
+
+ /* S series ROM mapping compatibility */
+ if ( HP48_S_SERIES || !(state->m_io[0x29] & 8) )
+ {
+ state->m_modules[5].off_mask = 0x7ffff;
+ }
+ else
+ {
+ state->m_modules[5].off_mask = 0xfffff;
+ }
+
+ /* from lowest to highest priority */
+ for ( i = 5; i >= 0; i-- )
+ {
+ UINT32 select_mask = state->m_modules[i].mask;
+ UINT32 nselect_mask = ~select_mask & 0xfffff;
+ UINT32 base = state->m_modules[i].base;
+ UINT32 off_mask = state->m_modules[i].off_mask;
+ UINT32 mirror = nselect_mask & ~off_mask;
+ UINT32 end = base + (off_mask & nselect_mask);
+ char bank[10];
+ sprintf(bank,"bank%d",i);
+
+ if ( state->m_modules[i].state != HP48_MODULE_CONFIGURED ) continue;
+
+ if ( (i == 4) && !nce2_enable ) continue;
+
+ /* our code assumes that the 20-bit select_mask is all 1s followed by all 0s */
+ if ( nselect_mask & (nselect_mask+1) )
+ {
+ logerror( "hp48_apply_modules: invalid mask %05x for module %s\n",
+ select_mask, hp48_module_names[i] );
+ continue;
+ }
+
+ if (state->m_modules[i].data)
+ space->install_read_bank( base, end, 0, mirror, bank );
+ else
+ {
+ if (state->m_modules[i].read != NULL)
+ space->install_legacy_read_handler( base, end, 0, mirror, state->m_modules[i].read, state->m_modules[i].read_name);
+ }
+
+ if (state->m_modules[i].isnop)
+ space->nop_write(base, end, 0, mirror);
+ else
+ {
+ if (state->m_modules[i].data)
+ space->install_write_bank( base, end, 0, mirror, bank );
+ else
+ {
+ if (state->m_modules[i].write != NULL)
+ space->install_legacy_write_handler( base, end, 0, mirror, state->m_modules[i].write, state->m_modules[i].write_name );
+ }
+ }
+
+ LOG(( "hp48_apply_modules: module %s configured at %05x-%05x, mirror %05x\n",
+ hp48_module_names[i], base, end, mirror ));
+
+ if ( state->m_modules[i].data )
+ {
+ state->membank( bank )->set_base( state->m_modules[i].data );
+ }
+
+ if ( i == 0 )
+ {
+ state->m_io_addr = base;
+ }
+ }
+}
+
+
+/* reset the configuration */
+static void hp48_reset_modules( running_machine &machine )
+{
+ hp48_state *state = machine.driver_data<hp48_state>();
+ int i;
+ /* fixed size for HDW */
+ state->m_modules[0].state = HP48_MODULE_MASK_KNOWN;
+ state->m_modules[0].mask = 0xfffc0;
+ /* unconfigure NCE2, CE1, CE2, NCE3 */
+ for ( i = 1; i < 5; i++ )
+ {
+ state->m_modules[i].state = HP48_MODULE_UNCONFIGURED;
+ }
+
+ /* fixed configuration for NCE1 */
+ state->m_modules[5].state = HP48_MODULE_CONFIGURED;
+ state->m_modules[5].base = 0;
+ state->m_modules[5].mask = 0;
+
+ hp48_apply_modules(state);
+}
+
+
+/* RESET opcode */
+void hp48_mem_reset( device_t *device )
+{
+ LOG(( "%05x %f hp48_mem_reset\n", cpu_get_previouspc(device->machine().device("maincpu")), device->machine().time().as_double() ));
+ hp48_reset_modules(device->machine());
+}
+
+
+/* CONFIG opcode */
+void hp48_mem_config( device_t *device, int v )
+{
+ hp48_state *state = device->machine().driver_data<hp48_state>();
+ int i;
+
+ LOG(( "%05x %f hp48_mem_config: %05x\n", cpu_get_previouspc(device->machine().device("maincpu")), device->machine().time().as_double(), v ));
+
+ /* find the highest priority unconfigured module (except non-configurable NCE1)... */
+ for ( i = 0; i < 5; i++ )
+ {
+ /* ... first call sets the address mask */
+ if ( state->m_modules[i].state == HP48_MODULE_UNCONFIGURED )
+ {
+ state->m_modules[i].mask = v & 0xff000;
+ state->m_modules[i].state = HP48_MODULE_MASK_KNOWN;
+ break;
+ }
+
+ /* ... second call sets the base address */
+ if ( state->m_modules[i].state == HP48_MODULE_MASK_KNOWN )
+ {
+ state->m_modules[i].base = v & state->m_modules[i].mask;
+ state->m_modules[i].state = HP48_MODULE_CONFIGURED;
+ LOG(( "hp48_mem_config: module %s configured base=%05x, mask=%05x\n",
+ hp48_module_names[i], state->m_modules[i].base, state->m_modules[i].mask ));
+ hp48_apply_modules(state);
+ break;
+ }
+ }
+}
+
+
+/* UNCFG opcode */
+void hp48_mem_unconfig( device_t *device, int v )
+{
+ hp48_state *state = device->machine().driver_data<hp48_state>();
+ int i;
+ LOG(( "%05x %f hp48_mem_unconfig: %05x\n", cpu_get_previouspc(device->machine().device("maincpu")), device->machine().time().as_double(), v ));
+
+ /* find the highest priority fully configured module at address v (except NCE1)... */
+ for ( i = 0; i < 5; i++ )
+ {
+ /* ... and unconfigure it */
+ if ( state->m_modules[i].state == HP48_MODULE_CONFIGURED &&
+ (state->m_modules[i].base == (v & state->m_modules[i].mask)) )
+ {
+ state->m_modules[i].state = i> 0 ? HP48_MODULE_UNCONFIGURED : HP48_MODULE_MASK_KNOWN;
+ LOG(( "hp48_mem_unconfig: module %s\n", hp48_module_names[i] ));
+ hp48_apply_modules(state);
+ break;
+ }
+ }
+}
+
+
+/* C=ID opcode */
+int hp48_mem_id( device_t *device )
+{
+ hp48_state *state = device->machine().driver_data<hp48_state>();
+ int i;
+ int data = 0; /* 0 = everything is configured */
+
+ /* find the highest priority unconfigured module (except NCE1)... */
+ for ( i = 0; i < 5; i++ )
+ {
+ /* ... mask need to be configured */
+ if ( state->m_modules[i].state == HP48_MODULE_UNCONFIGURED )
+ {
+ data = hp48_module_mask_id[i] | (state->m_modules[i].mask & ~0xff);
+ break;
+ }
+
+ /* ... address need to be configured */
+ if ( state->m_modules[i].state == HP48_MODULE_MASK_KNOWN )
+ {
+ data = hp48_module_addr_id[i] | (state->m_modules[i].base & ~0x3f);
+ break;
+ }
+ }
+
+ LOG(( "%05x %f hp48_mem_id = %02x\n",
+ cpu_get_previouspc(device->machine().device("maincpu")), device->machine().time().as_double(), data ));
+
+ return data; /* everything is configured */
+}
+
+
+
+/* --------- CRC ---------- */
+
+/* each memory read by the CPU updates the internal CRC state */
+void hp48_mem_crc( device_t *device, int addr, int data )
+{
+ hp48_state *state = device->machine().driver_data<hp48_state>();
+ /* no CRC for I/O RAM */
+ if ( addr >= state->m_io_addr && addr < state->m_io_addr + 0x40 ) return;
+
+ state->m_crc = (state->m_crc >> 4) ^ (((state->m_crc ^ data) & 0xf) * 0x1081);
+}
+
+
+
+/* ------ utilities ------- */
+
+
+/* decodes size bytes into 2*size nibbles (least significant first) */
+static void hp48_decode_nibble( UINT8* dst, UINT8* src, int size )
+{
+ int i;
+ for ( i=size-1; i >= 0; i-- )
+ {
+ dst[2*i+1] = src[i] >> 4;
+ dst[2*i] = src[i] & 0xf;
+ }
+}
+
+/* inverse of hp48_decode_nibble */
+static void hp48_encode_nibble( UINT8* dst, UINT8* src, int size )
+{
+ int i;
+ for ( i=0; i < size; i++ )
+ {
+ dst[i] = (src[2*i] & 0xf) | (src[2*i+1] << 4);
+ }
+}
+
+
+
+/* ----- card images ------ */
+
+/* port information configurations */
+const struct hp48_port_interface hp48sx_port1_config = { 0, 2, 128*1024 };
+const struct hp48_port_interface hp48sx_port2_config = { 1, 3, 128*1024 };
+const struct hp48_port_interface hp48gx_port1_config = { 0, 3, 128*1024 };
+const struct hp48_port_interface hp48gx_port2_config = { 1, 4, 4*1024*1024 };
+
+const device_type HP48_PORT = &device_creator<hp48_port_image_device>;
+
+/* helper for load and create */
+void hp48_port_image_device::hp48_fill_port()
+{
+ hp48_state *state = machine().driver_data<hp48_state>();
+ struct hp48_port_interface* conf = (struct hp48_port_interface*) static_config();
+ int size = state->m_port_size[conf->port];
+ LOG(( "hp48_fill_port: %s module=%i size=%i rw=%i\n", tag(), conf->module, size, state->m_port_write[conf->port] ));
+ state->m_port_data[conf->port] = (UINT8*)malloc( 2 * size );
+ memset( state->m_port_data[conf->port], 0, 2 * size );
+ state->m_modules[conf->module].off_mask = 2 * (( size > 128 * 1024 ) ? 128 * 1024 : size) - 1;
+ state->m_modules[conf->module].read = NULL;
+ state->m_modules[conf->module].write = NULL;
+ state->m_modules[conf->module].isnop = 0;
+ if (state->m_port_write[conf->port]) {
+ state->m_modules[conf->module].isnop = 1;
+ }
+ state->m_modules[conf->module].data = state->m_port_data[conf->port];
+ hp48_apply_modules(state);
+}
+
+/* helper for start and unload */
+void hp48_port_image_device::hp48_unfill_port()
+{
+ hp48_state *state = machine().driver_data<hp48_state>();
+ struct hp48_port_interface* conf = (struct hp48_port_interface*) static_config();
+ state->m_modules[conf->module].off_mask = 0x00fff; /* 2 KB */
+ state->m_modules[conf->module].read = NULL;
+ state->m_modules[conf->module].write = NULL;
+ state->m_modules[conf->module].data = NULL;
+}
+
+
+bool hp48_port_image_device::call_load()
+{
+ hp48_state *state = machine().driver_data<hp48_state>();
+ struct hp48_port_interface* conf = (struct hp48_port_interface*)static_config();
+ int size = length();
+ if ( size == 0 ) size = conf->max_size; /* default size */
+
+ /* check size */
+ if ( (size < 32*1024) || (size > conf->max_size) || (size & (size-1)) )
+ {
+ logerror( "hp48: image size for %s should be a power of two between %i and %i\n", tag(), 32*1024, conf->max_size );
+ return IMAGE_INIT_FAIL;
+ }
+
+ state->m_port_size[conf->port] = size;
+ state->m_port_write[conf->port] = !is_readonly();
+ hp48_fill_port( );
+ fread(state->m_port_data[conf->port], state->m_port_size[conf->port] );
+ hp48_decode_nibble( state->m_port_data[conf->port], state->m_port_data[conf->port], state->m_port_size[conf->port] );
+ return IMAGE_INIT_PASS;
+}
+
+bool hp48_port_image_device::call_create(int format_type, option_resolution *format_options)
+{
+ hp48_state *state = machine().driver_data<hp48_state>();
+ struct hp48_port_interface* conf = (struct hp48_port_interface*) static_config();
+ int size = conf->max_size;
+ /* XXX defaults to max_size; get user-specified size instead */
+
+ /* check size */
+ /* size must be a power of 2 between 32K and max_size */
+ if ( (size < 32*1024) || (size > conf->max_size) || (size & (size-1)) )
+ {
+ logerror( "hp48: image size for %s should be a power of two between %i and %i\n", tag(), 32*1024, conf->max_size );
+ return IMAGE_INIT_FAIL;
+ }
+
+ state->m_port_size[conf->port] = size;
+ state->m_port_write[conf->port] = 1;
+ hp48_fill_port();
+ return IMAGE_INIT_PASS;
+}
+
+void hp48_port_image_device::call_unload()
+{
+ hp48_state *state = machine().driver_data<hp48_state>();
+ struct hp48_port_interface* conf = (struct hp48_port_interface*) static_config();
+ LOG(( "hp48_port image unload: %s size=%i rw=%i\n",
+ tag(), state->m_port_size[conf->port] ,state->m_port_write[conf->port] ));
+ if ( state->m_port_write[conf->port] )
+ {
+ hp48_encode_nibble( state->m_port_data[conf->port], state->m_port_data[conf->port], state->m_port_size[conf->port] );
+ fseek( 0, SEEK_SET );
+ fwrite( state->m_port_data[conf->port], state->m_port_size[conf->port] );
+ }
+ free( state->m_port_data[conf->port] );
+ hp48_unfill_port();
+ hp48_apply_modules(state);
+}
+
+void hp48_port_image_device::device_start()
+{
+ hp48_unfill_port();
+}
+
+hp48_port_image_device::hp48_port_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, HP48_PORT, "HP48 memory card", tag, owner, clock),
+ device_image_interface(mconfig, *this)
+{
+}
+
+void hp48_port_image_device::device_config_complete()
+{
+ update_names(HP48_PORT, "port", "p");
+}
+
+/***************************************************************************
+ MACHINES
+***************************************************************************/
+
+DRIVER_INIT_MEMBER(hp48_state,hp48)
+{
+ int i;
+ LOG(( "hp48: driver init called\n" ));
+ for ( i = 0; i < 6; i++ )
+ {
+ m_modules[i].off_mask = 0x00fff; /* 2 KB */
+ m_modules[i].read = NULL;
+ m_modules[i].write = NULL;
+ m_modules[i].data = NULL;
+ }
+ m_port_size[0] = 0;
+ m_port_size[1] = 0;
+}
+
+MACHINE_RESET( hp48 )
+{
+ hp48_state *state = machine.driver_data<hp48_state>();
+ LOG(( "hp48: machine reset called\n" ));
+ hp48_reset_modules( machine );
+ hp48_update_annunciators(state);
+}
+
+static void hp48_machine_start( running_machine &machine, hp48_models model )
+{
+ hp48_state *state = machine.driver_data<hp48_state>();
+ UINT8* rom, *ram;
+ int ram_size, rom_size, i;
+
+ LOG(( "hp48_machine_start: model %i\n", model ));
+
+ state->m_model = model;
+
+ /* internal RAM */
+ ram_size = HP48_GX_MODEL ? (128 * 1024) : (32 * 1024);
+
+ ram = auto_alloc_array(machine, UINT8, 2 * ram_size);
+ machine.device<nvram_device>("nvram")->set_base(ram, 2 * ram_size);
+
+
+ /* ROM load */
+ rom_size = HP48_S_SERIES ? (256 * 1024) : (512 * 1024);
+ rom = auto_alloc_array(machine, UINT8, 2 * rom_size);
+ hp48_decode_nibble( rom, state->memregion( "maincpu" )->base(), rom_size );
+
+ /* init state */
+ memset( ram, 0, 2 * ram_size );
+ memset( state->m_io, 0, sizeof( state->m_io ) );
+ state->m_out = 0;
+ state->m_kdn = 0;
+ state->m_crc = 0;
+ state->m_timer1 = 0;
+ state->m_timer2 = 0;
+ state->m_bank_switch = 0;
+
+ /* static module configuration */
+ memset(state->m_modules,0,sizeof(state->m_modules)); // to put all on 0
+ /* I/O RAM */
+ state->m_modules[0].off_mask = 0x0003f; /* 32 B */
+ state->m_modules[0].read = hp48_io_r;
+ state->m_modules[0].read_name = "hp48_io_r";
+ state->m_modules[0].write = hp48_io_w;
+ state->m_modules[0].write_name = "hp48_io_w";
+
+ /* internal RAM */
+ state->m_modules[1].off_mask = 2 * ram_size - 1;
+ state->m_modules[1].read = NULL;
+ state->m_modules[1].write = NULL;
+ state->m_modules[1].data = ram;
+
+ if ( HP48_G_SERIES )
+ {
+ /* bank switcher */
+ state->m_modules[2].off_mask = 0x00fff; /* 2 KB */
+ state->m_modules[2].read = hp48_bank_r;
+ state->m_modules[2].read_name = "hp48_bank_r";
+ state->m_modules[2].write = NULL;
+ }
+
+ /* ROM */
+ state->m_modules[5].off_mask = 2 * rom_size - 1;
+ state->m_modules[5].read = NULL;
+ state->m_modules[5].write = NULL;
+ state->m_modules[5].isnop = 1;
+ state->m_modules[5].data = rom;
+
+ /* timers */
+ machine.scheduler().timer_pulse(attotime::from_hz( 16 ), FUNC(hp48_timer1_cb));
+ machine.scheduler().timer_pulse(attotime::from_hz( 8192 ), FUNC(hp48_timer2_cb));
+
+ /* 1ms keyboard polling */
+ machine.scheduler().timer_pulse(attotime::from_msec( 1 ), FUNC(hp48_kbd_cb));
+
+ /* save state */
+ state->save_item(NAME(state->m_out) );
+ state->save_item(NAME(state->m_kdn) );
+ state->save_item(NAME(state->m_io_addr) );
+ state->save_item(NAME(state->m_crc) );
+ state->save_item(NAME(state->m_timer1) );
+ state->save_item(NAME(state->m_timer2) );
+ state->save_item(NAME(state->m_bank_switch) );
+ for ( i = 0; i < 6; i++ )
+ {
+ state_save_register_item(machine, "globals", NULL, i, state->m_modules[i].state );
+ state_save_register_item(machine, "globals", NULL, i, state->m_modules[i].base );
+ state_save_register_item(machine, "globals", NULL, i, state->m_modules[i].mask );
+ }
+ state->save_item(NAME(state->m_io) );
+ //state_save_register_global_pointer(machine, machine.generic.nvram.u8, machine.generic.nvram_size );
+
+ machine.save().register_postload( save_prepost_delegate(FUNC(hp48_update_annunciators), state ));
+ machine.save().register_postload( save_prepost_delegate(FUNC(hp48_apply_modules), state ));
+
+#ifdef CHARDEV
+ /* direct I/O */
+ state->m_chardev = chardev_open_pty( machine, &hp48_chardev_iface );
+#endif
+}
+
+
+MACHINE_START( hp48s )
+{
+ hp48_machine_start( machine, HP48_S );
+}
+
+
+MACHINE_START( hp48sx )
+{
+ hp48_machine_start( machine, HP48_SX );
+}
+
+
+MACHINE_START( hp48g )
+{
+ hp48_machine_start( machine, HP48_G );
+}
+
+MACHINE_START( hp48gx )
+{
+ hp48_machine_start( machine, HP48_GX );
+}
+
+MACHINE_START( hp48gp )
+{
+ hp48_machine_start( machine, HP48_GP );
+}
diff --git a/src/mess/machine/i82371ab.c b/src/mess/machine/i82371ab.c
new file mode 100644
index 00000000000..81e51538a5a
--- /dev/null
+++ b/src/mess/machine/i82371ab.c
@@ -0,0 +1,263 @@
+/***************************************************************************
+
+ 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::i82371ab_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : southbridge_device(mconfig, I82371AB, "Intel 82371AB", tag, owner, clock),
+ 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;
+ }
+}
+
+static IRQ_CALLBACK(at_irq_callback)
+{
+ device_t *pic = device->machine().device(":pcibus:1:i82371ab:pic8259_master");
+ return pic8259_acknowledge(pic);
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void i82371ab_device::device_start()
+{
+ southbridge_device::device_start();
+ /* setup save states */
+ save_item(NAME(m_regs));
+
+ device_set_irq_callback(machine().device(":maincpu"), at_irq_callback);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void i82371ab_device::device_reset()
+{
+ southbridge_device::device_reset();
+ 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/mess/machine/i82371ab.h b/src/mess/machine/i82371ab.h
new file mode 100644
index 00000000000..f3d8e461308
--- /dev/null
+++ b/src/mess/machine/i82371ab.h
@@ -0,0 +1,52 @@
+/***************************************************************************
+
+ Intel 82371AB PCI IDE ISA Xcelerator (PIIX4)
+
+ Part of the Intel 430TX chipset
+
+***************************************************************************/
+
+#ifndef __I82371AB_H__
+#define __I82371AB_H__
+
+#include "machine/pci.h"
+#include "machine/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();
+ virtual void device_config_complete() { m_shortname = "i82371ab"; }
+
+ 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/mess/machine/i82371sb.c b/src/mess/machine/i82371sb.c
new file mode 100644
index 00000000000..a020bb94896
--- /dev/null
+++ b/src/mess/machine/i82371sb.c
@@ -0,0 +1,185 @@
+/***************************************************************************
+
+ 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::i82371sb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : southbridge_device(mconfig, I82371SB, "Intel 82371SB", tag, owner, clock),
+ 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);
+}
+
+static IRQ_CALLBACK(at_irq_callback)
+{
+ device_t *pic = device->machine().device(":pcibus:1:i82371sb:pic8259_master");
+ return pic8259_acknowledge(pic);
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void i82371sb_device::device_start()
+{
+ southbridge_device::device_start();
+ /* setup save states */
+ save_item(NAME(m_regs));
+
+ device_set_irq_callback(machine().device(":maincpu"), at_irq_callback);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void i82371sb_device::device_reset()
+{
+ southbridge_device::device_reset();
+ /* 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/mess/machine/i82371sb.h b/src/mess/machine/i82371sb.h
new file mode 100644
index 00000000000..5502f6b7f5a
--- /dev/null
+++ b/src/mess/machine/i82371sb.h
@@ -0,0 +1,49 @@
+/***************************************************************************
+
+ Intel 82371SB PCI IDE ISA Xcelerator (PIIX3)
+
+ Part of the Intel 430TX chipset
+
+***************************************************************************/
+
+#ifndef __I82371SB_H__
+#define __I82371SB_H__
+
+#include "machine/pci.h"
+#include "machine/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();
+ virtual void device_config_complete() { m_shortname = "i82371sb"; }
+
+ 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/mess/machine/i82439tx.c b/src/mess/machine/i82439tx.c
new file mode 100644
index 00000000000..24d8c42af0e
--- /dev/null
+++ b/src/mess/machine/i82439tx.c
@@ -0,0 +1,331 @@
+/***************************************************************************
+
+ Intel 82439TX System Controller (MTXC)
+
+***************************************************************************/
+
+#include "emu.h"
+#include "i82439tx.h"
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+const device_type I82439TX = &device_creator<i82439tx_device>;
+
+
+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),
+ pci_device_interface( mconfig, *this )
+{
+}
+
+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:
+ result = m_regs[(offset - 0x50) / 4];
+ break;
+
+ default:
+ fatalerror("i82439tx_pci_read(): Unexpected PCI read 0x%02X", offset);
+ break;
+ }
+ 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;
+ }
+
+ COMBINE_DATA(&m_regs[(offset - 0x50) / 4]);
+ break;
+
+ default:
+ fatalerror("i82439tx_pci_write(): Unexpected PCI write 0x%02X <-- 0x%08X", offset, data);
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void i82439tx_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const i82439tx_interface *intf = reinterpret_cast<const i82439tx_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<i82439tx_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_cputag, 0, sizeof(m_cputag));
+ memset(&m_rom_region, 0, sizeof(m_rom_region));
+ }
+ m_shortname = "i82439tx";
+}
+
+//-------------------------------------------------
+// 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_cputag);
+ assert(cpu != NULL);
+
+ m_space = cpu->memory().space(AS_PROGRAM);
+
+ /* get rom region */
+ m_rom = machine().root_device().memregion(m_rom_region)->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;
+
+ /* 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/mess/machine/i82439tx.h b/src/mess/machine/i82439tx.h
new file mode 100644
index 00000000000..1bbdea8d4c1
--- /dev/null
+++ b/src/mess/machine/i82439tx.h
@@ -0,0 +1,56 @@
+/***************************************************************************
+
+ Intel 82439TX System Controller (MTXC)
+
+ Part of the Intel 430TX chipset
+
+***************************************************************************/
+
+#ifndef __I82439TX_H__
+#define __I82439TX_H__
+
+#include "machine/pci.h"
+#include "machine/northbridge.h"
+
+// ======================> i82439tx_interface
+
+struct i82439tx_interface
+{
+ const char *m_cputag;
+ const char *m_rom_region;
+};
+
+// ======================> i82439tx_device
+
+class i82439tx_device : public northbridge_device,
+ public pci_device_interface,
+ public i82439tx_interface
+{
+public:
+ // construction/destruction
+ i82439tx_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();
+ virtual void device_config_complete();
+
+ void i82439tx_configure_memory(UINT8 val, offs_t begin, offs_t end);
+
+private:
+ 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/mess/machine/i8271.c b/src/mess/machine/i8271.c
new file mode 100644
index 00000000000..7863fb79f48
--- /dev/null
+++ b/src/mess/machine/i8271.c
@@ -0,0 +1,1600 @@
+/* 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"
+#include "imagedev/flopdrv.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
+
+typedef struct _i8271_t i8271_t;
+struct _i8271_t
+{
+ int flags;
+ int state;
+ unsigned char Command;
+ unsigned char StatusRegister;
+ unsigned char CommandRegister;
+ unsigned char ResultRegister;
+ unsigned char ParameterRegister;
+ unsigned char ResetRegister;
+ unsigned char data;
+
+ /* number of parameters required after command is specified */
+ unsigned long ParameterCount;
+ /* number of parameters written so far */
+ unsigned long ParameterCountWritten;
+
+ unsigned char CommandParameters[8];
+
+ /* current track for each drive */
+ unsigned long CurrentTrack[2];
+
+ /* 2 bad tracks for drive 0, followed by 2 bad tracks for drive 1 */
+ unsigned long BadTracks[4];
+
+ /* mode special register */
+ unsigned long Mode;
+
+
+ /* drive outputs */
+ int drive;
+ int side;
+
+ /* drive control output special register */
+ int drive_control_output;
+ /* drive control input special register */
+ int drive_control_input;
+
+ unsigned long StepRate;
+ unsigned long HeadSettlingTime;
+ unsigned long IndexCountBeforeHeadUnload;
+ unsigned long HeadLoadTime;
+
+ /* id on disc to find */
+ int ID_C;
+ int ID_H;
+ int ID_R;
+ int ID_N;
+
+ /* id of data for read/write */
+ int data_id;
+
+ int ExecutionPhaseTransferCount;
+ char *pExecutionPhaseData;
+ int ExecutionPhaseCount;
+
+ /* sector counter and id counter */
+ int Counter;
+
+ /* ==0, to cpu, !=0 =from cpu */
+ int data_direction;
+ const i8271_interface *intf;
+
+ emu_timer *data_timer;
+ emu_timer *command_complete_timer;
+};
+
+typedef enum
+{
+ I8271_STATE_EXECUTION_READ = 0,
+ I8271_STATE_EXECUTION_WRITE
+} I8271_STATE_t;
+
+/* 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
+
+static void i8271_command_execute(device_t *device);
+static void i8271_command_continue(device_t *device);
+static void i8271_command_complete(device_t *device,int result, int int_rq);
+static void i8271_data_request(device_t *device);
+static void i8271_timed_data_request(device_t *device);
+/* locate sector for read/write operation */
+static int i8271_find_sector(device_t *device);
+/* do a read operation */
+static void i8271_do_read(device_t *device);
+static void i8271_do_write(device_t *device);
+static void i8271_do_read_id(device_t *device);
+static void i8271_set_irq_state(device_t *device,int);
+static void i8271_set_dma_drq(device_t *device);
+
+static TIMER_CALLBACK(i8271_data_timer_callback);
+static TIMER_CALLBACK(i8271_timed_command_complete_callback);
+
+#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)
+
+static DEVICE_RESET( i8271 );
+
+INLINE i8271_t *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == I8271);
+
+ return (i8271_t *)downcast<legacy_device_base *>(device)->token();
+}
+
+
+static device_t *current_image(device_t *device)
+{
+ i8271_t *i8271 = get_safe_token(device);
+ if (i8271->intf->floppy_drive_tags[i8271->drive]!=NULL) {
+ return device->machine().device(i8271->intf->floppy_drive_tags[i8271->drive]);
+ } else {
+ return NULL;
+ }
+}
+
+
+static void i8271_seek_to_track(device_t *device,int track)
+{
+ device_t *img = current_image(device);
+ i8271_t *i8271 = get_safe_token(device);
+ 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 (floppy_tk00_r(img) && (StepCount != 0))
+ {
+/* logerror("step\n"); */
+ StepCount--;
+ floppy_drive_seek(img, -1);
+ }
+
+ i8271->CurrentTrack[i8271->drive] = 0;
+
+ /* failed to find track 0? */
+ if (StepCount==0)
+ {
+ /* Completion Type: operator intervation probably required for recovery */
+ /* Completion code: track 0 not found */
+ i8271->ResultRegister |= (2<<3) | 2<<1;
+ }
+
+ /* step out - towards track 0 */
+ i8271->drive_control_output &=~(1<<2);
+ }
+ else
+ {
+
+ signed int SignedTracks;
+
+ /* calculate number of tracks to seek */
+ SignedTracks = track - i8271->CurrentTrack[i8271->drive];
+
+ /* step towards 0 */
+ i8271->drive_control_output &= ~(1<<2);
+
+ if (SignedTracks>0)
+ {
+ /* step away from 0 */
+ i8271->drive_control_output |= (1<<2);
+ }
+
+
+ /* seek to track 0 */
+ floppy_drive_seek(img, SignedTracks);
+
+ i8271->CurrentTrack[i8271->drive] = track;
+ }
+}
+
+
+static TIMER_CALLBACK(i8271_data_timer_callback)
+{
+ device_t *device = (device_t *)ptr;
+ i8271_t *i8271 = get_safe_token(device);
+
+ /* ok, trigger data request now */
+ i8271_data_request(device);
+
+ /* stop it */
+ i8271->data_timer->reset();
+}
+
+/* setup a timed data request - data request will be triggered in a few usecs time */
+static void i8271_timed_data_request(device_t *device)
+{
+ int usecs;
+ i8271_t *i8271 = get_safe_token(device);
+ /* 64 for single density */
+ usecs = 64;
+
+ /* set timers */
+ i8271->command_complete_timer->reset();
+ i8271->data_timer->adjust(attotime::from_usec(usecs));
+}
+
+
+static TIMER_CALLBACK(i8271_timed_command_complete_callback)
+{
+ device_t *device = (device_t *)ptr;
+ i8271_t *i8271 = get_safe_token(device);
+
+ i8271_command_complete(device,1,1);
+
+ /* stop it, but don't allow it to be free'd */
+ i8271->command_complete_timer->reset();
+}
+
+/* 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! */
+static void i8271_timed_command_complete(device_t *device)
+{
+ int usecs;
+ i8271_t *i8271 = get_safe_token(device);
+
+ /* 64 for single density - 2 crc bytes later*/
+ usecs = 64*2;
+
+ /* set timers */
+ i8271->data_timer->reset();
+ i8271->command_complete_timer->adjust(attotime::from_usec(usecs));
+}
+
+static void i8271_set_irq_state(device_t *device,int state)
+{
+ i8271_t *i8271 = get_safe_token(device);
+ i8271->StatusRegister &= ~I8271_STATUS_INT_REQUEST;
+ if (state)
+ {
+ i8271->StatusRegister |= I8271_STATUS_INT_REQUEST;
+ }
+
+ if (i8271->intf->interrupt)
+ {
+ i8271->intf->interrupt(device, (i8271->StatusRegister & I8271_STATUS_INT_REQUEST));
+ }
+}
+
+static void i8271_set_dma_drq(device_t *device)
+{
+ i8271_t *i8271 = get_safe_token(device);
+ if (i8271->intf->dma_request)
+ {
+ i8271->intf->dma_request(device, (i8271->flags & I8271_FLAGS_DATA_REQUEST), (i8271->flags & I8271_FLAGS_DATA_DIRECTION));
+ }
+}
+
+static void i8271_load_bad_tracks(device_t *device, int surface)
+{
+ i8271_t *i8271 = get_safe_token(device);
+ i8271->BadTracks[(surface<<1) + 0] = i8271->CommandParameters[1];
+ i8271->BadTracks[(surface<<1) + 1] = i8271->CommandParameters[2];
+ i8271->CurrentTrack[surface] = i8271->CommandParameters[3];
+}
+
+static void i8271_write_bad_track(device_t *device, int surface, int track, int data)
+{
+ i8271_t *i8271 = get_safe_token(device);
+ i8271->BadTracks[(surface<<1) + (track-1)] = data;
+}
+
+static void i8271_write_current_track(device_t *device,int surface, int track)
+{
+ i8271_t *i8271 = get_safe_token(device);
+ i8271->CurrentTrack[surface] = track;
+}
+
+static int i8271_read_current_track(device_t *device,int surface)
+{
+ i8271_t *i8271 = get_safe_token(device);
+ return i8271->CurrentTrack[surface];
+}
+
+static int i8271_read_bad_track(device_t *device,int surface, int track)
+{
+ i8271_t *i8271 = get_safe_token(device);
+ return i8271->BadTracks[(surface<<1) + (track-1)];
+}
+
+static void i8271_get_drive(device_t *device)
+{
+ i8271_t *i8271 = get_safe_token(device);
+ /* &40 = drive 0 side 0 */
+ /* &80 = drive 1 side 0 */
+
+
+
+ if (i8271->CommandRegister & (1<<6))
+ {
+ i8271->drive = 0;
+ }
+
+ if (i8271->CommandRegister & (1<<7))
+ {
+ i8271->drive = 1;
+ }
+
+}
+
+static void i8271_check_all_parameters_written(device_t *device)
+{
+ i8271_t *i8271 = get_safe_token(device);
+ if (i8271->ParameterCount == i8271->ParameterCountWritten)
+ {
+ i8271->StatusRegister &= ~I8271_STATUS_COMMAND_FULL;
+
+ i8271_command_execute(device);
+ }
+}
+
+
+static void i8271_update_state(device_t *device)
+{
+ i8271_t *i8271 = get_safe_token(device);
+ switch (i8271->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 ((i8271->flags & I8271_FLAGS_DATA_REQUEST)==0)
+ {
+ /* setup data with byte */
+ i8271->data = i8271->pExecutionPhaseData[i8271->ExecutionPhaseCount];
+
+/* logerror("read data %02x\n", i8271->data); */
+
+ /* update counters */
+ i8271->ExecutionPhaseCount++;
+ i8271->ExecutionPhaseTransferCount--;
+
+ // logerror("Count: %04x\n", i8271->ExecutionPhaseCount);
+ // logerror("Remaining: %04x\n", i8271->ExecutionPhaseTransferCount);
+
+ /* completed? */
+ if (i8271->ExecutionPhaseTransferCount==0)
+ {
+ /* yes */
+
+ // logerror("sector read complete!\n");
+ /* continue command */
+ i8271_command_continue(device);
+ }
+ else
+ {
+ /* no */
+
+ /* issue data request */
+ i8271_timed_data_request(device);
+ }
+ }
+ }
+ break;
+
+ /* fdc reading data and passing it to cpu which must read it */
+ case I8271_STATE_EXECUTION_WRITE:
+ {
+ /* setup data with byte */
+ i8271->pExecutionPhaseData[i8271->ExecutionPhaseCount] = i8271->data;
+ /* update counters */
+ i8271->ExecutionPhaseCount++;
+ i8271->ExecutionPhaseTransferCount--;
+
+ /* completed? */
+ if (i8271->ExecutionPhaseTransferCount==0)
+ {
+ /* yes */
+
+ /* continue command */
+ i8271_command_continue(device);
+ }
+ else
+ {
+ /* no */
+
+ /* issue data request */
+ i8271_timed_data_request(device);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void i8271_initialise_execution_phase_read(device_t *device,int transfer_size)
+{
+ i8271_t *i8271 = get_safe_token(device);
+ /* read */
+ i8271->flags |= I8271_FLAGS_DATA_DIRECTION;
+ i8271->ExecutionPhaseCount = 0;
+ i8271->ExecutionPhaseTransferCount = transfer_size;
+ i8271->state = I8271_STATE_EXECUTION_READ;
+}
+
+
+static void i8271_initialise_execution_phase_write(device_t *device,int transfer_size)
+{
+ i8271_t *i8271 = get_safe_token(device);
+ /* write */
+ i8271->flags &= ~I8271_FLAGS_DATA_DIRECTION;
+ i8271->ExecutionPhaseCount = 0;
+ i8271->ExecutionPhaseTransferCount = transfer_size;
+ i8271->state = I8271_STATE_EXECUTION_WRITE;
+}
+
+/* for data transfers */
+static void i8271_data_request(device_t *device)
+{
+ i8271_t *i8271 = get_safe_token(device);
+ i8271->flags |= I8271_FLAGS_DATA_REQUEST;
+
+ if ((i8271->Mode & 0x01)!=0)
+ {
+ /* non-dma */
+ i8271->StatusRegister |= I8271_STATUS_NON_DMA_REQUEST;
+ /* set int */
+ i8271_set_irq_state(device,1);
+ }
+ else
+ {
+ /* dma */
+ i8271->StatusRegister &= ~I8271_STATUS_NON_DMA_REQUEST;
+
+ i8271_set_dma_drq(device);
+ }
+}
+
+static void i8271_command_complete(device_t *device,int result, int int_rq)
+{
+ i8271_t *i8271 = get_safe_token(device);
+ /* not busy, and not a execution phase data request in non-dma mode */
+ i8271->StatusRegister &= ~(I8271_STATUS_COMMAND_BUSY | I8271_STATUS_NON_DMA_REQUEST);
+
+ if (result)
+ {
+ i8271->StatusRegister |= I8271_STATUS_RESULT_FULL;
+ }
+
+ if (int_rq)
+ {
+ /* trigger an int */
+ i8271_set_irq_state(device,1);
+ }
+
+ /* correct?? */
+ i8271->drive_control_output &=~1;
+}
+
+
+/* for data transfers */
+static void i8271_clear_data_request(device_t *device)
+{
+ i8271_t *i8271 = get_safe_token(device);
+ i8271->flags &= ~I8271_FLAGS_DATA_REQUEST;
+
+ if ((i8271->Mode & 0x01)!=0)
+ {
+ /* non-dma */
+ i8271->StatusRegister &= ~I8271_STATUS_NON_DMA_REQUEST;
+ /* set int */
+ i8271_set_irq_state(device,0);
+ }
+ else
+ {
+ /* dma */
+ i8271_set_dma_drq(device);
+ }
+}
+
+
+static void i8271_command_continue(device_t *device)
+{
+ i8271_t *i8271 = get_safe_token(device);
+ switch (i8271->Command)
+ {
+ case I8271_COMMAND_READ_DATA_MULTI_RECORD:
+ case I8271_COMMAND_READ_DATA_SINGLE_RECORD:
+ {
+ /* completed all sectors? */
+ i8271->Counter--;
+ /* increment sector id */
+ i8271->ID_R++;
+
+ /* end command? */
+ if (i8271->Counter==0)
+ {
+
+ i8271_timed_command_complete(device);
+ return;
+ }
+
+ i8271_do_read(device);
+ }
+ break;
+
+ case I8271_COMMAND_WRITE_DATA_MULTI_RECORD:
+ case I8271_COMMAND_WRITE_DATA_SINGLE_RECORD:
+ {
+ /* put the buffer to the sector */
+ floppy_drive_write_sector_data(current_image(device), i8271->side, i8271->data_id, i8271->pExecutionPhaseData, 1<<(i8271->ID_N+7),0);
+
+ /* completed all sectors? */
+ i8271->Counter--;
+ /* increment sector id */
+ i8271->ID_R++;
+
+ /* end command? */
+ if (i8271->Counter==0)
+ {
+
+ i8271_timed_command_complete(device);
+ return;
+ }
+
+ i8271_do_write(device);
+ }
+ break;
+
+ case I8271_COMMAND_READ_ID:
+ {
+ i8271->Counter--;
+
+ if (i8271->Counter==0)
+ {
+ i8271_timed_command_complete(device);
+ return;
+ }
+
+ i8271_do_read_id(device);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void i8271_do_read(device_t *device)
+{
+ i8271_t *i8271 = get_safe_token(device);
+ /* find the sector */
+ if (i8271_find_sector(device))
+ {
+ /* get the sector into the buffer */
+ floppy_drive_read_sector_data(current_image(device), i8271->side, i8271->data_id, i8271->pExecutionPhaseData, 1<<(i8271->ID_N+7));
+
+ /* initialise for reading */
+ i8271_initialise_execution_phase_read(device, 1<<(i8271->ID_N+7));
+
+ /* update state - gets first byte and triggers a data request */
+ i8271_timed_data_request(device);
+ return;
+ }
+ LOG(("error getting sector data\n"));
+
+ i8271_timed_command_complete(device);
+}
+
+static void i8271_do_read_id(device_t *device)
+{
+ chrn_id id;
+ i8271_t *i8271 = get_safe_token(device);
+
+ /* get next id from disc */
+ floppy_drive_get_next_id(current_image(device), i8271->side,&id);
+
+ i8271->pExecutionPhaseData[0] = id.C;
+ i8271->pExecutionPhaseData[1] = id.H;
+ i8271->pExecutionPhaseData[2] = id.R;
+ i8271->pExecutionPhaseData[3] = id.N;
+
+ i8271_initialise_execution_phase_read(device, 4);
+}
+
+
+static void i8271_do_write(device_t *device)
+{
+ i8271_t *i8271 = get_safe_token(device);
+ /* find the sector */
+ if (i8271_find_sector(device))
+ {
+ /* initialise for reading */
+ i8271_initialise_execution_phase_write(device,1<<(i8271->ID_N+7));
+
+ /* update state - gets first byte and triggers a data request */
+ i8271_timed_data_request(device);
+ return;
+ }
+ LOG(("error getting sector data\n"));
+
+ i8271_timed_command_complete(device);
+}
+
+
+
+static int i8271_find_sector(device_t *device)
+{
+ device_t *img = current_image(device);
+ i8271_t *i8271 = get_safe_token(device);
+// 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 (floppy_drive_get_next_id(img, i8271->side,&id))
+ {
+ /* tested on Amstrad CPC - All bytes must match, otherwise
+ a NO DATA error is reported */
+ if (id.R == i8271->ID_R)
+ {
+ /* TODO: Is this correct? What about bad tracks? */
+ if (id.C == i8271->CurrentTrack[i8271->drive])
+ {
+ i8271->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 (floppy_drive_get_flag_state(img, FLOPPY_DRIVE_INDEX))
+ {
+ index_count++;
+ }
+
+ }
+ while (index_count!=2);
+
+ /* completion type: command/drive error */
+ /* completion code: sector not found */
+ i8271->ResultRegister |= (3<<3);
+
+ return 0;
+}
+
+static void i8271_command_execute(device_t *device)
+{
+ i8271_t *i8271 = get_safe_token(device);
+ device_t *img = current_image(device);
+
+ /* clear it = good completion status */
+ /* this will be changed if anything bad happens! */
+ i8271->ResultRegister = 0;
+
+ switch (i8271->Command)
+ {
+ case I8271_COMMAND_SPECIFY:
+ {
+ switch (i8271->CommandParameters[0])
+ {
+ case 0x0d:
+ {
+ LOG(("Initialization\n"));
+ i8271->StepRate = i8271->CommandParameters[1];
+ i8271->HeadSettlingTime = i8271->CommandParameters[2];
+ i8271->IndexCountBeforeHeadUnload = (i8271->CommandParameters[3]>>4) & 0x0f;
+ i8271->HeadLoadTime = (i8271->CommandParameters[3] & 0x0f);
+ }
+ break;
+
+ case 0x010:
+ {
+ LOG(("Load bad Tracks Surface 0\n"));
+ i8271_load_bad_tracks(device,0);
+
+ }
+ break;
+
+ case 0x018:
+ {
+ LOG(("Load bad Tracks Surface 1\n"));
+ i8271_load_bad_tracks(device,1);
+
+ }
+ break;
+ }
+
+ /* no result */
+ i8271_command_complete(device,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 (i8271->CommandParameters[0])
+ {
+ case I8271_SPECIAL_REGISTER_MODE_REGISTER:
+ {
+ data = i8271->Mode;
+ }
+ break;
+
+ case I8271_SPECIAL_REGISTER_SURFACE_0_CURRENT_TRACK:
+ {
+ data = i8271_read_current_track(device, 0);
+
+ }
+ break;
+
+ case I8271_SPECIAL_REGISTER_SURFACE_1_CURRENT_TRACK:
+ {
+ data = i8271_read_current_track(device, 1);
+ }
+ break;
+
+ case I8271_SPECIAL_REGISTER_SURFACE_0_BAD_TRACK_1:
+ {
+ data = i8271_read_bad_track(device, 0,1);
+ }
+ break;
+
+ case I8271_SPECIAL_REGISTER_SURFACE_0_BAD_TRACK_2:
+ {
+ data = i8271_read_bad_track(device, 0,2);
+ }
+ break;
+
+ case I8271_SPECIAL_REGISTER_SURFACE_1_BAD_TRACK_1:
+ {
+ data = i8271_read_bad_track(device, 1,1);
+ }
+ break;
+
+ case I8271_SPECIAL_REGISTER_SURFACE_1_BAD_TRACK_2:
+ {
+ data = i8271_read_bad_track(device, 1,2);
+ }
+ break;
+
+ case I8271_SPECIAL_REGISTER_DRIVE_CONTROL_OUTPUT_PORT:
+ {
+ FDC_LOG_COMMAND("Read Drive Control Output port\n");
+
+ i8271_get_drive(device);
+
+ /* assumption: select bits reflect the select bits from the previous
+ command. i.e. read drive status */
+ data = (i8271->drive_control_output & ~0x0c0)
+ | (i8271->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");
+
+
+ i8271->drive_control_input = (1<<6) | (1<<2);
+
+ /* bit 3 = 0 if write protected */
+ i8271->drive_control_input |= floppy_wpt_r(img) << 3;
+
+ /* bit 1 = 0 if head at track 0 */
+ i8271->drive_control_input |= floppy_tk00_r(img) << 1;
+
+ /* need to setup this register based on drive selected */
+ data = i8271->drive_control_input;
+ }
+ break;
+
+ }
+
+ i8271->ResultRegister = data;
+
+ i8271_command_complete(device,1,0);
+ }
+ break;
+
+
+ case I8271_COMMAND_WRITE_SPECIAL_REGISTER:
+ {
+ switch (i8271->CommandParameters[0])
+ {
+ case I8271_SPECIAL_REGISTER_MODE_REGISTER:
+ {
+ /* TODO: Check bits 6-7 and 5-2 are valid */
+ i8271->Mode = i8271->CommandParameters[1];
+
+ if (i8271->Mode & 0x01)
+ {
+ LOG(("Mode: Non-DMA\n"));
+ }
+ else
+ {
+ LOG(("Mode: DMA\n"));
+ }
+
+ if (i8271->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"));
+ i8271_write_current_track(device, 0, i8271->CommandParameters[1]);
+ }
+ break;
+
+ case I8271_SPECIAL_REGISTER_SURFACE_1_CURRENT_TRACK:
+ {
+ LOG(("Surface 1 Current Track\n"));
+ i8271_write_current_track(device, 1, i8271->CommandParameters[1]);
+ }
+ break;
+
+ case I8271_SPECIAL_REGISTER_SURFACE_0_BAD_TRACK_1:
+ {
+ LOG(("Surface 0 Bad Track 1\n"));
+ i8271_write_bad_track(device, 0, 1, i8271->CommandParameters[1]);
+ }
+ break;
+
+ case I8271_SPECIAL_REGISTER_SURFACE_0_BAD_TRACK_2:
+ {
+ LOG(("Surface 0 Bad Track 2\n"));
+ i8271_write_bad_track(device, 0, 2,i8271->CommandParameters[1]);
+ }
+ break;
+
+ case I8271_SPECIAL_REGISTER_SURFACE_1_BAD_TRACK_1:
+ {
+ LOG(("Surface 1 Bad Track 1\n"));
+
+
+ i8271_write_bad_track(device, 1, 1, i8271->CommandParameters[1]);
+ }
+ break;
+
+ case I8271_SPECIAL_REGISTER_SURFACE_1_BAD_TRACK_2:
+ {
+ LOG(("Surface 1 Bad Track 2\n"));
+
+ i8271_write_bad_track(device, 1, 2, i8271->CommandParameters[1]);
+ }
+ break;
+
+ case I8271_SPECIAL_REGISTER_DRIVE_CONTROL_OUTPUT_PORT:
+ {
+// /* get drive selected */
+// i8271->drive = (i8271->CommandParameters[1]>>6) & 0x03;
+
+ FDC_LOG_COMMAND("Write Drive Control Output port\n");
+
+
+ if (i8271->CommandParameters[1] & 0x01)
+ {
+ LOG(("Write Enable\n"));
+ }
+ if (i8271->CommandParameters[1] & 0x02)
+ {
+ LOG(("Seek/Step\n"));
+ }
+ if (i8271->CommandParameters[1] & 0x04)
+ {
+ LOG(("Direction\n"));
+ }
+ if (i8271->CommandParameters[1] & 0x08)
+ {
+ LOG(("Load Head\n"));
+ }
+ if (i8271->CommandParameters[1] & 0x010)
+ {
+ LOG(("Low head current\n"));
+ }
+ if (i8271->CommandParameters[1] & 0x020)
+ {
+ LOG(("Write Fault Reset\n"));
+ }
+
+ LOG(("Select %02x\n", (i8271->CommandParameters[1] & 0x0c0)>>6));
+
+ /* get drive */
+ i8271_get_drive(device);
+
+ /* on bbc dfs 09 this is the side select output */
+ i8271->side = (i8271->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 */
+ floppy_mon_w(img, !BIT(i8271->CommandParameters[1], 3));
+ floppy_drive_set_ready_state(img, 1, 1);
+
+ /* step pin changed? if so perform a step in the direction indicated */
+ if (((i8271->drive_control_output^i8271->CommandParameters[1]) & (1<<1))!=0)
+ {
+ /* step pin changed state? */
+
+ if ((i8271->CommandParameters[1] & (1<<1))!=0)
+ {
+ signed int signed_tracks;
+
+ if ((i8271->CommandParameters[1] & (1<<2))!=0)
+ {
+ signed_tracks = 1;
+ }
+ else
+ {
+ signed_tracks = -1;
+ }
+
+ floppy_drive_seek(img, signed_tracks);
+ }
+ }
+
+ i8271->drive_control_output = i8271->CommandParameters[1];
+
+
+ }
+ break;
+
+ case I8271_SPECIAL_REGISTER_DRIVE_CONTROL_INPUT_PORT:
+ {
+
+ FDC_LOG_COMMAND("Write Drive Control Input port\n");
+
+ // i8271->drive_control_input = i8271->CommandParameters[1];
+ }
+ break;
+
+ }
+
+ /* write doesn't supply a result */
+ i8271_command_complete(device,0,0);
+ }
+ break;
+
+ case I8271_COMMAND_READ_DRIVE_STATUS:
+ {
+ unsigned char status;
+
+ i8271_get_drive(device);
+
+ /* no write fault */
+ status = 0;
+
+ status |= (1<<2) | (1<<6);
+
+ /* these two do not appear to be set at all! ?? */
+
+ if (i8271->intf->floppy_drive_tags[0]!=NULL) {
+ if (floppy_drive_get_flag_state(device->machine().device(i8271->intf->floppy_drive_tags[0]), FLOPPY_DRIVE_READY))
+ {
+ status |= (1<<2);
+ }
+ }
+
+ if (i8271->intf->floppy_drive_tags[1]!=NULL) {
+ if (floppy_drive_get_flag_state(device->machine().device(i8271->intf->floppy_drive_tags[1]), FLOPPY_DRIVE_READY))
+ {
+ status |= (1<<6);
+ }
+ }
+
+ /* bit 3 = 1 if write protected */
+ status |= !floppy_wpt_r(img) << 3;
+
+ /* bit 1 = 1 if head at track 0 */
+ status |= !floppy_tk00_r(img) << 1;
+
+ i8271->ResultRegister = status;
+ i8271_command_complete(device,1,0);
+
+ }
+ break;
+
+ case I8271_COMMAND_SEEK:
+ {
+ i8271_get_drive(device);
+
+
+ i8271_seek_to_track(device,i8271->CommandParameters[0]);
+
+ /* check for bad seek */
+ i8271_timed_command_complete(device);
+
+ }
+ break;
+
+ case I8271_COMMAND_READ_DATA_MULTI_RECORD:
+ {
+ /* N value as stored in ID field */
+ i8271->ID_N = (i8271->CommandParameters[2]>>5) & 0x07;
+
+ /* starting sector id */
+ i8271->ID_R = i8271->CommandParameters[1];
+
+ /* number of sectors to transfer */
+ i8271->Counter = i8271->CommandParameters[2] & 0x01f;
+
+
+ FDC_LOG_COMMAND("READ DATA MULTI RECORD");
+
+ LOG(("Sector Count: %02x\n", i8271->Counter));
+ LOG(("Track: %02x\n",i8271->CommandParameters[0]));
+ LOG(("Sector: %02x\n", i8271->CommandParameters[1]));
+ LOG(("Sector Length: %02x bytes\n", 1<<(i8271->ID_N+7)));
+
+ i8271_get_drive(device);
+
+ if (!floppy_drive_get_flag_state(img, FLOPPY_DRIVE_READY))
+ {
+ /* Completion type: operation intervention probably required for recovery */
+ /* Completion code: Drive not ready */
+ i8271->ResultRegister = (2<<3);
+ i8271_timed_command_complete(device);
+ }
+ else
+ {
+ i8271_seek_to_track(device,i8271->CommandParameters[0]);
+
+
+ i8271_do_read(device);
+ }
+
+ }
+ break;
+
+ case I8271_COMMAND_READ_DATA_SINGLE_RECORD:
+ {
+ FDC_LOG_COMMAND("READ DATA SINGLE RECORD");
+
+ i8271->ID_N = 0;
+ i8271->Counter = 1;
+ i8271->ID_R = i8271->CommandParameters[1];
+
+ LOG(("Sector Count: %02x\n", i8271->Counter));
+ LOG(("Track: %02x\n",i8271->CommandParameters[0]));
+ LOG(("Sector: %02x\n", i8271->CommandParameters[1]));
+ LOG(("Sector Length: %02x bytes\n", 1<<(i8271->ID_N+7)));
+
+ i8271_get_drive(device);
+
+ if (!floppy_drive_get_flag_state(img, FLOPPY_DRIVE_READY))
+ {
+ /* Completion type: operation intervention probably required for recovery */
+ /* Completion code: Drive not ready */
+ i8271->ResultRegister = (2<<3);
+ i8271_timed_command_complete(device);
+ }
+ else
+ {
+ i8271_seek_to_track(device,i8271->CommandParameters[0]);
+
+ i8271_do_read(device);
+ }
+
+ }
+ break;
+
+ case I8271_COMMAND_WRITE_DATA_MULTI_RECORD:
+ {
+ /* N value as stored in ID field */
+ i8271->ID_N = (i8271->CommandParameters[2]>>5) & 0x07;
+
+ /* starting sector id */
+ i8271->ID_R = i8271->CommandParameters[1];
+
+ /* number of sectors to transfer */
+ i8271->Counter = i8271->CommandParameters[2] & 0x01f;
+
+ FDC_LOG_COMMAND("READ DATA MULTI RECORD");
+
+ LOG(("Sector Count: %02x\n", i8271->Counter));
+ LOG(("Track: %02x\n",i8271->CommandParameters[0]));
+ LOG(("Sector: %02x\n", i8271->CommandParameters[1]));
+ LOG(("Sector Length: %02x bytes\n", 1<<(i8271->ID_N+7)));
+
+ i8271_get_drive(device);
+
+ i8271->drive_control_output &=~1;
+
+ if (!floppy_drive_get_flag_state(img, FLOPPY_DRIVE_READY))
+ {
+ /* Completion type: operation intervention probably required for recovery */
+ /* Completion code: Drive not ready */
+ i8271->ResultRegister = (2<<3);
+ i8271_timed_command_complete(device);
+ }
+ else
+ {
+ if (floppy_wpt_r(img) == CLEAR_LINE)
+ {
+ /* Completion type: operation intervention probably required for recovery */
+ /* Completion code: Drive write protected */
+ i8271->ResultRegister = (2<<3) | (1<<1);
+ i8271_timed_command_complete(device);
+ }
+ else
+ {
+ i8271->drive_control_output |=1;
+
+ i8271_seek_to_track(device,i8271->CommandParameters[0]);
+
+ i8271_do_write(device);
+ }
+ }
+ }
+ break;
+
+ case I8271_COMMAND_WRITE_DATA_SINGLE_RECORD:
+ {
+ FDC_LOG_COMMAND("WRITE DATA SINGLE RECORD");
+
+ i8271->ID_N = 0;
+ i8271->Counter = 1;
+ i8271->ID_R = i8271->CommandParameters[1];
+
+
+ LOG(("Sector Count: %02x\n", i8271->Counter));
+ LOG(("Track: %02x\n",i8271->CommandParameters[0]));
+ LOG(("Sector: %02x\n", i8271->CommandParameters[1]));
+ LOG(("Sector Length: %02x bytes\n", 1<<(i8271->ID_N+7)));
+ i8271_get_drive(device);
+
+ i8271->drive_control_output &=~1;
+
+ if (!floppy_drive_get_flag_state(img, FLOPPY_DRIVE_READY))
+ {
+ /* Completion type: operation intervention probably required for recovery */
+ /* Completion code: Drive not ready */
+ i8271->ResultRegister = (2<<3);
+ i8271_timed_command_complete(device);
+ }
+ else
+ {
+ if (floppy_wpt_r(img) == CLEAR_LINE)
+ {
+ /* Completion type: operation intervention probably required for recovery */
+ /* Completion code: Drive write protected */
+ i8271->ResultRegister = (2<<3) | (1<<1);
+ i8271_timed_command_complete(device);
+ }
+ else
+ {
+
+ i8271->drive_control_output |=1;
+
+ i8271_seek_to_track(device,i8271->CommandParameters[0]);
+
+ i8271_do_write(device);
+ }
+ }
+
+ }
+ break;
+
+
+ case I8271_COMMAND_READ_ID:
+ {
+ FDC_LOG_COMMAND("READ ID");
+
+ LOG(("Track: %02x\n",i8271->CommandParameters[0]));
+ LOG(("ID Field Count: %02x\n", i8271->CommandParameters[2]));
+
+ i8271_get_drive(device);
+
+ if (!floppy_drive_get_flag_state(img, FLOPPY_DRIVE_READY))
+ {
+ /* Completion type: operation intervention probably required for recovery */
+ /* Completion code: Drive not ready */
+ i8271->ResultRegister = (2<<3);
+ i8271_timed_command_complete(device);
+ }
+ else
+ {
+
+ i8271->Counter = i8271->CommandParameters[2];
+
+ i8271_seek_to_track(device,i8271->CommandParameters[0]);
+
+ i8271_do_read_id(device);
+ }
+ }
+ break;
+
+ default:
+ LOG(("ERROR Unrecognised Command\n"));
+ break;
+ }
+}
+
+
+
+WRITE8_DEVICE_HANDLER(i8271_w)
+{
+ i8271_t *i8271 = get_safe_token(device);
+ switch (offset & 3)
+ {
+ case 0:
+ {
+ LOG(("I8271 W Command Register: %02x\n", data));
+
+ i8271->CommandRegister = data;
+ i8271->Command = i8271->CommandRegister & 0x03f;
+
+ i8271->StatusRegister |= I8271_STATUS_COMMAND_BUSY | I8271_STATUS_COMMAND_FULL;
+ i8271->StatusRegister &= ~I8271_STATUS_PARAMETER_FULL | I8271_STATUS_RESULT_FULL;
+ i8271->ParameterCountWritten = 0;
+
+ switch (i8271->Command)
+ {
+ case I8271_COMMAND_SPECIFY:
+ {
+ FDC_LOG_COMMAND("SPECIFY");
+
+ i8271->ParameterCount = 4;
+ }
+ break;
+
+ case I8271_COMMAND_SEEK:
+ {
+ FDC_LOG_COMMAND("SEEK");
+
+ i8271->ParameterCount = 1;
+ }
+ break;
+
+ case I8271_COMMAND_READ_DRIVE_STATUS:
+ {
+ FDC_LOG_COMMAND("READ DRIVE STATUS");
+
+ i8271->ParameterCount = 0;
+ }
+ break;
+
+ case I8271_COMMAND_READ_SPECIAL_REGISTER:
+ {
+ FDC_LOG_COMMAND("READ SPECIAL REGISTER");
+
+ i8271->ParameterCount = 1;
+ }
+ break;
+
+ case I8271_COMMAND_WRITE_SPECIAL_REGISTER:
+ {
+ FDC_LOG_COMMAND("WRITE SPECIAL REGISTER");
+
+ i8271->ParameterCount = 2;
+ }
+ break;
+
+ case I8271_COMMAND_FORMAT:
+ {
+ i8271->ParameterCount = 5;
+ }
+ break;
+
+ case I8271_COMMAND_READ_ID:
+ {
+ i8271->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:
+ {
+ i8271->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:
+ {
+ i8271->ParameterCount = 3;
+ }
+ break;
+
+ case I8271_COMMAND_SCAN_DATA:
+ case I8271_COMMAND_SCAN_DATA_AND_DELETED_DATA:
+ {
+ i8271->ParameterCount = 5;
+ }
+ break;
+
+
+
+
+
+
+ }
+
+ i8271_check_all_parameters_written(device);
+ }
+ break;
+
+ case 1:
+ {
+ LOG(("I8271 W Parameter Register: %02x\n",data));
+ i8271->ParameterRegister = data;
+
+ if (i8271->ParameterCount!=0)
+ {
+ i8271->CommandParameters[i8271->ParameterCountWritten] = data;
+ i8271->ParameterCountWritten++;
+ }
+
+ i8271_check_all_parameters_written(device);
+ }
+ break;
+
+ case 2:
+ {
+ LOG(("I8271 W Reset Register: %02x\n", data));
+ if (((data ^ i8271->ResetRegister) & 0x01)!=0)
+ {
+ if ((data & 0x01)==0)
+ {
+ DEVICE_RESET_CALL( i8271 );
+ }
+ }
+
+ i8271->ResetRegister = data;
+
+
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+READ8_DEVICE_HANDLER(i8271_r)
+{
+ i8271_t *i8271 = get_safe_token(device);
+ switch (offset & 3)
+ {
+ case 0:
+ {
+ /* bit 1,0 are zero other bits contain status data */
+ i8271->StatusRegister &= ~0x03;
+ LOG(("I8271 R Status Register: %02x\n",i8271->StatusRegister));
+ return i8271->StatusRegister;
+ }
+
+ case 1:
+ {
+
+ if ((i8271->StatusRegister & I8271_STATUS_COMMAND_BUSY)==0)
+ {
+ /* clear IRQ */
+ i8271_set_irq_state(device,0);
+
+ i8271->StatusRegister &= ~I8271_STATUS_RESULT_FULL;
+ LOG(("I8271 R Result Register %02x\n",i8271->ResultRegister));
+ return i8271->ResultRegister;
+ }
+
+ /* not useful information when command busy */
+ return 0x0ff;
+ }
+
+
+ default:
+ break;
+ }
+
+ return 0x0ff;
+}
+
+
+/* to be completed! */
+READ8_DEVICE_HANDLER(i8271_dack_r)
+{
+ return i8271_data_r(device, offset);
+}
+
+/* to be completed! */
+WRITE8_DEVICE_HANDLER(i8271_dack_w)
+{
+ i8271_data_w(device, offset, data);
+}
+
+ READ8_DEVICE_HANDLER(i8271_data_r)
+{
+ i8271_t *i8271 = get_safe_token(device);
+
+ i8271_clear_data_request(device);
+
+ i8271_update_state(device);
+
+ // logerror("I8271 R data: %02x\n",i8271->data);
+
+
+ return i8271->data;
+}
+
+WRITE8_DEVICE_HANDLER(i8271_data_w)
+{
+ i8271_t *i8271 = get_safe_token(device);
+ i8271->data = data;
+
+// logerror("I8271 W data: %02x\n",i8271->data);
+
+ i8271_clear_data_request(device);
+
+ i8271_update_state(device);
+}
+
+
+/* Device Interface */
+
+static DEVICE_START( i8271 )
+{
+ i8271_t *i8271 = get_safe_token(device);
+ // validate arguments
+
+ assert(device != NULL);
+ assert(device->tag() != NULL);
+ assert(device->static_config() != NULL);
+
+ i8271->intf = (const i8271_interface*)device->static_config();
+
+ i8271->data_timer = device->machine().scheduler().timer_alloc(FUNC(i8271_data_timer_callback), (void *)device);
+ i8271->command_complete_timer = device->machine().scheduler().timer_alloc(FUNC(i8271_timed_command_complete_callback), (void *)device);
+ i8271->drive = 0;
+ i8271->pExecutionPhaseData = auto_alloc_array(device->machine(), char, 0x4000);
+
+ // register for state saving
+ //state_save_register_item(device->machine(), "i8271", device->tag(), 0, i8271->number);
+}
+
+static DEVICE_RESET( i8271 )
+{
+ i8271_t *i8271 = get_safe_token(device);
+
+ i8271->StatusRegister = 0; //I8271_STATUS_INT_REQUEST | I8271_STATUS_NON_DMA_REQUEST;
+ i8271->Mode = 0x0c0; /* bits 0, 1 are initialized to zero */
+ i8271->ParameterCountWritten = 0;
+ i8271->ParameterCount = 0;
+
+ /* if timer is active remove */
+ i8271->command_complete_timer->reset();
+ i8271->data_timer->reset();
+
+ /* clear irq */
+ i8271_set_irq_state(device,0);
+ /* clear dma */
+ i8271_set_dma_drq(device);
+
+}
+
+DEVICE_GET_INFO( i8271 )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(i8271_t); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(i8271); break;
+ case DEVINFO_FCT_STOP: /* Nothing */ break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(i8271); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "Intel 8271"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "Intel 8271"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright MESS Team"); break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(I8271, i8271);
diff --git a/src/mess/machine/i8271.h b/src/mess/machine/i8271.h
new file mode 100644
index 00000000000..226a9055b7d
--- /dev/null
+++ b/src/mess/machine/i8271.h
@@ -0,0 +1,48 @@
+/*****************************************************************************
+ *
+ * machine/i8271.h
+ *
+ ****************************************************************************/
+
+#ifndef I8271_H_
+#define I8271_H_
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+DECLARE_LEGACY_DEVICE(I8271, i8271);
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct i8271_interface
+{
+ void (*interrupt)(device_t *device, int state);
+ void (*dma_request)(device_t *device, int state, int read_);
+ const char *floppy_drive_tags[2];
+} i8271_interface;
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+READ8_DEVICE_HANDLER (i8271_r);
+WRITE8_DEVICE_HANDLER(i8271_w);
+
+READ8_DEVICE_HANDLER (i8271_dack_r);
+WRITE8_DEVICE_HANDLER(i8271_dack_w);
+
+READ8_DEVICE_HANDLER (i8271_data_r);
+WRITE8_DEVICE_HANDLER(i8271_data_w);
+
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+#define MCFG_I8271_ADD(_tag, _intrf) \
+ MCFG_DEVICE_ADD(_tag, I8271, 0) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#endif /* I8271_H_ */
diff --git a/src/mess/machine/ieee488.c b/src/mess/machine/ieee488.c
new file mode 100644
index 00000000000..a20c1e093fc
--- /dev/null
+++ b/src/mess/machine/ieee488.c
@@ -0,0 +1,685 @@
+/**********************************************************************
+
+ IEEE-488.1 General Purpose Interface Bus emulation
+ (aka HP-IB, GPIB, CBM IEEE)
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#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<ieee488_device>;
+const device_type IEEE488_SLOT = &device_creator<ieee488_slot_device>;
+
+
+
+//**************************************************************************
+// 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),
+ device_slot_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// static_set_slot -
+//-------------------------------------------------
+
+void ieee488_slot_device::static_set_slot(device_t &device, int address)
+{
+ ieee488_slot_device &ieee488_card = dynamic_cast<ieee488_slot_device &>(device);
+ ieee488_card.m_address = address;
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void ieee488_slot_device::device_start()
+{
+ ieee488_device* bus = owner()->subdevice<ieee488_device>(IEEE488_TAG);
+ device_ieee488_interface *dev = dynamic_cast<device_ieee488_interface *>(get_card_device());
+ if (dev) bus->add_device(get_card_device(), m_address);
+}
+
+
+
+//**************************************************************************
+// DEVICE CONFIGURATION
+//**************************************************************************
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void ieee488_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const ieee488_interface *intf = reinterpret_cast<const ieee488_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<ieee488_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_eoi_cb, 0, sizeof(m_out_eoi_cb));
+ memset(&m_out_dav_cb, 0, sizeof(m_out_dav_cb));
+ memset(&m_out_nrfd_cb, 0, sizeof(m_out_nrfd_cb));
+ memset(&m_out_ndac_cb, 0, sizeof(m_out_ndac_cb));
+ memset(&m_out_ifc_cb, 0, sizeof(m_out_ifc_cb));
+ memset(&m_out_srq_cb, 0, sizeof(m_out_srq_cb));
+ memset(&m_out_atn_cb, 0, sizeof(m_out_atn_cb));
+ memset(&m_out_ren_cb, 0, sizeof(m_out_ren_cb));
+ }
+}
+
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// set_signal -
+//-------------------------------------------------
+
+inline 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_out_eoi_func(state); break;
+ case DAV: m_out_dav_func(state); break;
+ case NRFD: m_out_nrfd_func(state); break;
+ case NDAC: m_out_ndac_func(state); break;
+ case IFC: m_out_ifc_func(state); break;
+ case SRQ: m_out_srq_func(state); break;
+ case ATN: m_out_atn_func(state); break;
+ case REN: m_out_ren_func(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 -
+//-------------------------------------------------
+
+inline 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 -
+//-------------------------------------------------
+
+inline 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 -
+//-------------------------------------------------
+
+inline 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;
+}
+
+
+
+//**************************************************************************
+// 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, "IEEE488 bus", tag, owner, clock),
+ 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_out_eoi_func.resolve(m_out_eoi_cb, *this);
+ m_out_dav_func.resolve(m_out_dav_cb, *this);
+ m_out_nrfd_func.resolve(m_out_nrfd_cb, *this);
+ m_out_ndac_func.resolve(m_out_ndac_cb, *this);
+ m_out_ifc_func.resolve(m_out_ifc_cb, *this);
+ m_out_srq_func.resolve(m_out_srq_cb, *this);
+ m_out_atn_func.resolve(m_out_atn_cb, *this);
+ m_out_ren_func.resolve(m_out_ren_cb, *this);
+}
+
+//-------------------------------------------------
+// device_stop - device-specific stop
+//-------------------------------------------------
+
+void ieee488_device::device_stop()
+{
+ m_device_list.reset();
+}
+
+
+//-------------------------------------------------
+// add_device -
+//-------------------------------------------------
+
+void ieee488_device::add_device(device_t *target, int address)
+{
+ daisy_entry *entry = auto_alloc(machine(), daisy_entry(target));
+
+ entry->m_interface->m_bus = this;
+ entry->m_interface->m_address = address;
+
+ 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);
+}
+
+
+//-------------------------------------------------
+// dio_r -
+//-------------------------------------------------
+
+UINT8 ieee488_device::dio_r()
+{
+ return get_data();
+}
+
+
+//-------------------------------------------------
+// dio_r -
+//-------------------------------------------------
+
+READ8_MEMBER( ieee488_device::dio_r )
+{
+ return get_data();
+}
+
+
+//-------------------------------------------------
+// eoi_r -
+//-------------------------------------------------
+
+READ_LINE_MEMBER( ieee488_device::eoi_r )
+{
+ return get_signal(EOI);
+}
+
+
+//-------------------------------------------------
+// dav_r -
+//-------------------------------------------------
+
+READ_LINE_MEMBER( ieee488_device::dav_r )
+{
+ return get_signal(DAV);
+}
+
+
+//-------------------------------------------------
+// nrfd_r -
+//-------------------------------------------------
+
+READ_LINE_MEMBER( ieee488_device::nrfd_r )
+{
+ return get_signal(NRFD);
+}
+
+
+//-------------------------------------------------
+// ndac_r -
+//-------------------------------------------------
+
+READ_LINE_MEMBER( ieee488_device::ndac_r )
+{
+ return get_signal(NDAC);
+}
+
+
+//-------------------------------------------------
+// ifc_r -
+//-------------------------------------------------
+
+READ_LINE_MEMBER( ieee488_device::ifc_r )
+{
+ return get_signal(IFC);
+}
+
+
+//-------------------------------------------------
+// srq_r -
+//-------------------------------------------------
+
+READ_LINE_MEMBER( ieee488_device::srq_r )
+{
+ return get_signal(SRQ);
+}
+
+
+//-------------------------------------------------
+// atn_r -
+//-------------------------------------------------
+
+READ_LINE_MEMBER( ieee488_device::atn_r )
+{
+ return get_signal(ATN);
+}
+
+
+//-------------------------------------------------
+// ren_r -
+//-------------------------------------------------
+
+READ_LINE_MEMBER( ieee488_device::ren_r )
+{
+ return get_signal(REN);
+}
+
+
+//-------------------------------------------------
+// dio_w -
+//-------------------------------------------------
+
+void ieee488_device::dio_w(UINT8 data)
+{
+ return set_data(this, data);
+}
+
+
+//-------------------------------------------------
+// dio_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( ieee488_device::dio_w )
+{
+ return set_data(this, data);
+}
+
+
+//-------------------------------------------------
+// eoi_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( ieee488_device::eoi_w )
+{
+ set_signal(this, EOI, state);
+}
+
+
+//-------------------------------------------------
+// dav_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( ieee488_device::dav_w )
+{
+ set_signal(this, DAV, state);
+}
+
+
+//-------------------------------------------------
+// nrfd_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( ieee488_device::nrfd_w )
+{
+ set_signal(this, NRFD, state);
+}
+
+
+//-------------------------------------------------
+// ndac_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( ieee488_device::ndac_w )
+{
+ set_signal(this, NDAC, state);
+}
+
+
+//-------------------------------------------------
+// ifc_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( ieee488_device::ifc_w )
+{
+ set_signal(this, IFC, state);
+}
+
+
+//-------------------------------------------------
+// srq_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( ieee488_device::srq_w )
+{
+ set_signal(this, SRQ, state);
+}
+
+
+//-------------------------------------------------
+// atn_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( ieee488_device::atn_w )
+{
+ set_signal(this, ATN, state);
+}
+
+
+//-------------------------------------------------
+// ren_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( ieee488_device::ren_w )
+{
+ set_signal(this, REN, state);
+}
+
+
+//-------------------------------------------------
+// dio_w -
+//-------------------------------------------------
+
+void ieee488_device::dio_w(device_t *device, UINT8 data)
+{
+ return set_data(device, data);
+}
+
+
+//-------------------------------------------------
+// eoi_w -
+//-------------------------------------------------
+
+void ieee488_device::eoi_w(device_t *device, int state)
+{
+ set_signal(device, EOI, state);
+}
+
+
+//-------------------------------------------------
+// dav_w -
+//-------------------------------------------------
+
+void ieee488_device::dav_w(device_t *device, int state)
+{
+ set_signal(device, DAV, state);
+}
+
+
+//-------------------------------------------------
+// nrfd_w -
+//-------------------------------------------------
+
+void ieee488_device::nrfd_w(device_t *device, int state)
+{
+ set_signal(device, NRFD, state);
+}
+
+
+//-------------------------------------------------
+// ndac_w -
+//-------------------------------------------------
+
+void ieee488_device::ndac_w(device_t *device, int state)
+{
+ set_signal(device, NDAC, state);
+}
+
+
+//-------------------------------------------------
+// ifc_w -
+//-------------------------------------------------
+
+void ieee488_device::ifc_w(device_t *device, int state)
+{
+ set_signal(device, IFC, state);
+}
+
+
+//-------------------------------------------------
+// srq_w -
+//-------------------------------------------------
+
+void ieee488_device::srq_w(device_t *device, int state)
+{
+ set_signal(device, SRQ, state);
+}
+
+
+//-------------------------------------------------
+// atn_w -
+//-------------------------------------------------
+
+void ieee488_device::atn_w(device_t *device, int state)
+{
+ set_signal(device, ATN, state);
+}
+
+
+//-------------------------------------------------
+// ren_w -
+//-------------------------------------------------
+
+void ieee488_device::ren_w(device_t *device, int state)
+{
+ set_signal(device, REN, state);
+}
diff --git a/src/mess/machine/ieee488.h b/src/mess/machine/ieee488.h
new file mode 100644
index 00000000000..87a01af0141
--- /dev/null
+++ b/src/mess/machine/ieee488.h
@@ -0,0 +1,226 @@
+/**********************************************************************
+
+ IEEE-488.1 General Purpose Interface Bus emulation
+ (aka HP-IB, GPIB, CBM IEEE)
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __IEEE488__
+#define __IEEE488__
+
+#include "emu.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define IEEE488_TAG "ieee_bus"
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_IEEE488_BUS_ADD(_config) \
+ MCFG_DEVICE_ADD(IEEE488_TAG, IEEE488, 0) \
+ MCFG_DEVICE_CONFIG(_config)
+
+
+#define IEEE488_INTERFACE(_name) \
+ const ieee488_interface (_name) =
+
+
+#define MCFG_IEEE488_SLOT_ADD(_tag, _num, _slot_intf, _def_slot, _def_inp) \
+ MCFG_DEVICE_ADD(_tag, IEEE488_SLOT, 0) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false) \
+ ieee488_slot_device::static_set_slot(*device, _num);
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> ieee488_interface
+
+struct ieee488_interface
+{
+ devcb_write_line m_out_eoi_cb;
+ devcb_write_line m_out_dav_cb;
+ devcb_write_line m_out_nrfd_cb;
+ devcb_write_line m_out_ndac_cb;
+ devcb_write_line m_out_ifc_cb;
+ devcb_write_line m_out_srq_cb;
+ devcb_write_line m_out_atn_cb;
+ devcb_write_line m_out_ren_cb;
+};
+
+
+// ======================> ieee488_device
+
+class device_ieee488_interface;
+
+class ieee488_device : public device_t,
+ public ieee488_interface
+{
+public:
+ // construction/destruction
+ ieee488_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ void add_device(device_t *target, int address);
+
+ // reads for both host and peripherals
+ UINT8 dio_r();
+ READ8_MEMBER( dio_r );
+ DECLARE_READ_LINE_MEMBER( eoi_r );
+ DECLARE_READ_LINE_MEMBER( dav_r );
+ DECLARE_READ_LINE_MEMBER( nrfd_r );
+ DECLARE_READ_LINE_MEMBER( ndac_r );
+ DECLARE_READ_LINE_MEMBER( ifc_r );
+ DECLARE_READ_LINE_MEMBER( srq_r );
+ DECLARE_READ_LINE_MEMBER( atn_r );
+ DECLARE_READ_LINE_MEMBER( ren_r );
+
+ // writes for host (driver_device)
+ void dio_w(UINT8 data);
+ WRITE8_MEMBER( dio_w );
+ DECLARE_WRITE_LINE_MEMBER( eoi_w );
+ DECLARE_WRITE_LINE_MEMBER( dav_w );
+ DECLARE_WRITE_LINE_MEMBER( nrfd_w );
+ DECLARE_WRITE_LINE_MEMBER( ndac_w );
+ DECLARE_WRITE_LINE_MEMBER( ifc_w );
+ DECLARE_WRITE_LINE_MEMBER( srq_w );
+ DECLARE_WRITE_LINE_MEMBER( atn_w );
+ DECLARE_WRITE_LINE_MEMBER( ren_w );
+
+ // writes for peripherals (device_t)
+ void dio_w(device_t *device, UINT8 data);
+ void eoi_w(device_t *device, int state);
+ void dav_w(device_t *device, int state);
+ void nrfd_w(device_t *device, int state);
+ void ndac_w(device_t *device, int state);
+ void ifc_w(device_t *device, int state);
+ void srq_w(device_t *device, int state);
+ void atn_w(device_t *device, int state);
+ void ren_w(device_t *device, int state);
+
+protected:
+ enum
+ {
+ EOI = 0,
+ DAV,
+ NRFD,
+ NDAC,
+ IFC,
+ SRQ,
+ ATN,
+ REN,
+ SIGNAL_COUNT
+ };
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_config_complete();
+ 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<daisy_entry> m_device_list;
+
+private:
+ devcb_resolved_write_line m_out_eoi_func;
+ devcb_resolved_write_line m_out_dav_func;
+ devcb_resolved_write_line m_out_nrfd_func;
+ devcb_resolved_write_line m_out_ndac_func;
+ devcb_resolved_write_line m_out_ifc_func;
+ devcb_resolved_write_line m_out_srq_func;
+ devcb_resolved_write_line m_out_atn_func;
+ devcb_resolved_write_line m_out_ren_func;
+
+ inline void set_signal(device_t *device, int signal, int state);
+ inline int get_signal(int signal);
+ inline void set_data(device_t *device, UINT8 data);
+ inline 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);
+
+ // device-level overrides
+ virtual void device_start();
+
+ // inline configuration
+ static void static_set_slot(device_t &device, int address);
+
+private:
+ // configuration
+ 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;
+ int m_address;
+};
+
+
+// device type definition
+extern const device_type IEEE488;
+extern const device_type IEEE488_SLOT;
+
+
+
+#endif
diff --git a/src/mess/machine/interpod.c b/src/mess/machine/interpod.c
new file mode 100644
index 00000000000..6a6ad1e9119
--- /dev/null
+++ b/src/mess/machine/interpod.c
@@ -0,0 +1,267 @@
+/**********************************************************************
+
+ Oxford Computer Systems Interpod IEC to IEEE interface emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+/*
+
+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<interpod_device>;
+
+
+
+//**************************************************************************
+// DEVICE CONFIGURATION
+//**************************************************************************
+
+//-------------------------------------------------
+// IEEE488_INTERFACE( ieee488_intf )
+//-------------------------------------------------
+
+static IEEE488_INTERFACE( ieee488_intf )
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// 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_RAM // 6532
+ AM_RANGE(0x0400, 0x041f) AM_MIRROR(0x3be0) AM_DEVREADWRITE_LEGACY(R6532_TAG, riot6532_r, riot6532_w)
+ AM_RANGE(0x2000, 0x2000) AM_MIRROR(0x9ffe) AM_DEVREADWRITE(MC6850_TAG, acia6850_device, status_read, control_write)
+ AM_RANGE(0x2001, 0x2001) AM_MIRROR(0x9ffe) AM_DEVREADWRITE(MC6850_TAG, acia6850_device, data_read, data_write)
+ 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
+
+
+//-------------------------------------------------
+// via6522_interface via_intf
+//-------------------------------------------------
+
+static const via6522_interface via_intf =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// riot6532_interface riot_intf
+//-------------------------------------------------
+
+static const riot6532_interface riot_intf =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// ACIA6850_INTERFACE( acia_intf )
+//-------------------------------------------------
+
+static ACIA6850_INTERFACE( acia_intf )
+{
+ 0,
+ 0,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( interpod )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( interpod )
+ MCFG_CPU_ADD(R6502_TAG, M6502, 1000000)
+ MCFG_CPU_PROGRAM_MAP(interpod_mem)
+
+ MCFG_VIA6522_ADD(R6522_TAG, 1000000, via_intf)
+ MCFG_RIOT6532_ADD(R6532_TAG, 1000000, riot_intf)
+ MCFG_ACIA6850_ADD(MC6850_TAG, acia_intf)
+
+ MCFG_CBM_IEEE488_ADD(ieee488_intf, 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),
+ 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_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void interpod_device::device_config_complete()
+{
+ m_shortname = "interpod";
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void interpod_device::device_start()
+{
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void interpod_device::device_reset()
+{
+}
diff --git a/src/mess/machine/interpod.h b/src/mess/machine/interpod.h
new file mode 100644
index 00000000000..af0fb398aa0
--- /dev/null
+++ b/src/mess/machine/interpod.h
@@ -0,0 +1,84 @@
+/**********************************************************************
+
+ Oxford Computer Systems Interpod IEC to IEEE interface emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#pragma once
+
+#ifndef __INTERPOD__
+#define __INTERPOD__
+
+
+#include "emu.h"
+#include "cpu/m6502/m6502.h"
+#include "machine/6522via.h"
+#include "machine/6532riot.h"
+#include "machine/6850acia.h"
+#include "machine/c2031.h"
+#include "machine/c2040.h"
+#include "machine/c8280.h"
+#include "machine/d9060.h"
+#include "machine/cbmiec.h"
+#include "machine/cbmipt.h"
+#include "machine/ieee488.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();
+ virtual void device_config_complete();
+
+ required_device<cpu_device> m_maincpu;
+ required_device<via6522_device> m_via;
+ required_device<riot6532_device> m_riot;
+ required_device<acia6850_device> m_acia;
+ required_device<ieee488_device> m_ieee;
+};
+
+
+// device type definition
+extern const device_type INTERPOD;
+
+
+
+#endif
diff --git a/src/mess/machine/intv.c b/src/mess/machine/intv.c
new file mode 100644
index 00000000000..27dc0372d85
--- /dev/null
+++ b/src/mess/machine/intv.c
@@ -0,0 +1,853 @@
+#include "emu.h"
+#include "video/stic.h"
+#include "includes/intv.h"
+#include "cpu/cp1610/cp1610.h"
+#include "hashfile.h"
+
+#define INTELLIVOICE_MASK 0x02
+#define ECS_MASK 0x01
+
+
+
+WRITE16_MEMBER( intv_state::intvkbd_dualport16_w )
+{
+ unsigned char *RAM;
+
+ COMBINE_DATA(&m_intvkbd_dualport_ram[offset]);
+
+ /* copy the LSB over to the 6502 OP RAM, in case they are opcodes */
+ RAM = memregion("keyboard")->base();
+ RAM[offset] = (UINT8) (data >> 0);
+}
+
+READ8_MEMBER( intv_state::intvkbd_dualport8_lsb_r )
+{
+ return (UINT8) (m_intvkbd_dualport_ram[offset] >> 0);
+}
+
+WRITE8_MEMBER( intv_state::intvkbd_dualport8_lsb_w )
+{
+ unsigned char *RAM;
+
+ m_intvkbd_dualport_ram[offset] &= ~0x00FF;
+ m_intvkbd_dualport_ram[offset] |= ((UINT16) data) << 0;
+
+ /* copy over to the 6502 OP RAM, in case they are opcodes */
+ RAM = memregion("keyboard")->base();
+ RAM[offset] = data;
+}
+
+
+
+READ8_MEMBER( intv_state::intvkbd_dualport8_msb_r )
+{
+ unsigned char rv;
+
+ if (offset < 0x100)
+ {
+ switch (offset)
+ {
+ case 0x000:
+ rv = ioport("TEST")->read() & 0x80;
+ logerror("TAPE: Read %02x from 0x40%02x - XOR Data?\n",rv,offset);
+ break;
+ case 0x001:
+ rv = (ioport("TEST")->read() & 0x40) << 1;
+ logerror("TAPE: Read %02x from 0x40%02x - Sense 1?\n",rv,offset);
+ break;
+ case 0x002:
+ rv = (ioport("TEST")->read() & 0x20) << 2;
+ logerror("TAPE: Read %02x from 0x40%02x - Sense 2?\n",rv,offset);
+ break;
+ case 0x003:
+ rv = (ioport("TEST")->read() & 0x10) << 3;
+ logerror("TAPE: Read %02x from 0x40%02x - Tape Present\n",rv,offset);
+ break;
+ case 0x004:
+ rv = (ioport("TEST")->read() & 0x08) << 4;
+ logerror("TAPE: Read %02x from 0x40%02x - Comp (339/1)\n",rv,offset);
+ break;
+ case 0x005:
+ rv = (ioport("TEST")->read() & 0x04) << 5;
+ logerror("TAPE: Read %02x from 0x40%02x - Clocked Comp (339/13)\n",rv,offset);
+ break;
+ case 0x006:
+ if (m_sr1_int_pending)
+ rv = 0x00;
+ else
+ rv = 0x80;
+ logerror("TAPE: Read %02x from 0x40%02x - SR1 Int Pending\n",rv,offset);
+ break;
+ case 0x007:
+ if (m_tape_int_pending)
+ rv = 0x00;
+ else
+ rv = 0x80;
+ logerror("TAPE: Read %02x from 0x40%02x - Tape? Int Pending\n",rv,offset);
+ break;
+ case 0x060: /* Keyboard Read */
+ rv = 0xff;
+ if (m_intvkbd_keyboard_col == 0)
+ rv = ioport("ROW0")->read();
+ if (m_intvkbd_keyboard_col == 1)
+ rv = ioport("ROW1")->read();
+ if (m_intvkbd_keyboard_col == 2)
+ rv = ioport("ROW2")->read();
+ if (m_intvkbd_keyboard_col == 3)
+ rv = ioport("ROW3")->read();
+ if (m_intvkbd_keyboard_col == 4)
+ rv = ioport("ROW4")->read();
+ if (m_intvkbd_keyboard_col == 5)
+ rv = ioport("ROW5")->read();
+ if (m_intvkbd_keyboard_col == 6)
+ rv = ioport("ROW6")->read();
+ if (m_intvkbd_keyboard_col == 7)
+ rv = ioport("ROW7")->read();
+ if (m_intvkbd_keyboard_col == 8)
+ rv = ioport("ROW8")->read();
+ if (m_intvkbd_keyboard_col == 9)
+ rv = ioport("ROW9")->read();
+ break;
+ case 0x80:
+ rv = 0x00;
+ logerror("TAPE: Read %02x from 0x40%02x, clear tape int pending\n",rv,offset);
+ m_tape_int_pending = 0;
+ break;
+ case 0xa0:
+ rv = 0x00;
+ logerror("TAPE: Read %02x from 0x40%02x, clear SR1 int pending\n",rv,offset);
+ m_sr1_int_pending = 0;
+ 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:
+ /* TMS9927 regs */
+ rv = intvkbd_tms9927_r(space, offset-0xc0);
+ break;
+ default:
+ rv = (m_intvkbd_dualport_ram[offset]&0x0300)>>8;
+ logerror("Unknown read %02x from 0x40%02x\n",rv,offset);
+ break;
+ }
+ return rv;
+ }
+ else
+ return (m_intvkbd_dualport_ram[offset]&0x0300)>>8;
+}
+
+static const char *const tape_motor_mode_desc[8] =
+{
+ "IDLE", "IDLE", "IDLE", "IDLE",
+ "EJECT", "PLAY/RECORD", "REWIND", "FF"
+};
+
+WRITE8_MEMBER( intv_state::intvkbd_dualport8_msb_w )
+{
+ unsigned int mask;
+
+ if (offset < 0x100)
+ {
+ switch (offset)
+ {
+ case 0x020:
+ m_tape_motor_mode &= 3;
+ if (data & 1)
+ m_tape_motor_mode |= 4;
+ logerror("TAPE: Motor Mode: %s\n",tape_motor_mode_desc[m_tape_motor_mode]);
+ break;
+ case 0x021:
+ m_tape_motor_mode &= 5;
+ if (data & 1)
+ m_tape_motor_mode |= 2;
+ logerror("TAPE: Motor Mode: %s\n",tape_motor_mode_desc[m_tape_motor_mode]);
+ break;
+ case 0x022:
+ m_tape_motor_mode &= 6;
+ if (data & 1)
+ m_tape_motor_mode |= 1;
+ logerror("TAPE: Motor Mode: %s\n",tape_motor_mode_desc[m_tape_motor_mode]);
+ break;
+ case 0x023:
+ case 0x024:
+ case 0x025:
+ case 0x026:
+ case 0x027:
+ m_tape_unknown_write[offset - 0x23] = (data & 1);
+ break;
+ case 0x040:
+ m_tape_unknown_write[5] = (data & 1);
+ break;
+ case 0x041:
+ if (data & 1)
+ logerror("TAPE: Tape Interrupts Enabled\n");
+ else
+ logerror("TAPE: Tape Interrupts Disabled\n");
+ m_tape_interrupts_enabled = (data & 1);
+ break;
+ case 0x042:
+ if (data & 1)
+ logerror("TAPE: Cart Bus Interrupts Disabled\n");
+ else
+ logerror("TAPE: Cart Bus Interrupts Enabled\n");
+ break;
+ case 0x043:
+ if (data & 0x01)
+ m_intvkbd_text_blanked = 0;
+ else
+ m_intvkbd_text_blanked = 1;
+ break;
+ case 0x044:
+ m_intvkbd_keyboard_col &= 0x0e;
+ m_intvkbd_keyboard_col |= (data&0x01);
+ break;
+ case 0x045:
+ m_intvkbd_keyboard_col &= 0x0d;
+ m_intvkbd_keyboard_col |= ((data&0x01)<<1);
+ break;
+ case 0x046:
+ m_intvkbd_keyboard_col &= 0x0b;
+ m_intvkbd_keyboard_col |= ((data&0x01)<<2);
+ break;
+ case 0x047:
+ m_intvkbd_keyboard_col &= 0x07;
+ m_intvkbd_keyboard_col |= ((data&0x01)<<3);
+ break;
+ case 0x80:
+ logerror("TAPE: Write to 0x40%02x, clear tape int pending\n",offset);
+ m_tape_int_pending = 0;
+ break;
+ case 0xa0:
+ logerror("TAPE: Write to 0x40%02x, clear SR1 int pending\n",offset);
+ m_sr1_int_pending = 0;
+ 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:
+ /* TMS9927 regs */
+ intvkbd_tms9927_w(space, offset-0xc0, data);
+ break;
+ default:
+ logerror("%04X: Unknown write %02x to 0x40%02x\n",cpu_get_pc(&space.device()),data,offset);
+ break;
+ }
+ }
+ else
+ {
+ mask = m_intvkbd_dualport_ram[offset] & 0x00ff;
+ m_intvkbd_dualport_ram[offset] = mask | ((data<<8)&0x0300);
+ }
+}
+
+READ16_MEMBER( intv_state::intv_gram_r )
+{
+ //logerror("read: %d = GRAM(%d)\n",state->m_gram[offset],offset);
+ if (m_bus_copy_mode || !m_stic_handshake)
+ {
+ return (int)m_gram[offset];
+ }
+ else {return offset;}
+
+}
+
+WRITE16_MEMBER( intv_state::intv_gram_w )
+{
+ data &= 0xFF;
+ if(m_bus_copy_mode || !m_stic_handshake)
+ {
+ m_gram[offset] = data;
+ m_gramdirtybytes[offset] = 1;
+ m_gramdirty = 1;
+ }
+}
+
+
+READ16_MEMBER( intv_state::intv_ram8_r )
+{
+ //logerror("%x = ram8_r(%x)\n",state->m_ram8[offset],offset);
+ return (int)m_ram8[offset];
+}
+
+WRITE16_MEMBER( intv_state::intv_ram8_w )
+{
+ //logerror("ram8_w(%x) = %x\n",offset,data);
+ m_ram8[offset] = data&0xff;
+}
+
+READ16_MEMBER( intv_state::intv_ecs_ram8_r )
+{
+ return (int)m_ecs_ram8[offset];
+}
+
+WRITE16_MEMBER( intv_state::intv_ecs_ram8_w )
+{
+ m_ecs_ram8[offset] = data&0xff;
+}
+
+READ16_MEMBER( intv_state::intv_cart_ram8_r )
+{
+ return (int)m_cart_ram8[offset];
+}
+WRITE16_MEMBER( intv_state::intv_cart_ram8_w )
+{
+ m_cart_ram8[offset] = data&0xff;
+}
+
+READ16_MEMBER( intv_state::intv_ram16_r )
+{
+ //logerror("%x = ram16_r(%x)\n",state->m_ram16[offset],offset);
+ return (int)m_ram16[offset];
+}
+
+WRITE16_MEMBER( intv_state::intv_ram16_w )
+{
+ //logerror("%g: WRITING TO GRAM offset = %d\n",machine.time(),offset);
+ //logerror("ram16_w(%x) = %x\n",offset,data);
+ m_ram16[offset] = data&0xffff;
+}
+
+// ECS and Wsmlb bank switching register handlers
+WRITE16_MEMBER( intv_state::ecs_bank1_page_select )
+{
+ if (offset == 0xFFF)
+ {
+ if (data == 0x2A50)
+ {
+ membank("bank1")->set_base(machine().root_device().memregion("maincpu")->base() + (0x2000 << 1));
+ }
+ else if (data == 0x2A51)
+ {
+ membank("bank1")->set_base(machine().root_device().memregion("ecs_rom")->base() + (0x2000 << 1));
+ }
+ }
+}
+
+WRITE16_MEMBER( intv_state::ecs_bank2_page_select )
+{
+ if (offset == 0xFFF)
+ {
+ if (data == 0x7A50)
+ {
+ membank("bank2")->set_base(machine().root_device().memregion("ecs_rom")->base() + (0x7000 << 1)); // ECS ROM at 0x7000 is on page 1
+ }
+ else if (data == 0x7A51 )
+ {
+ membank("bank2")->set_base(machine().root_device().memregion("maincpu")->base() + (0x7000 << 1));
+ }
+ }
+}
+
+WRITE16_MEMBER( intv_state::ecs_bank3_page_select )
+{
+ if (offset == 0xFFF)
+ {
+ if (data == 0xEA50)
+ {
+ membank("bank3")->set_base(machine().root_device().memregion("maincpu")->base() + (0xE000 << 1));
+ }
+ else if (data == 0xEA51)
+ {
+ membank("bank3")->set_base(machine().root_device().memregion("ecs_rom")->base() + (0xE000 << 1));
+ }
+ }
+}
+
+WRITE16_MEMBER( intv_state::wsmlb_bank_page_select )
+{
+ logerror("offset %x data %x\n",offset,data);
+ if (offset == 0xFFF)
+ {
+ if (data == 0xFA50)
+ {
+ membank("bank4")->set_base(machine().root_device().memregion("maincpu")->base() + (0xF000 << 1));
+ }
+ else if (data == 0xFA51)
+ {
+ membank("bank4")->set_base(machine().root_device().memregion("ecs_rom")->base() + (0xF000 << 1));
+ }
+ }
+}
+
+static int intv_load_rom_file(device_image_interface &image)
+{
+ int i,j;
+
+ UINT8 temp;
+ UINT8 num_segments;
+ UINT8 start_seg;
+ UINT8 end_seg;
+
+ UINT32 current_address;
+ UINT32 end_address;
+
+ UINT8 high_byte;
+ UINT8 low_byte;
+
+ UINT8 *memory = image.device().machine().root_device().memregion("maincpu")->base();
+ intv_state *state = image.device().machine().driver_data<intv_state>();
+ address_space *program = image.device().machine().device("maincpu")->memory().space(AS_PROGRAM);
+ const char *filetype = image.filetype();
+
+ /* if it is in .rom format, we enter here */
+ if (!mame_stricmp (filetype, "rom"))
+ {
+ image.fread( &temp, 1); /* header */
+ if (temp != 0xa8)
+ {
+ return IMAGE_INIT_FAIL;
+ }
+
+ image.fread( &num_segments, 1);
+
+ image.fread( &temp, 1);
+ if (temp != (num_segments ^ 0xff))
+ {
+ return IMAGE_INIT_FAIL;
+ }
+
+ for (i = 0; i < num_segments; i++)
+ {
+ image.fread( &start_seg, 1);
+ current_address = start_seg * 0x100;
+
+ image.fread( &end_seg, 1);
+ end_address = end_seg * 0x100 + 0xff;
+
+ while (current_address <= end_address)
+ {
+ image.fread( &low_byte, 1);
+ memory[(current_address << 1) + 1] = low_byte;
+ image.fread( &high_byte, 1);
+ memory[current_address << 1] = high_byte;
+ current_address++;
+ }
+
+ /* Here we should calculate and compare the CRC16... */
+ image.fread( &temp, 1);
+ image.fread( &temp, 1);
+ }
+
+ /* Access tables and fine address restriction tables are not supported ATM */
+ for (i = 0; i < (16 + 32 + 2); i++)
+ {
+ image.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;
+ const char *extrainfo = hashfile_extrainfo(image);
+ if (!extrainfo)
+ {
+ /* If no extrainfo, we assume a single 0x2000 chunk at 0x5000 */
+ for (i = 0; i < 0x2000; i++ )
+ {
+ image.fread( &low_byte, 1);
+ memory[((0x5000 + i) << 1) + 1] = low_byte;
+ image.fread( &high_byte, 1);
+ memory[(0x5000 + i) << 1] = high_byte;
+ }
+ }
+ else
+ {
+ sscanf(extrainfo,"%d %d %d %d %d %d %d", &mapper, &rom[0], &rom[1], &rom[2],
+ &rom[3], &ram, &extra);
+
+// logerror("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;
+
+ program->install_readwrite_handler(start, start + size,
+ read16_delegate( FUNC( intv_state::intv_cart_ram8_r ), state),
+ write16_delegate( FUNC( intv_state::intv_cart_ram8_w ), state));
+ }
+ /* For now intellivoice always active
+ if (extra & INTELLIVOICE_MASK)
+ {
+ // tbd
+ }
+ */
+
+ if (extra & ECS_MASK)
+ {
+ logerror("Requires ECS Module\n");
+ }
+
+ for (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 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 (i = 0; i < size; i++ )
+ {
+ image.fread( &low_byte, 1);
+ memory[((start + i) << 1) + 1] = low_byte;
+ image.fread( &high_byte, 1);
+ memory[(start + i) << 1] = high_byte;
+ }
+ }
+ }
+
+ return IMAGE_INIT_PASS;
+ }
+}
+
+DEVICE_IMAGE_LOAD( intv_cart )
+{
+
+ if (image.software_entry() == NULL)
+ return intv_load_rom_file(image);
+ else
+ {
+ UINT16 offset[] = {0x4800, 0x5000, 0x6000, 0x7000, 0x9000, 0xa000, 0xc000, 0xd000, 0xf000};
+ const char* region_name[] = {"4800", "5000", "6000", "7000", "9000", "A000", "C000", "D000", "F000"};
+ UINT8 *memory = image.device().machine().root_device().memregion("maincpu")->base();
+ intv_state *state = image.device().machine().driver_data<intv_state>();
+ address_space *program = image.device().machine().device("maincpu")->memory().space(AS_PROGRAM);
+
+ UINT32 size=0;
+ UINT16 address = 0;
+ UINT8 *region;
+ for(int i = 0; i < 9; i++)
+ {
+ address = offset[i];
+ size = image.get_software_region_length(region_name[i]);
+ if (size)
+ {
+ region = image.get_software_region(region_name[i]);
+ for (int j = 0; j < (size>>1); j++)
+ {
+ memory[((address + j) << 1) + 1] = region[2*j];
+ memory[(address + j) << 1] = region[2*j+1];
+ }
+ }
+ }
+ // deal with wsmlb paged rom
+
+ UINT8 *ecs_rom_region = image.device().machine().root_device().memregion("ecs_rom")->base();
+ size = image.get_software_region_length("F000_bank1");
+ if (size && ecs_rom_region) // only load if ecs is plugged in (should probably be done a different way)
+ {
+ region = image.get_software_region("F000_bank1");
+ for (int j = 0; j < (size>>1); j++)
+ {
+ ecs_rom_region[((address + j) << 1) + 1] = region[2*j];
+ ecs_rom_region[(address + j) << 1] = region[2*j+1];
+ }
+ }
+
+ // Cartridge 8bit ram support
+ size = image.get_software_region_length("D000_RAM8");
+ if (size)
+ {
+ program->install_readwrite_handler(0xD000, 0xD000 + size,
+ read16_delegate( FUNC( intv_state::intv_cart_ram8_r ), state),
+ write16_delegate( FUNC( intv_state::intv_cart_ram8_w ), state));
+ }
+
+ size = image.get_software_region_length("8800_RAM8");
+ if (size)
+ {
+ program->install_readwrite_handler(0x8800, 0x8800 + size,
+ read16_delegate( FUNC( intv_state::intv_cart_ram8_r ), state),
+ write16_delegate( FUNC( intv_state::intv_cart_ram8_w ), state));
+ }
+ return IMAGE_INIT_PASS;
+ }
+}
+
+#ifdef UNUSED_FUNCTION
+DRIVER_INIT_MEMBER(intv_state,intv)
+{
+}
+#endif
+
+/* Set Reset and INTR/INTRM Vector */
+MACHINE_RESET( intv )
+{
+ device_set_input_line_vector(machine.device("maincpu"), CP1610_RESET, 0x1000);
+
+ /* These are actually the same vector, and INTR is unused */
+ device_set_input_line_vector(machine.device("maincpu"), CP1610_INT_INTRM, 0x1004);
+ device_set_input_line_vector(machine.device("maincpu"), CP1610_INT_INTR, 0x1004);
+
+ /* Set initial PC */
+ cpu_set_reg(machine.device("maincpu"), CP1610_R7, 0x1000);
+
+ return;
+}
+
+MACHINE_RESET( intvecs )
+{
+ intv_state *state = machine.driver_data<intv_state>();
+ state->membank("bank1")->set_base(machine.root_device().memregion("maincpu")->base() + (0x2000 << 1));
+ state->membank("bank2")->set_base(machine.root_device().memregion("ecs_rom")->base() + (0x7000 << 1));
+ state->membank("bank3")->set_base(machine.root_device().memregion("maincpu")->base() + (0xE000 << 1));
+ state->membank("bank4")->set_base(machine.root_device().memregion("maincpu")->base() + (0xF000 << 1));
+
+ device_set_input_line_vector(machine.device("maincpu"), CP1610_RESET, 0x1000);
+
+ /* These are actually the same vector, and INTR is unused */
+ device_set_input_line_vector(machine.device("maincpu"), CP1610_INT_INTRM, 0x1004);
+ device_set_input_line_vector(machine.device("maincpu"), CP1610_INT_INTR, 0x1004);
+
+ /* Set initial PC */
+ cpu_set_reg(machine.device("maincpu"), CP1610_R7, 0x1000);
+
+ return;
+}
+
+
+static TIMER_CALLBACK(intv_interrupt_complete)
+{
+ intv_state *state = machine.driver_data<intv_state>();
+ cputag_set_input_line(machine, "maincpu", CP1610_INT_INTRM, CLEAR_LINE);
+ state->m_bus_copy_mode = 0;
+}
+
+static TIMER_CALLBACK(intv_btb_fill)
+{
+ intv_state *state = machine.driver_data<intv_state>();
+ UINT8 column;
+ UINT8 row = state->m_backtab_row;
+ //device_adjust_icount(machine.device("maincpu"), -STIC_ROW_FETCH);
+ for(column=0; column < STIC_BACKTAB_WIDTH; column++)
+ {
+ state->m_backtab_buffer[row][column] = state->m_ram16[column + row * STIC_BACKTAB_WIDTH];
+ }
+
+ state->m_backtab_row += 1;
+}
+
+INTERRUPT_GEN( intv_interrupt )
+{
+ intv_state *state = device->machine().driver_data<intv_state>();
+ cputag_set_input_line(device->machine(), "maincpu", CP1610_INT_INTRM, ASSERT_LINE);
+ state->m_sr1_int_pending = 1;
+ state->m_bus_copy_mode = 1;
+ state->m_backtab_row = 0;
+ UINT8 row;
+ device_adjust_icount(device->machine().device("maincpu"), -(12*STIC_ROW_BUSRQ+STIC_FRAME_BUSRQ)); // Account for stic cycle stealing
+ device->machine().scheduler().timer_set(device->machine().device<cpu_device>("maincpu")
+ ->cycles_to_attotime(STIC_VBLANK_END), FUNC(intv_interrupt_complete));
+ for (row=0; row < STIC_BACKTAB_HEIGHT; row++)
+ {
+ device->machine().scheduler().timer_set(device->machine().device<cpu_device>("maincpu")
+ ->cycles_to_attotime(STIC_FIRST_FETCH-STIC_FRAME_BUSRQ+STIC_CYCLES_PER_SCANLINE*STIC_Y_SCALE*state->m_row_delay + (STIC_CYCLES_PER_SCANLINE*STIC_Y_SCALE*STIC_CARD_HEIGHT - STIC_ROW_BUSRQ)*row), FUNC(intv_btb_fill));
+ }
+
+ if (state->m_row_delay == 0)
+ {
+ device_adjust_icount(device->machine().device("maincpu"), -STIC_ROW_BUSRQ); // extra row fetch occurs if vertical delay == 0
+ }
+
+ intv_stic_screenrefresh(device->machine());
+}
+
+/* hand 0 == left, 1 == right, 2 == ECS hand controller 1, 3 == ECS hand controller 2 */
+UINT8 intv_control_r(address_space *space, int hand)
+{
+ static const char* const keypad_name[] = { "KEYPAD1", "KEYPAD2", "KEYPAD3", "KEYPAD4" };
+ static const UINT8 keypad_table[] =
+ {
+ 0xFF, 0x3F, 0x9F, 0x5F, 0xD7, 0xB7, 0x77, 0xDB,
+ 0xBB, 0x7B, 0xDD, 0xBD, 0x7D, 0xDE, 0xBE, 0x7E
+ };
+
+ static const char* const disc_name[] = { "DISC1", "DISC2", "DISC3", "DISC4" };
+ static const UINT8 disc_table[] =
+ {
+ 0xF3, 0xE3, 0xE7, 0xF7, 0xF6, 0xE6, 0xEE, 0xFE,
+ 0xFC, 0xEC, 0xED, 0xFD, 0xF9, 0xE9, 0xEB, 0xFB
+ };
+
+ static const char* const discx_name[] = { "DISCX1", "DISCX2", "DISCX3", "DISCX4" };
+ static const char* const discy_name[] = { "DISCY1", "DISCY2", "DISKY3", "DISCY4" };
+ 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 rv = 0xFF;
+
+ /* keypad */
+ x = space->machine().root_device().ioport(keypad_name[hand])->read();
+ for (y = 0; y < 16; y++)
+ {
+ if (x & (1 << y))
+ {
+ rv &= keypad_table[y];
+ }
+ }
+
+ switch ((space->machine().root_device().ioport("OPTIONS")->read() >> hand) & 1)
+ {
+ case 0: /* disc == digital */
+ default:
+
+ x = space->machine().root_device().ioport(disc_name[hand])->read();
+ for (y = 0; y < 16; y++)
+ {
+ if (x & (1 << y))
+ {
+ rv &= disc_table[y];
+ }
+ }
+ break;
+
+ case 1: /* disc == _fake_ analog */
+
+ x = space->machine().root_device().ioport(discx_name[hand])->read();
+ y = space->machine().root_device().ioport(discy_name[hand])->read();
+ rv &= discyx_table[y / 32][x / 32];
+ }
+
+ return rv;
+}
+
+READ8_MEMBER( intv_state::intv_left_control_r )
+{
+ return intv_control_r(&space, 0);
+}
+
+READ8_MEMBER( intv_state::intv_right_control_r )
+{
+ return intv_control_r(&space, 1);
+}
+
+READ8_MEMBER( intv_state::intv_ecs_porta_r )
+{
+ if (ioport("ECS_CNTRLSEL")->read() == 0)
+ return intv_control_r(&space, 2);
+ else
+ return 0xff; // not sure what to return here, maybe it should be last output?
+}
+
+READ8_MEMBER( intv_state::intv_ecs_portb_r )
+{
+ switch (ioport("ECS_CNTRLSEL")->read())
+ {
+ case 0x00: // hand controller
+ {
+ return intv_control_r(&space, 3);
+ }
+ case 0x01: // synthesizer keyboard
+ {
+ static const char* const ecs_synth_rows[] = { "ECS_SYNTH_ROW0", "ECS_SYNTH_ROW1", "ECS_SYNTH_ROW2", "ECS_SYNTH_ROW3", "ECS_SYNTH_ROW4", "ECS_SYNTH_ROW5", "ECS_SYNTH_ROW6" };
+ UINT8 rv = 0xFF;
+ // return correct result if more than one bit of 0xFE is set
+ for (int i=0; i<7; i++)
+ {
+ if (m_ecs_psg_porta & (1<<i))
+ rv &= ioport(ecs_synth_rows[i])->read();
+ }
+ return rv;
+ }
+ case 0x02: // ecs keyboard
+ {
+ static const char* const ecs_keyboard_rows[] = { "ECS_ROW0", "ECS_ROW1", "ECS_ROW2", "ECS_ROW3", "ECS_ROW4", "ECS_ROW5", "ECS_ROW6" };
+ UINT8 rv = 0xFF;
+ // return correct result if more than one bit of 0xFE is set
+ for (int i=0; i<7; i++)
+ {
+ if (m_ecs_psg_porta & (1<<i))
+ rv &= ioport(ecs_keyboard_rows[i])->read();
+ }
+ return rv;
+ }
+ default:
+ return 0xff;
+ }
+}
+
+WRITE8_MEMBER( intv_state::intv_ecs_porta_w )
+{
+ m_ecs_psg_porta = (~data) & 0xFF;
+}
+
+/* Intellivision console + keyboard component */
+
+DEVICE_IMAGE_LOAD( intvkbd_cart )
+{
+ if (strcmp(image.device().tag(),":cart1") == 0) /* Legacy cartridge slot */
+ {
+ /* First, initialize these as empty so that the intellivision
+ * will think that the playcable is not attached */
+ UINT8 *memory = image.device().machine().root_device().memregion("maincpu")->base();
+
+ /* assume playcable is absent */
+ memory[0x4800 << 1] = 0xff;
+ memory[(0x4800 << 1) + 1] = 0xff;
+
+ intv_load_rom_file(image);
+ }
+
+ if (strcmp(image.device().tag(),":cart2") == 0) /* Keyboard component cartridge slot */
+ {
+ UINT8 *memory = image.device().machine().root_device().memregion("keyboard")->base();
+
+ /* Assume an 8K cart, like BASIC */
+ image.fread( &memory[0xe000], 0x2000);
+ }
+
+ return IMAGE_INIT_PASS;
+
+}
diff --git a/src/mess/machine/iq151_disc2.c b/src/mess/machine/iq151_disc2.c
new file mode 100644
index 00000000000..ebc3f6a364f
--- /dev/null
+++ b/src/mess/machine/iq151_disc2.c
@@ -0,0 +1,149 @@
+/***************************************************************************
+
+ IQ151 Disc2 cartridge emulation
+
+***************************************************************************/
+
+#include "emu.h"
+#include "iq151_disc2.h"
+
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+static LEGACY_FLOPPY_OPTIONS_START( iq151_disc2 )
+ LEGACY_FLOPPY_OPTION( iq151_disk, "iqd", "IQ-151 disk image", basicdsk_identify_default, basicdsk_construct_default, NULL,
+ HEADS([1])
+ TRACKS([77])
+ SECTORS([26])
+ SECTOR_LENGTH([128])
+ FIRST_SECTOR_ID([1]))
+LEGACY_FLOPPY_OPTIONS_END
+
+static const floppy_interface iq151_disc2_intf =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ FLOPPY_STANDARD_8_SSSD,
+ LEGACY_FLOPPY_OPTIONS_NAME(iq151_disc2),
+ "floppy_8",
+ NULL
+};
+
+static const upd765_interface iq151_disc2_fdc_intf =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ NULL,
+ UPD765_RDY_PIN_NOT_CONNECTED,
+ { NULL, FLOPPY_0, FLOPPY_1, NULL }
+};
+
+static MACHINE_CONFIG_FRAGMENT( iq151_disc2 )
+ MCFG_UPD72065_ADD("fdc", iq151_disc2_fdc_intf)
+ MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(iq151_disc2_intf)
+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<iq151_disc2_device>;
+
+//**************************************************************************
+// 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),
+ 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)
+{
+ if (offset == 0xaa)
+ data = upd765_status_r(m_fdc, 0);
+ else if (offset == 0xab)
+ data = upd765_data_r(m_fdc, 0);
+}
+
+//-------------------------------------------------
+// IO write
+//-------------------------------------------------
+
+void iq151_disc2_device::io_write(offs_t offset, UINT8 data)
+{
+ if (offset == 0xab)
+ upd765_data_w(m_fdc, 0, data);
+ else if (offset == 0xac)
+ m_rom_enabled = (data == 0x01);
+}
+
diff --git a/src/mess/machine/iq151_disc2.h b/src/mess/machine/iq151_disc2.h
new file mode 100644
index 00000000000..524a469775e
--- /dev/null
+++ b/src/mess/machine/iq151_disc2.h
@@ -0,0 +1,51 @@
+#pragma once
+
+#ifndef __IQ151_DISC2_H__
+#define __IQ151_DISC2_H__
+
+#include "emu.h"
+#include "machine/iq151cart.h"
+#include "machine/upd765.h"
+#include "formats/basicdsk.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;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "iq151_disc2"; }
+
+ // 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<device_t> 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/mess/machine/iq151_minigraf.c b/src/mess/machine/iq151_minigraf.c
new file mode 100644
index 00000000000..1a5e33aad6d
--- /dev/null
+++ b/src/mess/machine/iq151_minigraf.c
@@ -0,0 +1,165 @@
+/***************************************************************************
+
+ IQ151 Aritma Minigraf 0507 module emulation
+
+***************************************************************************/
+
+#include "emu.h"
+#include "iq151_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<iq151_minigraf_device>;
+
+//**************************************************************************
+// 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),
+ 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_WHITE, RGB_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/mess/machine/iq151_minigraf.h b/src/mess/machine/iq151_minigraf.h
new file mode 100644
index 00000000000..81d11738224
--- /dev/null
+++ b/src/mess/machine/iq151_minigraf.h
@@ -0,0 +1,55 @@
+#pragma once
+
+#ifndef __IQ151_MINIGRAF_H__
+#define __IQ151_MINIGRAF_H__
+
+#include "emu.h"
+#include "machine/iq151cart.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();
+ virtual void device_config_complete() { m_shortname = "iq151_minigraf"; }
+
+ // 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/mess/machine/iq151_ms151a.c b/src/mess/machine/iq151_ms151a.c
new file mode 100644
index 00000000000..6533ff93d17
--- /dev/null
+++ b/src/mess/machine/iq151_ms151a.c
@@ -0,0 +1,165 @@
+/***************************************************************************
+
+ IQ151 MS151A XY plotter module emulation
+
+***************************************************************************/
+
+#include "emu.h"
+#include "iq151_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<iq151_ms151a_device>;
+
+//**************************************************************************
+// 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),
+ 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_WHITE, RGB_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/mess/machine/iq151_ms151a.h b/src/mess/machine/iq151_ms151a.h
new file mode 100644
index 00000000000..2535a89d153
--- /dev/null
+++ b/src/mess/machine/iq151_ms151a.h
@@ -0,0 +1,55 @@
+#pragma once
+
+#ifndef __IQ151_MS151A_H__
+#define __IQ151_MS151A_H__
+
+#include "emu.h"
+#include "machine/iq151cart.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();
+ virtual void device_config_complete() { m_shortname = "iq151_ms151a"; }
+
+ // 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/mess/machine/iq151_rom.c b/src/mess/machine/iq151_rom.c
new file mode 100644
index 00000000000..350a11072a9
--- /dev/null
+++ b/src/mess/machine/iq151_rom.c
@@ -0,0 +1,227 @@
+/***************************************************************************
+
+ IQ151 rom cartridge emulation
+
+ Supported cart:
+ - BASIC6
+ - BASICG
+ - AMOS OS (3 cart)
+
+***************************************************************************/
+
+#include "emu.h"
+#include "iq151_rom.h"
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+ROM_START( iq151_rom )
+ ROM_REGION(0x4000, "rom", ROMREGION_ERASEFF)
+ROM_END
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type IQ151_BASIC6 = &device_creator<iq151_basic6_device>;
+const device_type IQ151_BASICG = &device_creator<iq151_basicg_device>;
+const device_type IQ151_AMOS1 = &device_creator<iq151_amos1_device>;
+const device_type IQ151_AMOS2 = &device_creator<iq151_amos2_device>;
+const device_type IQ151_AMOS3 = &device_creator<iq151_amos3_device>;
+
+//**************************************************************************
+// 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) :
+ device_t(mconfig, type, name, tag, owner, clock),
+ 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)
+{
+}
+
+
+//-------------------------------------------------
+// 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)
+{
+}
+
+/*-------------------------------------------------
+ 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),
+ 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),
+ 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),
+ 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/mess/machine/iq151_rom.h b/src/mess/machine/iq151_rom.h
new file mode 100644
index 00000000000..f2d50d18a21
--- /dev/null
+++ b/src/mess/machine/iq151_rom.h
@@ -0,0 +1,143 @@
+#pragma once
+
+#ifndef __IQ151_ROM_H__
+#define __IQ151_ROM_H__
+
+#include "emu.h"
+#include "machine/iq151cart.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);
+
+ // 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:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "iq151_basic6"; }
+
+ // 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:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "iq151_basicg"; }
+
+ // 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:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "iq151_amos1"; }
+
+ // 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:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "iq151_amos2"; }
+
+ // 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:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "iq151_amos3"; }
+
+ // 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/mess/machine/iq151_staper.c b/src/mess/machine/iq151_staper.c
new file mode 100644
index 00000000000..2c072c531eb
--- /dev/null
+++ b/src/mess/machine/iq151_staper.c
@@ -0,0 +1,149 @@
+/***************************************************************************
+
+ 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 "iq151_staper.h"
+
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+static I8255_INTERFACE( iq151_staper_ppi_intf )
+{
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, iq151_staper_device, ppi_porta_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, iq151_staper_device, ppi_portb_w),
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, iq151_staper_device, ppi_portc_w)
+};
+
+static MACHINE_CONFIG_FRAGMENT( iq151_staper )
+ MCFG_I8255A_ADD("ppi8255", iq151_staper_ppi_intf)
+
+ MCFG_PRINTER_ADD("printer")
+MACHINE_CONFIG_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type IQ151_STAPER = &device_creator<iq151_staper_device>;
+
+//**************************************************************************
+// 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),
+ 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/mess/machine/iq151_staper.h b/src/mess/machine/iq151_staper.h
new file mode 100644
index 00000000000..80f7dc62a78
--- /dev/null
+++ b/src/mess/machine/iq151_staper.h
@@ -0,0 +1,58 @@
+#pragma once
+
+#ifndef __IQ151_STAPER_H__
+#define __IQ151_STAPER_H__
+
+#include "emu.h"
+#include "machine/iq151cart.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_config_complete() { m_shortname = "iq151_staper"; }
+ 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<i8255_device> m_ppi;
+ required_device<printer_image_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/mess/machine/iq151cart.c b/src/mess/machine/iq151cart.c
new file mode 100644
index 00000000000..fd34a225f81
--- /dev/null
+++ b/src/mess/machine/iq151cart.c
@@ -0,0 +1,220 @@
+/*********************************************************************
+
+ IQ151 cartridge slot emulation
+
+*********************************************************************/
+
+#include "emu.h"
+#include "iq151cart.h"
+#include "emuopts.h"
+
+#define LOG 0
+
+
+/***************************************************************************
+ PARAMETERS
+***************************************************************************/
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type IQ151CART_SLOT = &device_creator<iq151cart_slot_device>;
+
+//**************************************************************************
+// 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),
+ device_slot_interface(mconfig, *this),
+ device_image_interface(mconfig, *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<device_iq151cart_interface *>(get_card_device());
+
+ // resolve callbacks
+ m_out_irq0_func.resolve(m_out_irq0_cb, *this);
+ m_out_irq1_func.resolve(m_out_irq1_cb, *this);
+ m_out_irq2_func.resolve(m_out_irq2_cb, *this);
+ m_out_irq3_func.resolve(m_out_irq3_cb, *this);
+ m_out_irq4_func.resolve(m_out_irq4_cb, *this);
+ m_out_drq_func.resolve(m_out_drq_cb, *this);
+
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void iq151cart_slot_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const iq151cart_interface *intf = reinterpret_cast<const iq151cart_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<iq151cart_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_irq0_cb, 0, sizeof(m_out_irq0_cb));
+ memset(&m_out_irq1_cb, 0, sizeof(m_out_irq1_cb));
+ memset(&m_out_irq2_cb, 0, sizeof(m_out_irq2_cb));
+ memset(&m_out_irq3_cb, 0, sizeof(m_out_irq3_cb));
+ memset(&m_out_irq4_cb, 0, sizeof(m_out_irq4_cb));
+ memset(&m_out_drq_cb, 0, sizeof(m_out_drq_cb));
+ }
+
+ // 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(char *swlist, char *swname, rom_entry *start_entry)
+{
+ load_software_part_region(this, swlist, swname, start_entry );
+ return TRUE;
+}
+
+/*-------------------------------------------------
+ get default card software
+-------------------------------------------------*/
+
+const char * iq151cart_slot_device::get_default_card_software(const machine_config &config, emu_options &options)
+{
+ return software_get_default_slot(config, options, this, NULL);
+}
diff --git a/src/mess/machine/iq151cart.h b/src/mess/machine/iq151cart.h
new file mode 100644
index 00000000000..4314d8240f1
--- /dev/null
+++ b/src/mess/machine/iq151cart.h
@@ -0,0 +1,147 @@
+/*********************************************************************
+
+ 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
+***************************************************************************/
+
+// ======================> iq151cart_interface
+
+struct iq151cart_interface
+{
+ 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
+
+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 iq151cart_interface,
+ 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();
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_config_complete();
+
+ // image-level overrides
+ virtual bool call_load();
+ virtual bool call_softlist_load(char *swlist, char *swname, 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 const char * get_default_card_software(const machine_config &config, emu_options &options);
+
+ // 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_resolved_write_line m_out_irq0_func;
+ devcb_resolved_write_line m_out_irq1_func;
+ devcb_resolved_write_line m_out_irq2_func;
+ devcb_resolved_write_line m_out_irq3_func;
+ devcb_resolved_write_line m_out_irq4_func;
+ devcb_resolved_write_line m_out_drq_func;
+
+ device_iq151cart_interface* m_cart;
+};
+
+
+// device type definition
+extern const device_type IQ151CART_SLOT;
+
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+#define MCFG_IQ151_CARTRIDGE_ADD(_tag,_config,_slot_intf,_def_slot,_def_inp) \
+ MCFG_DEVICE_ADD(_tag, IQ151CART_SLOT, 0) \
+ MCFG_DEVICE_CONFIG(_config) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false)
+
+#endif /* __IQ151CART_H__ */
diff --git a/src/mess/machine/irisha.c b/src/mess/machine/irisha.c
new file mode 100644
index 00000000000..3936dd21438
--- /dev/null
+++ b/src/mess/machine/irisha.c
@@ -0,0 +1,155 @@
+/***************************************************************************
+
+ Irisha machine driver by Miodrag Milanovic
+
+ 27/03/2008 Preliminary driver.
+
+****************************************************************************/
+
+
+#include "includes/irisha.h"
+
+
+/* Driver initialization */
+DRIVER_INIT_MEMBER(irisha_state,irisha)
+{
+ m_keyboard_mask = 0;
+}
+
+
+
+static TIMER_CALLBACK( irisha_key )
+{
+ irisha_state *state = machine.driver_data<irisha_state>();
+ state->m_keypressed = 1;
+ state->m_keyboard_cnt = 0;
+}
+
+MACHINE_START( irisha )
+{
+ machine.scheduler().timer_pulse(attotime::from_msec(30), FUNC(irisha_key));
+}
+
+MACHINE_RESET( irisha )
+{
+ irisha_state *state = machine.driver_data<irisha_state>();
+ state->m_keypressed = 0;
+}
+
+void irisha_state::update_speaker()
+{
+ int level = ((m_ppi_portc & 0x20) || (m_ppi_porta & 0x10) || !m_sg1_line) ? 1 : 0;
+
+ speaker_level_w(m_speaker, level);
+}
+
+static const char *const keynames[] = {
+ "LINE0", "LINE1", "LINE2", "LINE3",
+ "LINE4", "LINE5", "LINE6", "LINE7",
+ "LINE8", "LINE9"
+};
+
+READ8_MEMBER(irisha_state::irisha_8255_portb_r)
+{
+ if (m_keypressed==1) {
+ m_keypressed = 0;
+ return 0x80;
+ }
+
+ return 0x00;
+}
+
+READ8_MEMBER(irisha_state::irisha_8255_portc_r)
+{
+ logerror("irisha_8255_portc_r\n");
+ return 0;
+}
+
+READ8_MEMBER(irisha_state::irisha_keyboard_r)
+{
+ UINT8 keycode;
+ if (m_keyboard_cnt!=0 && m_keyboard_cnt<11) {
+ keycode = ioport(keynames[m_keyboard_cnt-1])->read() ^ 0xff;
+ } else {
+ keycode = 0xff;
+ }
+ m_keyboard_cnt++;
+ return keycode;
+}
+
+WRITE8_MEMBER(irisha_state::irisha_8255_porta_w)
+{
+ logerror("irisha_8255_porta_w %02x\n",data);
+
+ m_ppi_porta = data;
+
+ update_speaker();
+}
+
+WRITE8_MEMBER(irisha_state::irisha_8255_portb_w)
+{
+ logerror("irisha_8255_portb_w %02x\n",data);
+}
+
+WRITE8_MEMBER(irisha_state::irisha_8255_portc_w)
+{
+ //logerror("irisha_8255_portc_w %02x\n",data);
+
+ if (data & 0x40)
+ pit8253_gate2_w(m_pit, (BIT(m_ppi_porta,5) && !BIT(data,5)) ? 1 : 0);
+
+ m_ppi_portc = data;
+
+ update_speaker();
+}
+
+WRITE_LINE_MEMBER(irisha_state::speaker_w)
+{
+ m_sg1_line = state;
+ update_speaker();
+}
+
+I8255A_INTERFACE( irisha_ppi8255_interface )
+{
+ DEVCB_NULL,
+ DEVCB_DRIVER_MEMBER(irisha_state, irisha_8255_porta_w),
+ DEVCB_DRIVER_MEMBER(irisha_state, irisha_8255_portb_r),
+ DEVCB_DRIVER_MEMBER(irisha_state, irisha_8255_portb_w),
+ DEVCB_DRIVER_MEMBER(irisha_state, irisha_8255_portc_r),
+ DEVCB_DRIVER_MEMBER(irisha_state, irisha_8255_portc_w),
+};
+
+static WRITE_LINE_DEVICE_HANDLER( irisha_pic_set_int_line )
+{
+ cputag_set_input_line(device->machine(), "maincpu", 0, state ? HOLD_LINE : CLEAR_LINE);
+}
+
+const struct pic8259_interface irisha_pic8259_config =
+{
+ DEVCB_LINE(irisha_pic_set_int_line),
+ DEVCB_LINE_VCC,
+ DEVCB_NULL
+};
+
+const struct pit8253_config irisha_pit8253_intf =
+{
+ {
+ {
+ XTAL_16MHz / 9,
+ DEVCB_LINE_VCC,
+ DEVCB_DEVICE_LINE("pic8259", pic8259_ir0_w)
+ },
+ {
+ XTAL_16MHz / 9 / 8 / 8,
+ DEVCB_LINE_VCC,
+ DEVCB_NULL // UART transmit/receive clock
+ },
+ {
+ XTAL_16MHz / 9,
+ DEVCB_NULL,
+ DEVCB_DRIVER_LINE_MEMBER(irisha_state, speaker_w)
+ }
+ }
+};
+
+
diff --git a/src/mess/machine/isa.c b/src/mess/machine/isa.c
new file mode 100644
index 00000000000..23c9af388d3
--- /dev/null
+++ b/src/mess/machine/isa.c
@@ -0,0 +1,636 @@
+/***************************************************************************
+
+ ISA bus device
+
+***************************************************************************/
+
+#include "emu.h"
+#include "emuopts.h"
+#include "machine/isa.h"
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_SLOT = &device_creator<isa8_slot_device>;
+
+//**************************************************************************
+// 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),
+ 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) :
+ device_t(mconfig, type, name, tag, owner, clock),
+ 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<isa8_slot_device &>(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<device_isa8_card_interface *>(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<isa16_slot_device>;
+
+//**************************************************************************
+// 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)
+{
+}
+
+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<isa16_slot_device &>(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<device_isa8_card_interface *>(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<isa8_device>;
+
+void isa8_device::static_set_cputag(device_t &device, const char *tag)
+{
+ isa8_device &isa = downcast<isa8_device &>(device);
+ isa.m_cputag = tag;
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void isa8_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const isa8bus_interface *intf = reinterpret_cast<const isa8bus_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<isa8bus_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_irq2_cb, 0, sizeof(m_out_irq2_cb));
+ memset(&m_out_irq3_cb, 0, sizeof(m_out_irq3_cb));
+ memset(&m_out_irq4_cb, 0, sizeof(m_out_irq4_cb));
+ memset(&m_out_irq5_cb, 0, sizeof(m_out_irq5_cb));
+ memset(&m_out_irq6_cb, 0, sizeof(m_out_irq6_cb));
+ memset(&m_out_irq7_cb, 0, sizeof(m_out_irq7_cb));
+ memset(&m_out_drq1_cb, 0, sizeof(m_out_drq1_cb));
+ memset(&m_out_drq2_cb, 0, sizeof(m_out_drq2_cb));
+ memset(&m_out_drq3_cb, 0, sizeof(m_out_drq3_cb));
+ }
+ m_maincpu = mconfig().device(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)
+{
+ for(int i=0;i<8;i++)
+ {
+ m_dma_device[i] = NULL;
+ m_dma_eop[i] = false;
+ }
+ m_nmi_enabled = false;
+}
+
+isa8_device::isa8_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)
+{
+ for(int i=0;i<8;i++)
+ {
+ m_dma_device[i] = NULL;
+ m_dma_eop[i] = false;
+ }
+ m_nmi_enabled = false;
+}
+
+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_out_irq2_func.resolve(m_out_irq2_cb, *this);
+ m_out_irq3_func.resolve(m_out_irq3_cb, *this);
+ m_out_irq4_func.resolve(m_out_irq4_cb, *this);
+ m_out_irq5_func.resolve(m_out_irq5_cb, *this);
+ m_out_irq6_func.resolve(m_out_irq6_cb, *this);
+ m_out_irq7_func.resolve(m_out_irq7_cb, *this);
+ m_out_drq1_func.resolve(m_out_drq1_cb, *this);
+ m_out_drq2_func.resolve(m_out_drq2_cb, *this);
+ m_out_drq3_func.resolve(m_out_drq3_cb, *this);
+}
+
+//-------------------------------------------------
+// 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_space_func rhandler, const char* rhandler_name, write8_space_func whandler, const char *whandler_name)
+{
+ int buswidth = m_maincpu->memory().space_config(spacenum)->m_databus_width;
+ switch(buswidth)
+ {
+ case 8:
+ m_maincpu->memory().space(spacenum)->install_legacy_readwrite_handler(start, end, mask, mirror, rhandler, rhandler_name, whandler, whandler_name,0);
+ break;
+ case 16:
+ m_maincpu->memory().space(spacenum)->install_legacy_readwrite_handler(start, end, mask, mirror, rhandler, rhandler_name, whandler, whandler_name,0xffff);
+ break;
+ case 32:
+ if ((start % 4) == 0) {
+ if ((end-start)==1) {
+ m_maincpu->memory().space(spacenum)->install_legacy_readwrite_handler(start, end+2, mask, mirror, rhandler, rhandler_name, whandler, whandler_name,0x0000ffff);
+ } else {
+ m_maincpu->memory().space(spacenum)->install_legacy_readwrite_handler(start, end, mask, mirror, rhandler, rhandler_name, whandler, whandler_name,0xffffffff);
+ }
+ } else {
+ // we handle just misalligned by 2
+ m_maincpu->memory().space(spacenum)->install_legacy_readwrite_handler(start-2, end, mask, mirror, rhandler, rhandler_name, whandler, whandler_name,0xffff0000);
+ }
+ break;
+ default:
+ fatalerror("ISA8: Bus width %d not supported", buswidth);
+ break;
+ }
+}
+
+
+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 = m_maincpu->memory().space_config(spacenum)->m_databus_width;
+ switch(buswidth)
+ {
+ case 8:
+ m_maincpu->memory().space(spacenum)->install_readwrite_handler(start, end, mask, mirror, rhandler, whandler, 0);
+ break;
+ case 16:
+ m_maincpu->memory().space(spacenum)->install_readwrite_handler(start, end, mask, mirror, rhandler, whandler, 0xffff);
+ break;
+ case 32:
+ if ((start % 4) == 0) {
+ if ((end-start)==1) {
+ m_maincpu->memory().space(spacenum)->install_readwrite_handler(start, end+2, mask, mirror, rhandler, whandler, 0x0000ffff);
+ } else {
+ m_maincpu->memory().space(spacenum)->install_readwrite_handler(start, end, mask, mirror, rhandler, whandler, 0xffffffff);
+ }
+ } else {
+ // we handle just misalligned by 2
+ m_maincpu->memory().space(spacenum)->install_readwrite_handler(start-2, end, mask, mirror, rhandler, whandler, 0xffff0000);
+ }
+ break;
+ default:
+ fatalerror("ISA8: Bus width %d not supported", buswidth);
+ break;
+ }
+}
+
+
+void isa8_device::install_space(address_spacenum spacenum, device_t *dev, offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_device_func rhandler, const char* rhandler_name, write8_device_func whandler, const char *whandler_name)
+{
+ int buswidth = m_maincpu->memory().space_config(spacenum)->m_databus_width;
+ switch(buswidth)
+ {
+ case 8:
+ m_maincpu->memory().space(spacenum)->install_legacy_readwrite_handler(*dev, start, end, mask, mirror, rhandler, rhandler_name, whandler, whandler_name,0);
+ break;
+ case 16:
+ m_maincpu->memory().space(spacenum)->install_legacy_readwrite_handler(*dev, start, end, mask, mirror, rhandler, rhandler_name, whandler, whandler_name,0xffff);
+ break;
+ case 32:
+ if ((start % 4) == 0) {
+ if ((end-start)==1) {
+ m_maincpu->memory().space(spacenum)->install_legacy_readwrite_handler(*dev, start, end+2, mask, mirror, rhandler, rhandler_name, whandler, whandler_name,0x0000ffff);
+ } else {
+ m_maincpu->memory().space(spacenum)->install_legacy_readwrite_handler(*dev, start, end, mask, mirror, rhandler, rhandler_name, whandler, whandler_name,0xffffffff);
+ }
+ } else {
+ // we handle just misalligned by 2
+ m_maincpu->memory().space(spacenum)->install_legacy_readwrite_handler(*dev, start-2, end, mask, mirror, rhandler, rhandler_name, whandler, whandler_name,0xffff0000);
+ }
+ break;
+ default:
+ fatalerror("ISA8: Bus width %d not supported", buswidth);
+ break;
+ }
+}
+
+
+void isa8_device::install_memory(device_t *dev, offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_device_func rhandler, const char* rhandler_name, write8_device_func whandler, const char *whandler_name)
+{
+ install_space(AS_PROGRAM, dev, start, end, mask, mirror, rhandler, rhandler_name, whandler, whandler_name);
+}
+
+
+void isa8_device::install_memory(offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_space_func rhandler, const char* rhandler_name, write8_space_func whandler, const char *whandler_name)
+{
+ install_space(AS_PROGRAM, start, end, mask, mirror, rhandler, rhandler_name, whandler, whandler_name);
+}
+
+
+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(device_t *dev, offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_device_func rhandler, const char* rhandler_name, write8_device_func whandler, const char *whandler_name)
+{
+ install_space(AS_IO, dev, start, end, mask, mirror, rhandler, rhandler_name, whandler, whandler_name);
+}
+
+
+void isa8_device::install_device(offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_space_func rhandler, const char* rhandler_name, write8_space_func whandler, const char *whandler_name)
+{
+ install_space(AS_IO, start, end, mask, mirror, rhandler, rhandler_name, whandler, whandler_name);
+}
+
+
+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)
+{
+ address_space *space = m_maincpu->memory().space(AS_PROGRAM);
+ space->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)
+{
+ address_space *space = m_maincpu->memory().space(AS_PROGRAM);
+ space->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)
+{
+ astring tempstring;
+ 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 {
+ address_space *space = m_maincpu->memory().space(AS_PROGRAM);
+ space->install_read_bank(start, end, mask, mirror, tag);
+ space->unmap_write(start, end, mask, mirror);
+ machine().root_device().membank(tag)->set_base(machine().root_device().memregion(dev->subtag(tempstring, region))->base());
+ }
+}
+
+void isa8_device::unmap_rom(offs_t start, offs_t end, offs_t mask, offs_t mirror)
+{
+ address_space *space = m_maincpu->memory().space(AS_PROGRAM);
+ space->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);
+ address_space *space = m_maincpu->memory().space(AS_PROGRAM);
+ for(int i = 0; i < size; i += 4096) // 4KB granularity should be enough
+ if(space->get_read_ptr(start + i)) return false;
+ return true;
+}
+
+// interrupt request from isa card
+WRITE_LINE_MEMBER( isa8_device::irq2_w ) { m_out_irq2_func(state); }
+WRITE_LINE_MEMBER( isa8_device::irq3_w ) { m_out_irq3_func(state); }
+WRITE_LINE_MEMBER( isa8_device::irq4_w ) { m_out_irq4_func(state); }
+WRITE_LINE_MEMBER( isa8_device::irq5_w ) { m_out_irq5_func(state); }
+WRITE_LINE_MEMBER( isa8_device::irq6_w ) { m_out_irq6_func(state); }
+WRITE_LINE_MEMBER( isa8_device::irq7_w ) { m_out_irq7_func(state); }
+
+// dma request from isa card
+WRITE_LINE_MEMBER( isa8_device::drq1_w ) { m_out_drq1_func(state); }
+WRITE_LINE_MEMBER( isa8_device::drq2_w ) { m_out_drq2_func(state); }
+WRITE_LINE_MEMBER( isa8_device::drq3_w ) { m_out_drq3_func(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 state)
+{
+ for (int i=0;i<8;i++) {
+ if (m_dma_eop[i]==TRUE && m_dma_device[i])
+ m_dma_device[i]->eop_w(state);
+ }
+}
+
+void isa8_device::nmi()
+{
+ if (m_nmi_enabled)
+ {
+ device_set_input_line( m_maincpu, INPUT_LINE_NMI, PULSE_LINE );
+ }
+}
+//**************************************************************************
+// 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_isa8_card_interface &>(device);
+ isa_card.m_isa_dev = isa_device;
+}
+
+void device_isa8_card_interface::set_isa_device()
+{
+ m_isa = dynamic_cast<isa8_device *>(m_isa_dev);
+}
+
+
+const device_type ISA16 = &device_creator<isa16_device>;
+
+//-------------------------------------------------
+// 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)
+{
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void isa16_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const isa16bus_interface *intf = reinterpret_cast<const isa16bus_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<isa16bus_interface *>(this) = *intf;
+ memcpy(&(isa8bus_interface::m_out_irq2_cb),&(isa16bus_interface::m_out_irq2_cb), sizeof(isa16bus_interface::m_out_irq2_cb));
+ memcpy(&(isa8bus_interface::m_out_irq3_cb),&(isa16bus_interface::m_out_irq3_cb), sizeof(isa16bus_interface::m_out_irq3_cb));
+ memcpy(&(isa8bus_interface::m_out_irq4_cb),&(isa16bus_interface::m_out_irq4_cb), sizeof(isa16bus_interface::m_out_irq4_cb));
+ memcpy(&(isa8bus_interface::m_out_irq5_cb),&(isa16bus_interface::m_out_irq5_cb), sizeof(isa16bus_interface::m_out_irq5_cb));
+ memcpy(&(isa8bus_interface::m_out_irq6_cb),&(isa16bus_interface::m_out_irq6_cb), sizeof(isa16bus_interface::m_out_irq6_cb));
+ memcpy(&(isa8bus_interface::m_out_irq7_cb),&(isa16bus_interface::m_out_irq7_cb), sizeof(isa16bus_interface::m_out_irq7_cb));
+ memcpy(&(isa8bus_interface::m_out_drq1_cb),&(isa16bus_interface::m_out_drq1_cb), sizeof(isa16bus_interface::m_out_drq1_cb));
+ memcpy(&(isa8bus_interface::m_out_drq2_cb),&(isa16bus_interface::m_out_drq2_cb), sizeof(isa16bus_interface::m_out_drq2_cb));
+ memcpy(&(isa8bus_interface::m_out_drq3_cb),&(isa16bus_interface::m_out_drq3_cb), sizeof(isa16bus_interface::m_out_drq3_cb));
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&(isa8bus_interface::m_out_irq2_cb), 0, sizeof(isa8bus_interface::m_out_irq2_cb));
+ memset(&(isa8bus_interface::m_out_irq3_cb), 0, sizeof(isa8bus_interface::m_out_irq3_cb));
+ memset(&(isa8bus_interface::m_out_irq4_cb), 0, sizeof(isa8bus_interface::m_out_irq4_cb));
+ memset(&(isa8bus_interface::m_out_irq5_cb), 0, sizeof(isa8bus_interface::m_out_irq5_cb));
+ memset(&(isa8bus_interface::m_out_irq6_cb), 0, sizeof(isa8bus_interface::m_out_irq6_cb));
+ memset(&(isa8bus_interface::m_out_irq7_cb), 0, sizeof(isa8bus_interface::m_out_irq7_cb));
+
+ memset(&m_out_irq10_cb, 0, sizeof(m_out_irq10_cb));
+ memset(&m_out_irq11_cb, 0, sizeof(m_out_irq11_cb));
+ memset(&m_out_irq12_cb, 0, sizeof(m_out_irq12_cb));
+ memset(&m_out_irq14_cb, 0, sizeof(m_out_irq14_cb));
+ memset(&m_out_irq15_cb, 0, sizeof(m_out_irq15_cb));
+
+ memset(&m_out_drq0_cb, 0, sizeof(m_out_drq0_cb));
+ memset(&(isa8bus_interface::m_out_drq1_cb), 0, sizeof(isa8bus_interface::m_out_drq1_cb));
+ memset(&(isa8bus_interface::m_out_drq2_cb), 0, sizeof(isa8bus_interface::m_out_drq2_cb));
+ memset(&(isa8bus_interface::m_out_drq3_cb), 0, sizeof(isa8bus_interface::m_out_drq3_cb));
+
+ memset(&m_out_drq5_cb, 0, sizeof(m_out_drq5_cb));
+ memset(&m_out_drq6_cb, 0, sizeof(m_out_drq6_cb));
+ memset(&m_out_drq7_cb, 0, sizeof(m_out_drq7_cb));
+ }
+ 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_func.resolve(m_out_irq10_cb, *this);
+ m_out_irq11_func.resolve(m_out_irq11_cb, *this);
+ m_out_irq12_func.resolve(m_out_irq12_cb, *this);
+ m_out_irq14_func.resolve(m_out_irq14_cb, *this);
+ m_out_irq15_func.resolve(m_out_irq15_cb, *this);
+
+ m_out_drq0_func.resolve(m_out_drq0_cb, *this);
+ m_out_drq5_func.resolve(m_out_drq5_cb, *this);
+ m_out_drq6_func.resolve(m_out_drq6_cb, *this);
+ m_out_drq7_func.resolve(m_out_drq7_cb, *this);
+}
+
+void isa16_device::install16_device(device_t *dev, offs_t start, offs_t end, offs_t mask, offs_t mirror, read16_device_func rhandler, const char* rhandler_name, write16_device_func whandler, const char *whandler_name)
+{
+ int buswidth = m_maincpu->memory().space_config(AS_PROGRAM)->m_databus_width;
+ switch(buswidth)
+ {
+ case 16:
+ m_maincpu->memory().space(AS_IO)->install_legacy_readwrite_handler(*dev, start, end, mask, mirror, rhandler, rhandler_name, whandler, whandler_name,0);
+ break;
+ case 32:
+ if ((start % 4) == 0) {
+ if ((end-start)==1) {
+ m_maincpu->memory().space(AS_IO)->install_legacy_readwrite_handler(*dev, start, end+2, mask, mirror, rhandler, rhandler_name, whandler, whandler_name,0x0000ffff);
+ } else {
+ m_maincpu->memory().space(AS_IO)->install_legacy_readwrite_handler(*dev, start, end, mask, mirror, rhandler, rhandler_name, whandler, whandler_name,0xffffffff);
+ }
+ } else {
+ // we handle just misalligned by 2
+ m_maincpu->memory().space(AS_IO)->install_legacy_readwrite_handler(*dev, start-2, end, mask, mirror, rhandler, rhandler_name, whandler, whandler_name,0xffff0000);
+ }
+
+ break;
+ default:
+ fatalerror("ISA16: Bus width %d not supported", buswidth);
+ break;
+ }
+}
+
+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_maincpu->memory().space_config(AS_PROGRAM)->m_databus_width;
+ switch(buswidth)
+ {
+ case 16:
+ m_maincpu->memory().space(AS_IO)->install_readwrite_handler(start, end, mask, mirror, rhandler, whandler, 0);
+ break;
+ case 32:
+ m_maincpu->memory().space(AS_IO)->install_readwrite_handler(start, end, mask, mirror, rhandler, whandler, 0xffffffff);
+ if ((start % 4) == 0) {
+ if ((end-start)==1) {
+ m_maincpu->memory().space(AS_IO)->install_readwrite_handler(start, end+2, mask, mirror, rhandler, whandler, 0x0000ffff);
+ } else {
+ m_maincpu->memory().space(AS_IO)->install_readwrite_handler(start, end, mask, mirror, rhandler, whandler, 0xffffffff);
+ }
+ } else {
+ // we handle just misalligned by 2
+ m_maincpu->memory().space(AS_IO)->install_readwrite_handler(start-2, end, mask, mirror, rhandler, whandler, 0xffff0000);
+ }
+
+ break;
+ default:
+ fatalerror("ISA16: Bus width %d not supported", buswidth);
+ break;
+ }
+}
+
+// interrupt request from isa card
+WRITE_LINE_MEMBER( isa16_device::irq10_w ) { m_out_irq10_func(state); }
+WRITE_LINE_MEMBER( isa16_device::irq11_w ) { m_out_irq11_func(state); }
+WRITE_LINE_MEMBER( isa16_device::irq12_w ) { m_out_irq12_func(state); }
+WRITE_LINE_MEMBER( isa16_device::irq14_w ) { m_out_irq14_func(state); }
+WRITE_LINE_MEMBER( isa16_device::irq15_w ) { m_out_irq15_func(state); }
+
+// dma request from isa card
+WRITE_LINE_MEMBER( isa16_device::drq0_w ) { m_out_drq0_func(state); }
+WRITE_LINE_MEMBER( isa16_device::drq5_w ) { m_out_drq5_func(state); }
+WRITE_LINE_MEMBER( isa16_device::drq6_w ) { m_out_drq6_func(state); }
+WRITE_LINE_MEMBER( isa16_device::drq7_w ) { m_out_drq7_func(state); }
+
+//-------------------------------------------------
+// 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<isa16_device *>(m_isa_dev);
+}
diff --git a/src/mess/machine/isa.h b/src/mess/machine/isa.h
new file mode 100644
index 00000000000..5e5599f90e8
--- /dev/null
+++ b/src/mess/machine/isa.h
@@ -0,0 +1,347 @@
+/***************************************************************************
+
+ 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_BUS_ADD(_tag, _cputag, _config) \
+ MCFG_DEVICE_ADD(_tag, ISA8, 0) \
+ MCFG_DEVICE_CONFIG(_config) \
+ isa8_device::static_set_cputag(*device, _cputag); \
+
+#define MCFG_ISA8_SLOT_ADD(_isatag, _tag, _slot_intf, _def_slot, _def_inp, _fixed) \
+ MCFG_DEVICE_ADD(_tag, ISA8_SLOT, 0) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, _fixed) \
+ isa8_slot_device::static_set_isa8_slot(*device, owner, _isatag); \
+
+#define MCFG_ISA16_BUS_ADD(_tag, _cputag, _config) \
+ MCFG_DEVICE_ADD(_tag, ISA16, 0) \
+ MCFG_DEVICE_CONFIG(_config) \
+ isa8_device::static_set_cputag(*device, _cputag); \
+
+#define MCFG_ISA16_SLOT_ADD(_isatag, _tag, _slot_intf, _def_slot, _def_inp, _fixed) \
+ MCFG_DEVICE_ADD(_tag, ISA16_SLOT, 0) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, _fixed) \
+ isa16_slot_device::static_set_isa16_slot(*device, owner, _isatag); \
+
+//**************************************************************************
+// 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);
+
+ // 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;
+
+// ======================> isa8bus_interface
+
+struct isa8bus_interface
+{
+ 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;
+};
+
+class device_isa8_card_interface;
+// ======================> isa8_device
+class isa8_device : public device_t,
+ public isa8bus_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);
+ // inline configuration
+ static void static_set_cputag(device_t &device, const char *tag);
+
+ void install_device(device_t *dev, offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_device_func rhandler, const char* rhandler_name, write8_device_func whandler, const char *whandler_name);
+ void install_device(offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_delegate rhandler, write8_delegate whandler);
+ void install_device(offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_space_func rhandler, const char* rhandler_name, write8_space_func whandler, const char *whandler_name);
+ 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(device_t *dev, offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_device_func rhandler, const char* rhandler_name, write8_device_func whandler, const char *whandler_name);
+ void install_memory(offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_delegate rhandler, write8_delegate whandler);
+ void install_memory(offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_space_func rhandler, const char* rhandler_name, write8_space_func whandler, const char *whandler_name);
+
+ 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 );
+
+ UINT8 dack_r(int line);
+ void dack_w(int line,UINT8 data);
+ void eop_w(int state);
+
+ void nmi();
+ void set_nmi_state(bool enabled) { m_nmi_enabled = enabled; }
+
+ void set_dma_channel(UINT8 channel, device_isa8_card_interface *dev, bool do_eop);
+protected:
+ void install_space(address_spacenum spacenum, device_t *dev, offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_device_func rhandler, const char* rhandler_name, write8_device_func whandler, const char *whandler_name);
+ void install_space(address_spacenum spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_space_func rhandler, const char* rhandler_name, write8_space_func whandler, const char *whandler_name);
+ 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
+ device_t *m_maincpu;
+
+ devcb_resolved_write_line m_out_irq2_func;
+ devcb_resolved_write_line m_out_irq3_func;
+ devcb_resolved_write_line m_out_irq4_func;
+ devcb_resolved_write_line m_out_irq5_func;
+ devcb_resolved_write_line m_out_irq6_func;
+ devcb_resolved_write_line m_out_irq7_func;
+
+ devcb_resolved_write_line m_out_drq1_func;
+ devcb_resolved_write_line m_out_drq2_func;
+ devcb_resolved_write_line m_out_drq3_func;
+
+ device_isa8_card_interface *m_dma_device[8];
+ bool m_dma_eop[8];
+ const char *m_cputag;
+ bool m_nmi_enabled;
+};
+
+
+// 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;
+};
+
+// ======================> isa16bus_interface
+
+struct isa16bus_interface
+{
+ devcb_write_line m_out_irq2_cb; // this goes to IRQ 9 on pic
+ 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_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_drq1_cb;
+ devcb_write_line m_out_drq2_cb;
+ devcb_write_line m_out_drq3_cb;
+ devcb_write_line m_out_drq5_cb;
+ devcb_write_line m_out_drq6_cb;
+ devcb_write_line m_out_drq7_cb;
+};
+
+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 isa16bus_interface
+{
+public:
+ // construction/destruction
+ isa16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ void install16_device(device_t *dev, offs_t start, offs_t end, offs_t mask, offs_t mirror, read16_device_func rhandler, const char* rhandler_name, write16_device_func whandler, const char *whandler_name);
+ void install16_device(offs_t start, offs_t end, offs_t mask, offs_t mirror, read16_delegate rhandler, write16_delegate whandler);
+
+ 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 );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_config_complete();
+
+private:
+ // internal state
+ devcb_resolved_write_line m_out_irq10_func;
+ devcb_resolved_write_line m_out_irq11_func;
+ devcb_resolved_write_line m_out_irq12_func;
+ devcb_resolved_write_line m_out_irq14_func;
+ devcb_resolved_write_line m_out_irq15_func;
+
+ devcb_resolved_write_line m_out_drq0_func;
+ devcb_resolved_write_line m_out_drq5_func;
+ devcb_resolved_write_line m_out_drq6_func;
+ devcb_resolved_write_line m_out_drq7_func;
+};
+
+
+// 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();
+
+ void set_isa_device();
+ isa16_device *m_isa;
+};
+
+#endif /* __ISA_H__ */
diff --git a/src/mess/machine/isa_adlib.c b/src/mess/machine/isa_adlib.c
new file mode 100644
index 00000000000..8bd280c5b3a
--- /dev/null
+++ b/src/mess/machine/isa_adlib.c
@@ -0,0 +1,91 @@
+/***************************************************************************
+
+ ISA 8 bit Adlib Sound Card
+
+***************************************************************************/
+
+#include "emu.h"
+#include "isa_adlib.h"
+#include "sound/speaker.h"
+#include "sound/3812intf.h"
+
+#define ym3812_StdClock 3579545
+
+static const ym3812_interface pc_ym3812_interface =
+{
+ NULL
+};
+
+static MACHINE_CONFIG_FRAGMENT( adlib_config )
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+ MCFG_SOUND_ADD("ym3812", YM3812, ym3812_StdClock)
+ MCFG_SOUND_CONFIG(pc_ym3812_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 3.00)
+MACHINE_CONFIG_END
+
+static READ8_DEVICE_HANDLER( ym3812_16_r )
+{
+ UINT8 retVal = 0xff;
+ switch(offset)
+ {
+ case 0 : retVal = ym3812_status_port_r( device, offset ); break;
+ }
+ return retVal;
+}
+
+static WRITE8_DEVICE_HANDLER( ym3812_16_w )
+{
+ switch(offset)
+ {
+ case 0 : ym3812_control_port_w( device, offset, data ); break;
+ case 1 : ym3812_write_port_w( device, offset, data ); break;
+ }
+}
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_ADLIB = &device_creator<isa8_adlib_device>;
+
+//-------------------------------------------------
+// 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),
+ device_isa8_card_interface( mconfig, *this )
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa8_adlib_device::device_start()
+{
+ set_isa_device();
+ m_isa->install_device(subdevice("ym3812"), 0x0388, 0x0389, 0, 0, FUNC(ym3812_16_r), FUNC(ym3812_16_w) );
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa8_adlib_device::device_reset()
+{
+}
diff --git a/src/mess/machine/isa_adlib.h b/src/mess/machine/isa_adlib.h
new file mode 100644
index 00000000000..b78acbb908b
--- /dev/null
+++ b/src/mess/machine/isa_adlib.h
@@ -0,0 +1,38 @@
+#pragma once
+
+#ifndef __ISA_ADLIB_H__
+#define __ISA_ADLIB_H__
+
+#include "emu.h"
+#include "machine/isa.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;
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "isa_adlib"; }
+private:
+ // internal state
+};
+
+
+// device type definition
+extern const device_type ISA8_ADLIB;
+
+#endif /* __ISA_ADLIB_H__ */
diff --git a/src/mess/machine/isa_aha1542.c b/src/mess/machine/isa_aha1542.c
new file mode 100644
index 00000000000..2b12335fc5b
--- /dev/null
+++ b/src/mess/machine/isa_aha1542.c
@@ -0,0 +1,210 @@
+/**********************************************************************
+ *
+ * Adaptec AHA-1542{,C,CF} SCSI Controller
+ *
+ * Copyright MESS Team.
+ * Visit http://mamedev.org for licensing and usage restrictions.
+ *
+ **********************************************************************/
+
+/*
+ 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 "isa_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<aha1542_device>;
+
+#define Z84C0010_TAG "u5"
+
+READ8_MEMBER( aha1542_device::aha1542_r )
+{
+ printf("aha1542_r(): pc=0x%08x offset=%d\n", (unsigned) cpu_get_reg(machine().firstcpu, STATE_GENPC), offset);
+ return 0xff;
+}
+
+WRITE8_MEMBER( aha1542_device::aha1542_w )
+{
+ printf("aha1542_w(): pc=0x%08x offset=%d data=0x%02x\n", (unsigned) cpu_get_reg(machine().firstcpu, STATE_GENPC), 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),
+ device_isa16_card_interface(mconfig, *this)
+{
+}
+
+void aha1542_device::device_config_complete()
+{
+ m_shortname = "aha1542";
+}
+
+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/mess/machine/isa_aha1542.h b/src/mess/machine/isa_aha1542.h
new file mode 100644
index 00000000000..df735ce6bc8
--- /dev/null
+++ b/src/mess/machine/isa_aha1542.h
@@ -0,0 +1,61 @@
+/**********************************************************************
+ *
+ * Adaptec AHA-1542{,C,CF} SCSI Controller
+ *
+ * Copyright MESS Team.
+ * Visit http://mamedev.org for licensing and usage restrictions.
+ *
+ **********************************************************************
+
+
+
+ **********************************************************************/
+
+#pragma once
+
+#ifndef __AHA1542__
+#define __AHA1542__
+
+
+#include "emu.h"
+#include "machine/isa.h"
+#include "machine/scsibus.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();
+ virtual void device_config_complete();
+
+ // device_isa16_card_interface
+
+private:
+ // internal state
+};
+
+// device type definition
+
+extern const device_type AHA1542;
+
+#endif
+
diff --git a/src/mess/machine/isa_com.c b/src/mess/machine/isa_com.c
new file mode 100644
index 00000000000..1ece2e85667
--- /dev/null
+++ b/src/mess/machine/isa_com.c
@@ -0,0 +1,192 @@
+/***************************************************************************
+
+ ISA 8 bit Generic Communication Card
+
+***************************************************************************/
+
+#include "isa_com.h"
+#include "machine/ser_mouse.h"
+#include "machine/terminal.h"
+#include "machine/null_modem.h"
+#include "machine/serial.h"
+#include "machine/ins8250.h"
+
+static const ins8250_interface genpc_com_interface[4]=
+{
+ {
+ DEVCB_DEVICE_LINE_MEMBER("serport0", serial_port_device, tx),
+ DEVCB_DEVICE_LINE_MEMBER("serport0", rs232_port_device, dtr_w),
+ DEVCB_DEVICE_LINE_MEMBER("serport0", rs232_port_device, rts_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, isa8_com_device, pc_com_interrupt_1),
+ DEVCB_NULL,
+ DEVCB_NULL
+ },
+ {
+ DEVCB_DEVICE_LINE_MEMBER("serport1", serial_port_device, tx),
+ DEVCB_DEVICE_LINE_MEMBER("serport1", rs232_port_device, dtr_w),
+ DEVCB_DEVICE_LINE_MEMBER("serport1", rs232_port_device, rts_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, isa8_com_device, pc_com_interrupt_2),
+ DEVCB_NULL,
+ DEVCB_NULL
+ },
+ {
+ DEVCB_DEVICE_LINE_MEMBER("serport2", serial_port_device, tx),
+ DEVCB_DEVICE_LINE_MEMBER("serport2", rs232_port_device, dtr_w),
+ DEVCB_DEVICE_LINE_MEMBER("serport2", rs232_port_device, rts_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, isa8_com_device, pc_com_interrupt_1),
+ DEVCB_NULL,
+ DEVCB_NULL
+ },
+ {
+ DEVCB_DEVICE_LINE_MEMBER("serport3", serial_port_device, tx),
+ DEVCB_DEVICE_LINE_MEMBER("serport3", rs232_port_device, dtr_w),
+ DEVCB_DEVICE_LINE_MEMBER("serport3", rs232_port_device, rts_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, isa8_com_device, pc_com_interrupt_2),
+ DEVCB_NULL,
+ DEVCB_NULL
+ }
+};
+
+static const rs232_port_interface serport_config[4] =
+{
+ {
+ DEVCB_DEVICE_LINE_MEMBER("uart_0", ins8250_uart_device, rx_w),
+ DEVCB_DEVICE_LINE_MEMBER("uart_0", ins8250_uart_device, dcd_w),
+ DEVCB_DEVICE_LINE_MEMBER("uart_0", ins8250_uart_device, dsr_w),
+ DEVCB_DEVICE_LINE_MEMBER("uart_0", ins8250_uart_device, ri_w),
+ DEVCB_DEVICE_LINE_MEMBER("uart_0", ins8250_uart_device, cts_w)
+ },
+ {
+ DEVCB_DEVICE_LINE_MEMBER("uart_1", ins8250_uart_device, rx_w),
+ DEVCB_DEVICE_LINE_MEMBER("uart_1", ins8250_uart_device, dcd_w),
+ DEVCB_DEVICE_LINE_MEMBER("uart_1", ins8250_uart_device, dsr_w),
+ DEVCB_DEVICE_LINE_MEMBER("uart_1", ins8250_uart_device, ri_w),
+ DEVCB_DEVICE_LINE_MEMBER("uart_1", ins8250_uart_device, cts_w)
+ },
+ {
+ DEVCB_DEVICE_LINE_MEMBER("uart_2", ins8250_uart_device, rx_w),
+ DEVCB_DEVICE_LINE_MEMBER("uart_2", ins8250_uart_device, dcd_w),
+ DEVCB_DEVICE_LINE_MEMBER("uart_2", ins8250_uart_device, dsr_w),
+ DEVCB_DEVICE_LINE_MEMBER("uart_2", ins8250_uart_device, ri_w),
+ DEVCB_DEVICE_LINE_MEMBER("uart_2", ins8250_uart_device, cts_w)
+ },
+ {
+ DEVCB_DEVICE_LINE_MEMBER("uart_3", ins8250_uart_device, rx_w),
+ DEVCB_DEVICE_LINE_MEMBER("uart_3", ins8250_uart_device, dcd_w),
+ DEVCB_DEVICE_LINE_MEMBER("uart_3", ins8250_uart_device, dsr_w),
+ DEVCB_DEVICE_LINE_MEMBER("uart_3", ins8250_uart_device, ri_w),
+ DEVCB_DEVICE_LINE_MEMBER("uart_3", ins8250_uart_device, cts_w)
+ }
+};
+
+static SLOT_INTERFACE_START(isa_com)
+ SLOT_INTERFACE("microsoft_mouse", MSFT_SERIAL_MOUSE)
+ SLOT_INTERFACE("msystems_mouse", MSYSTEM_SERIAL_MOUSE)
+ SLOT_INTERFACE("serial_terminal", SERIAL_TERMINAL)
+ SLOT_INTERFACE("null_modem", NULL_MODEM)
+SLOT_INTERFACE_END
+
+static MACHINE_CONFIG_FRAGMENT( com_config )
+ MCFG_INS8250_ADD( "uart_0", genpc_com_interface[0], XTAL_1_8432MHz )
+ MCFG_INS8250_ADD( "uart_1", genpc_com_interface[1], XTAL_1_8432MHz )
+ MCFG_INS8250_ADD( "uart_2", genpc_com_interface[2], XTAL_1_8432MHz )
+ MCFG_INS8250_ADD( "uart_3", genpc_com_interface[3], XTAL_1_8432MHz )
+ MCFG_RS232_PORT_ADD( "serport0", serport_config[0], isa_com, "microsoft_mouse", NULL )
+ MCFG_RS232_PORT_ADD( "serport1", serport_config[1], isa_com, NULL, NULL )
+ MCFG_RS232_PORT_ADD( "serport2", serport_config[2], isa_com, NULL, NULL )
+ MCFG_RS232_PORT_ADD( "serport3", serport_config[3], isa_com, NULL, NULL )
+MACHINE_CONFIG_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_COM = &device_creator<isa8_com_device>;
+
+//-------------------------------------------------
+// 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),
+ 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) :
+ device_t(mconfig, type, name, tag, owner, clock),
+ 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<ins8250_uart_device>("uart_0")), write8_delegate(FUNC(ins8250_device::ins8250_w), subdevice<ins8250_uart_device>("uart_0")) );
+ m_isa->install_device(0x02f8, 0x02ff, 0, 0, read8_delegate(FUNC(ins8250_device::ins8250_r), subdevice<ins8250_uart_device>("uart_1")), write8_delegate(FUNC(ins8250_device::ins8250_w), subdevice<ins8250_uart_device>("uart_1")) );
+ m_isa->install_device(0x03e8, 0x03ef, 0, 0, read8_delegate(FUNC(ins8250_device::ins8250_r), subdevice<ins8250_uart_device>("uart_2")), write8_delegate(FUNC(ins8250_device::ins8250_w), subdevice<ins8250_uart_device>("uart_2")) );
+ m_isa->install_device(0x02e8, 0x02ef, 0, 0, read8_delegate(FUNC(ins8250_device::ins8250_r), subdevice<ins8250_uart_device>("uart_3")), write8_delegate(FUNC(ins8250_device::ins8250_w), subdevice<ins8250_uart_device>("uart_3")) );
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa8_com_device::device_reset()
+{
+}
+
+static MACHINE_CONFIG_FRAGMENT( com_at_config )
+ MCFG_NS16450_ADD( "uart_0", genpc_com_interface[0], XTAL_1_8432MHz ) /* Verified: IBM P/N 6320947 Serial/Parallel card uses an NS16450N */
+ MCFG_NS16450_ADD( "uart_1", genpc_com_interface[1], XTAL_1_8432MHz )
+ MCFG_NS16450_ADD( "uart_2", genpc_com_interface[2], XTAL_1_8432MHz )
+ MCFG_NS16450_ADD( "uart_3", genpc_com_interface[3], XTAL_1_8432MHz )
+ MCFG_RS232_PORT_ADD( "serport0", serport_config[0], isa_com, "microsoft_mouse", NULL )
+ MCFG_RS232_PORT_ADD( "serport1", serport_config[1], isa_com, NULL, NULL )
+ MCFG_RS232_PORT_ADD( "serport2", serport_config[2], isa_com, NULL, NULL )
+ MCFG_RS232_PORT_ADD( "serport3", serport_config[3], isa_com, NULL, NULL )
+MACHINE_CONFIG_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_COM_AT = &device_creator<isa8_com_at_device>;
+
+//-------------------------------------------------
+// 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)
+{
+}
diff --git a/src/mess/machine/isa_com.h b/src/mess/machine/isa_com.h
new file mode 100644
index 00000000000..bb3b9165592
--- /dev/null
+++ b/src/mess/machine/isa_com.h
@@ -0,0 +1,58 @@
+#pragma once
+
+#ifndef __ISA_COM_H__
+#define __ISA_COM_H__
+
+#include "emu.h"
+#include "machine/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);
+
+ // 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();
+ virtual void device_config_complete() { m_shortname = "isa_com"; }
+};
+
+
+// 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;
+ virtual void device_config_complete() { m_shortname = "isa_com_at"; }
+};
+
+
+// device type definition
+extern const device_type ISA8_COM_AT;
+
+#endif /* __ISA_COM_H__ */
diff --git a/src/mess/machine/isa_fdc.c b/src/mess/machine/isa_fdc.c
new file mode 100644
index 00000000000..dda0c2a0a43
--- /dev/null
+++ b/src/mess/machine/isa_fdc.c
@@ -0,0 +1,485 @@
+/**********************************************************************
+
+ ISA 8 bit Floppy Disk Controller
+
+**********************************************************************/
+
+#include "emu.h"
+#include "machine/isa_fdc.h"
+#include "machine/upd765.h"
+#include "imagedev/flopdrv.h"
+#include "formats/pc_dsk.h"
+#include "machine/idectrl.h"
+
+static READ8_DEVICE_HANDLER ( pc_fdc_r );
+static WRITE8_DEVICE_HANDLER ( pc_fdc_w );
+
+/* if not 1, DACK and TC inputs to FDC are disabled, and DRQ and IRQ are held
+ * at high impedance i.e they are not affective */
+#define PC_FDC_FLAGS_DOR_DMA_ENABLED (1<<3)
+#define PC_FDC_FLAGS_DOR_FDC_ENABLED (1<<2)
+#define PC_FDC_FLAGS_DOR_MOTOR_ON (1<<4)
+
+#define LOG_FDC 0
+
+static const floppy_interface ibmpc_floppy_interface =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ FLOPPY_STANDARD_5_25_DSHD,
+ LEGACY_FLOPPY_OPTIONS_NAME(pc),
+ "floppy_5_25",
+ NULL
+};
+
+static WRITE_LINE_DEVICE_HANDLER( pc_fdc_hw_interrupt );
+static WRITE_LINE_DEVICE_HANDLER( pc_fdc_hw_dma_drq );
+static UPD765_GET_IMAGE ( pc_fdc_get_image );
+
+const upd765_interface pc_fdc_upd765_not_connected_interface =
+{
+ DEVCB_LINE(pc_fdc_hw_interrupt),
+ DEVCB_LINE(pc_fdc_hw_dma_drq),
+ pc_fdc_get_image,
+ UPD765_RDY_PIN_NOT_CONNECTED,
+ {FLOPPY_0, FLOPPY_1, NULL, NULL}
+};
+
+static MACHINE_CONFIG_FRAGMENT( fdc_config )
+ MCFG_UPD765A_ADD("upd765", pc_fdc_upd765_not_connected_interface)
+
+ MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(ibmpc_floppy_interface)
+MACHINE_CONFIG_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_FDC = &device_creator<isa8_fdc_device>;
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa8_fdc_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( fdc_config );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// isa8_fdc_device - constructor
+//-------------------------------------------------
+
+isa8_fdc_device::isa8_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, ISA8_FDC, "Diskette Drive Adapter", tag, owner, clock),
+ device_isa8_card_interface(mconfig, *this),
+ m_upd765(*this, "upd765")
+{
+}
+
+isa8_fdc_device::isa8_fdc_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),
+ device_isa8_card_interface(mconfig, *this),
+ m_upd765(*this, "upd765")
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa8_fdc_device::device_start()
+{
+ set_isa_device();
+ m_isa->install_device(this, 0x03f0, 0x03f7, 0, 0, FUNC(pc_fdc_r), FUNC(pc_fdc_w) );
+ m_isa->set_dma_channel(2, this, TRUE);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa8_fdc_device::device_reset()
+{
+ status_register_a = 0;
+ status_register_b = 0;
+ digital_output_register = 0;
+ tape_drive_register = 0;
+ data_rate_register = 2;
+ digital_input_register = 0x07f;
+ configuration_control_register = 0;
+ tc_state = 0;
+ dma_state = 0;
+ int_state = 0;
+
+ upd765_reset(m_upd765,0);
+
+ /* set FDC at reset */
+ upd765_reset_w(m_upd765, 1);
+}
+
+static device_t *get_floppy_subdevice(device_t *device, int drive)
+{
+ switch(drive) {
+ case 0 : return device->subdevice(FLOPPY_0);
+ case 1 : return device->subdevice(FLOPPY_1);
+ case 2 : return device->subdevice(FLOPPY_2);
+ case 3 : return device->subdevice(FLOPPY_3);
+ }
+ return NULL;
+}
+
+static UPD765_GET_IMAGE ( pc_fdc_get_image )
+{
+ isa8_fdc_device *fdc = downcast<isa8_fdc_device *>(device->owner());
+
+ return get_floppy_subdevice(fdc, fdc->digital_output_register & 0x03);
+}
+
+static WRITE_LINE_DEVICE_HANDLER( pc_fdc_set_tc_state)
+{
+ isa8_fdc_device *fdc = downcast<isa8_fdc_device *>(device);
+ /* store state */
+ fdc->tc_state = state;
+
+ /* if dma is not enabled, tc's are not acknowledged */
+ if ((fdc->digital_output_register & PC_FDC_FLAGS_DOR_DMA_ENABLED)!=0)
+ {
+ upd765_tc_w(fdc->m_upd765, state);
+ }
+}
+
+static WRITE_LINE_DEVICE_HANDLER( pc_fdc_hw_interrupt )
+{
+ isa8_fdc_device *fdc = downcast<isa8_fdc_device *>(device->owner());
+
+ fdc->int_state = state;
+
+ /* if dma is not enabled, irq's are masked */
+ if ((fdc->digital_output_register & PC_FDC_FLAGS_DOR_DMA_ENABLED)==0)
+ return;
+
+ // not masked, send interrupt request
+ fdc->m_isa->irq6_w(state);
+}
+
+
+static WRITE_LINE_DEVICE_HANDLER( pc_fdc_hw_dma_drq )
+{
+ isa8_fdc_device *fdc = downcast<isa8_fdc_device *>(device->owner());
+ fdc->dma_state = state;
+
+ /* if dma is not enabled, drqs are masked */
+ if ((fdc->digital_output_register & PC_FDC_FLAGS_DOR_DMA_ENABLED)==0)
+ return;
+
+ // not masked, send dma request
+ fdc->m_isa->drq2_w(state);
+}
+
+
+
+static WRITE8_DEVICE_HANDLER( pc_fdc_data_rate_w )
+{
+ isa8_fdc_device *fdc = downcast<isa8_fdc_device *>(device);
+ if ((data & 0x080)!=0)
+ {
+ /* set ready state */
+ upd765_ready_w(fdc->m_upd765,1);
+
+ /* toggle reset state */
+ upd765_reset_w(fdc->m_upd765, 1);
+ upd765_reset_w(fdc->m_upd765, 0);
+
+ /* bit is self-clearing */
+ data &= ~0x080;
+ }
+
+ fdc->data_rate_register = data;
+}
+
+
+
+/* FDC Digitial Output Register (DOR)
+
+ |7|6|5|4|3|2|1|0|
+ | | | | | | `------ floppy drive select (0=A, 1=B, 2=floppy C, ...)
+ | | | | | `-------- 1 = FDC enable, 0 = hold FDC at reset
+ | | | | `---------- 1 = DMA & I/O interface enabled
+ | | | `------------ 1 = turn floppy drive A motor on
+ | | `-------------- 1 = turn floppy drive B motor on
+ | `---------------- 1 = turn floppy drive C motor on
+ `------------------ 1 = turn floppy drive D motor on
+ */
+
+static WRITE8_DEVICE_HANDLER( pc_fdc_dor_w )
+{
+ isa8_fdc_device *fdc = downcast<isa8_fdc_device *>(device);
+ int selected_drive;
+ int floppy_count;
+
+ floppy_count = floppy_get_count(device->machine());
+
+ if (floppy_count > (fdc->digital_output_register & 0x03))
+ floppy_drive_set_ready_state(get_floppy_subdevice(device, fdc->digital_output_register & 0x03), 1, 0);
+
+ fdc->digital_output_register = data;
+
+ selected_drive = data & 0x03;
+
+ /* set floppy drive motor state */
+ if (floppy_count > 0)
+ floppy_mon_w(get_floppy_subdevice(device, 0), !BIT(data, 4));
+ if (floppy_count > 1)
+ floppy_mon_w(get_floppy_subdevice(device, 1), !BIT(data, 5));
+ if (floppy_count > 2)
+ floppy_mon_w(get_floppy_subdevice(device, 2), !BIT(data, 6));
+ if (floppy_count > 3)
+ floppy_mon_w(get_floppy_subdevice(device, 3), !BIT(data, 7));
+
+ if ((data>>4) & (1<<selected_drive))
+ {
+ if (floppy_count > selected_drive)
+ floppy_drive_set_ready_state(get_floppy_subdevice(device, selected_drive), 1, 0);
+ }
+
+ /* changing the DMA enable bit, will affect the terminal count state
+ from reaching the fdc - if dma is enabled this will send it through
+ otherwise it will be ignored */
+ pc_fdc_set_tc_state(device, fdc->tc_state);
+
+ /* changing the DMA enable bit, will affect the dma drq state
+ from reaching us - if dma is enabled this will send it through
+ otherwise it will be ignored */
+ pc_fdc_hw_dma_drq(fdc->m_upd765, fdc->dma_state);
+
+ /* changing the DMA enable bit, will affect the irq state
+ from reaching us - if dma is enabled this will send it through
+ otherwise it will be ignored */
+ pc_fdc_hw_interrupt(fdc->m_upd765, fdc->int_state);
+
+ /* reset? */
+ if ((fdc->digital_output_register & PC_FDC_FLAGS_DOR_FDC_ENABLED)==0)
+ {
+ /* yes */
+
+ /* pc-xt expects a interrupt to be generated
+ when the fdc is reset.
+ In the FDC docs, it states that a INT will
+ be generated if READY input is true when the
+ fdc is reset.
+
+ It also states, that outputs to drive are set to 0.
+ Maybe this causes the drive motor to go on, and therefore
+ the ready line is set.
+
+ This in return causes a int?? ---
+
+
+ what is not yet clear is if this is a result of the drives ready state
+ changing...
+ */
+ upd765_ready_w(fdc->m_upd765, 1);
+
+ /* set FDC at reset */
+ upd765_reset_w(fdc->m_upd765, 1);
+ }
+ else
+ {
+ pc_fdc_set_tc_state(device, 0);
+
+ /* release reset on fdc */
+ upd765_reset_w(fdc->m_upd765, 0);
+ }
+}
+
+#define RATE_250 2
+#define RATE_300 1
+#define RATE_500 0
+#define RATE_1000 3
+
+static void pc_fdc_check_data_rate(isa8_fdc_device *fdc, running_machine &machine)
+{
+ device_t *device = get_floppy_subdevice(fdc, fdc->digital_output_register & 0x03);
+ floppy_image_legacy *image;
+ int tracks, sectors, rate;
+
+ upd765_set_bad(fdc->m_upd765, 0); // unset in case format is unknown
+ if (!device) return;
+ image = flopimg_get_image(device);
+ if (!image) return;
+ tracks = floppy_get_tracks_per_disk(image);
+ tracks -= (tracks % 10); // ignore extra tracks
+ floppy_get_sector_count(image, 0, 0, &sectors);
+
+ if (tracks == 40) {
+ if ((fdc->data_rate_register != RATE_250) && (fdc->data_rate_register != RATE_300))
+ upd765_set_bad(fdc->m_upd765, 1);
+ return;
+ } else if (tracks == 80) {
+ if (sectors <= 14) rate = RATE_250; // 720KB 5 1/4 and 3 1/2
+ else if (sectors <= 24) rate = RATE_500; // 1.2MB 5 1/4 and 1.44MB 3 1/2
+ else rate = RATE_1000; // 2.88MB 3 1/2
+ } else return;
+
+ if (rate != (fdc->data_rate_register & 3))
+ upd765_set_bad(fdc->m_upd765, 1);
+}
+
+
+static READ8_DEVICE_HANDLER ( pc_fdc_r )
+{
+ UINT8 data = 0xff;
+
+ isa8_fdc_device *fdc = downcast<isa8_fdc_device *>(device);
+ device_t *hdd = NULL;
+ switch(offset)
+ {
+ case 0: /* status register a */
+ case 1: /* status register b */
+ data = 0x00;
+ break;
+ case 2:
+ data = fdc->digital_output_register;
+ break;
+ case 3: /* tape drive select? */
+ break;
+ case 4:
+ data = upd765_status_r(fdc->m_upd765, 0);
+ break;
+ case 5:
+ data = upd765_data_r(fdc->m_upd765, offset);
+ break;
+ case 6: /* FDC reserved */
+ hdd = device->machine().device(":board3:ide:ide");
+ if (hdd)
+ data = ide_controller16_r(hdd, 0x3f6/2, 0x00ff);
+ break;
+ case 7:
+ device_t *dev = get_floppy_subdevice(device, fdc->digital_output_register & 0x03);
+ data = fdc->digital_input_register;
+ if(dev!=NULL) data |= (!floppy_dskchg_r(dev)<<7);
+ break;
+ }
+
+ if (LOG_FDC)
+ logerror("pc_fdc_r(): pc=0x%08x offset=%d result=0x%02X\n", (unsigned) cpu_get_reg(device->machine().firstcpu,STATE_GENPC), offset, data);
+ return data;
+}
+
+
+
+static WRITE8_DEVICE_HANDLER ( pc_fdc_w )
+{
+ isa8_fdc_device *fdc = downcast<isa8_fdc_device *>(device);
+
+ if (LOG_FDC)
+ logerror("pc_fdc_w(): pc=0x%08x offset=%d data=0x%02X\n", (unsigned) cpu_get_reg(device->machine().firstcpu,STATE_GENPC), offset, data);
+ pc_fdc_check_data_rate(fdc,device->machine()); // check every time a command may start
+ device_t *hdd = NULL;
+
+ switch(offset)
+ {
+ case 0: /* n/a */
+ case 1: /* n/a */
+ break;
+ case 2:
+ pc_fdc_dor_w(device, 0, data);
+ break;
+ case 3:
+ /* tape drive select? */
+ break;
+ case 4:
+ pc_fdc_data_rate_w(device, 0, data);
+ break;
+ case 5:
+ upd765_data_w(fdc->m_upd765, 0, data);
+ break;
+ case 6:
+ /* FDC reserved */
+ hdd = device->machine().device(":board3:ide:ide");
+ if (hdd)
+ ide_controller16_w(hdd, 0x3f6/2, data, 0x00ff);
+ break;
+ case 7:
+ /* Configuration Control Register
+ *
+ * Currently unimplemented; bits 1-0 are supposed to control data
+ * flow rates:
+ * 0 0 500 kbps
+ * 0 1 300 kbps
+ * 1 0 250 kbps
+ * 1 1 1000 kbps
+ */
+ pc_fdc_data_rate_w(device, 0, data & 3);
+ break;
+ }
+}
+
+UINT8 isa8_fdc_device::dack_r(int line)
+{
+ /* what is output if dack is not acknowledged? */
+ int data = 0x0ff;
+
+ /* if dma is not enabled, dacks are not acknowledged */
+ if ((digital_output_register & PC_FDC_FLAGS_DOR_DMA_ENABLED)!=0)
+ {
+ data = upd765_dack_r(m_upd765, 0);
+ }
+
+ return data;
+}
+
+void isa8_fdc_device::dack_w(int line,UINT8 data)
+{
+ /* if dma is not enabled, dacks are not issued */
+ if ((digital_output_register & PC_FDC_FLAGS_DOR_DMA_ENABLED)!=0)
+ {
+ /* dma acknowledge - and send byte to fdc */
+ upd765_dack_w(m_upd765, 0,data);
+ }
+}
+void isa8_fdc_device::eop_w(int state)
+{
+ pc_fdc_set_tc_state( this, state);
+}
+
+static MACHINE_CONFIG_FRAGMENT( fdc_smc_config )
+ MCFG_SMC37C78_ADD("upd765", pc_fdc_upd765_not_connected_interface)
+
+ MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(ibmpc_floppy_interface)
+MACHINE_CONFIG_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_FDC_SMC = &device_creator<isa8_fdc_smc_device>;
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa8_fdc_smc_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( fdc_smc_config );
+}
+
+//-------------------------------------------------
+// isa8_fdc_smc_device - constructor
+//-------------------------------------------------
+
+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_SMC, "Diskette Drive Adapter (SMC37C78)", tag, owner, clock)
+{
+}
+
diff --git a/src/mess/machine/isa_fdc.h b/src/mess/machine/isa_fdc.h
new file mode 100644
index 00000000000..bd37f4bb968
--- /dev/null
+++ b/src/mess/machine/isa_fdc.h
@@ -0,0 +1,83 @@
+/**********************************************************************
+
+ ISA 8 bit Floppy Disk Controller
+
+**********************************************************************/
+#pragma once
+
+#ifndef ISA_FDC_H
+#define ISA_FDC_H
+
+#include "emu.h"
+#include "machine/isa.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, const char *tag, device_t *owner, UINT32 clock);
+ isa8_fdc_device(const machine_config &mconfig, device_type type, const char *name, 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();
+ virtual void device_config_complete() { m_shortname = "isa_fdc"; }
+private:
+ // internal state
+public:
+ virtual UINT8 dack_r(int line);
+ virtual void dack_w(int line,UINT8 data);
+ virtual void eop_w(int state);
+
+ int status_register_a;
+ int status_register_b;
+ int digital_output_register;
+ int tape_drive_register;
+ int data_rate_register;
+ int digital_input_register;
+ int configuration_control_register;
+
+ /* stored tc state - state present at pins */
+ int tc_state;
+ /* stored dma drq state */
+ int dma_state;
+ /* stored int state */
+ int int_state;
+
+ required_device<device_t> m_upd765;
+};
+
+
+// device type definition
+extern const device_type ISA8_FDC;
+
+// ======================> isa8_fdc_smc_device
+
+class isa8_fdc_smc_device :
+ public isa8_fdc_device
+{
+public:
+ // construction/destruction
+ isa8_fdc_smc_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 void device_config_complete() { m_shortname = "isa_fdc_smc"; }
+};
+
+
+// device type definition
+extern const device_type ISA8_FDC_SMC;
+
+#endif /* ISA_FDC_H */
diff --git a/src/mess/machine/isa_finalchs.c b/src/mess/machine/isa_finalchs.c
new file mode 100644
index 00000000000..d17e09fb772
--- /dev/null
+++ b/src/mess/machine/isa_finalchs.c
@@ -0,0 +1,127 @@
+/***************************************************************************
+
+ Final Chess Card by TASC
+
+ TODO:
+ - skeleton, just boots the CPU
+
+***************************************************************************/
+
+#include "emu.h"
+#include "isa_finalchs.h"
+#include "cpu/m6502/m6502.h"
+
+static UINT8 FCH_latch_data = 0;
+
+static WRITE8_HANDLER( io7ff8_write )
+{
+ FCH_latch_data = data;
+}
+
+static READ8_HANDLER( 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
+}
+
+static READ8_HANDLER( io6000_read )
+{
+ return 0x55;
+}
+
+static WRITE8_HANDLER( io6000_write )
+{
+ 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_LEGACY(io7ff8_read)
+ AM_RANGE( 0x7ff8, 0x7ff8 ) AM_WRITE_LEGACY(io7ff8_write)
+ AM_RANGE( 0x6000, 0x6000 ) AM_READ_LEGACY(io6000_read)
+ AM_RANGE( 0x6000, 0x6000 ) AM_WRITE_LEGACY(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<isa8_finalchs_device>;
+
+//-------------------------------------------------
+// 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),
+ device_isa8_card_interface( mconfig, *this )
+{
+ m_shortname = "finalchs";
+}
+
+//-------------------------------------------------
+// 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()
+{
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *isa8_finalchs_device::device_rom_region() const
+{
+ return ROM_NAME( finalchs );
+}
diff --git a/src/mess/machine/isa_finalchs.h b/src/mess/machine/isa_finalchs.h
new file mode 100644
index 00000000000..be8a9a3cc44
--- /dev/null
+++ b/src/mess/machine/isa_finalchs.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#ifndef __ISA_FINALCHS_H__
+#define __ISA_FINALCHS_H__
+
+#include "emu.h"
+#include "machine/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);
+ // 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 ISA8_FINALCHS;
+
+#endif /* __ISA_FINALCHS_H__ */
diff --git a/src/mess/machine/isa_gblaster.c b/src/mess/machine/isa_gblaster.c
new file mode 100644
index 00000000000..60b75796ed0
--- /dev/null
+++ b/src/mess/machine/isa_gblaster.c
@@ -0,0 +1,89 @@
+/***************************************************************************
+
+ ISA 8 bit Creative Labs Game Blaster Sound Card
+
+***************************************************************************/
+
+#include "emu.h"
+#include "isa_gblaster.h"
+#include "sound/speaker.h"
+#include "sound/saa1099.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_SOUND_ADD("saa1099.1", SAA1099, 4772720)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+ MCFG_SOUND_ADD("saa1099.2", SAA1099, 4772720)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+MACHINE_CONFIG_END
+
+static READ8_DEVICE_HANDLER( saa1099_16_r )
+{
+ return 0xff;
+}
+
+static WRITE8_DEVICE_HANDLER( saa1099_16_w )
+{
+ switch(offset)
+ {
+ case 0 : saa1099_control_w( device, offset, data ); break;
+ case 1 : saa1099_data_w( device, offset, data ); break;
+ }
+}
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_GAME_BLASTER = &device_creator<isa8_gblaster_device>;
+
+//-------------------------------------------------
+// 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),
+ device_isa8_card_interface(mconfig, *this)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa8_gblaster_device::device_start()
+{
+ set_isa_device();
+ m_isa->install_device(subdevice("saa1099.1"), 0x0220, 0x0221, 0, 0, FUNC(saa1099_16_r), FUNC(saa1099_16_w) );
+ m_isa->install_device(subdevice("saa1099.2"), 0x0222, 0x0223, 0, 0, FUNC(saa1099_16_r), FUNC(saa1099_16_w) );
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa8_gblaster_device::device_reset()
+{
+}
diff --git a/src/mess/machine/isa_gblaster.h b/src/mess/machine/isa_gblaster.h
new file mode 100644
index 00000000000..6fa5b527c17
--- /dev/null
+++ b/src/mess/machine/isa_gblaster.h
@@ -0,0 +1,38 @@
+#pragma once
+
+#ifndef __ISA_GAME_BLASTER_H__
+#define __ISA_GAME_BLASTER_H__
+
+#include "emu.h"
+#include "machine/isa.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;
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "isa_gblaster"; }
+private:
+ // internal state
+};
+
+
+// device type definition
+extern const device_type ISA8_GAME_BLASTER;
+
+#endif /* __ISA_GAME_BLASTER_H__ */
diff --git a/src/mess/machine/isa_gus.c b/src/mess/machine/isa_gus.c
new file mode 100644
index 00000000000..ff5d9a5739b
--- /dev/null
+++ b/src/mess/machine/isa_gus.c
@@ -0,0 +1,1704 @@
+/*
+ * Gravis Ultrasound ISA card
+ *
+ * Started: 28/01/2012
+ */
+
+
+#include "emu.h"
+#include "isa_gus.h"
+#include "sound/speaker.h"
+#include "machine/6850acia.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<gf1_device>;
+const device_type ISA16_GUS = &device_creator<isa16_gus_device>;
+
+#ifdef LOG_SOUND
+FILE* f;
+#endif
+
+/* 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_func(0);
+ m_timer2_irq_func(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_func(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_func(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_func(1);
+ }
+ m_timer2_count++;
+ }
+ break;
+ case DMA_TIMER:
+ m_drq1(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;
+ }
+ else
+ {
+ 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;
+ }
+ else
+ {
+ 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)
+ : device_t(mconfig, GGF1, "Gravis GF1", tag, owner, clock),
+ device_sound_interface( mconfig, *this )
+{
+}
+
+void gf1_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const gf1_interface *intf = reinterpret_cast<const gf1_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<gf1_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&wave_irq_cb, 0, sizeof(wave_irq_cb));
+ memset(&ramp_irq_cb, 0, sizeof(ramp_irq_cb));
+ memset(&timer1_irq_cb, 0, sizeof(timer1_irq_cb));
+ memset(&timer2_irq_cb, 0, sizeof(timer2_irq_cb));
+ memset(&sb_irq_cb, 0, sizeof(sb_irq_cb));
+ memset(&dma_irq_cb, 0, sizeof(dma_irq_cb));
+ memset(&drq1_cb, 0, sizeof(drq1_cb));
+ memset(&drq2_cb, 0, sizeof(drq2_cb));
+ memset(&nmi_cb, 0, sizeof(nmi_cb));
+ }
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void gf1_device::device_start()
+{
+ int i;
+ double out = (double)(1 << 13);
+
+ // TODO: make DRAM size configurable. Can be 256k, 512k, 768k, or 1024k
+ m_wave_ram = auto_alloc_array(machine(),UINT8,1024*1024);
+ memset(m_wave_ram,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_pointer(NAME(m_wave_ram),1024*1024);
+
+ m_wave_irq_func.resolve(wave_irq_cb, *this);
+ m_ramp_irq_func.resolve(ramp_irq_cb, *this);
+ m_timer1_irq_func.resolve(timer1_irq_cb, *this);
+ m_timer2_irq_func.resolve(timer2_irq_cb, *this);
+ m_sb_irq_func.resolve(sb_irq_cb, *this);
+ m_dma_irq_func.resolve(dma_irq_cb, *this);
+ m_drq1.resolve(drq1_cb,*this);
+ m_drq2.resolve(drq2_cb,*this);
+ m_nmi_func.resolve(nmi_cb, *this);
+
+ 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;
+
+ // 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_func(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;
+ 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_func(0);
+ m_ramp_irq_func(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 & 0x7f;
+ 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, independant 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_func(0);
+ if(!(data & 0x04))
+ {
+ m_adlib_status &= ~0x40;
+ m_timer1_irq_func(0);
+ }
+ if(!(data & 0x08))
+ {
+ m_adlib_status &= ~0x20;
+ m_timer2_irq_func(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:
+ 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_func(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_func(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_func(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_func(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_func(1);
+ m_voice_irq_fifo[m_voice_irq_ptr % 32] = m_irq_source;
+ m_voice_irq_ptr++;
+ }
+ if(source & IRQ_VOLUME_RAMP)
+ {
+ m_irq_source = 0xe0 | (voice & 0x1f);
+ m_irq_source &= ~0x40;
+ m_ramp_irq_func(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_func(0);
+ }
+ if(source & IRQ_VOLUME_RAMP)
+ {
+ m_irq_source |= 0x40;
+ m_ramp_irq_func(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(0);
+}
+
+void gf1_device::eop_w(int state)
+{
+ // end of transfer
+ m_dmatimer->reset();
+ //m_drq1(0);
+ if(m_dma_dram_ctrl & 0x20)
+ {
+ m_dma_dram_ctrl |= 0x40;
+ m_dma_irq_func(1);
+ }
+ logerror("GUS: End of transfer. (%05x)\n",m_dma_current);
+}
+
+
+/* 16-bit ISA card device implementation */
+
+static const acia6850_interface gus_midi_interface =
+{
+ GF1_CLOCK,
+ GF1_CLOCK, // a guess for now
+
+ DEVCB_NULL,
+ DEVCB_NULL,
+
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+
+ DEVCB_NULL
+ //DEVCB_LINE_MEMBER(isa16_gus_device,midi_irq)
+};
+
+static const gf1_interface gus_gf1_config =
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER,isa16_gus_device,wavetable_irq),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER,isa16_gus_device,volumeramp_irq),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER,isa16_gus_device,timer1_irq),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER,isa16_gus_device,timer2_irq),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER,isa16_gus_device,sb_irq),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER,isa16_gus_device,dma_irq),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER,isa16_gus_device,drq1_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER,isa16_gus_device,drq2_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER,isa16_gus_device,nmi_w)
+};
+
+static MACHINE_CONFIG_FRAGMENT( gus_config )
+ MCFG_SPEAKER_STANDARD_STEREO("lspeaker","rspeaker")
+ MCFG_SOUND_ADD("gf1",GGF1,GF1_CLOCK)
+ MCFG_SOUND_CONFIG(gus_gf1_config)
+ MCFG_SOUND_ROUTE(0,"lspeaker",0.50)
+ MCFG_SOUND_ROUTE(1,"rspeaker",0.50)
+// MCFG_ACIA6850_ADD("midi",gus_midi_interface)
+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),
+ device_isa16_card_interface( mconfig, *this )
+{
+}
+
+void isa16_gus_device::device_start()
+{
+ m_gf1 = subdevice<gf1_device>("gf1");
+ //m_midi = subdevice<acia6850_device>("midi");
+ 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;
+ }
+ 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);
+ 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_midi->status_read(space,0);
+// case 0x01:
+// return m_midi->data_read(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;
+ }
+ return 0xff;
+}
+
+WRITE8_MEMBER(isa16_gus_device::synth_w)
+{
+ switch(offset)
+ {
+ case 0x00:
+// m_midi->control_write(space,0,data);
+ break;
+ case 0x01:
+// m_midi->data_write(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_irq )
+{
+ if(state)
+ set_irq(IRQ_MIDI_TRANSMIT);
+ else
+ reset_irq(IRQ_MIDI_TRANSMIT);
+}
+
+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/mess/machine/isa_gus.h b/src/mess/machine/isa_gus.h
new file mode 100644
index 00000000000..853248d2c0d
--- /dev/null
+++ b/src/mess/machine/isa_gus.h
@@ -0,0 +1,284 @@
+/*
+ * 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 "machine/isa.h"
+#include "machine/6850acia.h"
+
+//**************************************************************************
+// 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
+};
+typedef struct _gus_voice gus_voice;
+
+struct _gf1_interface
+{
+ devcb_write_line wave_irq_cb;
+ devcb_write_line ramp_irq_cb;
+ devcb_write_line timer1_irq_cb;
+ devcb_write_line timer2_irq_cb;
+ devcb_write_line sb_irq_cb;
+ devcb_write_line dma_irq_cb;
+ devcb_write_line drq1_cb;
+ devcb_write_line drq2_cb;
+ devcb_write_line nmi_cb;
+};
+typedef struct _gf1_interface gf1_interface;
+
+class gf1_device :
+ public device_t,
+ public device_sound_interface,
+ public gf1_interface
+{
+public:
+ // construction/destruction
+ gf1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // current IRQ/DMA channel getters
+ UINT8 gf1_irq() { return m_gf1_irq; }
+ 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);
+ virtual void device_config_complete();
+
+ // 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();
+
+ UINT8* m_wave_ram;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_stop();
+
+ devcb_resolved_write_line m_wave_irq_func;
+ devcb_resolved_write_line m_ramp_irq_func;
+ devcb_resolved_write_line m_timer1_irq_func;
+ devcb_resolved_write_line m_timer2_irq_func;
+ devcb_resolved_write_line m_sb_irq_func;
+ devcb_resolved_write_line m_dma_irq_func;
+ devcb_resolved_write_line m_drq1;
+ devcb_resolved_write_line m_drq2;
+ devcb_resolved_write_line m_nmi_func;
+
+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;
+};
+
+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_irq);
+ 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);
+
+ // 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();
+ virtual void device_config_complete() { m_shortname = "isa_gus"; }
+private:
+ gf1_device* m_gf1;
+ acia6850_device* m_midi;
+
+ 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/mess/machine/isa_hdc.c b/src/mess/machine/isa_hdc.c
new file mode 100644
index 00000000000..079deb24627
--- /dev/null
+++ b/src/mess/machine/isa_hdc.c
@@ -0,0 +1,828 @@
+/**********************************************************************
+
+ ISA 8 bit XT Hard Disk Controller
+
+**********************************************************************/
+
+#include "emu.h"
+#include "machine/isa_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 READ8_DEVICE_HANDLER(pc_HDC_r);
+static WRITE8_DEVICE_HANDLER(pc_HDC_w);
+
+static MACHINE_CONFIG_FRAGMENT( hdc_config )
+ MCFG_HARDDISK_ADD("primary")
+ MCFG_HARDDISK_ADD("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
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_HDC = &device_creator<isa8_hdc_device>;
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa8_hdc_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( hdc_config );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *isa8_hdc_device::device_rom_region() const
+{
+ return ROM_NAME( 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),
+ device_isa8_card_interface(mconfig, *this)
+{
+ m_shortname = "hdc";
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa8_hdc_device::device_start()
+{
+ set_isa_device();
+ m_isa->install_rom(this, 0xc8000, 0xc9fff, 0, 0, "hdc", "hdc");
+ m_isa->install_device(this, 0x0320, 0x0323, 0, 0, FUNC(pc_HDC_r), FUNC(pc_HDC_w) );
+ m_isa->set_dma_channel(3, this, FALSE);
+ buffer = auto_alloc_array(machine(), UINT8, 17*4*512);
+ timer = machine().scheduler().timer_alloc(FUNC(pc_hdc_command), this);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa8_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;
+ dip = 0xff;
+
+}
+
+hard_disk_file *isa8_hdc_device::pc_hdc_file(int id)
+{
+ harddisk_image_device *img = NULL;
+ astring tempstring;
+ switch( id )
+ {
+ case 0:
+ img = dynamic_cast<harddisk_image_device *>(machine().device(subtag(tempstring,"primary")));
+ break;
+ case 1:
+ img = dynamic_cast<harddisk_image_device *>(machine().device(subtag(tempstring,"slave")));
+ break;
+ }
+ if ( img == NULL )
+ return NULL;
+
+ if (!img->exists())
+ return NULL;
+
+ return img->get_hard_disk_file();
+}
+
+void isa8_hdc_device::pc_hdc_result(int set_error_info)
+{
+ if ( ( hdc_control & 0x02 )) {
+ // dip switch selected IRQ 5 or 2
+ if (BIT(dip, 6))
+ m_isa->irq5_w(1);
+ else
+ m_isa->irq2_w(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 isa8_hdc_device::no_dma(void)
+{
+ return (hdc_control & CTL_DMA) == 0;
+}
+
+
+
+int isa8_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 isa8_hdc_device::pc_hdc_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_isa->drq3_w((hdcdma_read || hdcdma_size ) ? 1 : 0);
+ if(!(hdcdma_read || hdcdma_size)) pc_hdc_result(0);
+ }
+
+ return result;
+}
+
+
+
+void isa8_hdc_device::pc_hdc_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_isa->drq3_w(hdcdma_size ? 1 : 0);
+ if(!hdcdma_size) pc_hdc_result(1);
+ }
+}
+
+
+
+void isa8_hdc_device::execute_read()
+{
+ hard_disk_file *disk = NULL;
+ int size = sector_cnt[drv] * 512;
+ int read_ = 0;
+
+ disk = pc_hdc_file(drv);
+ if (!disk)
+ return;
+
+ hdcdma_src = hdcdma_data;
+ hdcdma_read = read_;
+ hdcdma_size = size;
+
+ if (no_dma())
+ {
+ do
+ {
+ buffer[data_cnt++] = pc_hdc_dack_r();
+ } while (hdcdma_read || hdcdma_size);
+ }
+ else
+ {
+ m_isa->drq3_w(1);
+ }
+}
+
+
+
+void isa8_hdc_device::execute_write()
+{
+ hard_disk_file *disk = NULL;
+ int size = sector_cnt[drv] * 512;
+ int write_ = 512;
+
+ disk = pc_hdc_file(drv);
+ if (!disk)
+ return;
+
+ hdcdma_dst = hdcdma_data;
+ hdcdma_write = write_;
+ hdcdma_size = size;
+
+ if (no_dma())
+ {
+ do
+ {
+ pc_hdc_dack_w(buffer[data_cnt++]);
+ }
+ while (hdcdma_write || hdcdma_size);
+ }
+ else
+ {
+ m_isa->drq3_w(1);
+ }
+}
+
+
+
+void isa8_hdc_device::get_drive()
+{
+ drv = (buffer[1] >> 5) & 1;
+ csb = (drv) ? CSB_LUN : 0x00;
+}
+
+
+
+void isa8_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 isa8_hdc_device::test_ready()
+{
+ if( !pc_hdc_file(drv) )
+ {
+ csb |= CSB_ERROR;
+ error |= 0x04; /* drive not ready */
+ return 0;
+ }
+ return 1;
+}
+
+void isa8_hdc_device::hdc_command()
+{
+ int set_error_info = 1;
+ int old_error = error; /* Previous error data is needed for CMD_SENSE */
+ UINT8 cmd;
+ const char *command_name;
+
+ csb = 0x00;
+ error = 0;
+
+ buffer_ptr = buffer;
+ cmd = buffer[0];
+
+ get_drive();
+
+ if (LOG_HDC_STATUS)
+ {
+ command_name = hdc_command_names[cmd] ? hdc_command_names[cmd] : "Unknown";
+ logerror("pc_hdc_command(): Executing command; pc=0x%08x cmd=0x%02x (%s) drv=%d\n",
+ (unsigned) cpu_get_reg(machine().firstcpu, STATE_GENPC), cmd, command_name, drv);
+ }
+
+ switch (cmd)
+ {
+ case CMD_TESTREADY:
+ set_error_info = 0;
+ test_ready();
+ 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;
+ break;
+ case CMD_RECALIBRATE:
+ get_chsn();
+ break;
+
+ case CMD_FORMATDRV:
+ case CMD_VERIFY:
+ case CMD_FORMATTRK:
+ case CMD_FORMATBAD:
+ case CMD_SEEK:
+ case CMD_DRIVEDIAG:
+ get_chsn();
+ test_ready();
+ break;
+
+ case CMD_READ:
+ case CMD_READLONG:
+ get_chsn();
+
+ if (LOG_HDC_STATUS)
+ {
+ logerror("hdc read pc=0x%08x D:%d C:%d H:%d S:%d N:%d CTL:$%02x\n",
+ (unsigned) cpu_get_reg(machine().firstcpu, STATE_GENPC), drv, cylinder[drv], head[drv], sector[drv], sector_cnt[drv], control[drv]);
+ }
+
+ if (test_ready())
+ execute_read();
+ set_error_info = 0;
+ break;
+
+ case CMD_WRITE:
+ case CMD_WRITELONG:
+ get_chsn();
+
+ if (LOG_HDC_STATUS)
+ {
+ logerror("hdc write pc=0x%08x D:%d C:%d H:%d S:%d N:%d CTL:$%02x\n",
+ (unsigned) cpu_get_reg(machine().firstcpu, STATE_GENPC), drv, cylinder[drv], head[drv], sector[drv], sector_cnt[drv], control[drv]);
+ }
+
+ if (test_ready())
+ execute_write();
+ 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];
+ break;
+
+ case CMD_GETECC:
+ buffer[data_cnt++] = ecc[drv];
+ break;
+
+ case CMD_READSBUFF:
+ case CMD_WRITESBUFF:
+ case CMD_RAMDIAG:
+ case CMD_INTERNDIAG:
+ break;
+
+ }
+ if(no_dma()) pc_hdc_result(set_error_info);
+}
+
+TIMER_CALLBACK(isa8_hdc_device::pc_hdc_command)
+{
+ reinterpret_cast<isa8_hdc_device *>(ptr)->hdc_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 isa8_hdc_device::pc_hdc_data_w(int data)
+{
+ if( data_cnt == 0 )
+ {
+ if (LOG_HDC_DATA)
+ logerror("hdc_data_w $%02x: ", data);
+
+ buffer_ptr = buffer;
+ 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\n", data);
+
+ *buffer_ptr++ = data;
+ status |= STA_READY;
+ if (--data_cnt == 0)
+ {
+ if (LOG_HDC_STATUS)
+ logerror("pc_hdc_data_w(): Launching command; pc=0x%08x\n", (unsigned) cpu_get_reg(machine().firstcpu, STATE_GENPC));
+
+ status &= ~STA_COMMAND;
+ status &= ~STA_REQUEST;
+ status &= ~STA_READY;
+ status |= STA_INPUT;
+
+ timer->adjust(attotime::from_msec(1),0);
+ }
+ }
+}
+
+
+
+void isa8_hdc_device::pc_hdc_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, 17*4*512);
+ buffer_ptr = buffer;
+ data_cnt = 0;
+}
+
+
+
+void isa8_hdc_device::pc_hdc_select_w(int data)
+{
+ status &= ~STA_INTERRUPT;
+ status |= STA_SELECT;
+}
+
+
+
+void isa8_hdc_device::pc_hdc_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))
+ {
+ if (BIT(dip, 6))
+ m_isa->irq5_w(0);
+ else
+ m_isa->irq2_w(0);
+ }
+}
+
+
+
+UINT8 isa8_hdc_device::pc_hdc_data_r()
+{
+ UINT8 data = 0xff;
+ 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;
+ }
+ }
+ return data;
+}
+
+
+
+UINT8 isa8_hdc_device::pc_hdc_status_r()
+{
+ return status;
+}
+
+
+
+/*
+ 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()
+{
+ return dip;
+}
+
+
+
+/*************************************************************************
+ *
+ * HDC
+ * hard disk controller
+ *
+ *************************************************************************/
+static READ8_DEVICE_HANDLER(pc_HDC_r )
+{
+ UINT8 data = 0xff;
+ isa8_hdc_device *hdc = downcast<isa8_hdc_device *>(device);
+
+ switch( offset )
+ {
+ case 0: data = hdc->pc_hdc_data_r(); break;
+ case 1: data = hdc->pc_hdc_status_r(); break;
+ case 2: data = hdc->pc_hdc_dipswitch_r(); break;
+ case 3: break;
+ }
+
+ if (LOG_HDC_CALL)
+ logerror("pc_HDC_r(): pc=%06X offs=%d result=0x%02x\n", cpu_get_pc(device->machine().firstcpu), offset, data);
+
+ return data;
+}
+
+static WRITE8_DEVICE_HANDLER( pc_HDC_w )
+{
+ isa8_hdc_device *hdc = downcast<isa8_hdc_device *>(device);
+ if (LOG_HDC_CALL)
+ logerror("pc_HDC_w(): pc=%06X offs=%d data=0x%02x\n", cpu_get_pc(device->machine().firstcpu), offset, data);
+
+ switch( offset )
+ {
+ case 0: hdc->pc_hdc_data_w(data); break;
+ case 1: hdc->pc_hdc_reset_w(data); break;
+ case 2: hdc->pc_hdc_select_w(data); break;
+ case 3: hdc->pc_hdc_control_w(data); break;
+ }
+}
+
+
+UINT8 isa8_hdc_device::dack_r(int line)
+{
+ return pc_hdc_dack_r();
+}
+
+void isa8_hdc_device::dack_w(int line,UINT8 data)
+{
+ pc_hdc_dack_w(data);
+}
diff --git a/src/mess/machine/isa_hdc.h b/src/mess/machine/isa_hdc.h
new file mode 100644
index 00000000000..7ca8b8aea96
--- /dev/null
+++ b/src/mess/machine/isa_hdc.h
@@ -0,0 +1,102 @@
+/**********************************************************************
+
+ ISA 8 bit XT Hard Disk Controller
+
+**********************************************************************/
+#pragma once
+
+#ifndef ISA_HDC_H
+#define ISA_HDC_H
+
+#include "emu.h"
+#include "machine/isa.h"
+#include "imagedev/harddriv.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> 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);
+
+ // 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:
+ 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 */
+
+ int csb; /* command status byte */
+ int status; /* drive status */
+ int error; /* error code */
+ int dip; /* dip switches */
+ emu_timer *timer;
+
+ int data_cnt; /* data count */
+ UINT8 *buffer; /* data buffer */
+ UINT8 *buffer_ptr; /* data pointer */
+ UINT8 hdc_control;
+
+ UINT8 hdcdma_data[512];
+ UINT8 *hdcdma_src;
+ UINT8 *hdcdma_dst;
+ int hdcdma_read;
+ int hdcdma_write;
+ int hdcdma_size;
+
+ // internal state
+public:
+ virtual UINT8 dack_r(int line);
+ virtual void dack_w(int line,UINT8 data);
+protected:
+ hard_disk_file *pc_hdc_file(int id);
+ void pc_hdc_result(int set_error_info);
+ int no_dma(void);
+ int get_lbasector();
+ int pc_hdc_dack_r();
+ void pc_hdc_dack_w(int data);
+ void execute_read();
+ void execute_write();
+ void get_drive();
+ void get_chsn();
+ int test_ready();
+ static TIMER_CALLBACK(pc_hdc_command);
+public:
+ void hdc_command();
+ void pc_hdc_data_w(int data);
+ void pc_hdc_reset_w(int data);
+ void pc_hdc_select_w(int data);
+ void pc_hdc_control_w(int data);
+ UINT8 pc_hdc_data_r();
+ UINT8 pc_hdc_status_r();
+ UINT8 pc_hdc_dipswitch_r();
+};
+
+
+// device type definition
+extern const device_type ISA8_HDC;
+
+#endif /* ISA_HDC_H */
diff --git a/src/mess/machine/isa_ibm_mfc.c b/src/mess/machine/isa_ibm_mfc.c
new file mode 100644
index 00000000000..fdc09313507
--- /dev/null
+++ b/src/mess/machine/isa_ibm_mfc.c
@@ -0,0 +1,537 @@
+/***************************************************************************
+
+ 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 "isa_ibm_mfc.h"
+#include "cpu/z80/z80.h"
+#include "machine/pit8253.h"
+#include "sound/speaker.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<isa8_ibm_mfc_device>;
+
+
+//-------------------------------------------------
+// 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_LEGACY("ym2151", ym2151_r, ym2151_w)
+ 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;
+}
+
+static I8255_INTERFACE( d71055c_0_intf )
+{
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, isa8_ibm_mfc_device, ppi0_i_a),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, isa8_ibm_mfc_device, ppi0_o_b),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, isa8_ibm_mfc_device, ppi0_i_c),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, isa8_ibm_mfc_device, ppi0_o_c),
+};
+
+
+//-------------------------------------------------
+// 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;
+}
+
+static I8255_INTERFACE( d71055c_1_intf )
+{
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, isa8_ibm_mfc_device, ppi1_o_a),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, isa8_ibm_mfc_device, ppi1_i_b),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, isa8_ibm_mfc_device, ppi1_o_c),
+};
+
+
+//-------------------------------------------------
+// D8253 PIT
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( isa8_ibm_mfc_device::d8253_clk0_out )
+{
+ if (m_tcr & TCR_TAE)
+ set_pc_interrupt(PC_IRQ_TIMERA, 1);
+}
+
+WRITE_LINE_MEMBER( isa8_ibm_mfc_device::d8253_clk1_out )
+{
+ if (m_tcr & TCR_TBE)
+ set_pc_interrupt(PC_IRQ_TIMERB, 1);
+}
+
+WRITE_LINE_MEMBER( isa8_ibm_mfc_device::d8253_clk2_out )
+{
+ pit8253_clk1_w(m_d8253, state);
+}
+
+static const struct pit8253_config d8253_intf =
+{
+ {
+ {
+ XTAL_4MHz / 8,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, isa8_ibm_mfc_device, d8253_clk0_out)
+ },
+ {
+ 0,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, isa8_ibm_mfc_device, d8253_clk1_out)
+ },
+ {
+ XTAL_4MHz / 2,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, isa8_ibm_mfc_device, d8253_clk2_out)
+ }
+ }
+};
+
+
+//-------------------------------------------------
+// uPD71051 USART
+//-------------------------------------------------
+
+READ_LINE_MEMBER( isa8_ibm_mfc_device::d70151_dsr_r )
+{
+ return (m_tcr & TCR_EXT8) ? 1 : 0;
+}
+
+void isa8_ibm_mfc_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ m_d71051->transmit_clock();
+ m_d71051->receive_clock();
+}
+
+static const i8251_interface d71051_intf =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, isa8_ibm_mfc_device, d70151_dsr_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// YM-2164
+//-------------------------------------------------
+
+
+WRITE_LINE_MEMBER(isa8_ibm_mfc_device::ibm_mfc_ym_irq)
+{
+ set_z80_interrupt(Z80_IRQ_YM, state);
+}
+
+static const ym2151_interface ibm_mfc_ym2151_interface =
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, isa8_ibm_mfc_device, ibm_mfc_ym_irq),
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// 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_I8255_ADD("d71055c_0", d71055c_0_intf)
+ MCFG_I8255_ADD("d71055c_1", d71055c_1_intf)
+ MCFG_I8251_ADD("d71051", d71051_intf)
+ MCFG_PIT8253_ADD("d8253", d8253_intf)
+
+ MCFG_SPEAKER_STANDARD_STEREO("ymleft", "ymright")
+ MCFG_SOUND_ADD("ym2151", YM2151, XTAL_4MHz)
+ MCFG_SOUND_CONFIG(ibm_mfc_ym2151_interface)
+ 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:
+ {
+ pit8253_w(m_d8253, 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);
+
+ 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),
+ 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));
+
+ // Create a 500KHz timer for the USART
+ m_serial_timer = timer_alloc();
+ m_serial_timer->adjust(attotime::zero, 0, attotime::from_hz(XTAL_4MHz / 8));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa8_ibm_mfc_device::device_reset()
+{
+ m_tcr = 0;
+ m_pc_irq_state = 0;
+ m_z80_irq_state = 0;
+}
diff --git a/src/mess/machine/isa_ibm_mfc.h b/src/mess/machine/isa_ibm_mfc.h
new file mode 100644
index 00000000000..185cc2d3f95
--- /dev/null
+++ b/src/mess/machine/isa_ibm_mfc.h
@@ -0,0 +1,97 @@
+/***************************************************************************
+
+ 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 "machine/isa.h"
+#include "machine/i8255.h"
+#include "machine/i8251.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);
+
+ // Optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual ioport_constructor device_input_ports() const;
+ virtual void device_config_complete() { m_shortname = "ibm_mfc"; }
+
+ 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_READ_LINE_MEMBER( d70151_dsr_r );
+
+ DECLARE_WRITE_LINE_MEMBER( d8253_clk0_out );
+ DECLARE_WRITE_LINE_MEMBER( d8253_clk1_out );
+ DECLARE_WRITE_LINE_MEMBER( d8253_clk2_out );
+
+ DECLARE_WRITE_LINE_MEMBER( ibm_mfc_ym_irq );
+
+ void set_z80_interrupt(int src, int 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);
+
+ const rom_entry* device_rom_region() const;
+
+private:
+ 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;
+
+ emu_timer *m_serial_timer;
+
+ required_device<cpu_device> m_cpu;
+ required_device<ym2151_device> m_ym2151;
+ required_device<device_t> m_d8253;
+ required_device<i8251_device> m_d71051;
+ required_device<i8255_device> m_d71055c_0;
+ required_device<i8255_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/mess/machine/isa_ide.c b/src/mess/machine/isa_ide.c
new file mode 100644
index 00000000000..833d8b54ea2
--- /dev/null
+++ b/src/mess/machine/isa_ide.c
@@ -0,0 +1,118 @@
+/***************************************************************************
+
+ ISA 16 bit IDE controller
+
+***************************************************************************/
+
+#include "emu.h"
+#include "isa_ide.h"
+#include "machine/idectrl.h"
+#include "imagedev/harddriv.h"
+
+static READ16_DEVICE_HANDLER( ide16_r )
+{
+ return ide_controller16_r(device, 0x1f0/2 + offset, mem_mask);
+}
+
+static WRITE16_DEVICE_HANDLER( ide16_w )
+{
+ ide_controller16_w(device, 0x1f0/2 + offset, data, mem_mask);
+}
+
+
+static READ16_DEVICE_HANDLER( ide16_alt_r )
+{
+ return ide_controller16_r(device, 0x3f6/2 + offset, 0x00ff);
+}
+
+static WRITE16_DEVICE_HANDLER( ide16_alt_w )
+{
+ ide_controller16_w(device, 0x3f6/2 + offset, data, 0x00ff);
+}
+
+static void ide_interrupt(device_t *device, int state)
+{
+ isa16_ide_device *ide = downcast<isa16_ide_device *>(device->owner());
+ if (ide->is_primary()) {
+ ide->m_isa->irq14_w(state);
+ } else {
+ ide->m_isa->irq15_w(state);
+ }
+}
+
+
+static MACHINE_CONFIG_FRAGMENT( ide )
+ MCFG_IDE_CONTROLLER_ADD("ide", ide_interrupt, ide_image_devices, "hdd", "hdd", false)
+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<isa16_ide_device>;
+
+//-------------------------------------------------
+// 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),
+ device_isa16_card_interface( mconfig, *this ),
+ m_is_primary(true)
+{
+}
+
+//-------------------------------------------------
+// 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->install16_device(subdevice("ide"), 0x01f0, 0x01f7, 0, 0, FUNC(ide16_r), FUNC(ide16_w) );
+ //m_isa->install16_device(subdevice("ide"), 0x03f6, 0x03f7, 0, 0, FUNC(ide16_alt_r), FUNC(ide16_alt_w) );
+ } else {
+ m_isa->install16_device(subdevice("ide"), 0x0170, 0x0177, 0, 0, FUNC(ide16_r), FUNC(ide16_w) );
+ m_isa->install16_device(subdevice("ide"), 0x0376, 0x0377, 0, 0, FUNC(ide16_alt_r), FUNC(ide16_alt_w) );
+ }
+}
diff --git a/src/mess/machine/isa_ide.h b/src/mess/machine/isa_ide.h
new file mode 100644
index 00000000000..5b269327739
--- /dev/null
+++ b/src/mess/machine/isa_ide.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#ifndef __ISA_IDE_H__
+#define __ISA_IDE_H__
+
+#include "emu.h"
+#include "machine/isa.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; }
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "isa_ide"; }
+private:
+ // internal state
+ bool m_is_primary;
+};
+
+
+// device type definition
+extern const device_type ISA16_IDE;
+
+#endif /* __ISA_IDE_H__ */
diff --git a/src/mess/machine/isa_ide_cd.c b/src/mess/machine/isa_ide_cd.c
new file mode 100644
index 00000000000..46e493cbec8
--- /dev/null
+++ b/src/mess/machine/isa_ide_cd.c
@@ -0,0 +1,464 @@
+/***************************************************************************
+
+ ISA 16 bit IDE controller
+
+***************************************************************************/
+
+#include "emu.h"
+#include "isa_ide_cd.h"
+
+static void atapi_irq(device_t *device, int state)
+{
+ isa16_ide_cd_device *ide = downcast<isa16_ide_cd_device *>(device);
+ if (ide->is_primary()) {
+ ide->m_isa->irq14_w(state);
+ } else {
+ ide->m_isa->irq15_w(state);
+ }
+}
+
+WRITE16_MEMBER( isa16_ide_cd_device::atapi_cmd_w )
+{
+}
+READ16_MEMBER( isa16_ide_cd_device::atapi_status_r )
+{
+ UINT8 *atapi_regs = m_atapi_regs;
+ int shift;
+ shift = 0;
+ switch(mem_mask)
+ {
+ case 0x000000ff:
+ break;
+ case 0x0000ff00:
+ shift=8;
+ break;
+ }
+ UINT32 data = atapi_regs[ATAPI_REG_CMDSTATUS];
+ data <<= shift;
+ return data;
+}
+
+READ16_MEMBER( isa16_ide_cd_device::atapi_r )
+{
+ UINT8 *atapi_regs = m_atapi_regs;
+ //running_machine &machine = machine();
+ int reg, data;
+ if (mem_mask == 0x0000ffff) // word-wide command read
+ {
+ //logerror("ATAPI: packet read = %02x%02x\n", m_atapi_data[m_atapi_data_ptr+1],m_atapi_data[m_atapi_data_ptr]);
+
+ // assert IRQ and drop DRQ
+ if (m_atapi_data_ptr == 0 && m_atapi_data_len == 0)
+ {
+ // get the data from the device
+ if( m_atapi_xferlen > 0 )
+ {
+ m_inserted_cdrom->ReadData( m_atapi_data, m_atapi_xferlen );
+ m_atapi_data_len = m_atapi_xferlen;
+ }
+
+ if (m_atapi_xfermod > MAX_TRANSFER_SIZE)
+ {
+ m_atapi_xferlen = MAX_TRANSFER_SIZE;
+ m_atapi_xfermod = m_atapi_xfermod - MAX_TRANSFER_SIZE;
+ }
+ else
+ {
+ m_atapi_xferlen = m_atapi_xfermod;
+ m_atapi_xfermod = 0;
+ }
+
+ //verboselog\\( machine, 2, "atapi_r: atapi_xferlen=%d\n", m_atapi_xferlen );
+ if( m_atapi_xferlen != 0 )
+ {
+ atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRQ | ATAPI_STAT_SERVDSC;
+ atapi_regs[ATAPI_REG_INTREASON] = ATAPI_INTREASON_IO;
+ }
+ else
+ {
+ //logerror("ATAPI: dropping DRQ\n");
+ atapi_regs[ATAPI_REG_CMDSTATUS] = 0;
+ atapi_regs[ATAPI_REG_INTREASON] = ATAPI_INTREASON_IO | ATAPI_INTREASON_COMMAND;
+ }
+
+ atapi_regs[ATAPI_REG_COUNTLOW] = m_atapi_xferlen & 0xff;
+ atapi_regs[ATAPI_REG_COUNTHIGH] = (m_atapi_xferlen>>8)&0xff;
+
+ atapi_irq(this, ASSERT_LINE);
+ }
+
+ if( m_atapi_data_ptr < m_atapi_data_len )
+ {
+ data = m_atapi_data[m_atapi_data_ptr++];
+ data |= ( m_atapi_data[m_atapi_data_ptr++] << 8 );
+ if( m_atapi_data_ptr >= m_atapi_data_len )
+ {
+
+ m_atapi_data_ptr = 0;
+ m_atapi_data_len = 0;
+
+ if( m_atapi_xferlen == 0 )
+ {
+ atapi_regs[ATAPI_REG_CMDSTATUS] = 0;
+ atapi_regs[ATAPI_REG_INTREASON] = ATAPI_INTREASON_IO | ATAPI_INTREASON_COMMAND;
+ atapi_irq(this, ASSERT_LINE);
+ }
+ }
+ }
+ else
+ {
+ data = 0;
+ }
+ }
+ else
+ {
+ atapi_irq(this, CLEAR_LINE);
+ int shift;
+ shift = 0;
+ reg = offset<<1;
+ switch(mem_mask)
+ {
+ case 0x000000ff:
+ break;
+ case 0x0000ff00:
+ reg+=1;
+ shift=8;
+ break;
+ }
+ if (m_cur_drive==1) return 0x00;
+ data = atapi_regs[reg];
+ //logerror("ATAPI: reg %d = %x (offset %x mask %x) [%08x][read]\n", reg, data, offset, mem_mask,cpu_get_pc(machine().device("maincpu")));
+ data <<= shift;
+ }
+ return data;
+}
+
+WRITE16_MEMBER( isa16_ide_cd_device::atapi_w )
+{
+ UINT8 *atapi_regs = m_atapi_regs;
+ UINT8 *atapi_data = m_atapi_data;
+ int reg;
+ if (mem_mask == 0x0000ffff) // word-wide command write
+ {
+ atapi_data[m_atapi_data_ptr++] = data & 0xff;
+ atapi_data[m_atapi_data_ptr++] = data >> 8;
+
+ if (m_atapi_cdata_wait)
+ {
+ //logerror("ATAPI: waiting, ptr %d wait %d\n", m_atapi_data_ptr, m_atapi_cdata_wait);
+ if (m_atapi_data_ptr == m_atapi_cdata_wait)
+ {
+ // send it to the device
+ m_inserted_cdrom->WriteData( atapi_data, m_atapi_cdata_wait );
+
+ // assert IRQ
+ atapi_irq(this, ASSERT_LINE);
+
+ // not sure here, but clear DRQ at least?
+ atapi_regs[ATAPI_REG_CMDSTATUS] = 0;
+ }
+ }
+
+ else if ( m_atapi_data_ptr == 12 )
+ {
+ int phase;
+ // reset data pointer for reading SCSI results
+ m_atapi_data_ptr = 0;
+ m_atapi_data_len = 0;
+ void *cdrom;
+ m_inserted_cdrom->GetDevice( &cdrom );
+ bool checkready = false;
+ switch(atapi_data[0]&0xff) {
+ case 0x00 :
+ case 0x25 :
+ case 0x28 :
+ case 0x2b :
+ case 0x43 :
+ case 0xa8 :
+ case 0xad :
+ case 0xbe :
+ checkready = true;
+ break;
+ }
+
+ if (checkready && cdrom_get_toc((cdrom_file *)cdrom)==NULL)
+ {
+ logerror("ATAPI: SCSI command %02x returned not ready\n", atapi_data[0]&0xff);
+ atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRDY | ATAPI_STAT_CHECK;
+ atapi_regs[ATAPI_REG_ERRFEAT] = (2 << 4) | ATAPI_ERRFEAT_ABRT;
+ // assert IRQ
+ atapi_irq(this, ASSERT_LINE);
+ } else {
+ // send it to the SCSI device
+ m_inserted_cdrom->SetCommand( m_atapi_data, 12 );
+ m_inserted_cdrom->ExecCommand( &m_atapi_xferlen );
+ m_inserted_cdrom->GetPhase( &phase );
+
+ if (m_atapi_xferlen != -1)
+ {
+ logerror("ATAPI: SCSI command %02x returned %d bytes from the device\n", atapi_data[0]&0xff, m_atapi_xferlen);
+ // store the returned command length in the ATAPI regs, splitting into
+ // multiple transfers if necessary
+ m_atapi_xfermod = 0;
+ if (m_atapi_xferlen > MAX_TRANSFER_SIZE)
+ {
+ m_atapi_xfermod = m_atapi_xferlen - MAX_TRANSFER_SIZE;
+ m_atapi_xferlen = MAX_TRANSFER_SIZE;
+ }
+
+ atapi_regs[ATAPI_REG_COUNTLOW] = m_atapi_xferlen & 0xff;
+ atapi_regs[ATAPI_REG_COUNTHIGH] = (m_atapi_xferlen>>8)&0xff;
+
+ if (m_atapi_xferlen == 0)
+ {
+ // if no data to return, set the registers properly
+ atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRDY;
+ atapi_regs[ATAPI_REG_INTREASON] = ATAPI_INTREASON_IO|ATAPI_INTREASON_COMMAND;
+ }
+ else
+ {
+ // indicate data ready: set DRQ and DMA ready, and IO in INTREASON
+ atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRQ | ATAPI_STAT_SERVDSC;
+ atapi_regs[ATAPI_REG_INTREASON] = ATAPI_INTREASON_IO;
+ }
+
+ switch( phase )
+ {
+ case SCSI_PHASE_DATAOUT:
+ m_atapi_cdata_wait = m_atapi_xferlen;
+ break;
+ }
+
+ // perform special ATAPI processing of certain commands
+ switch (atapi_data[0]&0xff)
+ {
+ case 0x00: // BUS RESET / TEST UNIT READY
+ case 0xbb: // SET CDROM SPEED
+ atapi_regs[ATAPI_REG_CMDSTATUS] = 0;
+ break;
+
+ case 0x45: // PLAY
+ atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_BSY;
+ //m_atapi_timer->adjust( downcast<cpu_device *>(this)->cycles_to_attotime( ATAPI_CYCLES_PER_SECTOR ) );
+ break;
+ }
+
+ // assert IRQ
+ atapi_irq(this, ASSERT_LINE);
+ }
+ else
+ {
+ logerror("ATAPI: SCSI device returned error!\n");
+
+ atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRQ | ATAPI_STAT_CHECK;
+ atapi_regs[ATAPI_REG_ERRFEAT] = 0x50; // sense key = ILLEGAL REQUEST
+ atapi_regs[ATAPI_REG_COUNTLOW] = 0;
+ atapi_regs[ATAPI_REG_COUNTHIGH] = 0;
+ }
+ }
+ }
+ }
+ else
+ {
+ reg = offset<<1;
+ switch(mem_mask)
+ {
+ case 0x000000ff:
+ break;
+ case 0x0000ff00:
+ reg+=1;
+ data >>= 8;
+ break;
+ }
+ if (reg==6) m_cur_drive = (data & 0x10) >> 4;
+ if (m_cur_drive==1) return;
+ atapi_regs[reg] = data;
+ //logerror("ATAPI: reg %d = %x (offset %x mask %x)\n", reg, data, offset, mem_mask);
+
+ if (reg == ATAPI_REG_CMDSTATUS)
+ {
+ logerror("ATAPI command %x issued!\n", data);
+ switch (data)
+ {
+ case 0xa0: // PACKET
+ atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRQ;
+ atapi_regs[ATAPI_REG_INTREASON] = ATAPI_INTREASON_COMMAND;
+
+ m_atapi_data_ptr = 0;
+ m_atapi_data_len = 0;
+
+ /* we have no data */
+ m_atapi_xferlen = 0;
+ m_atapi_xfermod = 0;
+
+ m_atapi_cdata_wait = 0;
+ break;
+
+ case 0xa1: // IDENTIFY PACKET DEVICE
+ atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_DRQ;
+
+ m_atapi_data_ptr = 0;
+ m_atapi_data_len = 512;
+
+ /* we have no data */
+ m_atapi_xferlen = 0;
+ m_atapi_xfermod = 0;
+
+ memset( atapi_data, 0, m_atapi_data_len );
+
+ atapi_data[ 0 ^ 1 ] = 0x85; // ATAPI device, cmd set 5 compliant, DRQ within 3 ms of PACKET command
+ atapi_data[ 1 ^ 1 ] = 0x80; // ATAPI device, removable media
+
+ memset( &atapi_data[ 46 ], ' ', 8 );
+ atapi_data[ 46 ^ 1 ] = '1';
+ atapi_data[ 47 ^ 1 ] = '.';
+ atapi_data[ 48 ^ 1 ] = '0';
+
+ memset( &atapi_data[ 54 ], ' ', 40 );
+ atapi_data[ 54 ^ 1 ] = 'M';
+ atapi_data[ 55 ^ 1 ] = 'A';
+ atapi_data[ 56 ^ 1 ] = 'M';
+ atapi_data[ 57 ^ 1 ] = 'E';
+ atapi_data[ 58 ^ 1 ] = ' ';
+ atapi_data[ 59 ^ 1 ] = 'C';
+ atapi_data[ 60 ^ 1 ] = 'o';
+ atapi_data[ 61 ^ 1 ] = 'm';
+ atapi_data[ 62 ^ 1 ] = 'p';
+ atapi_data[ 63 ^ 1 ] = 'r';
+ atapi_data[ 64 ^ 1 ] = 'e';
+ atapi_data[ 65 ^ 1 ] = 's';
+ atapi_data[ 66 ^ 1 ] = 's';
+ atapi_data[ 67 ^ 1 ] = 'e';
+ atapi_data[ 68 ^ 1 ] = 'd';
+ atapi_data[ 69 ^ 1 ] = ' ';
+ atapi_data[ 70 ^ 1 ] = 'C';
+ atapi_data[ 71 ^ 1 ] = 'D';
+ atapi_data[ 72 ^ 1 ] = '-';
+ atapi_data[ 73 ^ 1 ] = 'R';
+ atapi_data[ 74 ^ 1 ] = 'O';
+ atapi_data[ 75 ^ 1 ] = 'M';
+
+ atapi_data[ 98 ^ 1 ] = 0x06; // Word 49=Capabilities, IORDY may be disabled (bit_10), LBA Supported mandatory (bit_9)
+ atapi_data[ 99 ^ 1 ] = 0x00;
+
+ atapi_regs[ATAPI_REG_COUNTLOW] = 0;
+ atapi_regs[ATAPI_REG_COUNTHIGH] = 2;
+
+ atapi_irq(this, ASSERT_LINE);
+ break;
+ case 0xec: //IDENTIFY DEVICE - Must abort here and set for packet data
+ atapi_regs[ATAPI_REG_ERRFEAT] = ATAPI_ERRFEAT_ABRT;
+ atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_CHECK;
+
+ atapi_irq(this, ASSERT_LINE);
+ break;
+ case 0xef: // SET FEATURES
+ atapi_regs[ATAPI_REG_CMDSTATUS] = 0;
+
+ m_atapi_data_ptr = 0;
+ m_atapi_data_len = 0;
+
+ atapi_irq(this, ASSERT_LINE);
+ break;
+
+ case 0x08: // ATAPI RESET
+ atapi_regs[ATAPI_REG_CMDSTATUS] = 0x00;
+ atapi_regs[ATAPI_REG_ERRFEAT] = 0x01;
+ atapi_regs[ATAPI_REG_INTREASON] = 0x01; // SECTOR_COUNT
+ atapi_regs[ATAPI_REG_SAMTAG] = 0x01; // SECTOR_NUMBER
+ atapi_regs[ATAPI_REG_COUNTLOW] = 0x14; // CYLINDER_LSB
+ atapi_regs[ATAPI_REG_COUNTHIGH] = 0xeb; // CYLINDER_MSB
+ atapi_regs[ATAPI_REG_DRIVESEL] &= 0xf0; // HEAD_NUMBER
+
+ atapi_irq(this, ASSERT_LINE);
+ break;
+ default:
+ logerror("ATAPI: Unknown IDE command %x\n", data);
+ atapi_regs[ATAPI_REG_ERRFEAT] = ATAPI_ERRFEAT_ABRT;
+ atapi_regs[ATAPI_REG_CMDSTATUS] = ATAPI_STAT_CHECK;
+
+ atapi_irq(this, ASSERT_LINE);
+ break;
+ }
+ }
+ }
+}
+
+static MACHINE_CONFIG_FRAGMENT( ide )
+ MCFG_DEVICE_ADD("cdrom", SCSICD, 0)
+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_CD = &device_creator<isa16_ide_cd_device>;
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa16_ide_cd_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( ide );
+}
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+ioport_constructor isa16_ide_cd_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( ide );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// isa16_ide_cd_device - constructor
+//-------------------------------------------------
+
+isa16_ide_cd_device::isa16_ide_cd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, ISA16_IDE_CD, "IDE CD Drive Adapter", tag, owner, clock),
+ device_isa16_card_interface( mconfig, *this ),
+ m_is_primary(true),
+ m_inserted_cdrom(NULL)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa16_ide_cd_device::device_start()
+{
+ set_isa_device();
+ m_inserted_cdrom = subdevice<scsicd_device>("cdrom");
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa16_ide_cd_device::device_reset()
+{
+ m_is_primary = (ioport("DSW")->read() & 1) ? false : true;
+ if (m_is_primary) {
+ m_isa->install16_device(0x01f0, 0x01f7, 0, 0, read16_delegate(FUNC(isa16_ide_cd_device::atapi_r), this), write16_delegate(FUNC(isa16_ide_cd_device::atapi_w), this));
+ //m_isa->install16_device(0x03f0, 0x03f7, 0, 0, read16_delegate(FUNC(isa16_ide_cd_device::atapi_status_r), this), write16_delegate(FUNC(isa16_ide_cd_device::atapi_cmd_w), this));
+ } else {
+ m_isa->install16_device(0x0170, 0x0177, 0, 0, read16_delegate(FUNC(isa16_ide_cd_device::atapi_r), this), write16_delegate(FUNC(isa16_ide_cd_device::atapi_w), this));
+ m_isa->install16_device(0x0370, 0x0377, 0, 0, read16_delegate(FUNC(isa16_ide_cd_device::atapi_status_r), this), write16_delegate(FUNC(isa16_ide_cd_device::atapi_cmd_w), this));
+ }
+ m_cur_drive = 0;
+}
diff --git a/src/mess/machine/isa_ide_cd.h b/src/mess/machine/isa_ide_cd.h
new file mode 100644
index 00000000000..e0b2f7a789e
--- /dev/null
+++ b/src/mess/machine/isa_ide_cd.h
@@ -0,0 +1,93 @@
+#pragma once
+
+#ifndef __ISA_IDE_CD_H__
+#define __ISA_IDE_CD_H__
+
+#include "emu.h"
+#include "machine/isa.h"
+#include "imagedev/chd_cd.h"
+#include "machine/cr589.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+#define ATAPI_CYCLES_PER_SECTOR (5000) // plenty of time to allow DMA setup etc. BIOS requires this be at least 2000, individual games may vary.
+
+#define ATAPI_ERRFEAT_ABRT 0x04
+
+#define ATAPI_STAT_BSY 0x80
+#define ATAPI_STAT_DRDY 0x40
+#define ATAPI_STAT_DMARDDF 0x20
+#define ATAPI_STAT_SERVDSC 0x10
+#define ATAPI_STAT_DRQ 0x08
+#define ATAPI_STAT_CORR 0x04
+#define ATAPI_STAT_CHECK 0x01
+
+#define ATAPI_INTREASON_COMMAND 0x01
+#define ATAPI_INTREASON_IO 0x02
+#define ATAPI_INTREASON_RELEASE 0x04
+
+#define ATAPI_REG_DATA 0
+#define ATAPI_REG_ERRFEAT 1
+#define ATAPI_REG_INTREASON 2
+#define ATAPI_REG_SAMTAG 3
+#define ATAPI_REG_COUNTLOW 4
+#define ATAPI_REG_COUNTHIGH 5
+#define ATAPI_REG_DRIVESEL 6
+#define ATAPI_REG_CMDSTATUS 7
+#define ATAPI_REG_MAX 16
+
+#define ATAPI_DATA_SIZE ( 64 * 1024 )
+
+#define MAX_TRANSFER_SIZE ( 63488 )
+
+// ======================> isa16_ide_cd_device
+
+class isa16_ide_cd_device :
+ public device_t,
+ public device_isa16_card_interface
+{
+public:
+ // construction/destruction
+ isa16_ide_cd_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_READ16_MEMBER(atapi_r);
+ DECLARE_WRITE16_MEMBER(atapi_w);
+ DECLARE_READ16_MEMBER(atapi_status_r);
+ DECLARE_WRITE16_MEMBER(atapi_cmd_w);
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "isa_ide_cd"; }
+private:
+ // internal state
+ bool m_is_primary;
+
+ // CDROM
+ scsicd_device *m_inserted_cdrom;
+
+ int m_atapi_data_ptr;
+ int m_atapi_data_len;
+ int m_atapi_xferlen;
+ int m_atapi_cdata_wait;
+ int m_atapi_xfermod;
+ /* memory */
+ UINT8 m_atapi_regs[ATAPI_REG_MAX];
+ UINT8 m_atapi_data[ATAPI_DATA_SIZE];
+
+ int m_cur_drive;
+};
+
+
+// device type definition
+extern const device_type ISA16_IDE_CD;
+
+#endif /* __ISA_IDE_CD_H__ */
diff --git a/src/mess/machine/isa_mpu401.c b/src/mess/machine/isa_mpu401.c
new file mode 100644
index 00000000000..4b60e12166f
--- /dev/null
+++ b/src/mess/machine/isa_mpu401.c
@@ -0,0 +1,105 @@
+/***************************************************************************
+
+ MPU-401 MIDI device interface
+
+ TODO:
+ - skeleton, doesn't do anything
+
+***************************************************************************/
+
+#include "emu.h"
+#include "isa_mpu401.h"
+#include "machine/pic8259.h"
+
+/*
+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
+*/
+
+READ8_MEMBER( isa8_mpu401_device::mpu401_r )
+{
+ UINT8 res;
+
+ if(offset == 0) // data
+ {
+ res = 0xff;
+ }
+ else // status
+ {
+ res = 0x3f | 0x80; // bit 7 queue empty (DSR), bit 6 DRR (Data Receive Ready?)
+ }
+
+ return res;
+}
+
+WRITE8_MEMBER( isa8_mpu401_device::mpu401_w )
+{
+ if(offset == 0) // data
+ {
+ printf("%02x %02x\n",offset,data);
+ }
+ else // command
+ {
+ printf("%02x %02x\n",offset,data);
+
+ switch(data)
+ {
+ case 0xff: // reset
+ //m_isa->irq2_w(1);
+ break;
+ }
+ }
+
+}
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_MPU401 = &device_creator<isa8_mpu401_device>;
+
+
+//**************************************************************************
+// 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 Sound Card", tag, owner, clock),
+ device_isa8_card_interface( mconfig, *this )
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa8_mpu401_device::device_start()
+{
+ set_isa_device();
+ m_isa->install_device(0x330, 0x0331, 0, 0, read8_delegate(FUNC(isa8_mpu401_device::mpu401_r), this), write8_delegate(FUNC(isa8_mpu401_device::mpu401_w), this));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa8_mpu401_device::device_reset()
+{
+}
diff --git a/src/mess/machine/isa_mpu401.h b/src/mess/machine/isa_mpu401.h
new file mode 100644
index 00000000000..99601950c43
--- /dev/null
+++ b/src/mess/machine/isa_mpu401.h
@@ -0,0 +1,39 @@
+#pragma once
+
+#ifndef __ISA_MPU401_H__
+#define __ISA_MPU401_H__
+
+#include "emu.h"
+#include "machine/isa.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);
+
+ DECLARE_READ8_MEMBER(mpu401_r);
+ DECLARE_WRITE8_MEMBER(mpu401_w);
+ // optional information overrides
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "isa_mpu401"; }
+private:
+ // internal state
+};
+
+
+// device type definition
+extern const device_type ISA8_MPU401;
+
+#endif /* __ISA_MPU401_H__ */
diff --git a/src/mess/machine/isa_sblaster.c b/src/mess/machine/isa_sblaster.c
new file mode 100644
index 00000000000..8f5c481e0c1
--- /dev/null
+++ b/src/mess/machine/isa_sblaster.c
@@ -0,0 +1,616 @@
+/***************************************************************************
+
+ ISA 8 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 "emu.h"
+#include "isa_sblaster.h"
+#include "sound/speaker.h"
+#include "sound/3812intf.h"
+#include "sound/saa1099.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
+ also on sound blaster 1.0
+ option on sound blaster 1.5
+
+ jumperable? normally 0x220
+*/
+#define ym3812_StdClock XTAL_3_579545MHz
+
+static INPUT_PORTS_START( sblaster )
+ PORT_START("pc_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("SB: Joystick Button 1")
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON2) PORT_NAME("SB: Joystick Button 2")
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON3) PORT_NAME("SB: Joystick Button 3")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON4) PORT_NAME("SB: Joystick Button 4")
+
+ PORT_START("pc_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("pc_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
+
+ioport_constructor sb8_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( sblaster );
+}
+
+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, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x */
+ 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, /* 1x */
+ -1, -1, -1, -1, -1, -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, -1, -1, -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, -1, -1, -1, -1, -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 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* Bx */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -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][9] =
+{
+ { 1, -2, -4, 8, -16, 32, 64, -128, -106 },
+ { -1, 2, -4, 8, 16, -32, 64, -128, 165 },
+ { -1, 2, 4, -8, 16, -32, -64, 128, -151 },
+ { 1, -2, 4, -8, -16, 32, -64, 128, 90 }
+};
+
+static const ym3812_interface pc_ym3812_interface =
+{
+ NULL
+};
+
+static MACHINE_CONFIG_FRAGMENT( sblaster1_0_config )
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+ MCFG_SOUND_ADD("ym3812", YM3812, ym3812_StdClock)
+ MCFG_SOUND_CONFIG(pc_ym3812_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 3.00)
+ MCFG_SOUND_ADD("saa1099.1", SAA1099, 4772720)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+ MCFG_SOUND_ADD("saa1099.2", SAA1099, 4772720)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+
+ MCFG_SOUND_ADD("sbdac", DAC, 0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00)
+MACHINE_CONFIG_END
+
+static MACHINE_CONFIG_FRAGMENT( sblaster1_5_config )
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+ MCFG_SOUND_ADD("ym3812", YM3812, ym3812_StdClock)
+ MCFG_SOUND_CONFIG(pc_ym3812_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00)
+ /* no CM/S support (empty sockets) */
+
+ MCFG_SOUND_ADD("sbdac", DAC, 0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00)
+MACHINE_CONFIG_END
+
+
+static READ8_DEVICE_HANDLER( ym3812_16_r )
+{
+ UINT8 retVal = 0xff;
+ switch(offset)
+ {
+ case 0 : retVal = ym3812_status_port_r( device, offset ); break;
+ }
+ return retVal;
+}
+
+static WRITE8_DEVICE_HANDLER( ym3812_16_w )
+{
+ switch(offset)
+ {
+ case 0 : ym3812_control_port_w( device, offset, data ); break;
+ case 1 : ym3812_write_port_w( device, offset, data ); break;
+ }
+}
+
+static READ8_DEVICE_HANDLER( saa1099_16_r )
+{
+ return 0xff;
+}
+
+static WRITE8_DEVICE_HANDLER( saa1099_16_w )
+{
+ switch(offset)
+ {
+ case 0 : saa1099_control_w( device, offset, data ); break;
+ case 1 : saa1099_data_w( device, offset, data ); break;
+ }
+}
+
+void sb8_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 sb8_device::queue_r(UINT8 data)
+{
+ m_dsp.rbuf_status |= 0x80;
+
+ if (m_dsp.fifo_r_ptr < 15)
+ {
+ 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 sb8_device::dequeue_r()
+{
+ UINT8 data = m_dsp.fifo_r[0];
+
+ if (m_dsp.fifo_r_ptr > 0)
+ {
+ for (int i = 0; i < 15; i++)
+ m_dsp.fifo_r[i] = m_dsp.fifo_r[i + 1];
+
+ m_dsp.fifo_r[15] = 0;
+
+ m_dsp.fifo_r_ptr--;
+ }
+
+ if(m_dsp.fifo_r_ptr == 0)
+ m_dsp.rbuf_status &= ~0x80;
+
+ return data;
+}
+
+
+READ8_MEMBER( sb8_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( sb8_device::dsp_reset_w )
+{
+// printf("%02x to DSP reset @ %x\n", data, offset);
+ if(offset)
+ return;
+
+ 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;
+ m_isa->drq1_w(0);
+ m_dsp.dma_autoinit = 0;
+ m_isa->irq5_w(0);
+ 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;
+
+ //printf("%02x\n",data);
+}
+
+READ8_MEMBER( sb8_device::dsp_data_r )
+{
+// printf("read DSP data @ %x\n", offset);
+ if(offset)
+ return 0xff;
+
+ return dequeue_r();
+}
+
+WRITE8_MEMBER( sb8_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(sb8_device::dsp_rbuf_status_r)
+{
+// printf("read Rbufstat @ %x\n", offset);
+
+ if(offset)
+ return 0xff;
+
+// printf("Clear IRQ5\n");
+ m_isa->irq5_w(0); // reading this port ACKs the card's IRQ
+
+ return m_dsp.rbuf_status;
+}
+
+READ8_MEMBER(sb8_device::dsp_wbuf_status_r)
+{
+// printf("read Wbufstat @ %x\n", offset);
+ if(offset)
+ return 0xff;
+
+ return m_dsp.wbuf_status;
+}
+
+WRITE8_MEMBER(sb8_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 sb8_device::process_fifo(UINT8 cmd)
+{
+ if (m_cmd_fifo_length[cmd] == -1)
+ {
+ printf("unemulated or undefined fifo command %02x\n",cmd);
+ }
+ 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;
+ m_isa->drq1_w(1);
+ 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;
+ m_isa->drq1_w(1);
+ 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 0xd0: // halt 8-bit DMA
+ m_timer->adjust(attotime::never, 0);
+ m_isa->drq1_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
+ for (int i = 0; i < 8; i++)
+ {
+ if ((m_dsp.fifo[1] >> i) & 0x01)
+ {
+ m_dsp.prot_value += protection_magic[m_dsp.prot_count % 4][i];
+ }
+ }
+
+ m_dsp.prot_value += protection_magic[m_dsp.prot_count % 4][8];
+ m_dsp.prot_count++;
+
+ m_dack_out = (UINT8)(m_dsp.prot_value & 0xff);
+ m_isa->drq1_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
+ m_isa->irq5_w(1);
+ break;
+
+ case 0xf8: // ???
+ logerror("SB: Unknown command write 0xf8");
+ queue_r(0);
+ break;
+ }
+
+ m_dsp.fifo_ptr = 0;
+ }
+}
+
+WRITE8_MEMBER(sb8_device::dsp_cmd_w)
+{
+// printf("%02x to DSP command @ %x\n", data, offset);
+
+ if(offset)
+ return;
+
+ queue(data);
+
+ process_fifo(m_dsp.fifo[0]);
+}
+
+
+READ8_MEMBER ( sb8_device::joy_port_r )
+{
+ UINT8 data = 0;
+ int delta;
+ attotime new_time = machine().time();
+
+ {
+ data = ioport("pc_joy")->read() | 0x0f;
+
+ {
+ delta = ((new_time - m_joy_time) * 256 * 1000).seconds;
+
+ if (ioport("pc_joy_1")->read() < delta) data &= ~0x01;
+ if (ioport("pc_joy_2")->read() < delta) data &= ~0x02;
+ }
+ }
+
+ return data;
+}
+
+
+
+WRITE8_MEMBER ( sb8_device::joy_port_w )
+{
+ m_joy_time = machine().time();
+}
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_SOUND_BLASTER_1_0 = &device_creator<isa8_sblaster1_0_device>;
+const device_type ISA8_SOUND_BLASTER_1_5 = &device_creator<isa8_sblaster1_5_device>;
+
+//-------------------------------------------------
+// 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 );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+sb8_device::sb8_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock, const char *name) :
+ device_t(mconfig, type, name, tag, owner, clock),
+ device_isa8_card_interface(mconfig, *this),
+ m_dac(*this, "sbdac")
+{
+}
+
+
+//-------------------------------------------------
+// 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")
+{
+}
+
+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")
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void sb8_device::device_start()
+{
+ m_isa->install_device( 0x0200, 0x0207, 0, 0, read8_delegate(FUNC(sb8_device::joy_port_r), this), write8_delegate(FUNC(sb8_device::joy_port_w), this));
+ m_isa->install_device( 0x0226, 0x0227, 0, 0, read8_delegate(FUNC(sb8_device::dsp_reset_r), this), write8_delegate(FUNC(sb8_device::dsp_reset_w), this));
+ m_isa->install_device(subdevice("ym3812"), 0x0228, 0x0229, 0, 0, FUNC(ym3812_16_r), FUNC(ym3812_16_w) );
+ m_isa->install_device( 0x022a, 0x022b, 0, 0, read8_delegate(FUNC(sb8_device::dsp_data_r), this), write8_delegate(FUNC(sb8_device::dsp_data_w), this) );
+ m_isa->install_device( 0x022c, 0x022d, 0, 0, read8_delegate(FUNC(sb8_device::dsp_wbuf_status_r), this), write8_delegate(FUNC(sb8_device::dsp_cmd_w), this) );
+ m_isa->install_device( 0x022e, 0x022f, 0, 0, read8_delegate(FUNC(sb8_device::dsp_rbuf_status_r), this), write8_delegate(FUNC(sb8_device::dsp_rbuf_status_w), this) );
+ m_isa->install_device(subdevice("ym3812"), 0x0388, 0x0389, 0, 0, FUNC(ym3812_16_r), FUNC(ym3812_16_w) );
+
+ m_timer = timer_alloc(0, NULL);
+}
+
+void isa8_sblaster1_0_device::device_start()
+{
+ set_isa_device();
+ // 1.0 always has the SAA1099s for CMS back-compatibility
+ m_isa->install_device(subdevice("saa1099.1"), 0x0220, 0x0221, 0, 0, FUNC(saa1099_16_r), FUNC(saa1099_16_w) );
+ m_isa->install_device(subdevice("saa1099.2"), 0x0222, 0x0223, 0, 0, FUNC(saa1099_16_r), FUNC(saa1099_16_w) );
+ 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();
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void sb8_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;
+}
+
+UINT8 sb8_device::dack_r(int line)
+{
+// printf("dack_r: line %x out = %02x\n", line, m_dack_out);
+ m_isa->drq1_w(0); // drop DRQ?
+ return m_dack_out;
+}
+
+/* TODO: this mustn't be instant! */
+void sb8_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");
+ m_isa->drq1_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);
+
+ m_isa->drq1_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
+ {
+ m_isa->drq1_w(1); // raise DRQ again (page 3-15 of the Creative manual indicates auto-init will keep going until you stop it)
+ }
+ }
+
+ m_isa->irq5_w(1); // raise IRQ as per the Creative manual
+ }
+}
+
+void sb8_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr)
+{
+// printf("DMA timer expire\n");
+
+ m_dac->write_unsigned8(m_dsp.data[m_dsp.d_rptr]);
+ m_dsp.data[m_dsp.d_rptr++] = 0x80;
+ m_dsp.d_rptr %= 128;
+
+ if (m_dsp.dma_throttled)
+ {
+ if (m_dsp.d_rptr == m_dsp.d_wptr)
+ {
+// printf("unthrottling DRQ\n");
+ m_isa->drq1_w(1); // raise DRQ
+ m_dsp.dma_throttled = false;
+ }
+ }
+}
diff --git a/src/mess/machine/isa_sblaster.h b/src/mess/machine/isa_sblaster.h
new file mode 100644
index 00000000000..3e025f5332d
--- /dev/null
+++ b/src/mess/machine/isa_sblaster.h
@@ -0,0 +1,115 @@
+#pragma once
+
+#ifndef __ISA_SOUND_BLASTER_H__
+#define __ISA_SOUND_BLASTER_H__
+
+#include "emu.h"
+#include "machine/isa.h"
+#include "sound/dac.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+struct sb8_dsp_state
+{
+ UINT8 reset_latch;
+ UINT8 rbuf_status;
+ UINT8 wbuf_status;
+ UINT8 fifo[16],fifo_ptr;
+ UINT8 fifo_r[16],fifo_r_ptr;
+ UINT16 version;
+ UINT8 test_reg;
+ UINT8 speaker_on;
+ UINT32 prot_count;
+ INT32 prot_value;
+ UINT32 frequency;
+ UINT32 dma_length, dma_transferred;
+ UINT8 dma_autoinit;
+ UINT8 data[128], d_wptr, d_rptr;
+ bool dma_timer_started;
+ bool dma_throttled;
+};
+
+// ======================> sb8_device (parent)
+
+class sb8_device :
+ public device_t,
+ 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);
+
+ required_device<dac_device> m_dac;
+
+ 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_READ8_MEMBER(joy_port_r);
+ DECLARE_WRITE8_MEMBER(joy_port_w);
+ virtual ioport_constructor device_input_ports() const;
+
+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 device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+ struct sb8_dsp_state m_dsp;
+ UINT8 m_dack_out;
+ attotime m_joy_time;
+
+private:
+ emu_timer *m_timer;
+};
+
+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;
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_config_complete() { m_shortname = "isa_sblaster1_0"; }
+private:
+ // internal state
+};
+
+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();
+ virtual void device_config_complete() { m_shortname = "isa_sblaster1_5"; }
+private:
+ // internal state
+};
+
+// device type definition
+extern const device_type ISA8_SOUND_BLASTER_1_0;
+extern const device_type ISA8_SOUND_BLASTER_1_5;
+
+#endif /* __ISA_SOUND_BLASTER_H__ */
diff --git a/src/mess/machine/isa_wdxt_gen.c b/src/mess/machine/isa_wdxt_gen.c
new file mode 100644
index 00000000000..dd87f497674
--- /dev/null
+++ b/src/mess/machine/isa_wdxt_gen.c
@@ -0,0 +1,398 @@
+/**********************************************************************
+
+ Western Digital WDXT-GEN ISA XT MFM Hard Disk Controller
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+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 "machine/isa_wdxt_gen.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define WD1015_TAG "u6"
+#define WD11C00_17_TAG "u11"
+#define WD2010A_TAG "u7"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type WDXT_GEN = &device_creator<wdxt_gen_device>;
+
+
+//-------------------------------------------------
+// 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;
+}
+
+static WD11C00_17_INTERFACE( host_intf )
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, wdxt_gen_device, irq5_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, wdxt_gen_device, drq3_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, wdxt_gen_device, mr_w),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_CPU_INPUT_LINE(WD1015_TAG, MCS48_INPUT_IRQ),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, wdxt_gen_device, rd322_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, wdxt_gen_device, ram_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, wdxt_gen_device, ram_w),
+ DEVCB_DEVICE_MEMBER(WD2010A_TAG, wd2010_device, read),
+ DEVCB_DEVICE_MEMBER(WD2010A_TAG, wd2010_device, write)
+};
+
+
+//-------------------------------------------------
+// WD2010_INTERFACE( hdc_intf )
+//-------------------------------------------------
+
+static WD2010_INTERFACE( hdc_intf )
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(WD11C00_17_TAG, wd11c00_17_device, clct_w),
+ DEVCB_DEVICE_MEMBER(WD11C00_17_TAG, wd11c00_17_device, read),
+ DEVCB_DEVICE_MEMBER(WD11C00_17_TAG, wd11c00_17_device, write),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_LINE_VCC,
+ DEVCB_LINE_VCC,
+ DEVCB_LINE_VCC,
+ DEVCB_LINE_VCC,
+ DEVCB_LINE_VCC
+};
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( wdxt_gen )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( wdxt_gen )
+ MCFG_CPU_ADD(WD1015_TAG, I8049, 5000000)
+ MCFG_CPU_IO_MAP(wd1015_io)
+
+ MCFG_WD11C00_17_ADD(WD11C00_17_TAG, 5000000, host_intf)
+ MCFG_WD2010_ADD(WD2010A_TAG, 5000000, hdc_intf)
+
+ 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, WDXT_GEN, "Western Digital WDXT-GEN (Amstrad PC1512/1640)", tag, owner, clock),
+ 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_delegate(FUNC(wd11c00_17_device::io_r), (wd11c00_17_device*)m_host), write8_delegate(FUNC(wd11c00_17_device::io_w), (wd11c00_17_device*)m_host));
+ 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/mess/machine/isa_wdxt_gen.h b/src/mess/machine/isa_wdxt_gen.h
new file mode 100644
index 00000000000..6cb40a906f8
--- /dev/null
+++ b/src/mess/machine/isa_wdxt_gen.h
@@ -0,0 +1,87 @@
+/**********************************************************************
+
+ Western Digital WDXT-GEN ISA XT MFM Hard Disk Controller
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+
+ 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 __WDXT_GEN__
+#define __WDXT_GEN__
+
+
+#include "emu.h"
+#include "cpu/mcs48/mcs48.h"
+#include "machine/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();
+ virtual void device_config_complete() { m_shortname = "wdxt_gen"; }
+
+ // device_isa8_card_interface
+ virtual UINT8 dack_r(int line);
+ virtual void dack_w(int line, UINT8 data);
+
+private:
+ required_device<cpu_device> m_maincpu;
+ required_device<wd11c00_17_device> m_host;
+ required_device<wd2010_device> m_hdc;
+
+ UINT8 m_ram[0x800];
+
+ UINT8 m_hdc_addr;
+};
+
+
+// device type definition
+extern const device_type WDXT_GEN;
+
+#endif
diff --git a/src/mess/machine/jupiter.c b/src/mess/machine/jupiter.c
new file mode 100644
index 00000000000..e81c712bca4
--- /dev/null
+++ b/src/mess/machine/jupiter.c
@@ -0,0 +1,119 @@
+/***************************************************************************
+
+ machine.c
+
+ Functions to emulate general aspects of the machine (RAM, ROM, interrupts,
+ I/O ports)
+
+***************************************************************************/
+
+#include "emu.h"
+#include "cpu/z80/z80.h"
+#include "imagedev/snapquik.h"
+#include "includes/jupiter.h"
+
+
+
+/* Load in .ace files. These are memory images of 0x2000 to 0x7fff
+ and compressed as follows:
+
+ ED 00 : End marker
+ ED <cnt> <byt> : repeat <byt> count <cnt:1-240> times
+ <byt> : <byt>
+*/
+
+
+/******************************************************************************
+ Snapshot Handling
+******************************************************************************/
+
+SNAPSHOT_LOAD(jupiter)
+{
+ UINT8 *RAM = image.device().machine().root_device().memregion("maincpu")->base();
+ device_t *cpu = image.device().machine().device("maincpu");
+ address_space *space = image.device().machine().device("maincpu")->memory().space(AS_PROGRAM);
+ unsigned char jupiter_repeat, jupiter_byte, loop;
+ int done=0, jupiter_index=0x2000;
+
+ if (space->machine().root_device().ioport("CFG")->read()==0)
+ {
+ image.seterror(IMAGE_ERROR_INVALIDIMAGE, "At least 16KB RAM expansion required");
+ image.message("At least 16KB RAM expansion required");
+ return IMAGE_INIT_FAIL;
+ }
+
+ logerror("Loading file %s.\r\n", image.filename());
+ while (!done && (jupiter_index < 0x8001))
+ {
+ image.fread( &jupiter_byte, 1);
+ if (jupiter_byte == 0xed)
+ {
+ image.fread(&jupiter_byte, 1);
+ switch (jupiter_byte)
+ {
+ case 0x00:
+ logerror("File loaded!\r\n");
+ done = 1;
+ break;
+ case 0x01:
+ image.fread(&jupiter_byte, 1);
+ RAM[jupiter_index++] = jupiter_byte;
+ break;
+ default:
+ image.fread(&jupiter_repeat, 1);
+ for (loop = 0; loop < jupiter_byte; loop++)
+ RAM[jupiter_index++] = jupiter_repeat;
+ break;
+ }
+ }
+ else
+ RAM[jupiter_index++] = jupiter_byte;
+ }
+
+ logerror("Decoded %X bytes.\r\n", jupiter_index-0x2000);
+
+ if (!done)
+ {
+ image.seterror(IMAGE_ERROR_INVALIDIMAGE, "EOF marker not found");
+ image.message("EOF marker not found");
+ return IMAGE_INIT_FAIL;
+ }
+
+ // patch CPU registers
+ // Some games do not follow the standard, and have rubbish in the CPU area. So,
+ // we check that some other bytes are correct.
+ // 2080 = memory size of original machine, should be 0000 or 8000 or C000.
+ // 2118 = new stack pointer, do not use if between 8000 and FF00.
+
+ jupiter_index = RAM[0x2080] | (RAM[0x2081] << 8);
+
+ if ((jupiter_index & 0x3FFF)==0)
+ {
+ cpu_set_reg(cpu, Z80_AF, RAM[0x2100] | (RAM[0x2101] << 8));
+ cpu_set_reg(cpu, Z80_BC, RAM[0x2104] | (RAM[0x2105] << 8));
+ cpu_set_reg(cpu, Z80_DE, RAM[0x2108] | (RAM[0x2109] << 8));
+ cpu_set_reg(cpu, Z80_HL, RAM[0x210c] | (RAM[0x210d] << 8));
+ cpu_set_reg(cpu, Z80_IX, RAM[0x2110] | (RAM[0x2111] << 8));
+ cpu_set_reg(cpu, Z80_IY, RAM[0x2114] | (RAM[0x2115] << 8));
+ cpu_set_reg(cpu, STATE_GENPC, RAM[0x211c] | (RAM[0x211d] << 8));
+ cpu_set_reg(cpu, Z80_AF2, RAM[0x2120] | (RAM[0x2121] << 8));
+ cpu_set_reg(cpu, Z80_BC2, RAM[0x2124] | (RAM[0x2125] << 8));
+ cpu_set_reg(cpu, Z80_DE2, RAM[0x2128] | (RAM[0x2129] << 8));
+ cpu_set_reg(cpu, Z80_HL2, RAM[0x212c] | (RAM[0x212d] << 8));
+ cpu_set_reg(cpu, Z80_IM, RAM[0x2130]);
+ cpu_set_reg(cpu, Z80_IFF1, RAM[0x2134]);
+ cpu_set_reg(cpu, Z80_IFF2, RAM[0x2138]);
+ cpu_set_reg(cpu, Z80_I, RAM[0x213c]);
+ cpu_set_reg(cpu, Z80_R, RAM[0x2140]);
+
+ if ((RAM[0x2119] < 0x80) || !jupiter_index)
+ cpu_set_reg(cpu, STATE_GENSP, RAM[0x2118] | (RAM[0x2119] << 8));
+ }
+
+ /* Copy data to the address space */
+ for (jupiter_index = 0x2000; jupiter_index < 0x8000; jupiter_index++)
+ space->write_byte(jupiter_index, RAM[jupiter_index]);
+
+ return IMAGE_INIT_PASS;
+}
+
diff --git a/src/mess/machine/k7659kb.c b/src/mess/machine/k7659kb.c
new file mode 100644
index 00000000000..8c77065e710
--- /dev/null
+++ b/src/mess/machine/k7659kb.c
@@ -0,0 +1,312 @@
+/**********************************************************************
+
+ K7659 keyboard emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#include "k7659kb.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type K7659_KEYBOARD = &device_creator<k7659_keyboard_device>;
+
+
+
+//-------------------------------------------------
+// ROM( k7659_keyboard )
+//-------------------------------------------------
+
+ROM_START( k7659_keyboard )
+ ROM_REGION(0x0800, "k7659",0)
+ ROM_LOAD ("k7659n.bin", 0x0000, 0x0800, CRC(7454bf0a) SHA1(b97e7df93778fa371b96b6f4fb1a5b1c8b89d7ba) )
+ROM_END
+
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *k7659_keyboard_device::device_rom_region() const
+{
+ return ROM_NAME( k7659_keyboard );
+}
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( kb_io )
+//-------------------------------------------------
+
+
+
+//-------------------------------------------------
+// DISCRETE_SOUND_START( k7659kb )
+//-------------------------------------------------
+
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( k7659_keyboard )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( k7659_keyboard )
+
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor k7659_keyboard_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( k7659_keyboard );
+}
+
+
+//-------------------------------------------------
+// INPUT_PORTS( k7659_keyboard )
+//-------------------------------------------------
+
+static INPUT_PORTS_START( k7659_keyboard )
+ PORT_START("A1")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1 !") PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Q") PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') PORT_CHAR(0x11)
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("A") PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') PORT_CHAR(0x01)
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Y") PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') PORT_CHAR(0x19)
+ PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2 \"") PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"')
+ PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("W") PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') PORT_CHAR(0x17)
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("S") PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') PORT_CHAR(0x13)
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("X") PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') PORT_CHAR(0x18)
+ PORT_START("A2")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3") PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR(0xff)
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("E") PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') PORT_CHAR(0x05)
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("D") PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') PORT_CHAR(0x04)
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("C") PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') PORT_CHAR(0x03)
+ PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4 $") PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
+ PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("R") PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') PORT_CHAR(0x12)
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F") PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') PORT_CHAR(0x06)
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("V") PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') PORT_CHAR(0x16)
+ PORT_START("A3")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("5 %") PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("T") PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') PORT_CHAR(0x14)
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("G") PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') PORT_CHAR(0x07)
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("B") PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') PORT_CHAR(0x02)
+ PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("6 &") PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&')
+ PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Z") PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') PORT_CHAR(0x1a)
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("H") PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') PORT_CHAR(0x08)
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("N") PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') PORT_CHAR(0x0e)
+ PORT_START("A4")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("7 /") PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('/')
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("U") PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') PORT_CHAR(0x15)
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("J") PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') PORT_CHAR(0x0a)
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("M") PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') PORT_CHAR(0x0d)
+ PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("8 (") PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('(')
+ PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("I") PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') PORT_CHAR(0x09)
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("K") PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') PORT_CHAR(0x0b)
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(", ;") PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR(';')
+ PORT_START("A5")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("9 )") PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(')')
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("O") PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') PORT_CHAR(0x0f)
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("L") PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') PORT_CHAR(0x0c)
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(". :") PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR(':')
+ PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("0") PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR('=') PORT_CHAR('0')
+ PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("P") PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') PORT_CHAR(0x10)
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("| \\") PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('|') PORT_CHAR('\\') PORT_CHAR(0x1c)
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("- _") PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_')
+ PORT_START("A6")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("~ ?") PORT_CODE(KEYCODE_SLASH) PORT_CHAR('~') PORT_CHAR('?') PORT_CHAR(0x1e)
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("} ]") PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR('}') PORT_CHAR(']') PORT_CHAR(0x1d)
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("{ [") PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('{') PORT_CHAR('[') PORT_CHAR(0x1b)
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("<") PORT_CODE(KEYCODE_0_PAD) PORT_CHAR('<')
+ PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("+ *") PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('+') PORT_CHAR('*')
+ PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("# '") PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('#') PORT_CHAR('\'') PORT_CHAR(0x1f)
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("^ ~") PORT_CODE(KEYCODE_COLON) PORT_CHAR('^') PORT_CHAR('~') PORT_CHAR(0x1e)
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Tab") PORT_CODE(KEYCODE_TAB) PORT_CHAR(0x09)
+ PORT_START("A7")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(">") PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR('>')
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("CR") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(0x0d)
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("04") PORT_CODE(KEYCODE_TILDE) PORT_CHAR(0x04)
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("01") PORT_CODE(KEYCODE_TILDE) PORT_CHAR(0x01)
+ PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Space") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') PORT_CHAR(' ') PORT_CHAR('`')
+ PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Escape") PORT_CODE(KEYCODE_ESC) PORT_CHAR(0x1b) PORT_CHAR(0x1b) PORT_CHAR(0x1f)
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("13") PORT_CODE(KEYCODE_TILDE) PORT_CHAR(0x13)
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("06") PORT_CODE(KEYCODE_TILDE) PORT_CHAR(0x06)
+ PORT_START("A8")
+ 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_UNUSED)
+ PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_UNUSED)
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Shift") PORT_CODE(KEYCODE_RSHIFT)
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Shift") PORT_CODE(KEYCODE_LSHIFT)
+ PORT_START("A9")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_UNUSED)
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("CLS") PORT_CODE(KEYCODE_END) PORT_CHAR(0x0c)
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("DEL") PORT_CODE(KEYCODE_DEL) PORT_CHAR(0x7f) PORT_CHAR(0x1e) PORT_CHAR(0x1f)
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F01") PORT_CODE(KEYCODE_TILDE) PORT_CHAR(0x05)
+ PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F02") PORT_CODE(KEYCODE_TILDE) PORT_CHAR(0x18)
+ PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F03") PORT_CODE(KEYCODE_TILDE) PORT_CHAR(0x13)
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F04") PORT_CODE(KEYCODE_TILDE) PORT_CHAR(0x04)
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F06") PORT_CODE(KEYCODE_TILDE) PORT_CHAR(0x03)
+ PORT_START("A10")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F07") PORT_CODE(KEYCODE_TILDE) PORT_CHAR(0x1a)
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F08") PORT_CODE(KEYCODE_TILDE) PORT_CHAR(0x17)
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F09") PORT_CODE(KEYCODE_TILDE) PORT_CHAR(0x07)
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F10") PORT_CODE(KEYCODE_TILDE) PORT_CHAR(0x14)
+ PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F11") PORT_CODE(KEYCODE_TILDE) PORT_CHAR(0x19)
+ PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F12") PORT_CODE(KEYCODE_TILDE) PORT_CHAR(0x02)
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F13") PORT_CODE(KEYCODE_TILDE) PORT_CHAR(0x0b)
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F14") PORT_CODE(KEYCODE_TILDE) PORT_CHAR(0x11)
+ PORT_START("A11")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F05") PORT_CODE(KEYCODE_TILDE) PORT_CHAR(0x12)
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_UNUSED)
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Up") PORT_CODE(KEYCODE_UP) PORT_CHAR(0x1a)
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Down") PORT_CODE(KEYCODE_DOWN) PORT_CHAR(0x0a)
+ PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Right") PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(0x15)
+ PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Left") PORT_CODE(KEYCODE_LEFT) PORT_CHAR(0x08)
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_UNUSED)
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("E95") PORT_CODE(KEYCODE_TILDE) PORT_CHAR(0xff)
+ PORT_START("A12")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Reset") PORT_CODE(KEYCODE_TILDE)
+ 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_KEYBOARD) PORT_NAME("NMI") PORT_CODE(KEYCODE_TILDE)
+ PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_UNUSED)
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Ctrl") PORT_CODE(KEYCODE_LCONTROL) PORT_CODE(KEYCODE_RCONTROL)
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_UNUSED)
+INPUT_PORTS_END
+
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+ioport_constructor k7659_keyboard_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( k7659_keyboard );
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// k7659_keyboard_device - constructor
+//-------------------------------------------------
+
+k7659_keyboard_device::k7659_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, K7659_KEYBOARD, "K7659 Keyboard", tag, owner, clock)
+{}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void k7659_keyboard_device::device_start()
+{
+ m_timer = timer_alloc();
+ // state saving
+ //save_item(NAME(m_y));
+ //save_item(NAME(m_so));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void k7659_keyboard_device::device_reset()
+{
+ m_lookup = 0;
+ m_p_rom = memregion("k7659")->base();
+ m_timer->adjust(attotime::from_hz(200), 0, attotime::from_hz(200));
+}
+
+void k7659_keyboard_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ UINT8 retVal = 0;//m_lookup;
+ UINT8 a1 = ioport("A1")->read();
+ UINT8 a2 = ioport("A2")->read();
+ UINT8 a3 = ioport("A3")->read();
+ UINT8 a4 = ioport("A4")->read();
+ UINT8 a5 = ioport("A5")->read();
+ UINT8 a6 = ioport("A6")->read();
+ UINT8 a7 = ioport("A7")->read();
+ UINT8 a8 = ioport("A8")->read();
+ UINT8 a9 = ioport("A9")->read();
+ UINT8 a10 = ioport("A10")->read();
+ UINT8 a11 = ioport("A11")->read();
+ UINT8 a12 = ioport("A12")->read();
+ UINT16 code = 0;
+ if (a1)
+ code = 0x10 + key_pos(a1);
+ else if (a2)
+ code = 0x20 + key_pos(a2);
+ else if (a3)
+ code = 0x30 + key_pos(a3);
+ else if (a4)
+ code = 0x40 + key_pos(a4);
+ else if (a5)
+ code = 0x50 + key_pos(a5);
+ else if (a6)
+ code = 0x60 + key_pos(a6);
+ else if (a7)
+ code = 0x70 + key_pos(a7);
+ else if (a9)
+ code = 0x80 + key_pos(a9);
+ else if (a10)
+ code = 0x90 + key_pos(a10);
+ else if (a11)
+ code = 0xA0 + key_pos(a11);
+
+ if (code)
+ {
+ if (BIT(a8,6) || BIT(a8,7))
+ code |= 0x100;
+ else
+ if (BIT(a12,6))
+ code |= 0x200;
+
+ m_lookup = m_p_rom[code];
+ retVal = m_lookup | 0x80;
+ }
+ m_key = retVal;
+}
+
+UINT8 k7659_keyboard_device::key_pos(UINT8 val)
+{
+ if (BIT(val,0)) return 1;
+ if (BIT(val,1)) return 2;
+ if (BIT(val,2)) return 3;
+ if (BIT(val,3)) return 4;
+ if (BIT(val,4)) return 5;
+ if (BIT(val,5)) return 6;
+ if (BIT(val,6)) return 7;
+ if (BIT(val,7)) return 8;
+ return 0;
+}
+
+READ8_MEMBER(k7659_keyboard_device::read)
+{
+ return m_key;
+}
diff --git a/src/mess/machine/k7659kb.h b/src/mess/machine/k7659kb.h
new file mode 100644
index 00000000000..361465f3f2e
--- /dev/null
+++ b/src/mess/machine/k7659kb.h
@@ -0,0 +1,77 @@
+/**********************************************************************
+
+ K7659 keyboard emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#pragma once
+
+#ifndef __K7659_KEYBOARD__
+#define __K7659_KEYBOARD__
+
+
+#include "emu.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define K7659_KEYBOARD_TAG "k7659kb"
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_K7659_KEYBOARD_ADD() \
+ MCFG_DEVICE_ADD(K7659_KEYBOARD_TAG, K7659_KEYBOARD, 0)
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> k7659_keyboard_device
+
+class k7659_keyboard_device : public device_t
+{
+public:
+ // construction/destruction
+ k7659_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(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);
+ virtual void device_config_complete() { m_shortname = "k7659kb"; }
+ emu_timer *m_timer;
+
+private:
+ UINT8 key_pos(UINT8 val);
+ UINT8 m_lookup;
+ UINT8 m_key;
+ const UINT8 *m_p_rom;
+};
+
+
+// device type definition
+extern const device_type K7659_KEYBOARD;
+
+
+
+#endif
diff --git a/src/mess/machine/kay_kbd.c b/src/mess/machine/kay_kbd.c
new file mode 100644
index 00000000000..46e6b749ecf
--- /dev/null
+++ b/src/mess/machine/kay_kbd.c
@@ -0,0 +1,517 @@
+/******************************************************************************
+ *
+ * kay_kbd.c
+ *
+ * Kaypro II Serial Keyboard
+ *
+ * Most of this is copied from the old kaypro.c,
+ * rather than re-inventing the wheel.
+ *
+ * Juergen Buchmueller, July 1998
+ * Benjamin C. W. Sittler, July 1998 (new keyboard table)
+ *
+ * Converted to a serial device (as far as MESS will allow)
+ * by Robbbert, April 2009.
+ *
+ ******************************************************************************/
+
+#include "emu.h"
+#include "sound/beep.h"
+#include "includes/kaypro.h"
+
+
+/*
+ * The KAYPRO keyboard has roughly the following layout:
+ *
+ * [up] [down] [left] [right]
+ * [ESC] [1!] [2@] [3#] [4$] [5%] [6^] [7&] [8*] [9(] [0)] [-_] [=+] [`~] [BACK SPACE]
+ * [TAB] [qQ] [wW] [eE] [rR] [tT] [yY] [uU] [iI] [oO] [pP] [[{] []}] [DEL]
+ *[CTRL] [CAPS LOCK] [aA] [sS] [dD] [fF] [gG] [hH] [jJ] [kK] [lL] [;:] ['"] [RETURN] [\|]
+ * [SHIFT] [zZ] [xX] [cC] [vV] [bB] [nN] [mM] [,<] [.>] [/?] [SHIFT] [LINE FEED]
+ * [ SPACE ]
+ *
+ * [7] [8] [9] [-]
+ * [4] [5] [6] [,]
+ * [1] [2] [3]
+ * [ 0 ] [.] [ENTER]
+ *
+ * Notes on Appearance
+ * -------------------
+ * The RETURN key is shaped like a backwards "L". The keypad ENTER key is actually
+ * oriented vertically, not horizontally. The alpha keys are marked with the uppercase letters
+ * only. Other keys with two symbols have the shifted symbol printed above the unshifted symbol.
+ * The keypad is actually located to the right of the main keyboard; it is shown separately here
+ * as a convenience to users of narrow listing windows. The arrow keys are actually marked with
+ * arrow graphics pointing in the appropriate directions. The F and J keys are specially shaped,
+ * since they are the "home keys" for touch-typing. The CAPS LOCK key has a build-in red indicator
+ * which is lit when CAPS LOCK is pressed once, and extinguished when the key is pressed again.
+ *
+ * Technical Notes
+ * ---------------
+ * The keyboard interfaces to the computer using a serial protocol. Modifier keys are handled
+ * inside the keyboards, as is the CAPS LOCK key. The arrow keys and the numeric keypad send
+ * non-ASCII codes which are not affected by the modifier keys. The remaining keys send the
+ * appropriate ASCII values.
+ *
+ * The keyboard has a built-in buzzer which is activated briefly by a non-modifier keypress,
+ * producing a "clicking" sound for user feedback. Additionally, this buzzer can be activated
+ * for a longer period by sending a 0x04 byte to the keyboard. This is used by the ROM soft
+ * terminal to alert the user in case of a BEL.
+ *
+ * 2008-05 FP:
+ * Small note about natural keyboard support: currently,
+ * - "Line Feed" is mapped to the 'End' key
+ * - "Keypad ," is not mapped
+ */
+
+typedef struct _kay_kbd_t
+{
+ device_t *beeper;
+ UINT8 buff[16];
+ UINT8 head;
+ UINT8 tail;
+ UINT8 beep_on;
+ UINT8 control_status;
+ UINT8 keyrows[10];
+ int lastrow;
+ int mask;
+ int key;
+ int repeat;
+ int repeater;
+} kay_kbd_t;
+
+INPUT_PORTS_START( kay_kbd )
+ PORT_START("ROW0")
+ PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC))
+ PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')
+ PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@')
+ PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')
+ PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
+ PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')
+ PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^')
+ PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&')
+
+ PORT_START("ROW1")
+ PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*')
+ PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(')
+ PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')')
+ PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_')
+ PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+')
+ PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') PORT_CHAR('~')
+ PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_NAME("BACK SPACE") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8)
+ PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_TAB) PORT_CHAR('\t')
+
+ PORT_START("ROW2")
+ PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q')
+ PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W')
+ PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E')
+ PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R')
+ PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T')
+ PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y')
+ PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U')
+ PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I')
+
+ PORT_START("ROW3")
+ PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O')
+ PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P')
+ PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{')
+ PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}')
+ PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_NAME("RETURN") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13)
+ PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_NAME("DEL") PORT_CODE(KEYCODE_DEL) PORT_CHAR(UCHAR_MAMEKEY(DEL))
+ PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_SHIFT_2)
+ PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_CAPSLOCK) PORT_TOGGLE PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK))
+
+ PORT_START("ROW4")
+ PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A')
+ PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S')
+ PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D')
+ PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F')
+ PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G')
+ PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H')
+ PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J')
+ PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K')
+
+ PORT_START("ROW5")
+ PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L')
+ PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':')
+ PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('"')
+ PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|')
+ PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_MAMEKEY(LSHIFT))
+ PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z')
+ PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X')
+ PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C')
+
+ PORT_START("ROW6")
+ PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V')
+ PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B')
+ PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N')
+ PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M')
+ PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')
+ PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
+ PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?')
+ PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_MAMEKEY(RSHIFT))
+
+ PORT_START("ROW7")
+ PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_NAME("LINE FEED") PORT_CODE(KEYCODE_END) PORT_CHAR(UCHAR_MAMEKEY(END))
+ PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
+ PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD))
+ PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_NAME("Keypad ,") PORT_CODE(KEYCODE_PLUS_PAD)
+ PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD))
+ PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD))
+ PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD))
+ PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD))
+
+ PORT_START("ROW8")
+ PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD))
+ PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD))
+ PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD))
+ PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD))
+ PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD))
+ PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD))
+ PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD))
+ PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD))
+
+ PORT_START("ROW9")
+ PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_NAME("\xE2\x86\x91") PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP))
+ PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_NAME("\xE2\x86\x93") PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN))
+ PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_NAME("\xE2\x86\x90") PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
+ PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_NAME("\xE2\x86\x92") PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT))
+ PORT_BIT(0xf0, 0x00, IPT_UNUSED)
+INPUT_PORTS_END
+
+static void kay_kbd_in( running_machine &machine, UINT8 data );
+
+static const UINT8 keyboard[8][10][8] = {
+ { /* normal */
+ { 27,'1','2','3','4','5','6','7'},
+ {'8','9','0','-','=','`', 8, 9},
+ {'q','w','e','r','t','y','u','i'},
+ {'o','p','[',']', 13,127, 0, 0},
+ {'a','s','d','f','g','h','j','k'},
+ {'l',';', 39, 92, 0,'z','x','c'},
+ {'v','b','n','m',',','.','/', 0},
+ { 10, 32, 228, 211, 195, 178, 177, 192},
+ { 193, 194, 208, 209, 210, 225, 226, 227},
+ { 241, 242, 243, 244, 0, 0, 0, 0},
+ },
+ { /* Shift */
+ { 27,'!','@','#','$','%','^','&'},
+ {'*','(',')','_','+','~', 8, 9},
+ {'Q','W','E','R','T','Y','U','I'},
+ {'O','P','{','}', 13,127, 0, 0},
+ {'A','S','D','F','G','H','J','K'},
+ {'L',':','"','|', 0,'Z','X','C'},
+ {'V','B','N','M','<','>','?', 0},
+ { 10, 32, 228, 211, 195, 178, 177, 192},
+ { 193, 194, 208, 209, 210, 225, 226, 227},
+ { 241, 242, 243, 244, 0, 0, 0, 0},
+ },
+ { /* Control */
+ { 27,'1','2','3','4','5','6','7'},
+ {'8','9','0','-','=','`', 8, 9},
+ { 17, 23, 5, 18, 20, 25, 21, 9},
+ { 15, 16, 27, 29, 13,127, 0, 0},
+ { 1, 19, 4, 6, 7, 8, 10, 11},
+ { 12,';', 39, 28, 0, 26, 24, 3},
+ { 22, 2, 14, 13,',','.','/', 0},
+ { 10, 32, 228, 211, 195, 178, 177, 192},
+ { 193, 194, 208, 209, 210, 225, 226, 227},
+ { 241, 242, 243, 244, 0, 0, 0, 0},
+ },
+ { /* Shift+Control */
+ { 27,'!', 0,'#','$','%', 30,'&'},
+ {'*','(',')', 31,'+','~', 8, 9},
+ { 17, 23, 5, 18, 20, 25, 21, 9},
+ { 15, 16, 27, 29, 13,127, 0, 0},
+ { 1, 19, 4, 6, 7, 8, 10, 11},
+ { 12,':','"', 28, 0, 26, 24, 3},
+ { 22, 2, 14, 13,',','.','/', 0},
+ { 10, 32, 228, 211, 195, 178, 177, 192},
+ { 193, 194, 208, 209, 210, 225, 226, 227},
+ { 241, 242, 243, 244, 0, 0, 0, 0},
+ },
+ { /* CapsLock */
+ { 27,'1','2','3','4','5','6','7'},
+ {'8','9','0','-','=','`', 8, 9},
+ {'Q','W','E','R','T','Y','U','I'},
+ {'O','P','[',']', 13,127, 0, 0},
+ {'A','S','D','F','G','H','J','K'},
+ {'L',';', 39, 92, 0,'Z','X','C'},
+ {'V','B','N','M',',','.','/', 0},
+ { 10, 32, 228, 211, 195, 178, 177, 192},
+ { 193, 194, 208, 209, 210, 225, 226, 227},
+ { 241, 242, 243, 244, 0, 0, 0, 0},
+ },
+ { /* Shift+CapsLock */
+ { 27,'!','@','#','$','%','^','&'},
+ {'*','(',')','_','+','~', 8, 9},
+ {'Q','W','E','R','T','Y','U','I'},
+ {'O','P','{','}', 13,127, 0, 0},
+ {'A','S','D','F','G','H','J','K'},
+ {'L',':','"','|', 0,'Z','X','C'},
+ {'V','B','N','M','<','>','?', 0},
+ { 10, 32, 228, 211, 195, 178, 177, 192},
+ { 193, 194, 208, 209, 210, 225, 226, 227},
+ { 241, 242, 243, 244, 0, 0, 0, 0},
+ },
+ { /* Control+CapsLock */
+ { 27,'1','2','3','4','5','6','7'},
+ {'8','9','0','-','=','`', 8, 9},
+ { 17, 23, 5, 18, 20, 25, 21, 9},
+ { 15, 16, 27, 29, 13,127, 0, 0},
+ { 1, 19, 4, 6, 7, 8, 10, 11},
+ { 12,';', 39, 28, 0, 26, 24, 3},
+ { 22, 2, 14, 13,',','.','/', 0},
+ { 10, 32, 228, 211, 195, 178, 177, 192},
+ { 193, 194, 208, 209, 210, 225, 226, 227},
+ { 241, 242, 243, 244, 0, 0, 0, 0},
+ },
+ { /* Shift+Control+CapsLock */
+ { 27,'!', 0,'#','$','%', 30,'&'},
+ {'*','(',')', 31,'+','~', 8, 9},
+ { 17, 23, 5, 18, 20, 25, 21, 9},
+ { 15, 16, 27, 29, 13,127, 0, 0},
+ { 1, 19, 4, 6, 7, 8, 10, 11},
+ { 12,':','"', 28, 0, 26, 24, 3},
+ { 22, 2, 14, 13,',','.','/', 0},
+ { 10, 32, 228, 211, 195, 178, 177, 192},
+ { 193, 194, 208, 209, 210, 225, 226, 227},
+ { 241, 242, 243, 244, 0, 0, 0, 0},
+ },
+};
+
+MACHINE_RESET( kay_kbd )
+{
+ kaypro_state *state = machine.driver_data<kaypro_state>();
+ kay_kbd_t *kbd = state->m_kbd = auto_alloc_clear(machine, kay_kbd_t);
+
+ /* disable CapsLock LED initially */
+ set_led_status(machine, 1, 1);
+ set_led_status(machine, 1, 0);
+ kbd->beeper = machine.device(BEEPER_TAG);
+ kbd->beep_on = 1;
+ kbd->control_status = 0x14;
+ beep_set_state(kbd->beeper, 0);
+ beep_set_frequency(kbd->beeper, 950); /* piezo-device needs to be measured */
+ kbd->head = kbd->tail = 0; /* init buffer */
+}
+
+/******************************************************
+ * vertical blank interrupt
+ * used to scan keyboard; newly pressed keys
+ * are stuffed into a keyboard buffer;
+ * also drives keyboard LEDs and
+ * and handles autorepeating keys
+ ******************************************************/
+INTERRUPT_GEN( kay_kbd_interrupt )
+{
+ kaypro_state *state = device->machine().driver_data<kaypro_state>();
+ kay_kbd_t *kbd = state->m_kbd;
+ int mod, row, col, chg, newval;
+ UINT8 *keyrows = kbd->keyrows;
+
+ if( kbd->repeat )
+ {
+ if( !--kbd->repeat )
+ kbd->repeater = 4;
+ }
+ else
+ if( kbd->repeater )
+ {
+ kbd->repeat = kbd->repeater;
+ }
+
+ row = 9;
+ newval = device->machine().root_device().ioport("ROW9")->read();
+ chg = keyrows[row] ^ newval;
+
+ if (!chg) { newval = device->machine().root_device().ioport("ROW8")->read(); chg = keyrows[--row] ^ newval; }
+ if (!chg) { newval = device->machine().root_device().ioport("ROW7")->read(); chg = keyrows[--row] ^ newval; }
+ if (!chg) { newval = device->machine().root_device().ioport("ROW6")->read(); chg = keyrows[--row] ^ newval; }
+ if (!chg) { newval = device->machine().root_device().ioport("ROW5")->read(); chg = keyrows[--row] ^ newval; }
+ if (!chg) { newval = device->machine().root_device().ioport("ROW4")->read(); chg = keyrows[--row] ^ newval; }
+ if (!chg) { newval = device->machine().root_device().ioport("ROW3")->read(); chg = keyrows[--row] ^ newval; }
+ if (!chg) { newval = device->machine().root_device().ioport("ROW2")->read(); chg = keyrows[--row] ^ newval; }
+ if (!chg) { newval = device->machine().root_device().ioport("ROW1")->read(); chg = keyrows[--row] ^ newval; }
+ if (!chg) { newval = device->machine().root_device().ioport("ROW0")->read(); chg = keyrows[--row] ^ newval; }
+ if (!chg) --row;
+
+ if (row >= 0)
+ {
+ kbd->repeater = 0x00;
+ kbd->mask = 0x00;
+ kbd->key = 0x00;
+ kbd->lastrow = row;
+ /* CapsLock LED */
+ if( row == 3 && chg == 0x80 )
+ set_led_status(device->machine(), 1, (kbd->keyrows[3] & 0x80) ? 0 : 1);
+
+ if (newval & chg) /* key(s) pressed ? */
+ {
+ mod = 0;
+
+ /* Shift modifier */
+ if ( (keyrows[5] & 0x10) || (keyrows[6] & 0x80) )
+ mod |= 1;
+
+ /* Control modifier */
+ if (keyrows[3] & 0x40)
+ mod |= 2;
+
+ /* CapsLock modifier */
+ if (keyrows[3] & 0x80)
+ mod |= 4;
+
+ /* find newval key */
+ kbd->mask = 0x01;
+ for (col = 0; col < 8; col ++)
+ {
+ if (chg & kbd->mask)
+ {
+ newval &= kbd->mask;
+ kbd->key = keyboard[mod][row][col];
+ break;
+ }
+ kbd->mask <<= 1;
+ }
+ if( kbd->key ) /* normal key */
+ {
+ kbd->repeater = 30;
+ kay_kbd_in(device->machine(), kbd->key);
+ }
+ else
+ if( (row == 0) && (chg == 0x04) ) /* Ctrl-@ (NUL) */
+ kay_kbd_in(device->machine(), 0);
+ keyrows[row] |= newval;
+ }
+ else
+ {
+ kbd->keyrows[row] = newval;
+ }
+ kbd->repeat = kbd->repeater;
+ }
+ else if ( kbd->key && (keyrows[kbd->lastrow] & kbd->mask) && kbd->repeat == 0 )
+ {
+ kay_kbd_in(device->machine(), kbd->key);
+ }
+}
+
+#if 0
+
+/******************************************************
+ * kaypro_const_w (write console status ;)
+ * bit
+ * 0 flush keyboard buffer
+ ******************************************************/
+static WRITE8_HANDLER ( kaypro2_const_w )
+{
+ if (data & 1)
+ kbd->head = kbd->tail = 0;
+}
+
+#endif
+
+/******************************************************
+ * stuff character into the keyboard buffer
+ * releases CPU if it was waiting for a key
+ * sounds bell if buffer would overflow
+ ******************************************************/
+static void kay_kbd_in( running_machine &machine, UINT8 data )
+{
+ kaypro_state *state = machine.driver_data<kaypro_state>();
+ kay_kbd_t *kbd = state->m_kbd;
+ UINT8 kbd_head_old;
+
+ kbd_head_old = kbd->head;
+ kbd->buff[kbd->head] = data;
+ kbd->head = (kbd->head + 1) % sizeof(kbd->buff);
+ /* will the buffer overflow ? */
+ if (kbd->head == kbd->tail)
+ {
+ kbd->head = kbd_head_old;
+ kay_kbd_d_w(machine, 4);
+ }
+ else
+ kay_kbd_d_w(machine, 1);
+}
+
+
+UINT8 kay_kbd_c_r( running_machine &machine )
+{
+/* d4 transmit buffer empty - 1=ok to send
+ d2 appears to be receive buffer empty - 1=ok to receive
+ d0 keyboard buffer empty - 1=key waiting to be used */
+
+ kaypro_state *state = machine.driver_data<kaypro_state>();
+ kay_kbd_t *kbd = state->m_kbd;
+ UINT8 data = kbd->control_status;
+
+ if( kbd->head != kbd->tail )
+ data++;
+
+ return data;
+}
+
+UINT8 kay_kbd_d_r( running_machine &machine )
+{
+/* return next key in buffer */
+
+ kaypro_state *state = machine.driver_data<kaypro_state>();
+ kay_kbd_t *kbd = state->m_kbd;
+ UINT8 data = 0;
+
+ if (kbd->tail != kbd->head)
+ {
+ data = kbd->buff[kbd->tail];
+ kbd->tail = (kbd->tail + 1) % sizeof(kbd->buff);
+ }
+
+ return data;
+}
+
+static TIMER_CALLBACK( kay_kbd_beepoff )
+{
+ kaypro_state *state = machine.driver_data<kaypro_state>();
+ kay_kbd_t *kbd = state->m_kbd;
+ beep_set_state(kbd->beeper, 0);
+ kbd->control_status |= 4;
+}
+
+void kay_kbd_d_w( running_machine &machine, UINT8 data )
+{
+/* Beeper control - lengths need verifying
+ 01 - keyclick
+ 02 - short beep
+ 04 - standard bell beep
+ 08 - mute
+ 16 - unmute */
+
+ kaypro_state *state = machine.driver_data<kaypro_state>();
+ kay_kbd_t *kbd = state->m_kbd;
+ UINT16 length = 0;
+
+ if (data & 0x10)
+ kbd->beep_on = 1;
+ else
+ if (data & 0x08)
+ kbd->beep_on = 0;
+ else
+ if (kbd->beep_on)
+ {
+ if (data & 0x04)
+ length = 400;
+ else
+ if (data & 0x02)
+ length = 200;
+ else
+ if (data & 0x01)
+ length = 4;
+
+ if (length)
+ {
+ kbd->control_status &= 0xfb;
+ machine.scheduler().timer_set(attotime::from_msec(length), FUNC(kay_kbd_beepoff));
+ beep_set_state(kbd->beeper, 1);
+ }
+ }
+}
diff --git a/src/mess/machine/kaypro.c b/src/mess/machine/kaypro.c
new file mode 100644
index 00000000000..a136becf37d
--- /dev/null
+++ b/src/mess/machine/kaypro.c
@@ -0,0 +1,391 @@
+
+
+#include "includes/kaypro.h"
+
+
+
+
+/***********************************************************
+
+ PIO
+
+ Port B is unused on both PIOs
+
+************************************************************/
+
+static void kaypro_interrupt(device_t *device, int state)
+{
+ cputag_set_input_line(device->machine(), "maincpu", 0, state);
+}
+
+READ8_MEMBER( kaypro_state::pio_system_r )
+{
+ UINT8 data = 0;
+
+ /* centronics busy */
+ data |= m_centronics->not_busy_r() << 3;
+
+ /* PA7 is pulled high */
+ data |= 0x80;
+
+ return data;
+}
+
+WRITE8_MEMBER( kaypro_state::common_pio_system_w )
+{
+/* d7 bank select
+ d6 disk drive motors - (0=on)
+ d5 double-density enable (0=double density)
+ d4 Centronics strobe
+ d2 side select (1=side 1)
+ d1 drive B
+ d0 drive A */
+
+ /* get address space */
+ address_space *mem = m_maincpu->memory().space(AS_PROGRAM);
+
+ if (data & 0x80)
+ {
+ mem->unmap_readwrite (0x0000, 0x3fff);
+ mem->install_read_bank (0x0000, 0x0fff, "bank1");
+ membank("bank1")->set_base(machine().root_device().memregion("maincpu")->base());
+ mem->install_readwrite_handler (0x3000, 0x3fff, read8_delegate(FUNC(kaypro_state::kaypro_videoram_r), this), write8_delegate(FUNC(kaypro_state::kaypro_videoram_w), this));
+ }
+ else
+ {
+ mem->unmap_readwrite(0x0000, 0x3fff);
+ mem->install_read_bank (0x0000, 0x3fff, "bank2");
+ mem->install_write_bank (0x0000, 0x3fff, "bank3");
+ membank("bank2")->set_base(machine().root_device().memregion("rambank")->base());
+ membank("bank3")->set_base(machine().root_device().memregion("rambank")->base());
+ }
+
+ wd17xx_dden_w(m_fdc, BIT(data, 5));
+
+ m_centronics->strobe_w(BIT(data, 4));
+
+ if (BIT(data, 0))
+ wd17xx_set_drive(m_fdc, 0);
+
+ if (BIT(data, 1))
+ wd17xx_set_drive(m_fdc, 1);
+
+ output_set_value("ledA", BIT(data, 0)); /* LEDs in artwork */
+ output_set_value("ledB", BIT(data, 1));
+
+ /* CLEAR_LINE means to turn motors on */
+ floppy_mon_w(floppy_get_device(machine(), 0), BIT(data, 6) ? ASSERT_LINE : CLEAR_LINE);
+ floppy_mon_w(floppy_get_device(machine(), 1), BIT(data, 6) ? ASSERT_LINE : CLEAR_LINE);
+
+ m_system_port = data;
+}
+
+WRITE8_MEMBER( kaypro_state::kayproii_pio_system_w )
+{
+ common_pio_system_w(space, offset, data);
+
+ /* side select */
+ wd17xx_set_side(m_fdc, !BIT(data, 2));
+}
+
+WRITE8_MEMBER( kaypro_state::kaypro4_pio_system_w )
+{
+ common_pio_system_w(space, offset, data);
+
+ /* side select */
+ wd17xx_set_side(m_fdc, BIT(data, 2));
+}
+
+const z80pio_interface kayproii_pio_g_intf =
+{
+ DEVCB_CPU_INPUT_LINE("maincpu", INPUT_LINE_IRQ0),
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER("centronics", centronics_device, write),
+ DEVCB_NULL, /* portA ready active callback */
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL /* portB ready active callback */
+};
+
+const z80pio_interface kayproii_pio_s_intf =
+{
+ DEVCB_CPU_INPUT_LINE("maincpu", INPUT_LINE_IRQ0),
+ DEVCB_DRIVER_MEMBER(kaypro_state, pio_system_r), /* read printer status */
+ DEVCB_DRIVER_MEMBER(kaypro_state, kayproii_pio_system_w), /* activate various internal devices */
+ DEVCB_NULL, /* portA ready active callback */
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL /* portB ready active callback */
+};
+
+const z80pio_interface kaypro4_pio_s_intf =
+{
+ DEVCB_CPU_INPUT_LINE("maincpu", INPUT_LINE_IRQ0),
+ DEVCB_DRIVER_MEMBER(kaypro_state, pio_system_r), /* read printer status */
+ DEVCB_DRIVER_MEMBER(kaypro_state, kaypro4_pio_system_w), /* activate various internal devices */
+ DEVCB_NULL, /* portA ready active callback */
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL /* portB ready active callback */
+};
+
+/***********************************************************
+
+ KAYPRO2X SYSTEM PORT
+
+ The PIOs were replaced by a few standard 74xx chips
+
+************************************************************/
+
+READ8_MEMBER( kaypro_state::kaypro2x_system_port_r )
+{
+ UINT8 data = m_centronics->busy_r() << 6;
+ return (m_system_port & 0xbf) | data;
+}
+
+WRITE8_MEMBER( kaypro_state::kaypro2x_system_port_w )
+{
+/* d7 bank select
+ d6 alternate character set (write only)
+ d5 double-density enable
+ d4 disk drive motors (1=on)
+ d3 Centronics strobe
+ d2 side select (appears that 0=side 1?)
+ d1 drive B
+ d0 drive A */
+
+ /* get address space */
+ address_space *mem = machine().device("maincpu")->memory().space(AS_PROGRAM);
+
+ if (BIT(data, 7))
+ {
+ mem->unmap_readwrite (0x0000, 0x3fff);
+ mem->install_read_bank (0x0000, 0x1fff, "bank1");
+ membank("bank1")->set_base(mem->machine().root_device().memregion("maincpu")->base());
+ }
+ else
+ {
+ mem->unmap_readwrite (0x0000, 0x3fff);
+ mem->install_read_bank (0x0000, 0x3fff, "bank2");
+ mem->install_write_bank (0x0000, 0x3fff, "bank3");
+ membank("bank2")->set_base(mem->machine().root_device().memregion("rambank")->base());
+ membank("bank3")->set_base(mem->machine().root_device().memregion("rambank")->base());
+ }
+
+ wd17xx_dden_w(m_fdc, BIT(data, 5));
+
+ m_centronics->strobe_w(BIT(data, 3));
+
+ if (BIT(data, 0))
+ wd17xx_set_drive(m_fdc, 0);
+ else
+ if (BIT(data, 1))
+ wd17xx_set_drive(m_fdc, 1);
+
+ wd17xx_set_side(m_fdc, BIT(data, 2) ? 0 : 1);
+
+ output_set_value("ledA", BIT(data, 0)); /* LEDs in artwork */
+ output_set_value("ledB", BIT(data, 1));
+
+ /* CLEAR_LINE means to turn motors on */
+ floppy_mon_w(floppy_get_device(machine(), 0), BIT(data, 4) ? CLEAR_LINE : ASSERT_LINE);
+ floppy_mon_w(floppy_get_device(machine(), 1), BIT(data, 4) ? CLEAR_LINE : ASSERT_LINE);
+
+ m_system_port = data;
+}
+
+
+
+/***********************************************************************
+
+ SIO
+
+ On Kaypro2x, Channel B on both SIOs is hardwired to 300 baud.
+
+ Both devices on sio2 (printer and modem) are not emulated.
+
+************************************************************************/
+
+/* Set baud rate. bits 0..3 Rx and Tx are tied together. Baud Rate Generator is a AY-5-8116, SMC8116, WD1943, etc.
+ 00h 50
+ 11h 75
+ 22h 110
+ 33h 134.5
+ 44h 150
+ 55h 300
+ 66h 600
+ 77h 1200
+ 88h 1800
+ 99h 2000
+ AAh 2400
+ BBh 3600
+ CCh 4800
+ DDh 7200
+ EEh 9600
+ FFh 19200 */
+
+
+const z80sio_interface kaypro_sio_intf =
+{
+ kaypro_interrupt, /* interrupt handler */
+ 0, /* DTR changed handler */
+ 0, /* RTS changed handler */
+ 0, /* BREAK changed handler */
+ 0, /* transmit handler - which channel is this for? */
+ 0 /* receive handler - which channel is this for? */
+};
+
+READ8_DEVICE_HANDLER( kaypro_sio_r )
+{
+ if (!offset)
+ return dynamic_cast<z80sio_device*>(device)->data_read(0);
+ else
+ if (offset == 1)
+// return z80sio_d_r(device, 1);
+ return kay_kbd_d_r(device->machine());
+ else
+ if (offset == 2)
+ return dynamic_cast<z80sio_device*>(device)->control_read(0);
+ else
+// return z80sio_c_r(device, 1);
+ return kay_kbd_c_r(device->machine());
+}
+
+WRITE8_DEVICE_HANDLER( kaypro_sio_w )
+{
+ if (!offset)
+ dynamic_cast<z80sio_device*>(device)->data_write(0, data);
+ else
+ if (offset == 1)
+// z80sio_d_w(device, 1, data);
+ kay_kbd_d_w(device->machine(), data);
+ else
+ if (offset == 2)
+ dynamic_cast<z80sio_device*>(device)->control_write(0, data);
+ else
+ dynamic_cast<z80sio_device*>(device)->control_write(1, data);
+}
+
+
+/*************************************************************************************
+
+ Floppy DIsk
+
+ If DRQ or IRQ is set, and cpu is halted, the NMI goes low.
+ Since the HALT occurs last (and has no callback mechanism), we need to set
+ a short delay, to give time for the processor to execute the HALT before NMI
+ becomes active.
+
+*************************************************************************************/
+
+static TIMER_CALLBACK( kaypro_timer_callback )
+{
+ if (cpu_get_reg(machine.device("maincpu"), Z80_HALT))
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_NMI, ASSERT_LINE);
+}
+
+WRITE_LINE_MEMBER( kaypro_state::kaypro_fdc_intrq_w )
+{
+ if (state)
+ machine().scheduler().timer_set(attotime::from_usec(25), FUNC(kaypro_timer_callback));
+ else
+ cputag_set_input_line(machine(), "maincpu", INPUT_LINE_NMI, CLEAR_LINE);
+}
+
+WRITE_LINE_MEMBER( kaypro_state::kaypro_fdc_drq_w )
+{
+ if (state)
+ machine().scheduler().timer_set(attotime::from_usec(25), FUNC(kaypro_timer_callback));
+ else
+ cputag_set_input_line(machine(), "maincpu", INPUT_LINE_NMI, CLEAR_LINE);
+
+}
+
+const wd17xx_interface kaypro_wd1793_interface =
+{
+ DEVCB_NULL,
+ DEVCB_DRIVER_LINE_MEMBER(kaypro_state, kaypro_fdc_intrq_w),
+ DEVCB_DRIVER_LINE_MEMBER(kaypro_state, kaypro_fdc_drq_w),
+ {FLOPPY_0, FLOPPY_1, NULL, NULL}
+};
+
+
+/***********************************************************
+
+ Machine
+
+************************************************************/
+MACHINE_START( kayproii )
+{
+ kaypro_state *state = machine.driver_data<kaypro_state>();
+ state->m_pio_s->strobe_a(0);
+}
+
+MACHINE_RESET( kayproii )
+{
+ MACHINE_RESET_CALL(kay_kbd);
+}
+
+MACHINE_RESET( kaypro2x )
+{
+ kaypro_state *state = machine.driver_data<kaypro_state>();
+ address_space *space = state->m_maincpu->memory().space(AS_PROGRAM);
+ state->kaypro2x_system_port_w(*space, 0, 0x80);
+ MACHINE_RESET_CALL(kay_kbd);
+}
+
+/***********************************************************
+
+ Quickload
+
+ This loads a .COM file to address 0x100 then jumps
+ there. Sometimes .COM has been renamed to .CPM to
+ prevent windows going ballistic. These can be loaded
+ as well.
+
+************************************************************/
+
+QUICKLOAD_LOAD( kayproii )
+{
+ kaypro_state *state = image.device().machine().driver_data<kaypro_state>();
+ address_space *space = state->m_maincpu->memory().space(AS_PROGRAM);
+ UINT8 *RAM = state->memregion("rambank")->base();
+ UINT16 i;
+ UINT8 data;
+
+ /* Load image to the TPA (Transient Program Area) */
+ for (i = 0; i < quickload_size; i++)
+ {
+ if (image.fread( &data, 1) != 1) return IMAGE_INIT_FAIL;
+
+ RAM[i+0x100] = data;
+ }
+
+ state->common_pio_system_w(*space, 0, state->m_system_port & 0x7f); // switch TPA in
+ RAM[0x80]=0; // clear out command tail
+ RAM[0x81]=0;
+ cpu_set_reg(state->m_maincpu, STATE_GENPC, 0x100); // start program
+ return IMAGE_INIT_PASS;
+}
+
+QUICKLOAD_LOAD( kaypro2x )
+{
+ kaypro_state *state = image.device().machine().driver_data<kaypro_state>();
+ address_space *space = state->m_maincpu->memory().space(AS_PROGRAM);
+ UINT8 *RAM = state->memregion("rambank")->base();
+ UINT16 i;
+ UINT8 data;
+
+ for (i = 0; i < quickload_size; i++)
+ {
+ if (image.fread( &data, 1) != 1) return IMAGE_INIT_FAIL;
+
+ RAM[i+0x100] = data;
+ }
+
+ state->kaypro2x_system_port_w(*space, 0, state->m_system_port & 0x7f);
+ RAM[0x80]=0;
+ RAM[0x81]=0;
+ cpu_set_reg(state->m_maincpu, STATE_GENPC, 0x100);
+ return IMAGE_INIT_PASS;
+}
diff --git a/src/mess/machine/kb3600.c b/src/mess/machine/kb3600.c
new file mode 100644
index 00000000000..586f673a9b9
--- /dev/null
+++ b/src/mess/machine/kb3600.c
@@ -0,0 +1,178 @@
+/**********************************************************************
+
+ General Instruments AY-5-3600 Keyboard Encoder emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+/*
+
+ TODO:
+
+ - scan timer clock frequency
+ - more accurate emulation of real chip
+
+*/
+
+#include "kb3600.h"
+#include "machine/devhelpr.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LOG 0
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// devices
+const device_type AY3600 = &device_creator<ay3600_device>;
+
+
+
+//**************************************************************************
+// DEVICE CONFIGURATION
+//**************************************************************************
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void ay3600_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const ay3600_interface *intf = reinterpret_cast<const ay3600_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<ay3600_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_in_shift_cb, 0, sizeof(m_in_shift_cb));
+ memset(&m_in_control_cb, 0, sizeof(m_in_control_cb));
+ memset(&m_out_data_ready_cb, 0, sizeof(m_out_data_ready_cb));
+ memset(&m_out_ako_cb, 0, sizeof(m_out_ako_cb));
+ }
+}
+
+
+
+//**************************************************************************
+// 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)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void ay3600_device::device_start()
+{
+ // resolve callbacks
+ m_in_x_func[0].resolve(m_in_x0_cb, *this);
+ m_in_x_func[1].resolve(m_in_x1_cb, *this);
+ m_in_x_func[2].resolve(m_in_x2_cb, *this);
+ m_in_x_func[3].resolve(m_in_x3_cb, *this);
+ m_in_x_func[4].resolve(m_in_x4_cb, *this);
+ m_in_x_func[5].resolve(m_in_x5_cb, *this);
+ m_in_x_func[6].resolve(m_in_x6_cb, *this);
+ m_in_x_func[7].resolve(m_in_x7_cb, *this);
+ m_in_x_func[8].resolve(m_in_x8_cb, *this);
+ m_in_shift_func.resolve(m_in_shift_cb, *this);
+ m_in_control_func.resolve(m_in_control_cb, *this);
+ m_out_data_ready_func.resolve(m_out_data_ready_cb, *this);
+ m_out_ako_func.resolve(m_out_ako_cb, *this);
+
+ // allocate timers
+ m_scan_timer = timer_alloc();
+ m_scan_timer->adjust(attotime::from_hz(60), 0, attotime::from_hz(60));
+
+ // state saving
+ save_item(NAME(m_b));
+ save_item(NAME(m_ako));
+}
+
+
+//-------------------------------------------------
+// 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 = m_in_x_func[x](0,0xffff);
+
+ for (int y = 0; y < 10; y++)
+ {
+ if (BIT(data, y))
+ {
+ int b = (x * 10) + y;
+
+ ako = 1;
+
+ if (b > 63)
+ {
+ b -= 64;
+ b = 0x100 | b;
+ }
+
+ b |= (m_in_shift_func() << 6);
+ b |= (m_in_control_func() << 7);
+
+ if (m_b != b)
+ {
+ m_b = b;
+
+ m_out_data_ready_func(1);
+ return;
+ }
+ }
+ }
+ }
+
+ if (!ako)
+ {
+ m_b = -1;
+ }
+
+ if (ako != m_ako)
+ {
+ m_out_ako_func(ako);
+ m_ako = ako;
+ }
+}
+
+
+//-------------------------------------------------
+// b_r -
+//-------------------------------------------------
+
+UINT16 ay3600_device::b_r()
+{
+ UINT16 data = m_b;
+
+ m_out_data_ready_func(0);
+
+ return data;
+}
diff --git a/src/mess/machine/kb3600.h b/src/mess/machine/kb3600.h
new file mode 100644
index 00000000000..efd0d5932aa
--- /dev/null
+++ b/src/mess/machine/kb3600.h
@@ -0,0 +1,144 @@
+/**********************************************************************
+
+ General Instruments AY-5-3600 Keyboard Encoder emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+ _____ _____
+ 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_ADD(_tag, _clock, _config) \
+ MCFG_DEVICE_ADD(_tag, AY3600, _clock) \
+ MCFG_DEVICE_CONFIG(_config)
+
+
+#define AY3600_INTERFACE(name) \
+ const ay3600_interface (name) =
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> ay3600_interface
+
+struct ay3600_interface
+{
+ devcb_read16 m_in_x0_cb;
+ devcb_read16 m_in_x1_cb;
+ devcb_read16 m_in_x2_cb;
+ devcb_read16 m_in_x3_cb;
+ devcb_read16 m_in_x4_cb;
+ devcb_read16 m_in_x5_cb;
+ devcb_read16 m_in_x6_cb;
+ devcb_read16 m_in_x7_cb;
+ devcb_read16 m_in_x8_cb;
+
+ devcb_read_line m_in_shift_cb;
+ devcb_read_line m_in_control_cb;
+
+ devcb_write_line m_out_data_ready_cb;
+ devcb_write_line m_out_ako_cb;
+};
+
+
+// ======================> ay3600_device
+
+class ay3600_device : public device_t,
+ public ay3600_interface
+{
+public:
+ // construction/destruction
+ ay3600_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+public:
+ UINT16 b_r();
+
+protected:
+ // 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);
+
+private:
+ devcb_resolved_read16 m_in_x_func[9];
+
+ devcb_resolved_read_line m_in_shift_func;
+ devcb_resolved_read_line m_in_control_func;
+
+ devcb_resolved_write_line m_out_data_ready_func;
+ devcb_resolved_write_line m_out_ako_func;
+
+ int m_b; // output buffer
+ int m_ako; // any key down
+
+ // timers
+ emu_timer *m_scan_timer; // keyboard scan timer
+};
+
+
+// device type definition
+extern const device_type AY3600;
+
+
+
+#endif
diff --git a/src/mess/machine/kb_7007_3.h b/src/mess/machine/kb_7007_3.h
new file mode 100644
index 00000000000..67d1431be99
--- /dev/null
+++ b/src/mess/machine/kb_7007_3.h
@@ -0,0 +1,121 @@
+/*
+ * MC 7007 keyboard, variant 3, used by mc1502.
+ *
+ * Rus/Lat key is mapped to RAlt.
+ */
+
+INPUT_PORTS_START( mc7007_3_keyboard )
+ PORT_START("Y1")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad -") PORT_CODE(KEYCODE_MINUS_PAD)
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Scroll Lock")
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Right Shift") PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Left Shift") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad 7") PORT_CODE(KEYCODE_7_PAD) PORT_CODE(KEYCODE_HOME)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad 8") PORT_CODE(KEYCODE_8_PAD) PORT_CODE(KEYCODE_UP)
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad 9") PORT_CODE(KEYCODE_9_PAD) PORT_CODE(KEYCODE_PGUP)
+
+ PORT_START("Y2")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Esc") PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) /* ??2 */
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Tab") PORT_CODE(KEYCODE_TAB) PORT_CHAR('\t') /* ??? */
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Ctrl") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) /* ??? */
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Alt") PORT_CODE(KEYCODE_LALT) /* ??? */
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Rus/Lat") PORT_CODE(KEYCODE_RALT) /* ??? */
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad 0") PORT_CODE(KEYCODE_0_PAD) PORT_CODE(KEYCODE_INSERT) /* ??? */
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Delete") PORT_CODE(KEYCODE_DEL_PAD) /* ???? */
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad +") PORT_CODE(KEYCODE_PLUS_PAD)
+
+ PORT_START("Y3")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')
+ 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_A) PORT_CHAR('a') PORT_CHAR('A')
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z')
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Caps Lock") PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) /* ???? */
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad 1") PORT_CODE(KEYCODE_1_PAD) PORT_CODE(KEYCODE_END)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad 2") PORT_CODE(KEYCODE_2_PAD) PORT_CODE(KEYCODE_DOWN)
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad 3") PORT_CODE(KEYCODE_3_PAD) PORT_CODE(KEYCODE_PGDN)
+
+ PORT_START("Y4")
+ 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_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@')
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W')
+ 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_X) PORT_CHAR('x') PORT_CHAR('X')
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad 4") PORT_CODE(KEYCODE_4_PAD) PORT_CODE(KEYCODE_LEFT)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad 5") PORT_CODE(KEYCODE_5_PAD)
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Keypad 6") PORT_CODE(KEYCODE_6_PAD) PORT_CODE(KEYCODE_RIGHT)
+
+ PORT_START("Y5")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F2") PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2))
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E')
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D')
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C')
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("NumLock") PORT_CODE(KEYCODE_NUMLOCK)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F8") PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8))
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F9") PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9))
+
+ PORT_START("Y6")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F3") PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3))
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
+ 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_F) PORT_CHAR('f') PORT_CHAR('F')
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V')
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(UTF8_LEFT) PORT_CODE(KEYCODE_BACKSPACE)
+ 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("F6") PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6))
+
+ PORT_START("Y7")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T')
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G')
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B')
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Space") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Cursor right") PORT_CODE(KEYCODE_RIGHT)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Enter") PORT_CODE(KEYCODE_ENTER) PORT_CHAR('\r') /* keypad */
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("* PrtSc") PORT_CODE(KEYCODE_PRTSCR)
+
+ PORT_START("Y8")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F4") PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4))
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^')
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y')
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H')
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N')
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Cursor down") PORT_CODE(KEYCODE_DOWN)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Cursor up") PORT_CODE(KEYCODE_UP)
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|')
+
+ PORT_START("Y9")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F5") PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5))
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&')
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U')
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J')
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M')
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') PORT_CHAR('~')
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}')
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+')
+
+ PORT_START("Y10")
+ 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_I) PORT_CHAR('i') PORT_CHAR('I')
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K')
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Cursor left") PORT_CODE(KEYCODE_LEFT)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('"')
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{')
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_')
+
+ PORT_START("Y11")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(')
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O')
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L')
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?')
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':')
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P')
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')')
+
+ PORT_START("Y12")
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F10") PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10))
+INPUT_PORTS_END
+
diff --git a/src/mess/machine/kb_keytro.c b/src/mess/machine/kb_keytro.c
new file mode 100644
index 00000000000..52f18f6ac11
--- /dev/null
+++ b/src/mess/machine/kb_keytro.c
@@ -0,0 +1,651 @@
+/***************************************************************************
+
+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 "kb_keytro.h"
+#include "cpu/mcs51/mcs51.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define LOG 0
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _kb_keytr_state kb_keytr_state;
+struct _kb_keytr_state
+{
+ device_t *cpu;
+
+ devcb_resolved_write_line out_clock_func;
+ devcb_resolved_write_line out_data_func;
+
+ /* state of i/o signals */
+ int clock_signal;
+ int data_signal;
+
+ /* internal state */
+ UINT8 p1;
+ UINT8 p1_data;
+ UINT8 p2;
+ UINT8 p3;
+ UINT16 last_write_addr;
+};
+
+
+/*****************************************************************************
+ 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
+
+
+/***************************************************************************
+ ROM DEFINITIONS
+***************************************************************************/
+
+ROM_START( kb_keytr )
+ ROM_REGION(0x2000, "kb_keytr", 0)
+ ROM_LOAD("14166.bin", 0x0000, 0x2000, CRC(1aea1b53) SHA1(b75b6d4509036406052157bc34159f7039cdc72e))
+ROM_END
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type PC_KBD_KEYTRONIC_PC3270 = &device_creator<pc_kbd_keytronic_pc3270_device>;
+const device_type PC_KBD_KEYTRONIC_PC3270_AT = &device_creator<pc_kbd_keytronic_pc3270_at_device>;
+
+
+/*****************************************************************************
+ 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 ),
+ device_pc_kbd_interface(mconfig, *this),
+ m_cpu(*this, "kb_keytr")
+{
+ m_shortname = "keytronic_pc3270";
+}
+
+
+//-------------------------------------------------
+// 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;
+}
+
+
+//-------------------------------------------------
+// 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 )
+{
+ device_set_input_line( m_cpu, MCS51_INT0_LINE, state );
+}
+
+
+WRITE_LINE_MEMBER( pc_kbd_keytronic_pc3270_device::data_write )
+{
+ device_set_input_line( m_cpu, 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/mess/machine/kb_keytro.h b/src/mess/machine/kb_keytro.h
new file mode 100644
index 00000000000..1d0e58e98c8
--- /dev/null
+++ b/src/mess/machine/kb_keytro.h
@@ -0,0 +1,75 @@
+/***************************************************************************
+
+ Keytronic Keyboard
+
+***************************************************************************/
+
+#ifndef __KB_KEYTRO_H__
+#define __KB_KEYTRO_H__
+
+#include "devcb.h"
+#include "machine/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<cpu_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/mess/machine/kb_msnat.c b/src/mess/machine/kb_msnat.c
new file mode 100644
index 00000000000..9d8894d50f1
--- /dev/null
+++ b/src/mess/machine/kb_msnat.c
@@ -0,0 +1,435 @@
+/***************************************************************************
+
+ Microsoft Natural Keybaord emulation
+
+
+TODO:
+- Keyboard LEDs
+
+***************************************************************************/
+
+#include "emu.h"
+#include "machine/kb_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<pc_kbd_microsoft_natural_device>;
+
+/*****************************************************************************
+ 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 ),
+ device_pc_kbd_interface(mconfig, *this),
+ m_cpu(*this, "ms_natrl_cpu")
+{
+ m_shortname = "ms_natural";
+}
+
+
+//-------------------------------------------------
+// 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 &= ioport( "P2.0" )->read();
+ }
+
+ if ( ! ( m_p2 & 0x02 ) )
+ {
+ data &= ioport( "P2.1" )->read();
+ }
+
+ if ( ! ( m_p2 & 0x04 ) )
+ {
+ data &= ioport( "P2.2" )->read();
+ }
+
+ if ( ! ( m_p2 & 0x08 ) )
+ {
+ data &= ioport( "P2.3" )->read();
+ }
+
+ if ( ! ( m_p2 & 0x10 ) )
+ {
+ data &= ioport( "P2.4" )->read();
+ }
+
+ if ( ! ( m_p2 & 0x20 ) )
+ {
+ data &= ioport( "P2.5" )->read();
+ }
+
+ if ( ! ( m_p2 & 0x40 ) )
+ {
+ data &= ioport( "P2.6" )->read();
+ }
+
+ if ( ! ( m_p2 & 0x80 ) )
+ {
+ data &= ioport( "P2.7" )->read();
+ }
+
+ if ( ! ( m_p1 & 0x01 ) )
+ {
+ data &= ioport( "P1.0" )->read();
+ }
+
+ if ( ! ( m_p1 & 0x02 ) )
+ {
+ data &= ioport( "P1.1" )->read();
+ }
+
+ if ( ! ( m_p1 & 0x04 ) )
+ {
+ data &= ioport( "P1.2" )->read();
+ }
+
+ if ( ! ( m_p1 & 0x08 ) )
+ {
+ data &= ioport( "P1.3" )->read();
+ }
+
+ if ( ! ( m_p1 & 0x10 ) )
+ {
+ data &= ioport( "P1.4" )->read();
+ }
+
+ if ( ! ( m_p1 & 0x20 ) )
+ {
+ data &= ioport( "P1.5" )->read();
+ }
+
+ if ( ! ( m_p1 & 0x40 ) )
+ {
+ data &= ioport( "P1.6" )->read();
+ }
+
+ if ( ! ( m_p1 & 0x80 ) )
+ {
+ data &= ioport( "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/mess/machine/kb_msnat.h b/src/mess/machine/kb_msnat.h
new file mode 100644
index 00000000000..f7d15f3e3a0
--- /dev/null
+++ b/src/mess/machine/kb_msnat.h
@@ -0,0 +1,57 @@
+/***************************************************************************
+
+ Microsoft Natural Keyboard
+
+***************************************************************************/
+
+#ifndef __KB_MSNAT_H__
+#define __KB_MSNAT_H__
+
+#include "devcb.h"
+#include "machine/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<cpu_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:
+ // 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/mess/machine/kc.c b/src/mess/machine/kc.c
new file mode 100644
index 00000000000..c3cf9020c8c
--- /dev/null
+++ b/src/mess/machine/kc.c
@@ -0,0 +1,802 @@
+/* Core includes */
+#include "emu.h"
+#include "includes/kc.h"
+
+#define KC_DEBUG 0
+#define LOG(x) do { if (KC_DEBUG) logerror x; } while (0)
+
+struct kcc_header
+{
+ UINT8 name[10];
+ UINT8 reserved[6];
+ UINT8 number_addresses;
+ UINT8 load_address_l;
+ UINT8 load_address_h;
+ UINT8 end_address_l;
+ UINT8 end_address_h;
+ UINT8 execution_address_l;
+ UINT8 execution_address_h;
+ UINT8 pad[128-2-2-2-1-16];
+};
+
+/* appears to work a bit.. */
+/* load file, then type: MENU and it should now be displayed. */
+/* now type name that has appeared! */
+
+/* load snapshot */
+QUICKLOAD_LOAD(kc)
+{
+ kc_state *state = image.device().machine().driver_data<kc_state>();
+ UINT8 *data;
+ struct kcc_header *header;
+ int addr;
+ int datasize;
+ int execution_address;
+ int i;
+
+ /* get file size */
+ datasize = image.length();
+
+ if (datasize != 0)
+ {
+ /* malloc memory for this data */
+ data = (UINT8 *)auto_alloc_array(image.device().machine(), UINT8, datasize);
+
+ if (data != NULL)
+ image.fread( data, datasize);
+ }
+ else
+ {
+ return IMAGE_INIT_FAIL;
+ }
+
+ header = (struct kcc_header *) data;
+ addr = (header->load_address_l & 0x0ff) | ((header->load_address_h & 0x0ff)<<8);
+ datasize = ((header->end_address_l & 0x0ff) | ((header->end_address_h & 0x0ff)<<8)) - addr;
+ execution_address = (header->execution_address_l & 0x0ff) | ((header->execution_address_h & 0x0ff)<<8);
+
+ if (datasize + 128 > image.length())
+ {
+ mame_printf_info("Invalid snapshot size: expected 0x%04x, found 0x%04x\n", datasize, (UINT32)image.length() - 128);
+ datasize = image.length() - 128;
+ }
+
+ address_space *space = state->m_maincpu->memory().space( AS_PROGRAM );
+
+ for (i=0; i<datasize; i++)
+ space->write_byte((addr+i) & 0xffff, data[i+128]);
+
+ if (execution_address != 0 && header->number_addresses >= 3 )
+ {
+ // if specified, jumps to the quickload start address
+ cpu_set_reg(state->m_maincpu, STATE_GENPC, execution_address);
+ }
+
+ auto_free(image.device().machine(), data);
+
+ logerror("Snapshot loaded at: 0x%04x-0x%04x, execution address: 0x%04x\n", addr, addr + datasize - 1, execution_address);
+
+ return IMAGE_INIT_PASS;
+}
+
+
+//**************************************************************************
+// MODULE SYSTEM EMULATION
+//**************************************************************************
+
+// The KC85/4 and KC85/3 are "modular systems". These computers can be expanded with modules.
+
+READ8_MEMBER( kc_state::expansion_read )
+{
+ UINT8 result = 0xff;
+
+ // assert MEI line of first slot
+ m_expansions[0]->mei_w(ASSERT_LINE);
+
+ for (int i=0; i<3; i++)
+ m_expansions[i]->read(offset, result);
+
+ return result;
+}
+
+WRITE8_MEMBER( kc_state::expansion_write )
+{
+ // assert MEI line of first slot
+ m_expansions[0]->mei_w(ASSERT_LINE);
+
+ for (int i=0; i<3; i++)
+ m_expansions[i]->write(offset, data);
+}
+
+/*
+ port xx80
+
+ - xx is module id.
+
+ Only addressess divisible by 4 are checked.
+ If module does not exist, 0x0ff is returned.
+
+ When xx80 is read, if a module exists a id will be returned.
+ Id's for known modules are listed above.
+*/
+
+READ8_MEMBER( kc_state::expansion_io_read )
+{
+ UINT8 result = 0xff;
+
+ // assert MEI line of first slot
+ m_expansions[0]->mei_w(ASSERT_LINE);
+
+ if ((offset & 0xff) == 0x80)
+ {
+ UINT8 slot_id = (offset>>8) & 0xff;
+
+ if (slot_id == 0x08 || slot_id == 0x0c)
+ result = m_expansions[(slot_id - 8) >> 2]->module_id_r();
+ else
+ m_expansions[2]->io_read(offset, result);
+ }
+ else
+ {
+ for (int i=0; i<3; i++)
+ m_expansions[i]->io_read(offset, result);
+ }
+
+ return result;
+}
+
+WRITE8_MEMBER( kc_state::expansion_io_write )
+{
+ // assert MEI line of first slot
+ m_expansions[0]->mei_w(ASSERT_LINE);
+
+ if ((offset & 0xff) == 0x80)
+ {
+ UINT8 slot_id = (offset>>8) & 0xff;
+
+ if (slot_id == 0x08 || slot_id == 0x0c)
+ m_expansions[(slot_id - 8) >> 2]->control_w(data);
+ else
+ m_expansions[2]->io_write(offset, data);
+ }
+ else
+ {
+ for (int i=0; i<3; i++)
+ m_expansions[i]->io_write(offset, data);
+ }
+}
+
+// module read/write handlers
+READ8_MEMBER ( kc_state::expansion_4000_r ){ return expansion_read(space, offset + 0x4000); }
+WRITE8_MEMBER( kc_state::expansion_4000_w ){ expansion_write(space, offset + 0x4000, data); }
+READ8_MEMBER ( kc_state::expansion_8000_r ){ return expansion_read(space, offset + 0x8000); }
+WRITE8_MEMBER( kc_state::expansion_8000_w ){ expansion_write(space, offset + 0x8000, data); }
+READ8_MEMBER ( kc_state::expansion_c000_r ){ return expansion_read(space, offset + 0xc000); }
+WRITE8_MEMBER( kc_state::expansion_c000_w ){ expansion_write(space, offset + 0xc000, data); }
+READ8_MEMBER ( kc_state::expansion_e000_r ){ return expansion_read(space, offset + 0xe000); }
+WRITE8_MEMBER( kc_state::expansion_e000_w ){ expansion_write(space, offset + 0xe000, data); }
+
+
+//**************************************************************************
+// CASSETTE EMULATION
+//**************************************************************************
+
+/*
+ The cassette motor is controlled by bit 6 of PIO port A.
+ The cassette read data is connected to /ASTB input of the PIO.
+ A edge from the cassette therefore will trigger a interrupt
+ from the PIO.
+ The duration between two edges can be timed and the data-bit
+ identified.
+
+ I have used a timer to feed data into /ASTB. The timer is only
+ active when the cassette motor is on.
+*/
+
+void kc_state::update_cassette(int state)
+{
+ int astb = (state & m_ardy) ? 0 : 1;
+
+ // if state is changed updates the /ASTB line
+ if (m_astb ^ astb)
+ {
+ m_z80pio->strobe_a(astb);
+
+ m_astb = astb;
+
+ // FIXME: temporary for allow kc85_2-3 to load cassette
+ if ((m_cassette->get_state() & 0x03) == CASSETTE_PLAY)
+ m_z80pio->data_write(0, m_pio_data[0]);
+ }
+}
+
+static TIMER_CALLBACK(kc_cassette_oneshot_timer)
+{
+ kc_state *state = machine.driver_data<kc_state>();
+
+ state->update_cassette(0);
+
+ state->m_cassette_oneshot_timer->reset();
+}
+
+// timer used for polling data from cassette input
+// enabled only when cassette motor is on
+static TIMER_CALLBACK(kc_cassette_timer_callback)
+{
+ kc_state *state = machine.driver_data<kc_state>();
+
+ // read cassette data
+ int bit = (state->m_cassette->input() > 0.0038) ? 1 : 0;
+
+ // generates a pulse when the cassette input changes state
+ if (bit ^ state->m_cassette_in)
+ {
+ state->update_cassette(1);
+ state->m_cassette_in = bit;
+ state->m_cassette_oneshot_timer->adjust(attotime::from_double(TIME_OF_74LS123(RES_K(10), CAP_N(1))));
+ }
+}
+
+void kc_state::cassette_set_motor(int motor_state)
+{
+ /* set new motor state in cassette device */
+ m_cassette->change_state(motor_state ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR);
+
+ if (motor_state)
+ {
+ /* start timer */
+ m_cassette_timer->adjust(attotime::zero, 0, KC_CASSETTE_TIMER_FREQUENCY);
+ }
+ else
+ {
+ /* stop timer */
+ m_cassette_timer->reset();
+ }
+}
+
+/*
+ pin 2 = gnd
+ pin 3 = read
+ pin 1 = k1 ?? modulating signal
+ pin 4 = k0 ?? signal??
+ pin 5 = motor on
+
+
+ Tape signals:
+ K0, K1 ??
+ MOTON motor control
+ ASTB read?
+
+ T1-T4 give 4 bit a/d tone sound?
+ K1, K0 are mixed with tone.
+
+ Cassette read goes into ASTB of PIO.
+ From this, KC must be able to detect the length
+ of the pulses and can read the data.
+
+
+ Tape write: clock comes from CTC?
+ truck signal resets, 5v signal for set.
+ output gives k0 and k1.
+
+*/
+
+
+
+//**************************************************************************
+// KC85 bankswitch
+//**************************************************************************
+
+/* update status of memory area 0x0000-0x03fff */
+void kc_state::update_0x00000()
+{
+ address_space *space = m_maincpu->memory().space( AS_PROGRAM );
+
+ /* access ram? */
+ if (m_pio_data[0] & (1<<1))
+ {
+ LOG(("ram0 enabled\n"));
+
+ /* yes; set address of bank */
+ space->install_read_bank(0x0000, 0x3fff, "bank1");
+ membank("bank1")->set_base(m_ram_base);
+
+ /* write protect ram? */
+ if ((m_pio_data[0] & (1<<3)) == 0)
+ {
+ /* yes */
+ LOG(("ram0 write protected\n"));
+
+ /* ram is enabled and write protected */
+ space->unmap_write(0x0000, 0x3fff);
+ }
+ else
+ {
+ LOG(("ram0 write enabled\n"));
+
+ /* ram is enabled and write enabled */
+ space->install_write_bank(0x0000, 0x3fff, "bank1");
+ }
+ }
+ else
+ {
+ LOG(("Module at 0x0000\n"));
+
+ space->install_read_handler (0x0000, 0x3fff, 0, 0, read8_delegate(FUNC(kc_state::expansion_read), this), 0);
+ space->install_write_handler(0x0000, 0x3fff, 0, 0, write8_delegate(FUNC(kc_state::expansion_write), this), 0);
+ }
+}
+
+/* update status of memory area 0x4000-0x07fff */
+void kc_state::update_0x04000()
+{
+ address_space *space = m_maincpu->memory().space( AS_PROGRAM );
+
+ LOG(("Module at 0x4000\n"));
+
+ space->install_read_handler (0x4000, 0x7fff, 0, 0, read8_delegate(FUNC(kc_state::expansion_4000_r), this), 0);
+ space->install_write_handler(0x4000, 0x7fff, 0, 0, write8_delegate(FUNC(kc_state::expansion_4000_w), this), 0);
+
+}
+
+
+/* update memory address 0x0c000-0x0e000 */
+void kc_state::update_0x0c000()
+{
+ address_space *space = m_maincpu->memory().space( AS_PROGRAM );
+
+ if ((m_pio_data[0] & (1<<7)) && memregion("basic")->base() != NULL)
+ {
+ /* BASIC takes next priority */
+ LOG(("BASIC rom 0x0c000\n"));
+
+ membank("bank4")->set_base(memregion("basic")->base());
+ space->install_read_bank(0xc000, 0xdfff, "bank4");
+ space->unmap_write(0xc000, 0xdfff);
+ }
+ else
+ {
+ LOG(("Module at 0x0c000\n"));
+
+ space->install_read_handler (0xc000, 0xdfff, 0, 0, read8_delegate(FUNC(kc_state::expansion_c000_r), this), 0);
+ space->install_write_handler(0xc000, 0xdfff, 0, 0, write8_delegate(FUNC(kc_state::expansion_c000_w), this), 0);
+ }
+}
+
+/* update memory address 0x0e000-0x0ffff */
+void kc_state::update_0x0e000()
+{
+ address_space *space = m_maincpu->memory().space( AS_PROGRAM );
+
+ if (m_pio_data[0] & (1<<0))
+ {
+ /* enable CAOS rom in memory range 0x0e000-0x0ffff */
+ LOG(("CAOS rom 0x0e000\n"));
+ /* read will access the rom */
+ membank("bank5")->set_base(memregion("caos")->base() + 0x2000);
+ space->install_read_bank(0xe000, 0xffff, "bank5");
+ space->unmap_write(0xe000, 0xffff);
+ }
+ else
+ {
+ LOG(("Module at 0x0e000\n"));
+
+ space->install_read_handler (0xe000, 0xffff, 0, 0, read8_delegate(FUNC(kc_state::expansion_e000_r), this), 0);
+ space->install_write_handler(0xe000, 0xffff, 0, 0, write8_delegate(FUNC(kc_state::expansion_e000_w), this), 0);
+ }
+}
+
+
+/* update status of memory area 0x08000-0x0ffff */
+void kc_state::update_0x08000()
+{
+ address_space *space = m_maincpu->memory().space( AS_PROGRAM );
+
+ if (m_pio_data[0] & (1<<2))
+ {
+ /* IRM enabled */
+ LOG(("IRM enabled\n"));
+
+ membank("bank3")->set_base(m_video_ram);
+ space->install_readwrite_bank(0x8000, 0xbfff, "bank3");
+ }
+ else
+ {
+ LOG(("Module at 0x8000!\n"));
+
+ space->install_read_handler(0x8000, 0xbfff, 0, 0, read8_delegate(FUNC(kc_state::expansion_8000_r), this), 0);
+ space->install_write_handler(0x8000, 0xbfff, 0, 0, write8_delegate(FUNC(kc_state::expansion_8000_w), this), 0);
+ }
+}
+
+
+/* update status of memory area 0x4000-0x07fff */
+void kc85_4_state::update_0x04000()
+{
+ address_space *space = m_maincpu->memory().space( AS_PROGRAM );
+
+ /* access ram? */
+ if (m_port_86_data & (1<<0))
+ {
+ LOG(("RAM4 enabled\n"));
+
+ /* yes */
+ space->install_read_bank(0x4000, 0x7fff, "bank2");
+ /* set address of bank */
+ membank("bank2")->set_base(m_ram_base + 0x4000);
+
+ /* write protect ram? */
+ if ((m_port_86_data & (1<<1)) == 0)
+ {
+ /* yes */
+ LOG(("ram4 write protected\n"));
+
+ /* ram is enabled and write protected */
+ space->nop_write(0x4000, 0x7fff);
+ }
+ else
+ {
+ LOG(("ram4 write enabled\n"));
+
+ /* ram is enabled and write enabled */
+ space->install_write_bank(0x4000, 0x7fff, "bank2");
+ }
+ }
+ else
+ {
+ LOG(("Module at 0x4000\n"));
+
+ space->install_read_handler (0x4000, 0x7fff, 0, 0, read8_delegate(FUNC(kc_state::expansion_4000_r), this), 0);
+ space->install_write_handler(0x4000, 0x7fff, 0, 0, write8_delegate(FUNC(kc_state::expansion_4000_w), this), 0);
+ }
+
+}
+
+/* update memory address 0x0c000-0x0e000 */
+void kc85_4_state::update_0x0c000()
+{
+ address_space *space = m_maincpu->memory().space( AS_PROGRAM );
+
+ if (m_port_86_data & (1<<7))
+ {
+ /* CAOS rom takes priority */
+ LOG(("CAOS rom 0x0c000\n"));
+
+ membank("bank4")->set_base(memregion("caos")->base());
+ space->install_read_bank(0xc000, 0xdfff, "bank4");
+ space->unmap_write(0xc000, 0xdfff);
+ }
+ else
+ {
+ if (m_pio_data[0] & (1<<7))
+ {
+ /* BASIC takes next priority */
+ LOG(("BASIC rom 0x0c000\n"));
+
+ int bank = memregion("basic")->bytes() == 0x8000 ? (m_port_86_data>>5) & 0x03 : 0;
+
+ membank("bank4")->set_base(memregion("basic")->base() + (bank << 13));
+ space->install_read_bank(0xc000, 0xdfff, "bank4");
+ space->unmap_write(0xc000, 0xdfff);
+ }
+ else
+ {
+ LOG(("Module at 0x0c000\n"));
+
+ space->install_read_handler (0xc000, 0xdfff, 0, 0, read8_delegate(FUNC(kc_state::expansion_c000_r), this), 0);
+ space->install_write_handler(0xc000, 0xdfff, 0, 0, write8_delegate(FUNC(kc_state::expansion_c000_w), this), 0);
+ }
+ }
+}
+
+void kc85_4_state::update_0x08000()
+{
+ address_space *space = m_maincpu->memory().space( AS_PROGRAM );
+
+ if (m_pio_data[0] & (1<<2))
+ {
+ /* IRM enabled - has priority over RAM8 enabled */
+ LOG(("IRM enabled\n"));
+
+ UINT8* ram_page = m_video_ram + ((BIT(m_port_84_data, 2)<<15) | (BIT(m_port_84_data, 1)<<14));
+
+ membank("bank3")->set_base(ram_page);
+ space->install_readwrite_bank(0x8000, 0xa7ff, "bank3");
+
+ membank("bank6")->set_base(m_video_ram + 0x2800);
+ space->install_readwrite_bank(0xa800, 0xbfff, "bank6");
+ }
+ else if (m_pio_data[1] & (1<<5))
+ {
+ LOG(("RAM8 enabled\n"));
+
+ int ram8_block;
+ UINT8 *mem_ptr;
+
+ /* ram8 block chosen */
+
+ if (m_ram->size() == 64 * 1024)
+ {
+ // kc85_4 64K RAM
+ ram8_block = ((m_port_84_data)>>4) & 0x01;
+ mem_ptr = m_ram_base + 0x8000 + (ram8_block<<14);
+ }
+ else
+ {
+ // kc85_5 256K RAM
+ ram8_block = ((m_port_84_data)>>4) & 0x0f;
+ mem_ptr = m_ram_base + (ram8_block<<14);
+ }
+
+ membank("bank3")->set_base(mem_ptr);
+ membank("bank6")->set_base(mem_ptr + 0x2800);
+ space->install_read_bank(0x8000, 0xa7ff, "bank3");
+ space->install_read_bank(0xa800, 0xbfff, "bank6");
+
+ /* write protect RAM8 ? */
+ if ((m_pio_data[1] & (1<<6)) == 0)
+ {
+ /* ram8 is enabled and write protected */
+ LOG(("RAM8 write protected\n"));
+
+ space->nop_write(0x8000, 0xa7ff);
+ space->nop_write(0xa800, 0xbfff);
+ }
+ else
+ {
+ LOG(("RAM8 write enabled\n"));
+
+ /* ram8 is enabled and write enabled */
+ space->install_write_bank(0x8000, 0xa7ff, "bank3");
+ space->install_write_bank(0xa800, 0xbfff, "bank6");
+ }
+ }
+ else
+ {
+ LOG(("Module at 0x8000\n"));
+
+ space->install_read_handler(0x8000, 0xbfff, 0, 0, read8_delegate(FUNC(kc_state::expansion_8000_r), this), 0);
+ space->install_write_handler(0x8000, 0xbfff, 0, 0, write8_delegate(FUNC(kc_state::expansion_8000_w), this), 0);
+ }
+}
+
+//**************************************************************************
+// KC85 Z80PIO Interface
+//**************************************************************************
+
+
+/* PIO PORT A: port 0x088:
+
+bit 7: ROM C (BASIC)
+bit 6: Tape Motor on
+bit 5: LED
+bit 4: K OUT
+bit 3: WRITE PROTECT RAM 0
+bit 2: IRM
+bit 1: ACCESS RAM 0
+bit 0: CAOS ROM E
+*/
+
+READ8_MEMBER( kc_state::pio_porta_r )
+{
+ return m_pio_data[0];
+}
+
+WRITE8_MEMBER( kc_state::pio_porta_w )
+{
+ if (m_pio_data[0] != data) // to avoid a severe slowdown during cassette loading
+ {
+ m_pio_data[0] = data;
+
+ update_0x00000();
+ update_0x08000();
+ update_0x0c000();
+ update_0x0e000();
+
+ cassette_set_motor(BIT(data, 6));
+ }
+}
+
+
+/* PIO PORT B: port 0x089:
+bit 7: BLINK ENABLE
+bit 6: WRITE PROTECT RAM 8
+bit 5: ACCESS RAM 8
+bit 4: TONE 4
+bit 3: TONE 3
+bit 2: TONE 2
+bit 1: TONE 1
+bit 0: TRUCK */
+
+READ8_MEMBER( kc_state::pio_portb_r )
+{
+ return m_pio_data[1];
+}
+
+WRITE8_MEMBER( kc_state::pio_portb_w )
+{
+ m_pio_data[1] = data;
+
+ update_0x08000();
+
+ /* 16 speaker levels */
+ m_speaker_level = (data>>1) & 0x0f;
+
+ speaker_update();
+}
+
+/* port 0x84/0x85:
+
+bit 7: RAF3
+bit 6: RAF2
+bit 5: RAF1
+bit 4: RAF0
+bit 3: FPIX. high resolution
+bit 2: BLA1 .access screen
+bit 1: BLA0 .pixel/color
+bit 0: BILD .display screen 0 or 1
+*/
+
+WRITE8_MEMBER( kc85_4_state::kc85_4_84_w )
+{
+ LOG(("0x84 W: %02x\n", data));
+
+ m_port_84_data = data;
+
+ video_control_w(data);
+
+ update_0x08000();
+}
+
+READ8_MEMBER( kc85_4_state::kc85_4_84_r )
+{
+ return m_port_84_data;
+}
+
+
+/* port 0x86/0x87:
+
+bit 7: ROCC
+bit 6: ROF1
+bit 5: ROF0
+bit 4-2 are not connected
+bit 1: WRITE PROTECT RAM 4
+bit 0: ACCESS RAM 4
+*/
+
+WRITE8_MEMBER( kc85_4_state::kc85_4_86_w )
+{
+ LOG(("0x86 W: %02x\n", data));
+
+ m_port_86_data = data;
+
+ update_0x0c000();
+ update_0x04000();
+}
+
+READ8_MEMBER( kc85_4_state::kc85_4_86_r )
+{
+ return m_port_86_data;
+}
+
+/*****************************************************************/
+
+
+/* callback for ardy output from PIO */
+/* used in KC85/4 & KC85/3 cassette interface */
+WRITE_LINE_MEMBER( kc_state::pio_ardy_cb)
+{
+ m_ardy = state & 0x01;
+}
+
+/* callback for brdy output from PIO */
+/* used in KC85/4 & KC85/3 keyboard interface */
+WRITE_LINE_MEMBER( kc_state::pio_brdy_cb)
+{
+ m_brdy = state & 0x01;
+}
+
+/* used in cassette write -> K0 */
+WRITE_LINE_MEMBER( kc_state::ctc_zc0_callback )
+{
+ if (state)
+ {
+ m_k0_line^=1;
+ speaker_update();
+ }
+}
+
+/* used in cassette write -> K1 */
+WRITE_LINE_MEMBER( kc_state::ctc_zc1_callback)
+{
+ if (state)
+ {
+ m_k1_line^=1;
+ speaker_update();
+
+ // K1 line is also cassette output
+ m_cassette->output((m_k1_line & 1) ? +1 : -1);
+ }
+
+}
+
+TIMER_DEVICE_CALLBACK( kc_scanline )
+{
+ kc_state *state = timer.machine().driver_data<kc_state>();
+ int scanline = (int)param;
+
+ /* set clock input for channel 0 and 1 to ctc */
+ state->m_z80ctc->trg0(1);
+ state->m_z80ctc->trg0(0);
+ state->m_z80ctc->trg1(1);
+ state->m_z80ctc->trg1(0);
+
+ if (scanline == 256)
+ {
+ /* set clock input for channel 2 and 3 to ctc */
+ state->m_z80ctc->trg2(1);
+ state->m_z80ctc->trg2(0);
+ state->m_z80ctc->trg3(1);
+ state->m_z80ctc->trg3(0);
+ }
+}
+
+void kc_state::speaker_update()
+{
+ /* this might not be correct, the range might be logarithmic and not linear! */
+ speaker_level_w(m_speaker, m_k0_line ? (m_speaker_level | (m_k1_line ? 0x01 : 0)) : 0);
+}
+
+/* keyboard callback */
+WRITE_LINE_MEMBER( kc_state::keyboard_cb )
+{
+ m_z80pio->strobe_b(state & m_brdy);
+
+ // FIXME: understand why the PIO fail to acknowledge the irq on kc85_2/3
+ m_z80pio->data_write(1, m_pio_data[1]);
+}
+
+
+void kc_state::machine_start()
+{
+ m_cassette_timer = machine().scheduler().timer_alloc(FUNC(kc_cassette_timer_callback));
+ m_cassette_oneshot_timer = machine().scheduler().timer_alloc(FUNC(kc_cassette_oneshot_timer));
+
+ m_ram_base = m_ram->pointer();
+
+ m_expansions[0] = machine().device<kcexp_slot_device>("m8");
+ m_expansions[1] = machine().device<kcexp_slot_device>("mc");
+ m_expansions[2] = machine().device<kcexp_slot_device>("exp");
+}
+
+void kc_state::machine_reset()
+{
+ m_pio_data[0] = 0x0f;
+ m_pio_data[1] = 0xf1;
+
+ update_0x00000();
+ update_0x04000();
+ update_0x08000();
+ update_0x0c000();
+ update_0x0e000();
+
+ // set low resolution at reset
+ m_high_resolution = 0;
+
+ cassette_set_motor(0);
+
+ /* this is temporary. Normally when a Z80 is reset, it will
+ execute address 0. It appears the KC85 series pages the rom
+ at address 0x0000-0x01000 which has a single jump in it,
+ can't see yet where it disables it later!!!! so for now
+ here will be a override */
+ cpu_set_reg(m_maincpu, STATE_GENPC, 0x0f000);
+}
+
+void kc85_4_state::machine_reset()
+{
+ kc_state::machine_reset();
+
+ m_port_84_data = 0x00;
+ m_port_86_data = 0x00;
+}
diff --git a/src/mess/machine/kc_d002.c b/src/mess/machine/kc_d002.c
new file mode 100644
index 00000000000..716c4ce1d26
--- /dev/null
+++ b/src/mess/machine/kc_d002.c
@@ -0,0 +1,210 @@
+/***************************************************************************
+
+ kc_d002.c
+
+ KC85 D002 Bus Driver emulation
+
+***************************************************************************/
+
+#include "emu.h"
+#include "kc_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_func(state);
+}
+
+WRITE_LINE_MEMBER(kc_d002_device::out_nmi_w)
+{
+ m_slot->m_out_nmi_func(state);
+}
+
+WRITE_LINE_MEMBER(kc_d002_device::out_halt_w)
+{
+ m_slot->m_out_halt_func(state);
+}
+
+static const kcexp_interface kc_d002_interface =
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, kc_d002_device, out_irq_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, kc_d002_device, out_nmi_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, kc_d002_device, out_halt_w)
+};
+
+static MACHINE_CONFIG_FRAGMENT( kc_d002 )
+ MCFG_KC85_CARTRIDGE_ADD("m0", "m4", kc_d002_interface, kc85_cart, NULL, NULL)
+ MCFG_KC85_CARTRIDGE_ADD("m4", "m8", kc_d002_interface, kc85_cart, NULL, NULL)
+ MCFG_KC85_CARTRIDGE_ADD("m8", "mc", kc_d002_interface, kc85_cart, NULL, NULL)
+ MCFG_KC85_CARTRIDGE_ADD("mc", "exp", kc_d002_interface, kc85_cart, NULL, NULL)
+
+ // expansion interface
+ MCFG_KC85_EXPANSION_ADD("exp", NULL, kc_d002_interface, kc85_exp , NULL, NULL)
+MACHINE_CONFIG_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type KC_D002 = &device_creator<kc_d002_device>;
+
+//**************************************************************************
+// 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),
+ device_kcexp_interface( mconfig, *this )
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void kc_d002_device::device_start()
+{
+ m_slot = dynamic_cast<kcexp_slot_device *>(owner());
+
+ m_expansions[0] = downcast<kcexp_slot_device *>(subdevice("m0"));
+ m_expansions[1] = downcast<kcexp_slot_device *>(subdevice("m4"));
+ m_expansions[2] = downcast<kcexp_slot_device *>(subdevice("m8"));
+ m_expansions[3] = downcast<kcexp_slot_device *>(subdevice("mc"));
+ m_expansions[4] = downcast<kcexp_slot_device *>(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/mess/machine/kc_d002.h b/src/mess/machine/kc_d002.h
new file mode 100644
index 00000000000..28b3a6ebba0
--- /dev/null
+++ b/src/mess/machine/kc_d002.h
@@ -0,0 +1,59 @@
+#pragma once
+
+#ifndef __KC_D002_H__
+#define __KC_D002_H__
+
+#include "emu.h"
+#include "machine/kcexp.h"
+#include "machine/kc_ram.h"
+#include "machine/kc_rom.h"
+#include "machine/kc_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();
+ virtual void device_config_complete() { m_shortname = "kc_d002"; }
+
+ // 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/mess/machine/kc_d004.c b/src/mess/machine/kc_d004.c
new file mode 100644
index 00000000000..871c76ede37
--- /dev/null
+++ b/src/mess/machine/kc_d004.c
@@ -0,0 +1,530 @@
+/***************************************************************************
+
+ kc_d004.c
+
+ KC85 D004 Floppy Disk Interface
+
+***************************************************************************/
+
+#include "emu.h"
+#include "kc_d004.h"
+
+#define Z80_TAG "disk"
+#define Z80CTC_TAG "z80ctc"
+#define UPD765_TAG "upd765"
+#define IDE_TAG "ide"
+
+/***************************************************************************
+ 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, 0xf0) AM_DEVREAD_LEGACY(UPD765_TAG, upd765_status_r)
+ AM_RANGE(0xf1, 0xf1) AM_DEVREADWRITE_LEGACY(UPD765_TAG, upd765_data_r, upd765_data_w)
+ AM_RANGE(0xf2, 0xf3) AM_DEVREADWRITE_LEGACY(UPD765_TAG, upd765_dack_r, upd765_dack_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, 0x00f0) AM_MIRROR(0xff00) AM_DEVREAD_LEGACY(UPD765_TAG, upd765_status_r)
+ AM_RANGE(0x00f1, 0x00f1) AM_MIRROR(0xff00) AM_DEVREADWRITE_LEGACY(UPD765_TAG, upd765_data_r, upd765_data_w)
+ AM_RANGE(0x00f2, 0x00f3) AM_MIRROR(0xff00) AM_DEVREADWRITE_LEGACY(UPD765_TAG, upd765_dack_r, upd765_dack_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
+
+static LEGACY_FLOPPY_OPTIONS_START(kc_d004)
+ LEGACY_FLOPPY_OPTION(kc85, "img", "KC85 disk image 800KB", basicdsk_identify_default, basicdsk_construct_default, NULL,
+ HEADS([2])
+ TRACKS([80])
+ SECTORS([5])
+ SECTOR_LENGTH([1024])
+ FIRST_SECTOR_ID([1]))
+ LEGACY_FLOPPY_OPTION(kc85, "img", "KC85 disk image 720KB", basicdsk_identify_default, basicdsk_construct_default, NULL,
+ HEADS([2])
+ TRACKS([80])
+ SECTORS([9])
+ SECTOR_LENGTH([512])
+ FIRST_SECTOR_ID([1]))
+ LEGACY_FLOPPY_OPTION(kc85, "img", "KC85 disk image 640KB", basicdsk_identify_default, basicdsk_construct_default, NULL,
+ HEADS([2])
+ TRACKS([80])
+ SECTORS([16])
+ SECTOR_LENGTH([256])
+ FIRST_SECTOR_ID([1]))
+LEGACY_FLOPPY_OPTIONS_END
+
+static const floppy_interface kc_d004_floppy_interface =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ FLOPPY_STANDARD_5_25_DSHD,
+ LEGACY_FLOPPY_OPTIONS_NAME(kc_d004),
+ "floppy_5_25",
+ NULL
+};
+
+static device_t *kc_d004_get_fdd(device_t *device, int floppy_index)
+{
+ kc_d004_device* owner = dynamic_cast<kc_d004_device *>(device->owner());
+ return owner->get_active_fdd();
+}
+
+static const upd765_interface kc_d004_interface =
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, kc_d004_device, fdc_interrupt),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, kc_d004_device, fdc_dma_request),
+ kc_d004_get_fdd,
+ UPD765_RDY_PIN_NOT_CONNECTED,
+ {FLOPPY_0, FLOPPY_1, FLOPPY_2, FLOPPY_3}
+};
+
+static const z80_daisy_config kc_d004_daisy_chain[] =
+{
+ { Z80CTC_TAG },
+ { NULL }
+};
+
+static Z80CTC_INTERFACE( kc_d004_ctc_intf )
+{
+ DEVCB_CPU_INPUT_LINE(Z80_TAG, 0), /* interrupt callback */
+ DEVCB_DEVICE_LINE_MEMBER(Z80CTC_TAG, z80ctc_device, trg1), /* ZC/TO0 callback */
+ DEVCB_DEVICE_LINE_MEMBER(Z80CTC_TAG, z80ctc_device, trg2), /* ZC/TO1 callback */
+ DEVCB_DEVICE_LINE_MEMBER(Z80CTC_TAG, z80ctc_device, trg3) /* ZC/TO2 callback */
+};
+
+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_Z80CTC_ADD( Z80CTC_TAG, XTAL_8MHz/2, kc_d004_ctc_intf )
+
+ MCFG_UPD765A_ADD(UPD765_TAG, kc_d004_interface)
+ MCFG_LEGACY_FLOPPY_4_DRIVES_ADD(kc_d004_floppy_interface)
+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_IDE_CONTROLLER_ADD(IDE_TAG, NULL, ide_image_devices, "hdd", "hdd", 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_LOAD_OPTIONAL("d004v33_3.bin", 0x0000, 0x2000, CRC(945f3e4b) SHA1(cce5d9eea82582270660c8275336b15bf9906253)) // KC85/3
+ ROM_LOAD_OPTIONAL("d004v33_4.bin", 0x0000, 0x2000, CRC(1451efd7) SHA1(9db201af408adb02254094dc7aa7185bf5a7b9b1)) // KC85/4-5
+ ROM_LOAD_OPTIONAL("d004v30.bin", 0x0000, 0x2000, CRC(6fe0a283) SHA1(5582b2541a34a90c7a9516a6a222d4961fc54fcf)) // KC85/4-5
+ ROM_LOAD_OPTIONAL("d004v31.bin", 0x0000, 0x2000, CRC(712547de) SHA1(38b3164dce23573375fc0237f348d9a699fc6f9f)) // KC85/4-5
+ ROM_LOAD_OPTIONAL("d004v32.bin", 0x0000, 0x2000, CRC(9a3d3511) SHA1(8232adb5e5f0b25b52f9873cff14831da3a0398a)) // KC85/4-5
+ROM_END
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type KC_D004 = &device_creator<kc_d004_device>;
+const device_type KC_D004_GIDE = &device_creator<kc_d004_gide_device>;
+
+//**************************************************************************
+// 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),
+ device_kcexp_interface( mconfig, *this ),
+ m_cpu(*this, Z80_TAG),
+ m_fdc(*this, UPD765_TAG),
+ 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)
+ : device_t(mconfig, type, name, tag, owner, clock),
+ device_kcexp_interface( mconfig, *this ),
+ m_cpu(*this, Z80_TAG),
+ m_fdc(*this, UPD765_TAG),
+ 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);
+ m_tc_clear_timer = timer_alloc(TIMER_TC_CLEAR);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void kc_d004_device::device_reset()
+{
+ m_rom_base = 0xc000;
+ m_enabled = m_connected = 0;
+ m_floppy = downcast<device_t *>(subdevice(FLOPPY_0));
+
+ // 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:
+ device_set_input_line(m_cpu, INPUT_LINE_RESET, ASSERT_LINE);
+ break;
+ case TIMER_TC_CLEAR:
+ upd765_tc_w(m_fdc, 0x00);
+ 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)
+ device_set_input_line(m_cpu, INPUT_LINE_RESET, CLEAR_LINE);
+
+ if (data & 0x02)
+ {
+ for (int i=0; i<0xfc00; i++)
+ m_cpu->memory().space(AS_PROGRAM)->write_byte(i, 0);
+
+ device_set_input_line(m_cpu, INPUT_LINE_RESET, ASSERT_LINE);
+ }
+
+ if (data & 0x04)
+ device_set_input_line(m_cpu, INPUT_LINE_RESET, HOLD_LINE);
+
+ if (data & 0x08)
+ device_set_input_line(m_cpu, 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
+
+ */
+
+ if (floppy_ready_r(m_floppy))
+ m_hw_input_gate |= 0x20;
+ else
+ m_hw_input_gate &= ~0x20;
+
+ if (floppy_index_r(m_floppy))
+ m_hw_input_gate &= ~0x10;
+ else
+ m_hw_input_gate |= 0x10;
+
+ return m_hw_input_gate | 0x0f;
+}
+
+WRITE8_MEMBER(kc_d004_device::fdd_select_w)
+{
+ if (data & 0x01)
+ m_floppy = downcast<device_t *>(subdevice(FLOPPY_0));
+ else if (data & 0x02)
+ m_floppy = downcast<device_t *>(subdevice(FLOPPY_1));
+ else if (data & 0x04)
+ m_floppy = downcast<device_t *>(subdevice(FLOPPY_2));
+ else if (data & 0x08)
+ m_floppy = downcast<device_t *>(subdevice(FLOPPY_3));
+}
+
+WRITE8_MEMBER(kc_d004_device::hw_terminal_count_w)
+{
+ upd765_tc_w(m_fdc, 1);
+
+ m_tc_clear_timer->adjust(attotime::from_nsec(200));
+}
+
+WRITE_LINE_MEMBER( kc_d004_device::fdc_interrupt )
+{
+ if (state)
+ m_hw_input_gate &= ~0x40;
+ else
+ m_hw_input_gate |= 0x40;
+}
+
+WRITE_LINE_MEMBER( kc_d004_device::fdc_dma_request )
+{
+ if (state)
+ m_hw_input_gate &= ~0x80;
+ else
+ m_hw_input_gate |= 0x80;
+}
+
+
+
+//**************************************************************************
+// 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),
+ m_ide(*this, IDE_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_ide_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))
+ m_ide_data = ide_bus_r(m_ide, ide_cs, io_addr & 0x07);
+
+ data = (m_ide_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_ide_data = (data << data_shift) | (m_ide_data & (0xff00 >> data_shift));
+
+ if (io_addr == 0x06 || io_addr == 0x07 || io_addr > 0x08 || (io_addr == 0x08 && m_lh))
+ ide_bus_w(m_ide, ide_cs, io_addr & 0x07, m_ide_data);
+ }
+
+ m_lh = (io_addr == 0x08) ? !m_lh : ((io_addr > 0x08) ? 0 : m_lh);
+ }
+}
diff --git a/src/mess/machine/kc_d004.h b/src/mess/machine/kc_d004.h
new file mode 100644
index 00000000000..7d4640c4c2f
--- /dev/null
+++ b/src/mess/machine/kc_d004.h
@@ -0,0 +1,113 @@
+#pragma once
+
+#ifndef __KC_D004_H__
+#define __KC_D004_H__
+
+#include "emu.h"
+#include "machine/kcexp.h"
+#include "machine/z80ctc.h"
+#include "cpu/z80/z80.h"
+#include "machine/upd765.h"
+#include "machine/idectrl.h"
+#include "formats/basicdsk.h"
+#include "imagedev/flopdrv.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);
+
+ // 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();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+ virtual void device_config_complete() { m_shortname = "kc_d004"; }
+
+ // 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:
+ device_t* get_active_fdd() { return m_floppy; }
+ 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_interrupt);
+ DECLARE_WRITE_LINE_MEMBER(fdc_dma_request);
+
+private:
+ static const device_timer_id TIMER_RESET = 0;
+ static const device_timer_id TIMER_TC_CLEAR = 1;
+
+ required_device<cpu_device> m_cpu;
+ required_device<device_t> m_fdc;
+ required_shared_ptr<UINT8> m_koppel_ram;
+
+ // internal state
+ emu_timer * m_reset_timer;
+ emu_timer * m_tc_clear_timer;
+
+ UINT8 * m_rom;
+ UINT8 m_hw_input_gate;
+ UINT16 m_rom_base;
+ UINT8 m_enabled;
+ UINT8 m_connected;
+ UINT8 m_active_fdd;
+ device_t * 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();
+ virtual void device_config_complete() { m_shortname = "kc_d004gide"; }
+
+public:
+ DECLARE_READ8_MEMBER(gide_r);
+ DECLARE_WRITE8_MEMBER(gide_w);
+
+private:
+ required_device<device_t> m_ide;
+
+ UINT16 m_ide_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/mess/machine/kc_keyb.c b/src/mess/machine/kc_keyb.c
new file mode 100644
index 00000000000..151965e76f2
--- /dev/null
+++ b/src/mess/machine/kc_keyb.c
@@ -0,0 +1,633 @@
+/*********************************************************************
+
+ kc_keyb.c
+
+ KC85_2/3/4/5 Keyboard emulation
+
+**********************************************************************
+
+ E-mail from Torsten Paul about the keyboard:
+
+ Torsten.Paul@gmx.de
+
+"> I hope that you will be able to help me so I can add keyboard
+> emulation to it.
+>
+Oh yes the keyboard caused me a lot of trouble too. I still don't
+understand it completely.
+A first dirty but working keyboard support is quite easy because
+of the good and modular system rom. Most programs use the supplied
+routines to read keyboard input so patching the right memory address
+with the keycode that is originally supplied by the interrupt
+routines for keyboard input will work. So if you first want to
+have a simple start to get other things to work you can try this.
+
+ * write keycode (ascii) to address IX+0dh (0x1fd)
+ * set bit 0 at address IX+08h (0x1f8) - simply writing 01h
+ worked for me but some other bits are used too
+ this bit is reset if the key is read by the system
+
+> From the schematics I see that the keyboard is linked to the CTC and PIO,
+> but I don't understand it fully.
+> Please can you tell me more about how the keyboard is scanned?
+>
+The full emulation is quite tricky and I still have some programs that
+behave odd. (A good hint for a correct keyboard emulation is Digger ;-).
+
+Ok, now the technical things:
+
+The keyboard of the KC is driven by a remote control circuit that is
+originally designed for infrared remote control. This one was named
+U807 and I learned there should be a similar chip called SAB 3021
+available but I never found the specs on the web. The SAB 3021 was
+produced by Valvo which doesn't exist anymore (bought by Phillips
+if I remember correctly). If you have more luck finding the specs
+I'm still interested.
+There also was a complementary chip for the recieving side but that
+was not used in the KC unfortunately. They choosed to measure the
+pulses sent by the U807 via PIO and CTC.
+
+Anyway here is what I know about the protocol:
+
+The U807 sends impulses with equal length. The information is
+given by the time between two impulses. Short time means bit is 1
+long time mean bit is 0. The impulses are modulated by a 62.5 kHz
+Signal but that's not interesting for the emulator.
+The timing comes from a base clock of 4 MHz that is divided
+multiple times:
+
+4 MHz / 64 - 62.5 kHz -> used for filtered amplification
+62.5 kHz / 64 - 976 Hz -> 1.024 ms
+976 / 7 - 140 Hz -> 7.2 ms
+976 / 5 - 195 Hz -> 5.1 ms
+
+short - 5.12 ms - 1 bit
+long - 7.168 ms - 0 bit
+
+ +-+ +-+ +-+ +-+
+ | | | | | | | |
+ +--+ +-----+ +-------+ +-----+ +--....
+
+ | | |---0---| |--1--|
+ ^
+ |
+ Startbit = shift key
+
+The keyboard can have 64 keys with an additional key that is used by
+the KC as shift key. This additional key is directly connected to the
+chip and changes the startbit. All other keys are arranged in a matrix.
+
+The chip sends full words of 7 bits (including the startbit) at least
+twice for each keypress with a spacing of 14 * 1.024 ms. If the key
+is still pressed the double word is repeated after 19 * 1.024 ms.
+
+The impulses trigger the pio interrupt line for channel B that
+triggers the time measurement by the CTC channel 3."
+
+
+**********************************************************************
+
+
+ The CTC timer 3 count is initialised at 0x08f and counts down.
+
+ The pulses are connected into PIO /BSTB and generate a interrupt
+ on a positive edge. A pulse will not get through if BRDY from PIO is
+ not true!
+
+ Then the interrupt occurs, the CTC count is read. The time between
+ pulses is therefore measured by the CTC.
+
+ The time is checked and depending on the value the KC detects
+ a 1 or 0 bit sent from the keyboard.
+
+ Summary From code below:
+
+ 0x065<=count<0x078 -> 0 bit "short pulse"
+ 0x042<=count<0x065 -> 1 bit "long pulse"
+ count<0x014 -> ignore
+ count>=0x078 -> ignore
+ 0x014<=count<0x042 -> signal end of code "very long pulse"
+
+ codes are sent bit 0, bit 1, bit 2...bit 7. bit 0 is the state
+ of the shift key.
+
+ Torsten's e-mail indicates "short pulse" for 1 bit, and "long
+ pulse" for 0 bit, but I found this to be incorrect. However,
+ the timings are correct.
+
+
+ Keyboard reading procedure extracted from KC85/4 system rom:
+
+0345 f5 push af
+0346 db8f in a,(#8f) ; get CTC timer 3 count
+0348 f5 push af
+0349 3ea7 ld a,#a7 ; channel 3, enable int, select counter mode, control word
+ ; write, software reset, time constant follows
+034b d38f out (#8f),a
+034d 3e8f ld a,#8f ; time constant
+034f d38f out (#8f),a
+0351 f1 pop af
+
+0352 fb ei
+0353 b7 or a ; count is over
+0354 284d jr z,#03a3 ;
+
+ ;; check count is in range
+0356 fe14 cp #14
+0358 3849 jr c,#03a3 ;
+035a fe78 cp #78
+035c 3045 jr nc,#03a3 ;
+
+ ;; at this point, time must be between #14 and #77 to be valid
+
+ ;; if >=#65, then carry=0, and a 0 bit has been detected
+
+035e fe65 cp #65
+0360 303d jr nc,#039f ; (61)
+
+ ;; if <#65, then a 1 bit has been detected. carry is set with the addition below.
+ ;; a carry will be generated if the count is >#42
+
+ ;; therefore for a 1 bit to be generated, then #42<=time<#65
+ ;; must be true.
+
+0362 c6be add a,#be
+0364 3839 jr c,#039f ; (57)
+
+ ;; this code appears to take the transmitted scan-code
+ ;; and converts it into a useable code by the os???
+0366 e5 push hl
+0367 d5 push de
+ ;; convert hardware scan-code into os code
+0368 dd7e0c ld a,(ix+#0c)
+036b 1f rra
+036c ee01 xor #01
+036e dd6e0e ld l,(ix+#0e)
+0371 dd660f ld h,(ix+#0f)
+0374 1600 ld d,#00
+0376 5f ld e,a
+0377 19 add hl,de
+0378 7e ld a,(hl)
+0379 d1 pop de
+037a e1 pop hl
+
+ ;; shift lock pressed?
+037b ddcb087e bit 7,(ix+#08)
+037f 200a jr nz,#038b
+ ;; no.
+
+ ;; alpha char?
+0381 fe40 cp #40
+0383 3806 jr c,#038b
+0385 fe80 cp #80
+0387 3002 jr nc,#038b
+ ;; yes, it is a alpha char
+ ;; force to lower case
+0389 ee20 xor #20
+
+038b ddbe0d cp (ix+#0d) ;; same as stored?
+038e 201d jr nz,#03ad
+
+ ;; yes - must be held for a certain time before it can repeat?
+0390 f5 push af
+0391 3ae0b7 ld a,(#b7e0)
+0394 ddbe0a cp (ix+#0a)
+0397 3811 jr c,#03aa
+0399 f1 pop af
+
+039a dd340a inc (ix+#0a) ;; incremenent repeat count?
+039d 1804 jr #03a3
+
+ ;; update scan-code received so far
+
+039f ddcb0c1e rr (ix+#0c) ; shift in 0 or 1 bit depending on what has been selected
+
+03a3 db89 in a,(#89) ; used to clear brdy
+03a5 d389 out (#89),a
+03a7 f1 pop af
+03a8 ed4d reti
+
+03aa f1 pop af
+03ab 1808 jr #03b5
+
+;; clear count
+03ad dd360a00 ld (ix+#0a),#00
+
+;; shift lock?
+03b1 fe16 cp #16
+03b3 2809 jr z,#03be
+
+;; store char
+03b5 dd770d ld (ix+#0d),a
+03b8 ddcb08c6 set 0,(ix+#08)
+03bc 18e5 jr #03a3
+
+;; toggle shift lock on/off
+03be dd7e08 ld a,(ix+#08)
+03c1 ee80 xor #80
+03c3 dd7708 ld (ix+#08),a
+;; shift/lock was last key pressed
+03c6 3e16 ld a,#16
+03c8 18eb jr #03b5
+
+03ca b7 or a
+03cb ddcb0846 bit 0,(ix+#08)
+03cf c8 ret z
+03d0 dd7e0d ld a,(ix+#0d)
+03d3 37 scf
+03d4 c9 ret
+03d5 cdcae3 call #e3ca
+03d8 d0 ret nc
+03d9 ddcb0886 res 0,(ix+#08)
+03dd c9 ret
+03de cdcae3 call #e3ca
+03e1 d0 ret nc
+03e2 fe03 cp #03
+03e4 37 scf
+03e5 c8 ret z
+03e6 a7 and a
+03e7 c9 ret
+
+
+ Keyboard reading procedure extracted from KC85/3 rom:
+
+
+019a f5 push af
+019b db8f in a,(#8f)
+019d f5 push af
+019e 3ea7 ld a,#a7
+01a0 d38f out (#8f),a
+01a2 3e8f ld a,#8f
+01a4 d38f out (#8f),a
+01a6 f1 pop af
+01a7 ddcb085e bit 3,(ix+#08)
+01ab ddcb089e res 3,(ix+#08)
+01af 2055 jr nz,#0206 ; (85)
+
+01b1 fe65 cp #65
+01b3 3054 jr nc,#0209
+
+
+ ;; count>=#65 = 0 bit
+ ;; #44<=count<#65 = 1 bit
+ ;; count<#44 = end of code
+
+01b5 fe44 cp #44
+01b7 3053 jr nc,#020c
+01b9 e5 push hl
+01ba d5 push de
+01bb ddcb0c3e srl (ix+#0c)
+01bf dd7e08 ld a,(ix+#08)
+01c2 e680 and #80
+01c4 07 rlca
+01c5 ddae0c xor (ix+#0c)
+01c8 2600 ld h,#00
+01ca dd5e0e ld e,(ix+#0e)
+01cd dd560f ld d,(ix+#0f)
+01d0 6f ld l,a
+01d1 19 add hl,de
+01d2 7e ld a,(hl)
+01d3 d1 pop de
+01d4 e1 pop hl
+01d5 ddbe0d cp (ix+#0d)
+01d8 2811 jr z,#01eb ; (17)
+01da dd770d ld (ix+#0d),a
+01dd ddcb08a6 res 4,(ix+#08)
+01e1 ddcb08c6 set 0,(ix+#08)
+01e5 dd360a00 ld (ix+#0a),#00
+01e9 181b jr #0206 ; (27)
+01eb dd340a inc (ix+#0a)
+01ee ddcb0866 bit 4,(ix+#08)
+01f2 200c jr nz,#0200 ; (12)
+01f4 ddcb0a66 bit 4,(ix+#0a)
+01f8 280c jr z,#0206 ; (12)
+01fa ddcb08e6 set 4,(ix+#08)
+01fe 18e1 jr #01e1 ; (-31)
+0200 ddcb0a4e bit 1,(ix+#0a)
+0204 20db jr nz,#01e1 ; (-37)
+0206 f1 pop af
+0207 ed4d reti
+0209 b7 or a
+020a 1801 jr #020d ; (1)
+020c 37 scf
+020d ddcb0c1e rr (ix+#0c)
+0211 18f3 jr #0206 ; (-13)
+
+*********************************************************************/
+
+
+#include "emu.h"
+#include "kc_keyb.h"
+
+#define VERBOSE 0
+#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type KC_KEYBOARD = &device_creator<kc_keyboard_device>;
+
+//**************************************************************************
+// Input Ports
+//**************************************************************************
+
+// this is a fake keyboard layout. The keys are converted into codes
+// which are transmitted by the keyboard to the base-unit. key code can
+// be calculated as (line*8)+bit_index
+
+static INPUT_PORTS_START( kc_keyboard )
+ // start of keyboard scan-codes
+ // codes 0-7
+ PORT_START("KEY0")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('W') PORT_CHAR('w')
+ 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_2) PORT_CHAR('2') PORT_CHAR('"')
+ 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_HOME) PORT_CHAR(UCHAR_MAMEKEY(HOME))
+ PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('-') PORT_CHAR('=')
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2))
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y') PORT_CHAR('y')
+ // codes 8-15
+ PORT_START("KEY1")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('E') PORT_CHAR('e')
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('S') PORT_CHAR('s')
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('^') PORT_CHAR(0x00AC)
+ PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Clr") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8)
+ 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_F3) PORT_CHAR(UCHAR_MAMEKEY(F3))
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('X') PORT_CHAR('x')
+ // codes 16-23
+ PORT_START("KEY2")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('T') PORT_CHAR('t')
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('F') PORT_CHAR('f')
+ 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_P) PORT_CHAR('P') PORT_CHAR('p')
+ PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Del") PORT_CODE(KEYCODE_DEL) PORT_CHAR(UCHAR_MAMEKEY(DEL))
+ PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR('@')
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5))
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('V') PORT_CHAR('v')
+ // codes 24-31
+ PORT_START("KEY3")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('U') PORT_CHAR('u')
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('H') PORT_CHAR('h')
+ 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_O) PORT_CHAR('O') PORT_CHAR('o')
+ PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Ins") PORT_CODE(KEYCODE_INSERT) PORT_CHAR(UCHAR_MAMEKEY(INSERT))
+ PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(')')
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Brk") PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC))
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('N') PORT_CHAR('n')
+ // codes 32-39
+ PORT_START("KEY4")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('I') PORT_CHAR('i')
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('J') PORT_CHAR('j')
+ 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_SPACE) PORT_CHAR(' ')
+ 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_COMMA) PORT_CHAR(',') PORT_CHAR('<')
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Stop") PORT_CODE(KEYCODE_END) PORT_CHAR(UCHAR_MAMEKEY(PAUSE))
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('M') PORT_CHAR('m')
+ // codes 40-47
+ PORT_START("KEY5")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z') PORT_CHAR('z')
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('G') PORT_CHAR('g')
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&')
+ PORT_BIT(0x08, 0x00, IPT_UNUSED)
+ 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_STOP) PORT_CHAR('.') PORT_CHAR('>')
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6))
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('B') PORT_CHAR('b')
+ // codes 48-56
+ PORT_START("KEY6")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('R') PORT_CHAR('r')
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('D') PORT_CHAR('d')
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('-') PORT_CHAR('|')
+ PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR('+') PORT_CHAR(';')
+ 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_F4) PORT_CHAR(UCHAR_MAMEKEY(F4))
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('C') PORT_CHAR('c')
+ // codes 56-63
+ PORT_START("KEY7")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_CHAR('Q') PORT_CHAR('q')
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Shift Lock") PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK))
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN))
+ PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP))
+ PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT))
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1))
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13)
+ // end of keyboard scan-codes
+ PORT_START("SHIFT")
+ // has a single shift key. Mapped here to left and right shift.
+ // shift is connected to the MOC pin of the U807
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
+INPUT_PORTS_END
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// kc_keyboard_device - constructor
+//-------------------------------------------------
+kc_keyboard_device::kc_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, KC_KEYBOARD, "KC Keyboard", tag, owner, clock)
+{
+}
+
+//-------------------------------------------------
+// kc_keyboard_device - destructor
+//-------------------------------------------------
+
+kc_keyboard_device::~kc_keyboard_device()
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void kc_keyboard_device::device_start()
+{
+ // resolve callbacks
+ m_keyboard_out_func.resolve(m_keyboard_out_cb, *this);
+
+ m_timer_transmit_pulse = timer_alloc(TIMER_TRANSMIT_PULSE);
+
+ m_timer_transmit_pulse->adjust(attotime::from_usec(1024), 0, attotime::from_usec(1024));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void kc_keyboard_device::device_reset()
+{
+ // set initial state
+ m_keyboard_out_func(CLEAR_LINE);
+
+ m_transmit_buffer.pulse_sent = 0;
+ m_transmit_buffer.pulse_count = 0;
+
+ memset(&m_transmit_buffer, 0, sizeof(m_transmit_buffer));
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void kc_keyboard_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const kc_keyb_interface *intf = reinterpret_cast<const kc_keyb_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<kc_keyb_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_keyboard_out_func, 0, sizeof(m_keyboard_out_func));
+ }
+}
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+ioport_constructor kc_keyboard_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( kc_keyboard );
+}
+
+//-------------------------------------------------
+// device_timer - handler timer events
+//-------------------------------------------------
+
+void kc_keyboard_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch(id)
+ {
+ case TIMER_TRANSMIT_PULSE:
+ if (m_transmit_buffer.pulse_sent < m_transmit_buffer.pulse_count)
+ {
+ // byte containing pulse state
+ int pulse_byte_count = m_transmit_buffer.pulse_sent>>3;
+ // bit within byte containing pulse state
+ int pulse_bit_count = 7 - (m_transmit_buffer.pulse_sent & 0x07);
+
+ // get current pulse state
+ int pulse_state = (m_transmit_buffer.data[pulse_byte_count]>>pulse_bit_count) & 0x01;
+
+ LOG(("KC keyboard sending pulse: %02x\n", pulse_state));
+
+ // send pulse
+ m_keyboard_out_func(pulse_state ? ASSERT_LINE : CLEAR_LINE);
+
+ // update counts
+ m_transmit_buffer.pulse_sent++;
+ }
+ else
+ {
+ // if there is nothing to send, rescan the keyboard
+ static const char *const keynames[] = { "KEY0", "KEY1", "KEY2", "KEY3", "KEY4", "KEY5", "KEY6", "KEY7" };
+
+ m_transmit_buffer.pulse_sent = 0;
+ m_transmit_buffer.pulse_count = 0;
+
+ // scan all lines (excluding shift)
+ for (int i=0; i<8; i++)
+ {
+ UINT8 keyboard_line_data = ioport(keynames[i])->read();
+
+ // scan through each bit
+ for (int b=0; b<8; b++)
+ {
+ // is pressed?
+ if ((keyboard_line_data & (1<<b)) != 0)
+ {
+ // generate fake code
+ UINT8 code = (i<<3) | b;
+ LOG(("Code: %02x\n",code));
+
+ transmit_scancode(code);
+ }
+ }
+ }
+ }
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// add a pulse
+//-------------------------------------------------
+
+void kc_keyboard_device::add_pulse_to_transmit_buffer(int pulse_state, int pulse_number)
+{
+ if (m_transmit_buffer.pulse_count + 1 < KC_TRANSMIT_BUFFER_LENGTH)
+ {
+ for (int i=0; i<pulse_number; i++)
+ {
+ int pulse_byte_count = m_transmit_buffer.pulse_count>>3;
+ int pulse_bit_count = 7-(m_transmit_buffer.pulse_count & 0x07);
+
+ if (pulse_state)
+ m_transmit_buffer.data[pulse_byte_count] |= (1<<pulse_bit_count);
+ else
+ m_transmit_buffer.data[pulse_byte_count] &= ~(1<<pulse_bit_count);
+
+ m_transmit_buffer.pulse_count++;
+ }
+ }
+}
+
+//-------------------------------------------------
+// fill transmit buffer with pulse for 0 or 1 bit
+//-------------------------------------------------
+
+void kc_keyboard_device::add_bit(int bit)
+{
+ if (bit)
+ add_pulse_to_transmit_buffer(0, 7);
+ else
+ add_pulse_to_transmit_buffer(0, 5);
+
+ // "end of bit" pulse -> end of time for bit
+ add_pulse_to_transmit_buffer(1);
+}
+
+
+//-------------------------------------------------
+// begin pulse transmit
+//-------------------------------------------------
+
+void kc_keyboard_device::transmit_scancode(UINT8 scan_code)
+{
+ // initial pulse -> start of code
+ add_pulse_to_transmit_buffer(1);
+
+ // state of shift key
+ add_bit((ioport("SHIFT")->read() & 0x01)^0x01);
+
+ for (int i=0; i<6; i++)
+ {
+ // each bit in turn
+ add_bit(scan_code & (1<<i));
+ }
+
+ // signal end of scan-code
+ add_pulse_to_transmit_buffer(0, 14);
+
+ add_pulse_to_transmit_buffer(1);
+
+ // back to original state
+ add_pulse_to_transmit_buffer(0);
+}
diff --git a/src/mess/machine/kc_keyb.h b/src/mess/machine/kc_keyb.h
new file mode 100644
index 00000000000..d8c50ec55be
--- /dev/null
+++ b/src/mess/machine/kc_keyb.h
@@ -0,0 +1,76 @@
+/*********************************************************************
+
+ kc_keyb.h
+
+*********************************************************************/
+
+#ifndef __KC_KEYB_H__
+#define __KC_KEYB_H__
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* number of pulses that can be stored */
+#define KC_TRANSMIT_BUFFER_LENGTH 256
+
+// ======================> kc_keyb_interface
+
+struct kc_keyb_interface
+{
+ devcb_write_line m_keyboard_out_cb;
+};
+
+// ======================> kc_keyboard_device
+
+class kc_keyboard_device : public device_t,
+ public kc_keyb_interface
+{
+public:
+ // construction/destruction
+ kc_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ virtual ~kc_keyboard_device();
+
+ // optional information overrides
+ virtual ioport_constructor device_input_ports() const;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+ void add_pulse_to_transmit_buffer(int pulse_state, int pulse_number = 1);
+ void add_bit(int bit);
+ void transmit_scancode(UINT8 scan_code);
+
+private:
+ static const device_timer_id TIMER_TRANSMIT_PULSE = 1;
+
+ // internal state
+ emu_timer * m_timer_transmit_pulse;
+ devcb_resolved_write_line m_keyboard_out_func;
+
+ // pulses to transmit
+ struct
+ {
+ UINT8 data[KC_TRANSMIT_BUFFER_LENGTH>>3];
+ int pulse_sent;
+ int pulse_count;
+ } m_transmit_buffer;
+};
+
+// device type definition
+extern const device_type KC_KEYBOARD;
+
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+#define MCFG_KC_KEYBOARD_ADD(_tag,_clock,_config) \
+ MCFG_DEVICE_ADD(_tag, KC_KEYBOARD, _clock) \
+ MCFG_DEVICE_CONFIG(_config) \
+
+#endif /* __KC_KEYB_H__ */
diff --git a/src/mess/machine/kc_ram.c b/src/mess/machine/kc_ram.c
new file mode 100644
index 00000000000..bf90e91fb3d
--- /dev/null
+++ b/src/mess/machine/kc_ram.c
@@ -0,0 +1,447 @@
+/***************************************************************************
+
+ kc_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 "kc_ram.h"
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type KC_M011 = &device_creator<kc_m011_device>;
+const device_type KC_M022 = &device_creator<kc_m022_device>;
+const device_type KC_M032 = &device_creator<kc_m032_device>;
+const device_type KC_M034 = &device_creator<kc_m034_device>;
+const device_type KC_M035 = &device_creator<kc_m035_device>;
+const device_type KC_M036 = &device_creator<kc_m036_device>;
+
+//**************************************************************************
+// 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),
+ 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)
+ : device_t(mconfig, type, name, tag, owner, clock),
+ device_kcexp_interface( mconfig, *this )
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void kc_m011_device::device_start()
+{
+ m_slot = dynamic_cast<kcexp_slot_device *>(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)
+{
+}
+
+/*-------------------------------------------------
+ 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)
+{
+}
+
+//-------------------------------------------------
+// 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)
+{
+}
+
+//-------------------------------------------------
+// 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)
+{
+}
+
+/*-------------------------------------------------
+ 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)
+{
+}
+
+//-------------------------------------------------
+// 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/mess/machine/kc_ram.h b/src/mess/machine/kc_ram.h
new file mode 100644
index 00000000000..3149c484e0a
--- /dev/null
+++ b/src/mess/machine/kc_ram.h
@@ -0,0 +1,188 @@
+#pragma once
+
+#ifndef __KC_RAM_H__
+#define __KC_RAM_H__
+
+#include "emu.h"
+#include "machine/kcexp.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);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "kc_m011"; }
+
+ // 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:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "kc_m022"; }
+
+ // 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();
+ virtual void device_config_complete() { m_shortname = "kc_m032"; }
+
+ // 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();
+ virtual void device_config_complete() { m_shortname = "kc_m034"; }
+
+ // 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:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "kc_m035"; }
+
+ // 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();
+ virtual void device_config_complete() { m_shortname = "kc_m036"; }
+
+ // 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/mess/machine/kc_rom.c b/src/mess/machine/kc_rom.c
new file mode 100644
index 00000000000..631dbda7ce4
--- /dev/null
+++ b/src/mess/machine/kc_rom.c
@@ -0,0 +1,228 @@
+/***************************************************************************
+
+ kc_rom.c
+
+ KC 85 ROM modules emulation
+
+ Supported modules:
+ - Generic 8KB ROM module
+ - M006 BASIC
+ - M033 TypeStar
+
+***************************************************************************/
+
+#include "emu.h"
+#include "kc_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<kc_8k_device>;
+const device_type KC_M006 = &device_creator<kc_m006_device>;
+const device_type KC_M033 = &device_creator<kc_m033_device>;
+
+//**************************************************************************
+// 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),
+ 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)
+ : device_t(mconfig, type, name, tag, owner, clock),
+ device_kcexp_interface( mconfig, *this )
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void kc_8k_device::device_start()
+{
+ m_slot = dynamic_cast<kcexp_slot_device *>(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)
+{
+}
+
+/*-------------------------------------------------
+ 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)
+{
+}
+
+//-------------------------------------------------
+// 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/mess/machine/kc_rom.h b/src/mess/machine/kc_rom.h
new file mode 100644
index 00000000000..d63c013112c
--- /dev/null
+++ b/src/mess/machine/kc_rom.h
@@ -0,0 +1,101 @@
+#pragma once
+
+#ifndef __KC_ROM_H__
+#define __KC_ROM_H__
+
+#include "emu.h"
+#include "machine/kcexp.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);
+
+ // optional information overrides
+ const rom_entry *device_rom_region() const;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "kc_8k"; }
+
+ // 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:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "kc_m006"; }
+
+ // 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();
+ virtual void device_config_complete() { m_shortname = "kc_m033"; }
+
+ // 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/mess/machine/kcexp.c b/src/mess/machine/kcexp.c
new file mode 100644
index 00000000000..ceac6016efd
--- /dev/null
+++ b/src/mess/machine/kcexp.c
@@ -0,0 +1,394 @@
+/*********************************************************************
+
+ kcexp.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 "kcexp.h"
+#include "emuopts.h"
+
+#define LOG 0
+
+
+/***************************************************************************
+ PARAMETERS
+***************************************************************************/
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type KCEXP_SLOT = &device_creator<kcexp_slot_device>;
+const device_type KCCART_SLOT = &device_creator<kccart_slot_device>;
+
+
+//**************************************************************************
+// 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),
+ device_slot_interface(mconfig, *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) :
+ device_t(mconfig, type, name, tag, owner, clock),
+ device_slot_interface(mconfig, *this)
+{
+}
+
+void kcexp_slot_device::static_set_next_slot(device_t &device, const char *next_slot_tag)
+{
+ kcexp_slot_device &kc_slot = dynamic_cast<kcexp_slot_device &>(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<device_kcexp_interface *>(get_card_device());
+ m_next_slot = m_next_slot_tag ? owner()->subdevice<kcexp_slot_device>(m_next_slot_tag) : NULL;
+
+ // resolve callbacks
+ m_out_irq_func.resolve(m_out_irq_cb, *this);
+ m_out_nmi_func.resolve(m_out_nmi_cb, *this);
+ m_out_halt_func.resolve(m_out_halt_cb, *this);
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void kcexp_slot_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const kcexp_interface *intf = reinterpret_cast<const kcexp_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<kcexp_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_irq_cb, 0, sizeof(m_out_irq_cb));
+ memset(&m_out_nmi_cb, 0, sizeof(m_out_nmi_cb));
+ memset(&m_out_halt_cb, 0, sizeof(m_out_halt_cb));
+ }
+}
+
+
+/*-------------------------------------------------
+ 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),
+ 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()
+{
+ kcexp_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(char *swlist, char *swname, rom_entry *start_entry)
+{
+ load_software_part_region(this, swlist, swname, start_entry );
+ return TRUE;
+}
+
+/*-------------------------------------------------
+ get default card software
+-------------------------------------------------*/
+
+const char * kccart_slot_device::get_default_card_software(const machine_config &config, emu_options &options)
+{
+ return software_get_default_slot(config, options, this, "standard");
+}
diff --git a/src/mess/machine/kcexp.h b/src/mess/machine/kcexp.h
new file mode 100644
index 00000000000..095ffe08251
--- /dev/null
+++ b/src/mess/machine/kcexp.h
@@ -0,0 +1,137 @@
+/*********************************************************************
+
+ kcexp.h
+
+ KC85_2/3/4/5 expansion slot emulation
+
+*********************************************************************/
+
+#ifndef __KCEXP_H__
+#define __KCEXP_H__
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+// ======================> kcext_interface
+
+struct kcexp_interface
+{
+ devcb_write_line m_out_irq_cb;
+ devcb_write_line m_out_nmi_cb;
+ devcb_write_line m_out_halt_cb;
+};
+
+
+// ======================> 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 kcexp_interface,
+ 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);
+ virtual ~kcexp_slot_device();
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_config_complete();
+
+ // 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_resolved_write_line m_out_irq_func;
+ devcb_resolved_write_line m_out_nmi_func;
+ devcb_resolved_write_line m_out_halt_func;
+
+ 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(char *swlist, char *swname, 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 const char * get_default_card_software(const machine_config &config, emu_options &options);
+};
+
+// device type definition
+extern const device_type KCEXP_SLOT;
+extern const device_type KCCART_SLOT;
+
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+#define MCFG_KC85_EXPANSION_ADD(_tag,_next_slot_tag,_config,_slot_intf,_def_slot,_def_inp) \
+ MCFG_DEVICE_ADD(_tag, KCEXP_SLOT, 0) \
+ MCFG_DEVICE_CONFIG(_config) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false) \
+ kcexp_slot_device::static_set_next_slot(*device, _next_slot_tag);
+
+#define MCFG_KC85_CARTRIDGE_ADD(_tag,_next_slot_tag,_config,_slot_intf,_def_slot,_def_inp) \
+ MCFG_DEVICE_ADD(_tag, KCCART_SLOT, 0) \
+ MCFG_DEVICE_CONFIG(_config) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false) \
+ kcexp_slot_device::static_set_next_slot(*device, _next_slot_tag);
+
+#endif /* __KCEXP_H__ */
diff --git a/src/mess/machine/keyboard.c b/src/mess/machine/keyboard.c
new file mode 100644
index 00000000000..e4834c2e34f
--- /dev/null
+++ b/src/mess/machine/keyboard.c
@@ -0,0 +1,461 @@
+/***************************************************************************
+Generic ASCII Keyboard
+
+Use MCFG_SERIAL_KEYBOARD_ADD to attach this as a serial device to a terminal
+or computer.
+
+Use MCFG_ASCII_KEYBOARD_ADD 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_ASCII_KEYBOARD_ADD(KEYBOARD_TAG, keyboard_intf)
+
+In the code:
+
+WRITE8_MEMBER( xxx_state::kbd_put )
+{
+ (code to capture the key as it is pressed)
+}
+
+static ASCII_KEYBOARD_INTERFACE( keyboard_intf )
+{
+ DEVCB_DRIVER_MEMBER(xxx_state, kbd_put)
+};
+
+***************************************************************************/
+
+#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)
+ : device_t(mconfig, type, name, tag, owner, clock)
+{
+}
+
+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)
+{
+}
+
+
+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)
+{
+ static const char *const keynames[] = { "TERM_LINE0", "TERM_LINE1", "TERM_LINE2", "TERM_LINE3", "TERM_LINE4", "TERM_LINE5", "TERM_LINE6", "TERM_LINE7" };
+ int i;
+ UINT8 code;
+ UINT8 key_code = 0;
+ UINT8 retVal = 0;
+ UINT8 shift = BIT(ioport("TERM_LINEC")->read(), 1);
+ UINT8 caps = BIT(ioport("TERM_LINEC")->read(), 2);
+ UINT8 ctrl = BIT(ioport("TERM_LINEC")->read(), 0);
+ i = *scan_line;
+ {
+ code = ioport(keynames[i])->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<=4 && 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==5 && shift==1 && ctrl==1) {
+ key_code = 0x00 + row_number(code) + (i-2)*8; // for letters + ctrl
+ }
+ 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
+ }
+ }
+ retVal = key_code;
+ } else {
+ *scan_line += 1;
+ if (*scan_line==8) {
+ *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_func.resolve(m_keyboard_cb, *this);
+ m_timer = timer_alloc();
+}
+
+void generic_keyboard_device::device_config_complete()
+{
+ const _keyboard_interface *intf = reinterpret_cast<const _keyboard_interface *>(static_config());
+ if(intf != NULL)
+ {
+ *static_cast<_keyboard_interface *>(this) = *intf;
+ }
+ else
+ {
+ memset(&m_keyboard_cb, 0, sizeof(m_keyboard_cb));
+ }
+}
+
+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
+
+*/
+static 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_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_START("TERM_LINE6")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Left") PORT_CODE(KEYCODE_LEFT)
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Right") PORT_CODE(KEYCODE_RIGHT)
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Up") PORT_CODE(KEYCODE_UP)
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Down") PORT_CODE(KEYCODE_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)
+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<generic_keyboard_device>;
+
+static INPUT_PORTS_START(serial_keyboard)
+ PORT_INCLUDE(generic_keyboard)
+ PORT_START("TERM_FRAME")
+ PORT_CONFNAME(0x0f, 0x06, "Baud") PORT_CHANGED_MEMBER(DEVICE_SELF, serial_keyboard_device, update_frame, 0)
+ PORT_CONFSETTING( 0x00, "150")
+ PORT_CONFSETTING( 0x01, "300")
+ PORT_CONFSETTING( 0x02, "600")
+ PORT_CONFSETTING( 0x03, "1200")
+ PORT_CONFSETTING( 0x04, "2400")
+ PORT_CONFSETTING( 0x05, "4800")
+ PORT_CONFSETTING( 0x06, "9600")
+ PORT_CONFSETTING( 0x07, "14400")
+ PORT_CONFSETTING( 0x08, "19200")
+ PORT_CONFSETTING( 0x09, "28800")
+ PORT_CONFSETTING( 0x0a, "38400")
+ PORT_CONFSETTING( 0x0b, "57600")
+ PORT_CONFSETTING( 0x0c, "115200")
+ PORT_CONFNAME(0x30, 0x00, "Format") PORT_CHANGED_MEMBER(DEVICE_SELF, serial_keyboard_device, update_frame, 0)
+ PORT_CONFSETTING( 0x00, "8N1")
+ PORT_CONFSETTING( 0x10, "7E1")
+INPUT_PORTS_END
+
+ioport_constructor serial_keyboard_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME(serial_keyboard);
+}
+
+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),
+ device_serial_interface(mconfig, *this),
+ device_serial_port_interface(mconfig, *this)
+{
+}
+
+void serial_keyboard_device::device_config_complete()
+{
+ const serial_keyboard_interface *intf = reinterpret_cast<const serial_keyboard_interface *>(static_config());
+ if(intf != NULL)
+ {
+ *static_cast<serial_keyboard_interface *>(this) = *intf;
+ }
+ else
+ {
+ memset(&m_out_tx_cb, 0, sizeof(m_out_tx_cb));
+ }
+ m_shortname = "serial_keyboard";
+}
+
+static int rates[] = {150, 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600, 115200};
+
+void serial_keyboard_device::device_start()
+{
+ int baud = clock();
+ if(!baud) baud = 9600;
+ m_owner = dynamic_cast<serial_port_device *>(owner());
+ m_out_tx_func.resolve(m_out_tx_cb, *this);
+ m_slot = m_owner && 1;
+ m_timer = timer_alloc();
+ set_tra_rate(baud);
+ set_data_frame(8, 1, SERIAL_PARITY_NONE);
+}
+
+INPUT_CHANGED_MEMBER(serial_keyboard_device::update_frame)
+{
+ set_tra_rate(rates[newval & 0x0f]);
+
+ switch(newval & 0x30)
+ {
+ case 0x10:
+ set_data_frame(7, 1, SERIAL_PARITY_EVEN);
+ break;
+ case 0x00:
+ default:
+ set_data_frame(8, 1, SERIAL_PARITY_NONE);
+ break;
+ }
+}
+
+void serial_keyboard_device::device_reset()
+{
+ generic_keyboard_device::device_reset();
+ m_rbit = 1;
+ if(m_slot)
+ m_owner->out_rx(m_rbit);
+ else
+ m_out_tx_func(m_rbit);
+}
+
+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()
+{
+ m_rbit = transmit_register_get_data_bit();
+ if(m_slot)
+ m_owner->out_rx(m_rbit);
+ else
+ m_out_tx_func(m_rbit);
+}
+
+void serial_keyboard_device::tra_complete()
+{
+ if(m_key_valid)
+ {
+ transmit_register_setup(m_curr_key);
+ m_key_valid = false;
+ }
+}
+
+READ_LINE_MEMBER(serial_keyboard_device::tx_r)
+{
+ return m_rbit;
+}
+
+const device_type SERIAL_KEYBOARD = &device_creator<serial_keyboard_device>;
diff --git a/src/mess/machine/keyboard.h b/src/mess/machine/keyboard.h
new file mode 100644
index 00000000000..5013d323cf6
--- /dev/null
+++ b/src/mess/machine/keyboard.h
@@ -0,0 +1,101 @@
+#ifndef __KEYBOARD_H__
+#define __KEYBOARD_H__
+
+#include "emu.h"
+#include "machine/serial.h"
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _keyboard_interface keyboard_interface;
+struct _keyboard_interface
+{
+ devcb_write8 m_keyboard_cb;
+};
+
+#define ASCII_KEYBOARD_INTERFACE(name) const keyboard_interface (name) =
+
+struct serial_keyboard_interface
+{
+ devcb_write_line m_out_tx_cb;
+};
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+#define KEYBOARD_TAG "keyboard"
+
+#define MCFG_ASCII_KEYBOARD_ADD(_tag, _intrf) \
+ MCFG_DEVICE_ADD(_tag, GENERIC_KEYBOARD, 0) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#define MCFG_SERIAL_KEYBOARD_ADD(_tag, _intrf, _clock) \
+ MCFG_DEVICE_ADD(_tag, SERIAL_KEYBOARD, _clock) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+class generic_keyboard_device :
+ public device_t,
+ public _keyboard_interface
+{
+public:
+ generic_keyboard_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
+ generic_keyboard_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 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();
+ virtual void send_key(UINT8 code) { m_keyboard_func(0, code); }
+ emu_timer *m_timer;
+private:
+ UINT8 keyboard_handler(UINT8 last_code, UINT8 *scan_line);
+ UINT8 row_number(UINT8 code);
+ UINT8 m_last_code;
+ UINT8 m_scan_line;
+
+ devcb_resolved_write8 m_keyboard_func;
+};
+
+extern const device_type GENERIC_KEYBOARD;
+
+class serial_keyboard_device :
+ public generic_keyboard_device,
+ public device_serial_interface,
+ public device_serial_port_interface,
+ public serial_keyboard_interface
+{
+public:
+ serial_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ DECLARE_WRITE_LINE_MEMBER(rx_w) { m_tbit = state; check_for_start(state); }
+ DECLARE_READ_LINE_MEMBER(tx_r);
+ virtual ioport_constructor device_input_ports() const;
+
+ DECLARE_INPUT_CHANGED_MEMBER(update_frame);
+protected:
+ virtual void device_start();
+ virtual void device_config_complete();
+ virtual void device_reset();
+ virtual void tra_callback();
+ virtual void tra_complete();
+ virtual void input_callback(UINT8 state) { m_input_state = state; }
+ virtual void send_key(UINT8 code);
+private:
+ serial_port_device *m_owner;
+ bool m_slot;
+ UINT8 m_curr_key;
+ bool m_key_valid;
+ devcb_resolved_write_line m_out_tx_func;
+};
+
+extern const device_type SERIAL_KEYBOARD;
+
+#endif /* __KEYBOARD_H__ */
diff --git a/src/mess/machine/kr2376.c b/src/mess/machine/kr2376.c
new file mode 100644
index 00000000000..ac207f518c9
--- /dev/null
+++ b/src/mess/machine/kr2376.c
@@ -0,0 +1,397 @@
+/**********************************************************************
+
+ SMC KR2376 Keyboard Encoder emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#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
+ }
+};
+
+typedef struct _kr2376_t kr2376_t;
+struct _kr2376_t
+{
+ const kr2376_interface *intf;
+ int pins[41];
+
+ int ring11; /* sense input scan counter */
+ int ring8; /* drive output scan counter */
+ int modifiers; /* modifier inputs */
+
+ int strobe; /* strobe output */
+ int strobe_old;
+ int parity;
+ int data;
+
+ /* timers */
+ emu_timer *scan_timer; /* keyboard scan timer */
+};
+
+INLINE kr2376_t *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == KR2376);
+
+ return (kr2376_t *)downcast<legacy_device_base *>(device)->token();
+}
+
+/*-------------------------------------------------
+ kr2376_set_input_pin - set an input pin
+-------------------------------------------------*/
+void kr2376_set_input_pin( device_t *device, kr2376_input_pin_t pin, int data )
+{
+ kr2376_t *kr2376 = get_safe_token(device);
+
+ data = data ? 1 : 0;
+ switch ( pin )
+ {
+ case KR2376_PII:
+ case KR2376_DSII:
+ kr2376->pins[pin] = data;
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+ kr2376_get_output_pin - get the status of an output pin
+-------------------------------------------------*/
+int kr2376_get_output_pin( device_t *device, kr2376_output_pin_t pin )
+{
+ kr2376_t *kr2376 = get_safe_token(device);
+
+ return kr2376->pins[pin];
+}
+
+
+static void change_output_lines(device_t *device)
+{
+ kr2376_t *kr2376 = get_safe_token(device);
+
+ if (kr2376->strobe != kr2376->strobe_old)
+ {
+ kr2376->strobe_old = kr2376->strobe;
+
+ if (kr2376->strobe) // strobe 0 --> 1 transition
+ {
+ /* update parity */
+ kr2376->pins[KR2376_PO] = kr2376->parity ^ kr2376->pins[KR2376_PII];
+ }
+ kr2376->pins[KR2376_SO] = kr2376->strobe ^ kr2376->pins[KR2376_DSII];
+ if (kr2376->intf->on_strobe_changed)
+ kr2376->intf->on_strobe_changed(device, 0, kr2376->strobe ^ kr2376->pins[KR2376_DSII]);
+ }
+}
+
+static void clock_scan_counters(device_t *device)
+{
+ kr2376_t *kr2376 = get_safe_token(device);
+
+ /* ring counters inhibited while strobe active */
+ if (!kr2376->strobe)
+ {
+ kr2376->ring11++;
+ if (kr2376->ring11 == 11)
+ {
+ kr2376->ring11 = 0;
+ kr2376->ring8++;
+ if (kr2376->ring8 == 8)
+ kr2376->ring8 = 0;
+ }
+ }
+}
+
+static void detect_keypress(device_t *device)
+{
+ kr2376_t *kr2376= get_safe_token(device);
+
+ static const char *const keynames[] = { "X0", "X1", "X2", "X3", "X4", "X5", "X6", "X7" };
+
+ if (device->machine().root_device().ioport(keynames[kr2376->ring8])->read() == (1 << kr2376->ring11))
+ {
+ kr2376->modifiers = device->machine().root_device().ioport("MODIFIERS")->read();
+
+ kr2376->strobe = 1;
+ /* strobe 0->1 transition, encode char and update parity */
+ if (!kr2376->strobe_old)
+ {
+ int i;
+ int parbit;
+ int shift = BIT(kr2376->modifiers, 0);
+ int control = BIT(kr2376->modifiers, 1);
+ int alpha = BIT(kr2376->modifiers, 2);
+ int table = 0;
+
+ if (shift || alpha)
+ table = 1;
+ else if (control)
+ table = 2;
+
+ kr2376->data = KR2376_KEY_CODES[table][kr2376->ring8][kr2376->ring11];
+
+ /* Compute ODD parity */
+ kr2376->parity = kr2376->data;
+ parbit = 0;
+ for (i=0; i<8; i++)
+ parbit ^= (kr2376->parity >> i) & 1;
+ kr2376->parity = parbit;
+ }
+ }
+ else
+ {
+ kr2376->strobe = 0;
+ }
+}
+
+static TIMER_CALLBACK( kr2376_scan_tick )
+{
+ device_t *device = (device_t *)ptr;
+
+ change_output_lines(device);
+ clock_scan_counters(device);
+ detect_keypress(device);
+}
+
+/* Keyboard Data */
+
+READ8_DEVICE_HANDLER( kr2376_data_r )
+{
+ kr2376_t *kr2376 = get_safe_token(device);
+
+ if (kr2376->pins[KR2376_DSII])
+ return kr2376->data ^ 0xff;
+ else
+ return kr2376->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
+
+
+static DEVICE_START( kr2376 )
+{
+ kr2376_t *kr2376 = get_safe_token(device);
+
+ /* validate arguments */
+ assert(device != NULL);
+ assert(device->tag() != NULL);
+
+ kr2376->intf = (const kr2376_interface*)device->static_config();
+
+ assert(kr2376->intf != NULL);
+ assert(kr2376->intf->clock > 0);
+
+ /* set initial values */
+ kr2376->ring11 = 0;
+ kr2376->ring8 = 0;
+ kr2376->modifiers = 0;
+ kr2376->strobe = 0;
+ kr2376->strobe_old = 0;
+ kr2376->parity = 0;
+ kr2376->data = 0;
+ change_output_lines(device);
+
+ /* create the timers */
+ kr2376->scan_timer = device->machine().scheduler().timer_alloc(FUNC(kr2376_scan_tick), (void *)device);
+ kr2376->scan_timer->adjust(attotime::zero, 0, attotime::from_hz(kr2376->intf->clock));
+
+ /* register for state saving */
+ device->save_item(NAME(kr2376->ring11));
+ device->save_item(NAME(kr2376->ring8));
+ device->save_item(NAME(kr2376->modifiers));
+ device->save_item(NAME(kr2376->strobe));
+ device->save_item(NAME(kr2376->strobe_old));
+ device->save_item(NAME(kr2376->parity));
+ device->save_item(NAME(kr2376->data));
+}
+
+DEVICE_GET_INFO( kr2376 )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(kr2376_t); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(kr2376); break;
+ case DEVINFO_FCT_STOP: /* Nothing */ break;
+ case DEVINFO_FCT_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "SMC KR2376"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "SMC"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright MESS Team"); break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(KR2376, kr2376);
diff --git a/src/mess/machine/kr2376.h b/src/mess/machine/kr2376.h
new file mode 100644
index 00000000000..6c5073ae7da
--- /dev/null
+++ b/src/mess/machine/kr2376.h
@@ -0,0 +1,88 @@
+/**********************************************************************
+
+ SMC KR2376 Keyboard Encoder emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+ _____ _____
+ 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__
+
+typedef void (*kr2376_on_strobe_changed_func) (device_t *device, int level);
+#define KR2376_ON_STROBE_CHANGED(name) void name(device_t *device, int level)
+
+DECLARE_LEGACY_DEVICE(KR2376, kr2376);
+
+#define MCFG_KR2376_ADD(_tag, _intrf) \
+ MCFG_DEVICE_ADD(_tag, KR2376, 0) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#define MCFG_KR2376_REMOVE(_tag) \
+ MCFG_DEVICE_REMOVE(_tag, KR2376)
+
+/*
+ * Input pins
+ */
+typedef enum
+{
+ KR2376_DSII=20, /* DSII - Pin 20 - Data & Strobe Invert Input */
+ KR2376_PII=6 /* PII - Pin 6 - Parity Invert Input */
+} kr2376_input_pin_t;
+
+typedef enum
+{
+ KR2376_SO=16, /* SO - Pin 16 - Strobe Output */
+ KR2376_PO=7 /* PO - Pin 7 - Parity Output */
+} kr2376_output_pin_t;
+
+/* interface */
+typedef struct _kr2376_interface kr2376_interface;
+struct _kr2376_interface
+{
+ /* The clock of the chip (Typical 50 kHz) */
+ int clock;
+
+ /* This will be called for every change of the strobe pin (pin 16). Optional */
+// kr2376_on_strobe_changed_func on_strobe_changed;
+ write8_device_func on_strobe_changed;
+};
+#define KR2376_INTERFACE(name) const kr2376_interface (name)=
+/* keyboard matrix */
+INPUT_PORTS_EXTERN( kr2376 );
+
+/* keyboard data */
+READ8_DEVICE_HANDLER( kr2376_data_r );
+
+/* Set an input pin */
+void kr2376_set_input_pin( device_t *device, kr2376_input_pin_t pin, int data );
+
+
+/* Get an output pin */
+int kr2376_get_output_pin( device_t *device, kr2376_output_pin_t pin );
+
+#endif
diff --git a/src/mess/machine/kramermc.c b/src/mess/machine/kramermc.c
new file mode 100644
index 00000000000..b95fe9d6531
--- /dev/null
+++ b/src/mess/machine/kramermc.c
@@ -0,0 +1,54 @@
+/***************************************************************************
+
+ Kramer MC machine driver by Miodrag Milanovic
+
+ 13/09/2008 Preliminary driver.
+
+****************************************************************************/
+
+
+#include "emu.h"
+#include "machine/z80pio.h"
+#include "includes/kramermc.h"
+
+
+static READ8_DEVICE_HANDLER (kramermc_port_a_r)
+{
+ return 0xff;
+}
+
+static READ8_DEVICE_HANDLER (kramermc_port_b_r)
+{
+ kramermc_state *state = device->machine().driver_data<kramermc_state>();
+ static const char *const keynames[] = { "LINE0", "LINE1", "LINE2", "LINE3", "LINE4", "LINE5", "LINE6", "LINE7" };
+
+ return device->machine().root_device().ioport(keynames[state->m_key_row])->read();
+}
+
+static WRITE8_DEVICE_HANDLER (kramermc_port_a_w)
+{
+ kramermc_state *state = device->machine().driver_data<kramermc_state>();
+ state->m_key_row = ((data >> 1) & 0x07);
+}
+
+Z80PIO_INTERFACE( kramermc_z80pio_intf )
+{
+ DEVCB_NULL, /* callback when change interrupt status */
+ DEVCB_HANDLER(kramermc_port_a_r),
+ DEVCB_HANDLER(kramermc_port_a_w),
+ DEVCB_NULL,
+ DEVCB_HANDLER(kramermc_port_b_r),
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+/* Driver initialization */
+DRIVER_INIT_MEMBER(kramermc_state,kramermc)
+{
+}
+
+MACHINE_RESET( kramermc )
+{
+ kramermc_state *state = machine.driver_data<kramermc_state>();
+ state->m_key_row = 0;
+}
diff --git a/src/mess/machine/laser128.c b/src/mess/machine/laser128.c
new file mode 100644
index 00000000000..fa5ccd204ea
--- /dev/null
+++ b/src/mess/machine/laser128.c
@@ -0,0 +1,123 @@
+/*********************************************************************
+
+ 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<a2bus_laser128_device>;
+
+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) :
+ device_t(mconfig, type, name, tag, owner, clock),
+ device_a2bus_card_interface(mconfig, *this)
+{
+ m_shortname = "a2laser128";
+}
+
+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),
+ device_a2bus_card_interface(mconfig, *this)
+{
+ m_shortname = "a2laser128";
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void a2bus_laser128_device::device_start()
+{
+ // set_a2bus_device makes m_slot valid
+ set_a2bus_device();
+}
+
+void a2bus_laser128_device::device_reset()
+{
+ m_rom = device().machine().root_device().memregion("maincpu")->base();
+ m_slot7_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:
+ return m_rom[(offset & 0x7ff) + 0x5c00 + m_slot7_bank];
+ }
+
+ return 0xff;
+}
+
+void a2bus_laser128_device::write_c800(address_space &space, UINT16 offset, UINT8 data)
+{
+}
+
+bool a2bus_laser128_device::take_c800()
+{
+ if ((m_slot == 1) || (m_slot == 2) || (m_slot == 5) || (m_slot == 7))
+ {
+ return true;
+ }
+
+ return false;
+}
+
diff --git a/src/mess/machine/laser128.h b/src/mess/machine/laser128.h
new file mode 100644
index 00000000000..ecd1581234c
--- /dev/null
+++ b/src/mess/machine/laser128.h
@@ -0,0 +1,52 @@
+/*********************************************************************
+
+ laser128.h
+
+ Helper to implement the Laser 128's built-in slot peripherals
+
+*********************************************************************/
+
+#ifndef __A2BUS_LASER128__
+#define __A2BUS_LASER128__
+
+#include "emu.h"
+#include "machine/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);
+ 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;
+ int m_slot7_bank;
+};
+
+// device type definition
+extern const device_type A2BUS_LASER128;
+
+#endif /* __A2BUS_LASER128__ */
+
diff --git a/src/mess/machine/lh5810.c b/src/mess/machine/lh5810.c
new file mode 100644
index 00000000000..3a364746f3a
--- /dev/null
+++ b/src/mess/machine/lh5810.c
@@ -0,0 +1,192 @@
+/**********************************************************************
+
+ LH5810/LH5811 Input/Output Port Controller
+
+ TODO:
+ - serial data transfer
+ - data transfer to the cassette tape
+
+**********************************************************************/
+
+#include "emu.h"
+#include "machine/devhelpr.h"
+#include "lh5810.h"
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type LH5810 = &device_creator<lh5810_device>;
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void lh5810_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const lh5810_interface *intf = reinterpret_cast<const lh5810_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<lh5810_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_porta_r_cb, 0, sizeof(m_porta_r_cb));
+ memset(&m_porta_w_cb, 0, sizeof(m_porta_w_cb));
+ memset(&m_portb_r_cb, 0, sizeof(m_portb_r_cb));
+ memset(&m_portb_w_cb, 0, sizeof(m_portb_w_cb));
+ memset(&m_portc_w_cb, 0, sizeof(m_portc_w_cb));
+ memset(&m_out_int_cb, 0, sizeof(m_out_int_cb));
+ }
+}
+
+
+//**************************************************************************
+// 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)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void lh5810_device::device_start()
+{
+ // resolve callbacks
+ m_porta_r_func.resolve(m_porta_r_cb, *this);
+ m_porta_w_func.resolve(m_porta_w_cb, *this);
+ m_portb_r_func.resolve(m_portb_r_cb, *this);
+ m_portb_w_func.resolve(m_portb_w_cb, *this);
+ m_portc_w_func.resolve(m_portc_w_cb, *this);
+ m_out_int_func.resolve(m_out_int_cb, *this);
+
+ // 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_func(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_func(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_func(0) & ~m_reg[LH5810_DDB]);
+ m_out_int_func((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_func(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_func(0, m_reg[offset]);
+ m_out_int_func((m_reg[offset] & 0x80 && m_reg[LH5810_MSK] & 0x02) ? ASSERT_LINE : CLEAR_LINE);
+ break;
+
+ case LH5810_OPC:
+ m_reg[offset] = data;
+ m_portc_w_func(0, m_reg[offset]);
+ break;
+ }
+}
+
diff --git a/src/mess/machine/lh5810.h b/src/mess/machine/lh5810.h
new file mode 100644
index 00000000000..53ae788560e
--- /dev/null
+++ b/src/mess/machine/lh5810.h
@@ -0,0 +1,97 @@
+/**********************************************************************
+
+ 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_ADD(_tag, _config) \
+ MCFG_DEVICE_ADD((_tag), LH5810, 0) \
+ MCFG_DEVICE_CONFIG(_config)
+
+
+
+//*************************************************************************
+// TYPE DEFINITIONS
+//*************************************************************************
+
+// ======================> lh5810_interface
+
+struct lh5810_interface
+{
+ 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
+};
+
+// ======================> lh5810_device
+
+class lh5810_device : public device_t,
+ public lh5810_interface
+{
+public:
+ // construction/destruction
+ lh5810_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ 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_config_complete();
+
+private:
+
+ devcb_resolved_read8 m_porta_r_func;
+ devcb_resolved_write8 m_porta_w_func;
+ devcb_resolved_read8 m_portb_r_func;
+ devcb_resolved_write8 m_portb_w_func;
+ devcb_resolved_write8 m_portc_w_func;
+ devcb_resolved_write_line m_out_int_func;
+
+ UINT8 m_reg[0x10];
+ UINT8 m_irq;
+};
+
+
+// device type definition
+extern const device_type LH5810;
+
+#endif
diff --git a/src/mess/machine/lisa.c b/src/mess/machine/lisa.c
new file mode 100644
index 00000000000..5aff73d9a3d
--- /dev/null
+++ b/src/mess/machine/lisa.c
@@ -0,0 +1,2027 @@
+/*
+ experimental LISA driver
+
+ This driver runs most ROM test code successfully, and it loads the boot
+ file, but it locks when booting from Lisa OS (probably because of floppy
+ write bug). MacWorks boots fine, though (I think it looks when we
+ attempt to write to floppy, too).
+
+ TODO :
+ * fix floppy write bug
+ * *** Boot and run LisaTest !!! ***
+ * finish MMU (does not switch to bank 0 on 68k trap) --- fixed in June 2003???
+ * support hard disk to boot office system
+ * finish keyboard/mouse support
+ * finish clock support
+ * write SCC support
+ * finalize sound support (involves adding new features to the 6522 VIA core)
+ * fix warm-reset (I think I need to use a callback when 68k RESET
+ instruction is called)
+ * write support for additionnal hardware (hard disk, etc...)
+ * emulate LISA1 (?)
+ * optimize MMU emulation !
+
+ DONE (just a reminder to uplift my spirit) :
+ * the lion's share of MMU (spring 2000)
+ * video hardware (except contrast control) (spring 2000)
+ * LISA2/Mac XL floppy hardware (november 2000)
+
+ Credits :
+ * the lisaemu project (<http://www.sundernet.com/>) has gathered much
+ hardware information (books, schematics...) without which this driver
+ could never have been written
+ * The driver raised the interest of several MESS regulars (Paul Lunga,
+ Dennis Munsie...) who supported my feeble efforts
+
+ Raphael Nabet, 2000-2003
+*/
+
+#include "emu.h"
+#include "includes/lisa.h"
+#include "machine/6522via.h"
+#include "machine/applefdc.h"
+#include "devices/sonydriv.h"
+#include "cpu/m68000/m68000.h"
+#include "sound/speaker.h"
+
+
+/*
+ pointers with RAM & ROM location
+*/
+
+/* up to 2MB of 68k RAM (normally 1MB or 512kb), generally 16kb of ROM */
+
+/* offsets in "maincpu" */
+#define RAM_OFFSET 0x004000
+#define ROM_OFFSET 0x000000
+
+/* 1kb of RAM for 6504 floppy disk controller (shared with 68000), and 4kb of
+ROM (8kb on some boards, but then only one 4kb bank is selected, according to
+the drive type (TWIGGY or 3.5'')) */
+
+/* special ROM (includes S/N) */
+
+
+/*
+ MMU regs
+*/
+
+
+
+
+
+/*
+ parity logic - only hard errors are emulated for now, since
+ a) the ROMs power-up test only tests hard errors
+ b) most memory boards do not use soft errors (i.e. they only generate 1
+ parity bit to detect errors, instead of generating several ECC bits to
+ fix errors)
+*/
+
+
+
+
+/*
+ video
+*/
+
+
+/*
+ 2 vias : one is used for communication with COPS ; the other may be used to interface
+ a hard disk
+*/
+
+static READ8_DEVICE_HANDLER(COPS_via_in_b);
+static WRITE8_DEVICE_HANDLER(COPS_via_out_a);
+static WRITE8_DEVICE_HANDLER(COPS_via_out_b);
+static WRITE8_DEVICE_HANDLER(COPS_via_out_ca2);
+static WRITE8_DEVICE_HANDLER(COPS_via_out_cb2);
+static void COPS_via_irq_func(device_t *device, int val);
+static READ8_DEVICE_HANDLER(parallel_via_in_b);
+
+
+const via6522_interface lisa_via6522_0_intf =
+{
+ /* COPS via */
+ DEVCB_NULL, DEVCB_HANDLER(COPS_via_in_b),
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_HANDLER(COPS_via_out_a), DEVCB_HANDLER(COPS_via_out_b),
+ DEVCB_HANDLER(COPS_via_out_ca2), DEVCB_HANDLER(COPS_via_out_cb2),
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_LINE(COPS_via_irq_func),
+};
+
+const via6522_interface lisa_via6522_1_intf =
+{
+ /* parallel interface via - incomplete */
+ DEVCB_NULL, DEVCB_HANDLER(parallel_via_in_b),
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_NULL, DEVCB_NULL,
+};
+
+/*
+ floppy disk interface
+*/
+
+
+
+
+/*
+ lisa model identification
+*/
+enum lisa_model_t
+{
+ /*lisa1,*/ /* twiggy floppy drive */
+ lisa2, /* 3.5'' Sony floppy drive */
+ lisa210, /* modified I/O board, and internal 10Meg drive */
+ mac_xl /* same as above with modified video */
+};
+
+
+
+/*
+ protos
+*/
+
+
+
+
+
+/*
+ Interrupt handling
+*/
+
+static void lisa_field_interrupts(running_machine &machine)
+{
+ lisa_state *state = machine.driver_data<lisa_state>();
+ if (state->m_parity_error_pending)
+ return; /* don't touch anything... */
+
+#if 0
+ if (RSIR)
+ // serial interrupt
+ cputag_set_input_line_and_vector(machine, "maincpu", M68K_IRQ_6, ASSERT_LINE, M68K_INT_ACK_AUTOVECTOR);
+ else if (int0)
+ // external interrupt
+ cputag_set_input_line_and_vector(machine, "maincpu", M68K_IRQ_5, ASSERT_LINE, M68K_INT_ACK_AUTOVECTOR);
+ else if (int1)
+ // external interrupt
+ cputag_set_input_line_and_vector(machine, "maincpu", M68K_IRQ_4, ASSERT_LINE, M68K_INT_ACK_AUTOVECTOR);
+ else if (int2)
+ // external interrupt
+ cputag_set_input_line_and_vector(machine, "maincpu", M68K_IRQ_3, ASSERT_LINE, M68K_INT_ACK_AUTOVECTOR);
+ else
+#endif
+ if (state->m_KBIR)
+ /* COPS VIA interrupt */
+ cputag_set_input_line_and_vector(machine, "maincpu", M68K_IRQ_2, ASSERT_LINE, M68K_INT_ACK_AUTOVECTOR);
+ else if (state->m_FDIR || state->m_VTIR)
+ /* floppy disk or VBl */
+ cputag_set_input_line_and_vector(machine, "maincpu", M68K_IRQ_1, ASSERT_LINE, M68K_INT_ACK_AUTOVECTOR);
+ else
+ /* clear all interrupts */
+ cputag_set_input_line_and_vector(machine, "maincpu", M68K_IRQ_1, CLEAR_LINE, M68K_INT_ACK_AUTOVECTOR);
+}
+
+static void set_parity_error_pending(running_machine &machine, int value)
+{
+ lisa_state *state = machine.driver_data<lisa_state>();
+#if 1
+ /* does not work well due to bugs in 68k cores */
+ state->m_parity_error_pending = value;
+ if (state->m_parity_error_pending)
+ {
+ cputag_set_input_line_and_vector(machine, "maincpu", M68K_IRQ_7, ASSERT_LINE, M68K_INT_ACK_AUTOVECTOR);
+ }
+ else
+ {
+ cputag_set_input_line(machine, "maincpu", M68K_IRQ_7, CLEAR_LINE);
+ }
+#else
+ /* work-around... */
+ if ((! state->m_parity_error_pending) && value)
+ {
+ state->m_parity_error_pending = 1;
+ cputag_set_input_line_and_vector(machine, "maincpu", M68K_IRQ_7, PULSE_LINE, M68K_INT_ACK_AUTOVECTOR);
+ }
+ else if (state->m_parity_error_pending && (! value))
+ {
+ state->m_parity_error_pending = 0;
+ lisa_field_interrupts(machine);
+ }
+#endif
+}
+
+INLINE void set_VTIR(running_machine &machine, int value)
+{
+ lisa_state *state = machine.driver_data<lisa_state>();
+ if (state->m_VTIR != value)
+ {
+ state->m_VTIR = value;
+ if (state->m_VTIR==1)
+ lisa_field_interrupts(machine);
+ }
+}
+
+
+
+/*
+ keyboard interface (COPS simulation; our COPS CPU core is too broken and too esoteric to emulate this correctly, I tried)
+*/
+
+INLINE void COPS_send_data_if_possible(running_machine &machine)
+{
+ lisa_state *state = machine.driver_data<lisa_state>();
+ via6522_device *via_0 = machine.device<via6522_device>("via6522_0");
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ if ((! state->m_hold_COPS_data) && state->m_fifo_size && (! state->m_COPS_Ready))
+ {
+// printf("COPsim: sending %02x to VIA\n", state->m_fifo_data[state->m_fifo_head]);
+
+ via_0->write_porta(*space, 0, state->m_fifo_data[state->m_fifo_head]); /* output data */
+ if (state->m_fifo_head == state->m_mouse_data_offset)
+ state->m_mouse_data_offset = -1; /* we just phased out the mouse data in buffer */
+ state->m_fifo_head = (state->m_fifo_head+1) & 0x7;
+ state->m_fifo_size--;
+ via_0->write_ca1(1); /* pulse ca1 so that VIA reads it */
+ via_0->write_ca1(0); /* BTW, I have no idea how a real COPS does it ! */
+ }
+}
+
+/* send data (queue it into the FIFO if needed) */
+static void COPS_queue_data(running_machine &machine, const UINT8 *data, int len)
+{
+ lisa_state *state = machine.driver_data<lisa_state>();
+#if 0
+ if (state->m_fifo_size + len <= 8)
+#else
+ /* trash old data */
+ while (state->m_fifo_size > 8 - len)
+ {
+ if (state->m_fifo_head == state->m_mouse_data_offset)
+ state->m_mouse_data_offset = -1; /* we just phased out the mouse data in buffer */
+ state->m_fifo_head = (state->m_fifo_head+1) & 0x7;
+ state->m_fifo_size--;
+ }
+#endif
+
+ {
+// printf("Adding %d bytes of data to FIFO\n", len);
+
+ while (len--)
+ {
+ state->m_fifo_data[state->m_fifo_tail] = * (data++);
+ state->m_fifo_tail = (state->m_fifo_tail+1) & 0x7;
+ state->m_fifo_size++;
+ }
+
+ /*logerror("COPS_queue_data : trying to send data to VIA\n");*/
+ COPS_send_data_if_possible(machine);
+ }
+}
+
+/*
+ scan_keyboard()
+
+ scan the keyboard, and add key transition codes to buffer as needed
+*/
+/* shamelessly stolen from machine/mac.c :-) */
+
+/* keyboard matrix to detect transition */
+
+static void scan_keyboard(running_machine &machine)
+{
+ lisa_state *state = machine.driver_data<lisa_state>();
+ int i, j;
+ int keybuf;
+ UINT8 keycode;
+ static const char *const keynames[] = { "LINE0", "LINE1", "LINE2", "LINE3", "LINE4", "LINE5", "LINE6", "LINE7" };
+
+ if (! state->m_COPS_force_unplug)
+ for (i=0; i<8; i++)
+ {
+ keybuf = machine.root_device().ioport(keynames[i])->read();
+
+ if (keybuf != state->m_key_matrix[i])
+ { /* if state has changed, find first bit which has changed */
+ /*logerror("keyboard state changed, %d %X\n", i, keybuf);*/
+
+ for (j=0; j<16; j++)
+ {
+ if (((keybuf ^ state->m_key_matrix[i]) >> j) & 1)
+ {
+ /* update key_matrix */
+ state->m_key_matrix[i] = (state->m_key_matrix[i] & ~ (1 << j)) | (keybuf & (1 << j));
+
+ /* create key code */
+ keycode = (i << 4) | j;
+ if (keybuf & (1 << j))
+ { /* key down */
+ keycode |= 0x80;
+ }
+#if 0
+ if (keycode == state->m_NMIcode)
+ { /* generate NMI interrupt */
+ cputag_set_input_line(machine, "maincpu", M68K_IRQ_7, PULSE_LINE);
+ device_set_input_line_vector(machine.device("maincpu"), M68K_IRQ_7, M68K_INT_ACK_AUTOVECTOR);
+ }
+#endif
+ COPS_queue_data(machine, & keycode, 1);
+ }
+ }
+ }
+ }
+}
+
+/* handle mouse moves */
+/* shamelessly stolen from machine/mac.c :-) */
+static TIMER_CALLBACK(handle_mouse)
+{
+ lisa_state *state = machine.driver_data<lisa_state>();
+ int diff_x = 0, diff_y = 0;
+ int new_mx, new_my;
+
+#if 0
+ if (state->m_COPS_force_unplug)
+ return; /* ???? */
+#endif
+
+ new_mx = machine.root_device().ioport("MOUSE_X")->read();
+ new_my = machine.root_device().ioport("MOUSE_Y")->read();
+
+ /* see if it moved in the x coord */
+ if (new_mx != state->m_last_mx)
+ {
+ diff_x = new_mx - state->m_last_mx;
+
+ /* check for wrap */
+ if (diff_x > 0x80)
+ diff_x = 0x100-diff_x;
+ if (diff_x < -0x80)
+ diff_x = -0x100-diff_x;
+
+ state->m_last_mx = new_mx;
+ }
+ /* see if it moved in the y coord */
+ if (new_my != state->m_last_my)
+ {
+ diff_y = new_my - state->m_last_my;
+
+ /* check for wrap */
+ if (diff_y > 0x80)
+ diff_y = 0x100-diff_y;
+ if (diff_y < -0x80)
+ diff_y = -0x100-diff_y;
+
+ state->m_last_my = new_my;
+ }
+
+ /* update any remaining count and then return */
+ if (diff_x || diff_y)
+ {
+ if (state->m_mouse_data_offset != -1)
+ {
+ state->m_fifo_data[state->m_mouse_data_offset] += diff_x;
+ state->m_fifo_data[(state->m_mouse_data_offset+1) & 0x7] += diff_y;
+ }
+ else
+ {
+#if 0
+ if (state->m_fifo_size <= 5)
+#else
+ /* trash old data */
+ while (state->m_fifo_size > 5)
+ {
+ state->m_fifo_head = (state->m_fifo_head+1) & 0x7;
+ state->m_fifo_size--;
+ }
+#endif
+
+ {
+ /*logerror("Adding 3 bytes of mouse data to FIFO\n");*/
+
+ state->m_fifo_data[state->m_fifo_tail] = 0;
+ state->m_mouse_data_offset = state->m_fifo_tail = (state->m_fifo_tail+1) & 0x7;
+ state->m_fifo_data[state->m_fifo_tail] = diff_x;
+ state->m_fifo_tail = (state->m_fifo_tail+1) & 0x7;
+ state->m_fifo_data[state->m_fifo_tail] = diff_y;
+ state->m_fifo_tail = (state->m_fifo_tail+1) & 0x7;
+ state->m_fifo_size += 3;
+
+ /*logerror("handle_mouse : trying to send data to VIA\n");*/
+ COPS_send_data_if_possible(machine);
+ }
+ /* else, mouse data is lost forever (correct ??) */
+ }
+ }
+}
+
+/* read command from the VIA port A */
+static TIMER_CALLBACK(read_COPS_command)
+{
+ lisa_state *state = machine.driver_data<lisa_state>();
+ int command;
+ via6522_device *via_0 = machine.device<via6522_device>("via6522_0");
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ state->m_COPS_Ready = 0;
+
+ /*logerror("read_COPS_command : trying to send data to VIA\n");*/
+ COPS_send_data_if_possible(machine);
+
+ /* some pull-ups allow the COPS to read 1s when the VIA port is not set as output */
+ command = (state->m_COPS_command | (~ via_0->read(*space, VIA_DDRA))) & 0xff;
+
+// printf("Dropping Ready, command = %02x\n", command);
+
+ if (command & 0x80)
+ return; /* NOP */
+
+ if (command & 0xF0)
+ { /* commands with 4-bit immediate operand */
+ int immediate = command & 0xf;
+
+ switch ((command & 0xF0) >> 4)
+ {
+ case 0x1: /* write clock data */
+ if (state->m_clock_regs.clock_write_ptr != -1)
+ {
+ switch (state->m_clock_regs.clock_write_ptr)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ /* alarm */
+ state->m_clock_regs.alarm &= ~ (0xf << (4 * (4 - state->m_clock_regs.clock_write_ptr)));
+ state->m_clock_regs.alarm |= immediate << (4 * (4 - state->m_clock_regs.clock_write_ptr));
+ break;
+ case 5:
+ /* year */
+ state->m_clock_regs.years = immediate;
+ break;
+ case 6:
+ /* day */
+ state->m_clock_regs.days1 = immediate;
+ break;
+ case 7:
+ /* day */
+ state->m_clock_regs.days2 = immediate;
+ break;
+ case 8:
+ /* day */
+ state->m_clock_regs.days3 = immediate;
+ break;
+ case 9:
+ /* hours */
+ state->m_clock_regs.hours1 = immediate;
+ break;
+ case 10:
+ /* hours */
+ state->m_clock_regs.hours2 = immediate;
+ break;
+ case 11:
+ /* minutes */
+ state->m_clock_regs.minutes1 = immediate;
+ break;
+ case 12:
+ /* minutes */
+ state->m_clock_regs.minutes1 = immediate;
+ break;
+ case 13:
+ /* seconds */
+ state->m_clock_regs.seconds1 = immediate;
+ break;
+ case 14:
+ /* seconds */
+ state->m_clock_regs.seconds2 = immediate;
+ break;
+ case 15:
+ /* tenth */
+ state->m_clock_regs.tenths = immediate;
+ break;
+ }
+ state->m_clock_regs.clock_write_ptr++;
+ if (state->m_clock_regs.clock_write_ptr == 16)
+ state->m_clock_regs.clock_write_ptr = -1;
+ }
+
+ break;
+
+ case 0x2: /* set clock mode */
+ if (immediate & 0x8)
+ { /* start setting the clock */
+ state->m_clock_regs.clock_write_ptr = 0;
+ }
+ else
+ { /* clock write disabled */
+ state->m_clock_regs.clock_write_ptr = -1;
+ }
+
+ if (! (immediate & 0x4))
+ { /* enter sleep mode */
+ /* ... */
+ }
+ else
+ { /* wake up */
+ /* should never happen */
+ }
+
+ state->m_clock_regs.clock_mode = (clock_mode_t)(immediate & 0x3);
+ break;
+
+#if 0
+ /* LED commands - not implemented in production LISAs */
+ case 0x3: /* write 4 keyboard LEDs */
+ keyboard_leds = (keyboard_leds & 0x0f) | (immediate << 4);
+ break;
+
+ case 0x4: /* write next 4 keyboard LEDs */
+ keyboard_leds = (keyboard_leds & 0xf0) | immediate;
+ break;
+#endif
+
+ case 0x5: /* set high nibble of NMI character to nnnn */
+ state->m_NMIcode = (state->m_NMIcode & 0x0f) | (immediate << 4);
+ break;
+
+ case 0x6: /* set low nibble of NMI character to nnnn */
+ state->m_NMIcode = (state->m_NMIcode & 0xf0) | immediate;
+ break;
+
+ case 0x7: /* send mouse command */
+ if (immediate & 0x8)
+ state->m_mouse_timer->adjust(attotime::zero, 0, attotime::from_msec((immediate & 0x7)*4)); /* enable mouse */
+ else
+ state->m_mouse_timer->reset();
+ break;
+ }
+ }
+ else
+ { /* operand-less commands */
+ switch (command)
+ {
+ case 0x0: /*Turn I/O port on (???) */
+
+ break;
+
+ case 0x1: /*Turn I/O port off (???) */
+
+ break;
+
+ case 0x2: /* Read clock data */
+ {
+ /* format and send reply */
+
+ UINT8 reply[7];
+
+ reply[0] = 0x80;
+ reply[1] = 0xE0 | state->m_clock_regs.years;
+ reply[2] = (state->m_clock_regs.days1 << 4) | state->m_clock_regs.days2;
+ reply[3] = (state->m_clock_regs.days3 << 4) | state->m_clock_regs.hours1;
+ reply[4] = (state->m_clock_regs.hours2 << 4) | state->m_clock_regs.minutes1;
+ reply[5] = (state->m_clock_regs.minutes2 << 4) | state->m_clock_regs.seconds1;
+ reply[6] = (state->m_clock_regs.seconds2 << 4) | state->m_clock_regs.tenths;
+
+ COPS_queue_data(machine, reply, 7);
+ }
+ break;
+ }
+ }
+}
+
+/* this timer callback raises the COPS Ready line, which tells the COPS is about to read a command */
+static TIMER_CALLBACK(set_COPS_ready)
+{
+ lisa_state *state = machine.driver_data<lisa_state>();
+ state->m_COPS_Ready = 1;
+
+ /* impulsion width : +/- 20us */
+ machine.scheduler().timer_set(attotime::from_usec(20), FUNC(read_COPS_command));
+}
+
+static void reset_COPS(lisa_state *state)
+{
+ int i;
+
+ state->m_fifo_size = 0;
+ state->m_fifo_head = 0;
+ state->m_fifo_tail = 0;
+ state->m_mouse_data_offset = -1;
+
+ for (i=0; i<8; i++)
+ state->m_key_matrix[i] = 0;
+
+ state->m_mouse_timer->reset();
+}
+
+static void unplug_keyboard(running_machine &machine)
+{
+ static const UINT8 cmd[2] =
+ {
+ 0x80, /* RESET code */
+ 0xFD /* keyboard unplugged */
+ };
+
+ COPS_queue_data(machine, cmd, 2);
+}
+
+
+static void plug_keyboard(running_machine &machine)
+{
+ /*
+ possible keyboard IDs according to Lisa Hardware Manual and boot ROM source code
+
+ 2 MSBs : "mfg code" (-> 0x80 for Keytronics, 0x00 for "APD")
+ 6 LSBs :
+ 0x0x : "old US keyboard"
+ 0x3f : US keyboard
+ 0x3d : Canadian keyboard
+ 0x2f : UK
+ 0x2e : German
+ 0x2d : French
+ 0x27 : Swiss-French
+ 0x26 : Swiss-German
+ unknown : spanish, US dvorak, italian & swedish
+ */
+
+ static const UINT8 cmd[2] =
+ {
+ 0x80, /* RESET code */
+ 0x3f /* keyboard ID - US for now */
+ };
+
+ COPS_queue_data(machine, cmd, 2);
+}
+
+
+/* called at power-up */
+static void init_COPS(running_machine &machine)
+{
+ lisa_state *state = machine.driver_data<lisa_state>();
+ state->m_COPS_Ready = 0;
+
+ reset_COPS(state);
+}
+
+
+
+/* VIA1 accessors (COPS, sound, and 2 hard disk lines) */
+
+/*
+ PA0-7 (I/O) : VIA <-> COPS data bus
+ CA1 (I) : COPS sending valid data
+ CA2 (O) : VIA -> COPS handshake
+*/
+static WRITE8_DEVICE_HANDLER(COPS_via_out_a)
+{
+ lisa_state *state = device->machine().driver_data<lisa_state>();
+// printf("VIA A = %02x\n", data);
+ state->m_COPS_command = data;
+}
+
+static WRITE8_DEVICE_HANDLER(COPS_via_out_ca2)
+{
+ lisa_state *state = device->machine().driver_data<lisa_state>();
+ state->m_hold_COPS_data = data;
+
+ /*logerror("COPS CA2 line state : %d\n", val);*/
+
+ /*logerror("COPS_via_out_ca2 : trying to send data to VIA\n");*/
+ COPS_send_data_if_possible(device->machine());
+}
+
+/*
+ PB7 (O) : CR* ("Controller Reset", used by hard disk interface) ???
+ PB6 (I) : CRDY ("COPS ready") : set low by the COPS for 20us when it is reading a command
+ from the data bus (command latched at low-to-high transition)
+ PB5 (I/O) : PR* ; as output : "parity error latch reset" (only when CR* and RESET* are
+ inactive) ; as input : low when CR* or RESET are low.
+ PB4 (I) : FDIR (floppy disk interrupt request - the fdc shared RAM should not be accessed
+ unless this bit is 1)
+ PB1-3 (O) : sound volume
+ PB0 (O) : forces disconnection of keyboard and mouse (allows to retrive keyboard ID, etc.)
+
+ CB1 : not used
+ CB2 (O) : sound output
+*/
+static READ8_DEVICE_HANDLER(COPS_via_in_b)
+{
+ lisa_state *state = device->machine().driver_data<lisa_state>();
+ int val = 0;
+
+ if (state->m_COPS_Ready)
+ val |= 0x40;
+
+ if (state->m_FDIR)
+ val |= 0x10;
+
+ return val;
+}
+
+static WRITE8_DEVICE_HANDLER(COPS_via_out_b)
+{
+ lisa_state *state = device->machine().driver_data<lisa_state>();
+ via6522_device *via_0 = device->machine().device<via6522_device>("via6522_0");
+ address_space *space = device->machine().device("maincpu")->memory().space(AS_PROGRAM);
+
+ /* pull-up */
+ data |= (~ via_0->read(*space,VIA_DDRA)) & 0x01;
+
+ if (data & 0x01)
+ {
+ if (state->m_COPS_force_unplug)
+ {
+ state->m_COPS_force_unplug = 0;
+ plug_keyboard(device->machine());
+ }
+ }
+ else
+ {
+ if (! state->m_COPS_force_unplug)
+ {
+ state->m_COPS_force_unplug = 1;
+ unplug_keyboard(device->machine());
+ //reset_COPS(state);
+ }
+ }
+}
+
+static WRITE8_DEVICE_HANDLER(COPS_via_out_cb2)
+{
+ device_t *speaker = device->machine().device(SPEAKER_TAG);
+ speaker_level_w(speaker, data);
+}
+
+static void COPS_via_irq_func(device_t *device, int val)
+{
+ lisa_state *state = device->machine().driver_data<lisa_state>();
+ if (state->m_KBIR != val)
+ {
+ state->m_KBIR = val;
+ lisa_field_interrupts(device->machine());
+ }
+}
+
+/* VIA2 accessors (hard disk, and a few floppy disk lines) */
+
+/*
+ PA0-7 (I/O) : VIA <-> hard disk data bus (cf PB3)
+ CA1 (I) : hard disk BSY line
+ CA2 (O) : hard disk PSTRB* line
+*/
+
+/*
+ PB7 (O) : WCNT line : set contrast latch on low-to-high transition ?
+ PB6 (I) : floppy disk DISK DIAG line
+ PB5 (I) : hard disk data DD0-7 current parity (does not depend on PB2)
+ PB4 (O) : hard disk CMD* line
+ PB3 (O) : hard disk DR/W* line ; controls the direction of the drivers on the data bus
+ PB2 (O) : when low, disables hard disk interface drivers
+ PB1 (I) : hard disk BSY line
+ PB0 (I) : hard disk OCD (Open Cable Detect) line : 0 when hard disk attached
+ CB1 : not used
+ CB2 (I) : current parity latch value
+*/
+static READ8_DEVICE_HANDLER(parallel_via_in_b)
+{
+ lisa_state *state = device->machine().driver_data<lisa_state>();
+ int val = 0;
+
+ if (state->m_DISK_DIAG)
+ val |= 0x40;
+
+ /* tell there is no hard disk : */
+ val |= 0x1;
+
+ /* keep busy high to work around a bug??? */
+ //val |= 0x2;
+
+ return val;
+}
+
+
+
+
+
+
+/*
+ LISA video emulation
+*/
+
+VIDEO_START( lisa )
+{
+}
+
+/*
+ Video update
+*/
+SCREEN_UPDATE_IND16( lisa )
+{
+ lisa_state *state = screen.machine().driver_data<lisa_state>();
+ UINT16 *v;
+ int x, y;
+ /* resolution is 720*364 on lisa, vs 608*431 on mac XL */
+ int resx = (state->m_features.has_mac_xl_video) ? 608 : 720; /* width */
+ int resy = (state->m_features.has_mac_xl_video) ? 431 : 364; /* height */
+
+ UINT8 line_buffer[720];
+
+ v = state->m_videoram_ptr;
+
+ for (y = 0; y < resy; y++)
+ {
+ for (x = 0; x < resx; x++)
+// line_buffer[x] = (v[(x+y*resx)>>4] & (0x8000 >> ((x+y*resx) & 0xf))) ? 0 : 1;
+ line_buffer[x] = (v[(x+y*resx)>>4] & (0x8000 >> (x & 0xf))) ? 0 : 1;
+ draw_scanline8(bitmap, 0, y, resx, line_buffer, screen.machine().pens);
+ }
+ return 0;
+}
+
+#if 0 // we can execute directly out of read handlers now, so this shouldn't be necessary any more. #if 0'd for documentation until we get everything working.
+DIRECT_UPDATE_HANDLER (lisa_OPbaseoverride)
+{
+ lisa_state *state = machine.driver_data<lisa_state>();
+ /* upper 7 bits -> segment # */
+ int segment = (address >> 17) & 0x7f;
+ int the_seg = state->m_seg;
+
+ address &= 0xffffff;
+
+ printf("lisa: logical address %x\n", address);
+
+ if (state->m_setup)
+ {
+ if (address & 0x004000)
+ {
+// the_seg = 0; /* correct ??? */
+ }
+ else
+ {
+ if (address & 0x008000)
+ { /* MMU register : BUS error ??? */
+ printf("illegal opbase address %lX\n", (long) address);
+ }
+ else
+ { /* system ROMs */
+ direct.explicit_configure((address & 0xffc000), (address & 0xffc000) + 0x003fff, 0xffffff, state->m_rom_ptr - (address & 0x3fff));
+ }
+
+ return -1;
+ }
+
+ }
+
+ if (cpu_get_reg(machine.device("maincpu"), M68K_SR) & 0x2000)
+ {
+ /* supervisor mode -> force register file 0 */
+ the_seg = 0;
+ }
+
+ {
+ int seg_offset = address & 0x01ffff;
+
+ /* add revelant origin -> address */
+ offs_t mapped_address = (state->m_mmu_regs[the_seg][segment].sorg + seg_offset) & 0x1fffff;
+
+ switch ((mmu_entry_t)state->m_mmu_regs[the_seg][segment].type)
+ {
+
+ case RAM_r:
+ case RAM_rw:
+ if (seg_offset > state->m_mmu_regs[the_seg][segment].slim)
+ {
+ /* out of segment limits : bus error */
+ printf("illegal opbase address%lX\n", (long) address);
+ }
+ direct.explicit_configure((address & 0xffc000), (address & 0xffc000) + 0x003fff, 0xffffff, state->m_ram_ptr + mapped_address - address);
+ printf("RAM\n");
+ break;
+
+ case RAM_stack_r:
+ case RAM_stack_rw: /* stack : bus error ??? */
+ case IO: /* I/O : bus error ??? */
+ case invalid: /* unmapped segment */
+ /* bus error */
+ printf("illegal opbase address%lX\n", (long) address);
+ break;
+
+ case special_IO:
+ direct.explicit_configure((address & 0xffc000), (address & 0xffc000) + 0x003fff, 0xffffff, state->m_rom_ptr + (mapped_address & 0x003fff) - address);
+ printf("ROM\n");
+ break;
+ }
+ }
+
+ return -1;
+}
+#endif
+
+/* should save PRAM to file */
+/* TODO : save time difference with host clock, set default date, etc */
+NVRAM_HANDLER(lisa)
+{
+ lisa_state *state = machine.driver_data<lisa_state>();
+ if (read_or_write)
+ {
+ file->write(state->m_fdc_ram, 1024);
+ }
+ else
+ {
+ if (file)
+ file->read(state->m_fdc_ram, 1024);
+ else
+ memset(state->m_fdc_ram, 0, 1024);
+
+ {
+ /* Now we copy the host clock into the Lisa clock */
+ system_time systime;
+ machine.base_datetime(systime);
+
+ state->m_clock_regs.alarm = 0xfffffL;
+ /* The clock count starts on 1st January 1980 */
+ state->m_clock_regs.years = (systime.local_time.year - 1980) & 0xf;
+ state->m_clock_regs.days1 = (systime.local_time.day + 1) / 100;
+ state->m_clock_regs.days2 = ((systime.local_time.day + 1) / 10) % 10;
+ state->m_clock_regs.days3 = (systime.local_time.day + 1) % 10;
+ state->m_clock_regs.hours1 = systime.local_time.hour / 10;
+ state->m_clock_regs.hours2 = systime.local_time.hour % 10;
+ state->m_clock_regs.minutes1 = systime.local_time.minute / 10;
+ state->m_clock_regs.minutes2 = systime.local_time.minute % 10;
+ state->m_clock_regs.seconds1 = systime.local_time.second / 10;
+ state->m_clock_regs.seconds2 = systime.local_time.second % 10;
+ state->m_clock_regs.tenths = 0;
+ }
+ state->m_clock_regs.clock_mode = timer_disable;
+ state->m_clock_regs.clock_write_ptr = -1;
+ }
+
+
+#if 0
+ UINT32 temp32;
+ SINT8 temp8;
+ temp32 = (state->m_clock_regs.alarm << 12) | (state->m_clock_regs.years << 8) | (state->m_clock_regs.days1 << 4)
+ | state->m_clock_regs.days2;
+
+ temp32 = (state->m_clock_regs.days3 << 28) | (state->m_clock_regs.hours1 << 24) | (state->m_clock_regs.hours2 << 20)
+ | (state->m_clock_regs.minutes1 << 16) | (state->m_clock_regs.minutes2 << 12)
+ | (state->m_clock_regs.seconds1 << 8) | (state->m_clock_regs.seconds2 << 4) | state->m_clock_regs.tenths;
+
+ temp8 = clock_mode; /* clock mode */
+
+ temp8 = state->m_clock_regs.clock_write_ptr; /* clock byte to be written next (-1 if clock write disabled) */
+#endif
+}
+
+#ifdef UNUSED_FUNCTION
+void init_lisa1(void)
+{
+ lisa_state *state = machine.driver_data<lisa_state>();
+ state->m_model = lisa1;
+ state->m_features.has_fast_timers = 0;
+ state->m_features.floppy_hardware = twiggy;
+ state->m_features.has_double_sided_floppy = 1;
+ state->m_features.has_mac_xl_video = 0;
+}
+#endif
+
+DRIVER_INIT_MEMBER(lisa_state,lisa2)
+{
+ m_ram_ptr = machine().root_device().memregion("maincpu")->base() + RAM_OFFSET;
+ m_rom_ptr = memregion("maincpu")->base() + ROM_OFFSET;
+ m_model = lisa2;
+ m_features.has_fast_timers = 0;
+ m_features.floppy_hardware = sony_lisa2;
+ m_features.has_double_sided_floppy = 0;
+ m_features.has_mac_xl_video = 0;
+
+ m_bad_parity_table = auto_alloc_array(machine(), UINT8, 0x40000); /* 1 bit per byte of CPU RAM */
+}
+
+DRIVER_INIT_MEMBER(lisa_state,lisa210)
+{
+ m_ram_ptr = machine().root_device().memregion("maincpu")->base() + RAM_OFFSET;
+ m_rom_ptr = memregion("maincpu")->base() + ROM_OFFSET;
+ m_model = lisa210;
+ m_features.has_fast_timers = 1;
+ m_features.floppy_hardware = sony_lisa210;
+ m_features.has_double_sided_floppy = 0;
+ m_features.has_mac_xl_video = 0;
+
+ m_bad_parity_table = auto_alloc_array(machine(), UINT8, 0x40000); /* 1 bit per byte of CPU RAM */
+}
+
+DRIVER_INIT_MEMBER(lisa_state,mac_xl)
+{
+ m_ram_ptr = machine().root_device().memregion("maincpu")->base() + RAM_OFFSET;
+ m_rom_ptr = memregion("maincpu")->base() + ROM_OFFSET;
+ m_model = mac_xl;
+ m_features.has_fast_timers = 1;
+ m_features.floppy_hardware = sony_lisa210;
+ m_features.has_double_sided_floppy = 0;
+ m_features.has_mac_xl_video = 1;
+
+ m_bad_parity_table = auto_alloc_array(machine(), UINT8, 0x40000); /* 1 bit per byte of CPU RAM */
+}
+
+MACHINE_START( lisa )
+{
+ lisa_state *state = machine.driver_data<lisa_state>();
+ state->m_mouse_timer = machine.scheduler().timer_alloc(FUNC(handle_mouse));
+
+ /* read command every ms (don't know the real value) */
+ machine.scheduler().timer_pulse(attotime::from_msec(1), FUNC(set_COPS_ready));
+}
+
+MACHINE_RESET( lisa )
+{
+ lisa_state *state = machine.driver_data<lisa_state>();
+ state->m_ram_ptr = machine.root_device().memregion("maincpu")->base() + RAM_OFFSET;
+ state->m_rom_ptr = machine.root_device().memregion("maincpu")->base() + ROM_OFFSET;
+ state->m_videoROM_ptr = state->memregion("gfx1")->base();
+
+// machine.device("maincpu")->memory().space(AS_PROGRAM)->set_direct_update_handler(direct_update_delegate_create_static(lisa_OPbaseoverride, *machine));
+// m68k_set_reset_callback(machine.device("maincpu"), /*lisa_reset_instr_callback*/NULL);
+
+ /* init MMU */
+ state->m_setup = 1;
+ state->m_seg = 0;
+
+ /* init parity */
+ state->m_diag2 = 0;
+ state->m_test_parity = 0;
+ state->m_parity_error_pending = 0;
+
+ state->m_bad_parity_count = 0;
+ memset(state->m_bad_parity_table, 0, 0x40000); /* Clear */
+
+ /* init video */
+
+ state->m_VTMSK = 0;
+ set_VTIR(machine, 0);
+
+ state->m_video_address_latch = 0;
+ state->m_videoram_ptr = (UINT16 *) state->m_ram_ptr;
+
+ /* reset COPS keyboard/mouse controller */
+ init_COPS(machine);
+
+ {
+ via6522_device *via_0 = machine.device<via6522_device>("via6522_0");
+ COPS_via_out_ca2(via_0, 0, 0); /* VIA core forgets to do so */
+ }
+
+ /* initialize floppy */
+ {
+ if (state->m_features.floppy_hardware == sony_lisa2)
+ {
+ sony_set_enable_lines(machine.device("fdc"),1); /* on lisa2, drive unit 1 is always selected (?) */
+ }
+ }
+
+ /* reset 68k to pick up proper vectors from MMU */
+ devtag_reset(machine, "maincpu");
+}
+
+INTERRUPT_GEN( lisa_interrupt )
+{
+ lisa_state *state = device->machine().driver_data<lisa_state>();
+ if ((++state->m_frame_count) == 6)
+ { /* increment clock every 1/10s */
+ state->m_frame_count = 0;
+
+ if (state->m_clock_regs.clock_mode != clock_timer_disable)
+ {
+ if ((++state->m_clock_regs.tenths) == 10)
+ {
+ state->m_clock_regs.tenths = 0;
+
+ if (state->m_clock_regs.clock_mode != timer_disable)
+ {
+ if (state->m_clock_regs.alarm == 0)
+ {
+ /* generate reset (should cause a VIA interrupt...) */
+ static const UINT8 cmd[2] =
+ {
+ 0x80, /* RESET code */
+ 0xFC /* timer time-out */
+ };
+ COPS_queue_data(device->machine(), cmd, 2);
+
+ state->m_clock_regs.alarm = 0xfffffL;
+ }
+ else
+ {
+ state->m_clock_regs.alarm--;
+ }
+ }
+
+ if ((++state->m_clock_regs.seconds2) == 10)
+ {
+ state->m_clock_regs.seconds2 = 0;
+
+ if ((++state->m_clock_regs.seconds1) == 6)
+ {
+ state->m_clock_regs.seconds1 = 0;
+
+ if ((++state->m_clock_regs.minutes2) == 10)
+ {
+ state->m_clock_regs.minutes2 = 0;
+
+ if ((++state->m_clock_regs.minutes1) == 6)
+ {
+ state->m_clock_regs.minutes1 = 0;
+
+ if ((++state->m_clock_regs.hours2) == 10)
+ {
+ state->m_clock_regs.hours2 = 0;
+
+ state->m_clock_regs.hours1++;
+ }
+
+ if ((state->m_clock_regs.hours1*10 + state->m_clock_regs.hours2) == 24)
+ {
+ state->m_clock_regs.hours1 = state->m_clock_regs.hours2 = 0;
+
+ if ((++state->m_clock_regs.days3) == 10)
+ {
+ state->m_clock_regs.days3 = 0;
+
+ if ((++state->m_clock_regs.days2) == 10)
+ {
+ state->m_clock_regs.days2 = 0;
+
+ state->m_clock_regs.days1++;
+ }
+ }
+
+ if ((state->m_clock_regs.days1*100 + state->m_clock_regs.days2*10 + state->m_clock_regs.days3) ==
+ ((state->m_clock_regs.years % 4) ? 366 : 367))
+ {
+ state->m_clock_regs.days1 = state->m_clock_regs.days2 = state->m_clock_regs.days3 = 0;
+
+ state->m_clock_regs.years = (state->m_clock_regs.years + 1) & 0xf;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* set VBI */
+ if (state->m_VTMSK)
+ set_VTIR(device->machine(), 1);
+ else
+ set_VTIR(device->machine(), 0);
+
+ /* do keyboard scan */
+ scan_keyboard(device->machine());
+}
+
+/*
+ Lots of fun with the Lisa fdc hardware
+
+ The iwm floppy select line is connected to the drive SEL line in Lisa2 (which is why Lisa 2
+ cannot support 2 floppy drives)...
+*/
+
+INLINE void lisa_fdc_ttl_glue_access(running_machine &machine, offs_t offset)
+{
+ lisa_state *state = machine.driver_data<lisa_state>();
+ switch ((offset & 0x000E) >> 1)
+ {
+ case 0:
+ /*stop = offset & 1;*/ /* stop/run motor pulse generation */
+ break;
+ case 2:
+ /*MT0 = offset & 1;*/ /* ???? */
+ break;
+ case 3:
+ /* enable/disable the motor on Lisa 1 */
+ /* can disable the motor on Lisa 2/10, too (although it is not useful) */
+ /* On lisa 2, commands the loading of the speed register on lisalite board */
+ if (state->m_features.floppy_hardware == sony_lisa2)
+ {
+ int oldMT1 = state->m_MT1;
+ state->m_MT1 = offset & 1;
+ if (state->m_MT1 && ! oldMT1)
+ {
+ device_t *fdc = machine.device("fdc");
+
+ state->m_PWM_floppy_motor_speed = (state->m_PWM_floppy_motor_speed << 1) & 0xff;
+ if (applefdc_get_lines(fdc) & APPLEFDC_PH0)
+ state->m_PWM_floppy_motor_speed |= 1;
+ sony_set_speed(((256-state->m_PWM_floppy_motor_speed) * 1.3) + 237);
+ }
+ }
+ /*else
+ state->m_MT1 = offset & 1;*/
+ break;
+ case 4:
+ /*DIS = offset & 1;*/ /* forbids access from the 68000 to our RAM */
+ break;
+ case 5:
+ /*HDS = offset & 1;*/ /* head select (-> disk side) on twiggy */
+#if 0
+ if (state->m_features.floppy_hardware == twiggy)
+ twiggy_set_head_line(offset & 1);
+ else
+#endif
+ if (state->m_features.floppy_hardware == sony_lisa210)
+ sony_set_sel_line(machine.device("fdc"), offset & 1);
+ break;
+ case 6:
+ state->m_DISK_DIAG = offset & 1;
+ break;
+ case 7:
+ state->m_FDIR = offset & 1; /* Interrupt request to 68k */
+ lisa_field_interrupts(machine);
+ break;
+ }
+}
+
+READ8_MEMBER(lisa_state::lisa_fdc_io_r)
+{
+ int answer=0;
+ device_t *fdc = machine().device("fdc");
+
+ switch ((offset & 0x0030) >> 4)
+ {
+ case 0: /* IWM */
+ answer = applefdc_r(fdc, offset);
+ break;
+
+ case 1: /* TTL glue */
+ lisa_fdc_ttl_glue_access(machine(), offset);
+ answer = 0; /* ??? */
+ break;
+
+ case 2: /* pulses the PWM LOAD line (bug!) */
+ answer = 0; /* ??? */
+ break;
+
+ case 3: /* not used */
+ answer = 0; /* ??? */
+ break;
+ }
+
+ return answer;
+}
+
+WRITE8_MEMBER(lisa_state::lisa_fdc_io_w)
+{
+ device_t *fdc = machine().device("fdc");
+
+ switch ((offset & 0x0030) >> 4)
+ {
+ case 0: /* IWM */
+ applefdc_w(fdc, offset, data);
+ break;
+
+ case 1: /* TTL glue */
+ lisa_fdc_ttl_glue_access(machine(), offset);
+ break;
+
+ case 2: /* writes the PWM register */
+ /* the written value is used to generate the motor speed control signal */
+#if 0
+ if (m_features.floppy_hardware == twiggy)
+ twiggy_set_speed((256-data) * 1.3 /* ??? */ + 237 /* ??? */);
+ else
+#endif
+ if (m_features.floppy_hardware == sony_lisa210)
+ sony_set_speed(((256-data) * 1.3) + 237);
+ break;
+
+ case 3: /* not used */
+ break;
+ }
+}
+
+READ8_MEMBER(lisa_state::lisa_fdc_r)
+{
+ if (! (offset & 0x1000))
+ {
+ if (! (offset & 0x0800))
+ if (! (offset & 0x0400))
+ return m_fdc_ram[offset & 0x03ff];
+ else
+ return lisa_fdc_io_r(space, offset & 0x03ff);
+ else
+ return 0; /* ??? */
+ }
+ else
+ return m_fdc_rom[offset & 0x0fff];
+}
+
+READ8_MEMBER(lisa_state::lisa210_fdc_r)
+{
+ if (! (offset & 0x1000))
+ {
+ if (! (offset & 0x0400))
+ if (! (offset & 0x0800))
+ return m_fdc_ram[offset & 0x03ff];
+ else
+ return lisa_fdc_io_r(space, offset & 0x03ff);
+ else
+ return 0; /* ??? */
+ }
+ else
+ return m_fdc_rom[offset & 0x0fff];
+}
+
+WRITE8_MEMBER(lisa_state::lisa_fdc_w)
+{
+ if (! (offset & 0x1000))
+ {
+ if (! (offset & 0x0800))
+ {
+ if (! (offset & 0x0400))
+ m_fdc_ram[offset & 0x03ff] = data;
+ else
+ lisa_fdc_io_w(space, offset & 0x03ff, data);
+ }
+ }
+}
+
+WRITE8_MEMBER(lisa_state::lisa210_fdc_w)
+{
+ if (! (offset & 0x1000))
+ {
+ if (! (offset & 0x0400))
+ {
+ if (! (offset & 0x0800))
+ m_fdc_ram[offset & 0x03ff] = data;
+ else
+ lisa_fdc_io_w(space, offset & 0x03ff, data);
+ }
+ }
+}
+
+READ16_MEMBER(lisa_state::lisa_r)
+{
+ int answer=0;
+
+ /* segment register set */
+ int the_seg = m_seg;
+
+ /* upper 7 bits -> segment # */
+ int segment = (offset >> 16) & 0x7f;
+
+ /*logerror("read, logical address%lX\n", offset);*/
+
+ if (m_setup)
+ { /* special setup mode */
+ if (offset & 0x002000)
+ {
+ the_seg = 0; // TRUSTED by Lisa Hardware Manual section 2.3.3 and MMU startup test
+ }
+ else
+ {
+ if (offset & 0x004000)
+ { /* read MMU register */
+ /*logerror("read from segment registers (%X:%X) ", the_seg, segment);*/
+ if (offset & 0x000004)
+ { /* sorg register */
+ answer = m_real_mmu_regs[the_seg][segment].sorg;
+ /*logerror("sorg, data = %X\n", answer);*/
+ }
+ else
+ { /* slim register */
+ answer = m_real_mmu_regs[the_seg][segment].slim;
+ /*logerror("slim, data = %X\n", answer);*/
+ }
+ }
+ else
+ { /* system ROMs */
+ answer = ((UINT16*)m_rom_ptr)[(offset & 0x001fff)];
+ /*logerror("dst address in ROM (setup mode)\n");*/
+ }
+
+ return answer;
+ }
+ }
+
+ if (cpu_get_reg(machine().device("maincpu"), M68K_SR) & 0x2000)
+ /* supervisor mode -> force register file 0 */
+ the_seg = 0;
+
+ {
+ /* offset in segment */
+ int seg_offset = (offset & 0x00ffff) << 1;
+
+ /* add revelant origin -> address */
+ offs_t address = (m_mmu_regs[the_seg][segment].sorg + seg_offset) & 0x1fffff;
+
+ /*logerror("read, logical address%lX\n", offset);
+ logerror("physical address%lX\n", address);*/
+
+ switch (m_mmu_regs[the_seg][segment].type)
+ {
+
+ case RAM_stack_r:
+ case RAM_stack_rw:
+ if (address <= m_mmu_regs[the_seg][segment].slim)
+ {
+ /* out of segment limits : bus error */
+
+ }
+ answer = *(UINT16 *)(m_ram_ptr + address);
+
+ if (m_bad_parity_count && m_test_parity
+ && (m_bad_parity_table[address >> 3] & (0x3 << (address & 0x7))))
+ {
+ m_mem_err_addr_latch = address >> 5;
+ set_parity_error_pending(machine(), 1);
+ }
+
+ break;
+
+ case RAM_r:
+ case RAM_rw:
+ if (address > m_mmu_regs[the_seg][segment].slim)
+ {
+ /* out of segment limits : bus error */
+
+ }
+ answer = *(UINT16 *)(m_ram_ptr + address);
+
+ if (m_bad_parity_count && m_test_parity
+ && (m_bad_parity_table[address >> 3] & (0x3 << (address & 0x7))))
+ {
+ m_mem_err_addr_latch = address >> 5;
+ set_parity_error_pending(machine(), 1);
+ }
+
+ break;
+
+ case IO:
+ answer = lisa_IO_r(space, (address & 0x00ffff) >> 1, mem_mask);
+
+ break;
+
+ case invalid: /* unmapped segment */
+ /* bus error */
+
+ answer = 0;
+
+ break;
+
+ case special_IO:
+ if (! (address & 0x008000))
+ answer = *(UINT16 *)(m_rom_ptr + (address & 0x003fff));
+ else
+ { /* read serial number from ROM */
+ /* this has to be be the least efficient way to read a ROM :-) */
+ /* this emulation is not guaranteed accurate */
+
+ /* problem : due to collisions with video, timings of the LISA CPU
+ are slightly different from timings of a bare 68k */
+ /* so we use a kludge... */
+ int time_in_frame = machine().primary_screen->vpos();
+
+ /* the BOOT ROM only reads 56 bits, so there must be some wrap-around for
+ videoROM_address <= 56 */
+ /* pixel clock 20MHz, memory access rate 1.25MHz, horizontal clock 22.7kHz
+ according to Apple, which must stand for 1.25MHz/55 = 22727kHz, vertical
+ clock approximately 60Hz, which means there are about 380 lines, including VBlank */
+ /* The values are different on the Mac XL, and I don't know the correct values
+ for sure. */
+
+ /* Something appears to be wrong with the timings, since we expect to read the
+ 2nd half when v-syncing, i.e. for lines beyond the 431th or 364th one (provided
+ there are no additionnal margins).
+ This is caused by the fact that 68k timings are wrong (memory accesses are
+ interlaced with the video hardware, which is not emulated). */
+ if (m_features.has_mac_xl_video)
+ {
+ if ((time_in_frame >= 374) && (time_in_frame <= 392)) /* these values have not been tested */
+ answer = m_videoROM_ptr[m_videoROM_address|0x80] << 8;
+ else
+ answer = m_videoROM_ptr[m_videoROM_address] << 8;
+ }
+ else
+ {
+ if ((time_in_frame >= 364) && (time_in_frame <= 375))
+ {
+ answer = m_videoROM_ptr[m_videoROM_address|0x80] << 8;
+ logerror("reading1 %06X=%04x PC=%06x time=%d\n", address, answer, cpu_get_pc(machine().device("maincpu")), time_in_frame);
+ }
+ else
+ {
+ answer = m_videoROM_ptr[m_videoROM_address] << 8;
+ logerror("reading2 %06X=%04x PC=%06x time=%d\n", address, answer, cpu_get_pc(machine().device("maincpu")), time_in_frame);
+ }
+ }
+
+
+ m_videoROM_address = (m_videoROM_address + 1) & 0x7f;
+ if (m_videoROM_address == ((m_features.has_mac_xl_video) ? 48 : 56)) {
+ logerror("loop %d\n", m_videoROM_address);
+ m_videoROM_address = 0;
+ }
+
+ }
+
+ break;
+ }
+ }
+
+ /*logerror("result %X\n", answer);*/
+
+ return answer;
+}
+
+WRITE16_MEMBER(lisa_state::lisa_w)
+{
+ /* segment register set */
+ int the_seg = m_seg;
+
+ /* upper 7 bits -> segment # */
+ int segment = (offset >> 16) & 0x7f;
+
+
+ if (m_setup)
+ {
+ if (offset & 0x002000)
+ {
+ the_seg = 0; // TRUSTED by Lisa Hardware Manual section 2.3.3 and MMU startup test
+ }
+ else
+ {
+ if (offset & 0x004000)
+ { /* write to MMU register */
+ logerror("write to segment registers (%X:%X) ", the_seg, segment);
+ if (offset & 0x000004)
+ { /* sorg register */
+ logerror("sorg, data = %X\n", data);
+ m_real_mmu_regs[the_seg][segment].sorg = data & 0xFFF;
+ m_mmu_regs[the_seg][segment].sorg = (data & 0x0fff) << 9;
+ }
+ else
+ { /* slim register */
+ logerror("slim, data = %X\n", data);
+ m_real_mmu_regs[the_seg][segment].slim = data & 0xFFF;
+ m_mmu_regs[the_seg][segment].slim = (~ (data << 9)) & 0x01ffff;
+ switch ((data & 0x0f00) >> 8)
+ {
+ case 0x4:
+ /*logerror("type : RAM stack r\n");*/
+ m_mmu_regs[the_seg][segment].type = RAM_stack_r;
+ break;
+ case 0x5:
+ /*logerror("type : RAM r\n");*/
+ m_mmu_regs[the_seg][segment].type = RAM_r;
+ break;
+ case 0x6:
+ /*logerror("type : RAM stack rw\n");*/
+ m_mmu_regs[the_seg][segment].type = RAM_stack_rw;
+ break;
+ case 0x7:
+ /*logerror("type : RAM rw\n");*/
+ m_mmu_regs[the_seg][segment].type = RAM_rw;
+ break;
+ case 0x8:
+ case 0x9: /* not documented, but used by ROMs (?) */
+ /*logerror("type : I/O\n");*/
+ m_mmu_regs[the_seg][segment].type = IO;
+ break;
+ case 0xC:
+ /*logerror("type : invalid\n");*/
+ m_mmu_regs[the_seg][segment].type = invalid;
+ break;
+ case 0xF:
+ logerror("type : special I/O\n");
+ m_mmu_regs[the_seg][segment].type = special_IO;
+ break;
+ default: /* "unpredictable results" */
+ logerror("type : unknown\n");
+ m_mmu_regs[the_seg][segment].type = invalid;
+ break;
+ }
+ }
+ }
+ else
+ { /* system ROMs : read-only ??? */
+ /* bus error ??? */
+ }
+ return;
+ }
+ }
+
+ if (cpu_get_reg(machine().device("maincpu"), M68K_SR) & 0x2000)
+ /* supervisor mode -> force register file 0 */
+ the_seg = 0;
+
+ {
+ /* offset in segment */
+ int seg_offset = (offset & 0x00ffff) << 1;
+
+ /* add revelant origin -> address */
+ offs_t address = (m_mmu_regs[the_seg][segment].sorg + seg_offset) & 0x1fffff;
+
+ switch (m_mmu_regs[the_seg][segment].type)
+ {
+
+ case RAM_stack_rw:
+ if (address <= m_mmu_regs[the_seg][segment].slim)
+ {
+ /* out of segment limits : bus error */
+
+ }
+ COMBINE_DATA((UINT16 *) (m_ram_ptr + address));
+ if (m_diag2)
+ {
+ if ((ACCESSING_BITS_0_7)
+ && ! (m_bad_parity_table[address >> 3] & (0x1 << (address & 0x7))))
+ {
+ m_bad_parity_table[address >> 3] |= 0x1 << (address & 0x7);
+ m_bad_parity_count++;
+ }
+ if ((ACCESSING_BITS_8_15)
+ && ! (m_bad_parity_table[address >> 3] & (0x2 << (address & 0x7))))
+ {
+ m_bad_parity_table[address >> 3] |= 0x2 << (address & 0x7);
+ m_bad_parity_count++;
+ }
+ }
+ else if (m_bad_parity_table[address >> 3] & (0x3 << (address & 0x7)))
+ {
+ if ((ACCESSING_BITS_0_7)
+ && (m_bad_parity_table[address >> 3] & (0x1 << (address & 0x7))))
+ {
+ m_bad_parity_table[address >> 3] &= ~ (0x1 << (address & 0x7));
+ m_bad_parity_count--;
+ }
+ if ((ACCESSING_BITS_8_15)
+ && (m_bad_parity_table[address >> 3] & (0x2 << (address & 0x7))))
+ {
+ m_bad_parity_table[address >> 3] &= ~ (0x2 << (address & 0x7));
+ m_bad_parity_count--;
+ }
+ }
+ break;
+
+ case RAM_rw:
+ if (address > m_mmu_regs[the_seg][segment].slim)
+ {
+ /* out of segment limits : bus error */
+
+ }
+ COMBINE_DATA((UINT16 *) (m_ram_ptr + address));
+ if (m_diag2)
+ {
+ if ((ACCESSING_BITS_0_7)
+ && ! (m_bad_parity_table[address >> 3] & (0x1 << (address & 0x7))))
+ {
+ m_bad_parity_table[address >> 3] |= 0x1 << (address & 0x7);
+ m_bad_parity_count++;
+ }
+ if ((ACCESSING_BITS_8_15)
+ && ! (m_bad_parity_table[address >> 3] & (0x2 << (address & 0x7))))
+ {
+ m_bad_parity_table[address >> 3] |= 0x2 << (address & 0x7);
+ m_bad_parity_count++;
+ }
+ }
+ else if (m_bad_parity_table[address >> 3] & (0x3 << (address & 0x7)))
+ {
+ if ((ACCESSING_BITS_0_7)
+ && (m_bad_parity_table[address >> 3] & (0x1 << (address & 0x7))))
+ {
+ m_bad_parity_table[address >> 3] &= ~ (0x1 << (address & 0x7));
+ m_bad_parity_count--;
+ }
+ if ((ACCESSING_BITS_8_15)
+ && (m_bad_parity_table[address >> 3] & (0x2 << (address & 0x7))))
+ {
+ m_bad_parity_table[address >> 3] &= ~ (0x2 << (address & 0x7));
+ m_bad_parity_count--;
+ }
+ }
+ break;
+
+ case IO:
+ lisa_IO_w(space, (address & 0x00ffff) >> 1, data, mem_mask);
+ break;
+
+ case RAM_stack_r: /* read-only */
+ case RAM_r: /* read-only */
+ case special_IO: /* system ROMs : read-only ??? */
+ case invalid: /* unmapped segment */
+ /* bus error */
+
+ break;
+ }
+ }
+}
+
+
+/**************************************************************************************\
+* I/O Slot Memory *
+* *
+* 000000 - 001FFF Slot 0 Low Decode *
+* 002000 - 003FFF Slot 0 High Decode *
+* 004000 - 005FFF Slot 1 Low Decode *
+* 006000 - 007FFF Slot 1 High Decode *
+* 008000 - 009FFF Slot 2 Low Decode *
+* 00A000 - 00BFFF Slot 2 High Decode *
+* 00C000 - 00CFFF Floppy Disk Controller shared RAM *
+* 00c001-00c7ff floppy disk control *
+* 00D000 - 00DFFF I/O Board Devices *
+* 00d000-00d3ff serial ports control *
+* 00d800-00dbff paralel port *
+* 00dc00-00dfff keyboard/mouse cops via *
+* 00E000 - 00FFFF CPU Board Devices *
+* 00e000-00e01e cpu board control *
+* 00e01f-00e7ff unused *
+* 00e8xx-video address latch *
+* 00f0xx memory error address latch *
+* 00f8xx status register *
+* *
+\**************************************************************************************/
+
+INLINE void cpu_board_control_access(running_machine &machine, offs_t offset)
+{
+ lisa_state *state = machine.driver_data<lisa_state>();
+ switch ((offset & 0x03ff) << 1)
+ {
+ case 0x0002: /* Set DIAG1 Latch */
+ case 0x0000: /* Reset DIAG1 Latch */
+ break;
+ case 0x0006: /* Set Diag2 Latch */
+ state->m_diag2 = 1;
+ break;
+ case 0x0004: /* ReSet Diag2 Latch */
+ state->m_diag2 = 0;
+ break;
+ case 0x000A: /* SEG1 Context Selection bit SET */
+ /*logerror("seg bit 0 set\n");*/
+ state->m_seg |= 1;
+ break;
+ case 0x0008: /* SEG1 Context Selection bit RESET */
+ /*logerror("seg bit 0 clear\n");*/
+ state->m_seg &= ~1;
+ break;
+ case 0x000E: /* SEG2 Context Selection bit SET */
+ /*logerror("seg bit 1 set\n");*/
+ state->m_seg |= 2;
+ break;
+ case 0x000C: /* SEG2 Context Selection bit RESET */
+ /*logerror("seg bit 1 clear\n");*/
+ state->m_seg &= ~2;
+ break;
+ case 0x0010: /* SETUP register SET */
+ logerror("setup SET PC=%x\n", cpu_get_pc(machine.device("maincpu")));
+ state->m_setup = 1;
+ break;
+ case 0x0012: /* SETUP register RESET */
+ logerror("setup UNSET PC=%x\n", cpu_get_pc(machine.device("maincpu")));
+ state->m_setup = 0;
+ break;
+ case 0x001A: /* Enable Vertical Retrace Interrupt */
+ logerror("enable retrace PC=%x\n", cpu_get_pc(machine.device("maincpu")));
+ state->m_VTMSK = 1;
+ break;
+ case 0x0018: /* Disable Vertical Retrace Interrupt */
+ logerror("disable retrace PC=%x\n", cpu_get_pc(machine.device("maincpu")));
+ state->m_VTMSK = 0;
+ set_VTIR(machine, 2);
+ break;
+ case 0x0016: /* Enable Soft Error Detect. */
+ case 0x0014: /* Disable Soft Error Detect. */
+ break;
+ case 0x001E: /* Enable Hard Error Detect */
+ state->m_test_parity = 1;
+ break;
+ case 0x001C: /* Disable Hard Error Detect */
+ state->m_test_parity = 0;
+ set_parity_error_pending(machine, 0);
+ break;
+ }
+}
+
+READ16_MEMBER(lisa_state::lisa_IO_r)
+{
+ via6522_device *via_0 = machine().device<via6522_device>("via6522_0");
+ via6522_device *via_1 = machine().device<via6522_device>("via6522_1");
+ int answer=0;
+
+ switch ((offset & 0x7000) >> 12)
+ {
+ case 0x0:
+ /* Slot 0 Low */
+ break;
+
+ case 0x1:
+ /* Slot 0 High */
+ break;
+
+ case 0x2:
+ /* Slot 1 Low */
+ break;
+
+ case 0x3:
+ /* Slot 1 High */
+ break;
+
+ case 0x4:
+ /* Slot 2 Low */
+ break;
+
+ case 0x5:
+ /* Slot 2 High */
+ break;
+
+ case 0x6:
+ if (! (offset & 0x800))
+ {
+ if (! (offset & 0x400))
+ {
+ /*if (ACCESSING_BITS_0_7)*/ /* Geez, who cares ? */
+ answer = m_fdc_ram[offset & 0x03ff] & 0xff; /* right ??? */
+ }
+ }
+ else
+ {
+ /* I/O Board Devices */
+ switch ((offset & 0x0600) >> 9)
+ {
+ case 0: /* serial ports control */
+ return m_scc->reg_r(space, offset&7);
+ break;
+
+ case 2: /* parallel port */
+ /* 1 VIA located at 0xD901 */
+ if (ACCESSING_BITS_0_7)
+ return via_1->read(space, (offset >> 2) & 0xf);
+ break;
+
+ case 3: /* keyboard/mouse cops via */
+ /* 1 VIA located at 0xDD81 */
+ if (ACCESSING_BITS_0_7)
+ return via_0->read(space, offset & 0xf);
+ break;
+ }
+ }
+ break;
+
+ case 0x7:
+ /* CPU Board Devices */
+ switch ((offset & 0x0C00) >> 10)
+ {
+ case 0x0: /* cpu board control */
+ cpu_board_control_access(machine(), offset & 0x03ff);
+ break;
+
+ case 0x1: /* Video Address Latch */
+ answer = m_video_address_latch;
+ break;
+
+ case 0x2: /* Memory Error Address Latch */
+ answer = m_mem_err_addr_latch;
+ break;
+
+ case 0x3: /* Status Register */
+ answer = 0;
+ if (! m_parity_error_pending)
+ answer |= 0x02;
+ if (m_VTIR<=1)
+// GFE : needs to be in phase with Serial NUM
+ {
+ int time_in_frame = machine().primary_screen->vpos();
+ if (m_features.has_mac_xl_video)
+ {
+ if ((time_in_frame >= 374) && (time_in_frame <= 392)) /* these values have not been tested */
+ { /* if VSyncing, read ROM 2nd half ? */
+ }
+ else
+ {
+ m_VTIR=0;
+ answer |= 0x04;
+ }
+ }
+ else
+ {
+ logerror("read status time=%x\n", time_in_frame);
+ if ((time_in_frame >= 364) && (time_in_frame <= 383)) /* these values are approximative */
+ { /* if VSyncing, read ROM 2nd half ? */
+ }
+ else
+ {
+ m_VTIR=0;
+ answer |= 0x04;
+ }
+ }
+
+ }
+ else
+ answer |= 0x04;
+ /* huh... we need to emulate some other bits */
+ logerror("read status PC=%x val=%x\n", cpu_get_pc(machine().device("maincpu")), answer);
+
+ break;
+ }
+ break;
+ }
+
+ return answer;
+}
+
+WRITE16_MEMBER(lisa_state::lisa_IO_w)
+{
+ via6522_device *via_0 = machine().device<via6522_device>("via6522_0");
+ via6522_device *via_1 = machine().device<via6522_device>("via6522_1");
+
+ switch ((offset & 0x7000) >> 12)
+ {
+ case 0x0:
+ /* Slot 0 Low */
+ break;
+
+ case 0x1:
+ /* Slot 0 High */
+ break;
+
+ case 0x2:
+ /* Slot 1 Low */
+ break;
+
+ case 0x3:
+ /* Slot 1 High */
+ break;
+
+ case 0x4:
+ /* Slot 2 Low */
+ break;
+
+ case 0x5:
+ /* Slot 2 High */
+ break;
+
+ case 0x6:
+ if (! (offset & 0x0800))
+ {
+ /* Floppy Disk Controller shared RAM */
+ if (! (offset & 0x0400))
+ {
+ if (ACCESSING_BITS_0_7)
+ m_fdc_ram[offset & 0x03ff] = data & 0xff;
+ }
+ }
+ else
+ {
+ /* I/O Board Devices */
+ switch ((offset & 0x0600) >> 9)
+ {
+ case 0: /* serial ports control */
+ m_scc->reg_w(space, offset&7, data);
+ break;
+
+ case 2: /* paralel port */
+ if (ACCESSING_BITS_0_7)
+ via_1->write(space, (offset >> 2) & 0xf, data & 0xff);
+ break;
+
+ case 3: /* keyboard/mouse cops via */
+ if (ACCESSING_BITS_0_7)
+ via_0->write(space, offset & 0xf, data & 0xff);
+ break;
+ }
+ }
+ break;
+
+ case 0x7:
+ /* CPU Board Devices */
+ switch ((offset & 0x0C00) >> 10)
+ {
+ case 0x0: /* cpu board control */
+ cpu_board_control_access(machine(), offset & 0x03ff);
+ break;
+
+ case 0x1: /* Video Address Latch */
+ /*logerror("video address latch write offs=%X, data=%X\n", offset, data);*/
+ COMBINE_DATA(& m_video_address_latch);
+ m_videoram_ptr = ((UINT16 *)m_ram_ptr) + ((m_video_address_latch << 6) & 0xfc000);
+ /*logerror("video address latch %X -> base address %X\n", m_video_address_latch,
+ (m_video_address_latch << 7) & 0x1f8000);*/
+ break;
+ }
+ break;
+ }
+}
+
+void lisa_state::set_scc_interrupt(bool value)
+{
+}
+
diff --git a/src/mess/machine/llc.c b/src/mess/machine/llc.c
new file mode 100644
index 00000000000..2a230d34c29
--- /dev/null
+++ b/src/mess/machine/llc.c
@@ -0,0 +1,245 @@
+/***************************************************************************
+
+ LLC driver by Miodrag Milanovic
+
+ 17/04/2009 Preliminary driver.
+
+****************************************************************************/
+
+
+#include "includes/llc.h"
+
+
+// LLC1 BASIC keyboard
+READ8_MEMBER(llc_state::llc1_port2_b_r)
+{
+ UINT8 retVal = 0;
+
+ if (m_term_status)
+ {
+ retVal = m_term_status;
+ m_term_status = 0;
+ }
+ else
+ retVal = m_term_data;
+
+ return retVal;
+}
+
+READ8_MEMBER(llc_state::llc1_port2_a_r)
+{
+ return 0;
+}
+
+// LLC1 Monitor keyboard
+READ8_MEMBER(llc_state::llc1_port1_a_r)
+{
+ UINT8 data = 0;
+ if (!BIT(m_porta, 4))
+ data = ioport("X4")->read();
+ if (!BIT(m_porta, 5))
+ data = ioport("X5")->read();
+ if (!BIT(m_porta, 6))
+ data = ioport("X6")->read();
+ if (data & 0xf0)
+ data = (data >> 4) | 0x80;
+
+ data |= (m_porta & 0x70);
+
+ // do not repeat key
+ if (data & 15)
+ {
+ if (data == m_llc1_key)
+ data &= 0x70;
+ else
+ m_llc1_key = data;
+ }
+ else
+ if ((data & 0x70) == (m_llc1_key & 0x70))
+ m_llc1_key = 0;
+
+ return data;
+}
+
+WRITE8_MEMBER(llc_state::llc1_port1_a_w)
+{
+ m_porta = data;
+}
+
+WRITE8_MEMBER(llc_state::llc1_port1_b_w)
+{
+ static UINT8 count = 0, digit = 0;
+
+ if (data == 0)
+ {
+ digit = 0;
+ count = 0;
+ }
+ else
+ count++;
+
+ if (count == 1)
+ output_set_digit_value(digit, data & 0x7f);
+ else
+ if (count == 3)
+ {
+ count = 0;
+ digit++;
+ }
+}
+
+// timer 0 irq does digit display, and timer 3 irq does scan of the
+// monitor keyboard.
+// No idea how the CTC is connected, so guessed.
+Z80CTC_INTERFACE( llc1_ctc_intf )
+{
+ DEVCB_CPU_INPUT_LINE("maincpu", INPUT_LINE_IRQ0),
+ DEVCB_DEVICE_LINE_MEMBER("z80ctc", z80ctc_device, trg1),
+ DEVCB_DEVICE_LINE_MEMBER("z80ctc", z80ctc_device, trg3),
+ DEVCB_NULL
+};
+
+Z80PIO_INTERFACE( llc1_z80pio1_intf )
+{
+ DEVCB_NULL, /* callback when change interrupt status */
+ DEVCB_DRIVER_MEMBER(llc_state, llc1_port1_a_r),
+ DEVCB_DRIVER_MEMBER(llc_state, llc1_port1_a_w),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DRIVER_MEMBER(llc_state, llc1_port1_b_w),
+ DEVCB_NULL
+};
+
+Z80PIO_INTERFACE( llc1_z80pio2_intf )
+{
+ DEVCB_NULL, /* callback when change interrupt status */
+ DEVCB_DRIVER_MEMBER(llc_state, llc1_port2_a_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DRIVER_MEMBER(llc_state, llc1_port2_b_r),
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+DRIVER_INIT_MEMBER(llc_state,llc1)
+{
+}
+
+MACHINE_RESET( llc1 )
+{
+ llc_state *state = machine.driver_data<llc_state>();
+ state->m_term_status = 0;
+ state->m_llc1_key = 0;
+}
+
+MACHINE_START(llc1)
+{
+}
+
+Z80CTC_INTERFACE( llc2_ctc_intf )
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+
+/* Driver initialization */
+DRIVER_INIT_MEMBER(llc_state,llc2)
+{
+ m_p_videoram.set_target( machine().device<ram_device>(RAM_TAG)->pointer() + 0xc000,m_p_videoram.bytes());
+}
+
+MACHINE_RESET( llc2 )
+{
+ llc_state *state = machine.driver_data<llc_state>();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ space->unmap_write(0x0000, 0x3fff);
+ state->membank("bank1")->set_base(machine.root_device().memregion("maincpu")->base());
+
+ space->unmap_write(0x4000, 0x5fff);
+ state->membank("bank2")->set_base(machine.root_device().memregion("maincpu")->base() + 0x4000);
+
+ space->unmap_write(0x6000, 0xbfff);
+ state->membank("bank3")->set_base(machine.root_device().memregion("maincpu")->base() + 0x6000);
+
+ space->install_write_bank(0xc000, 0xffff, "bank4");
+ state->membank("bank4")->set_base(machine.device<ram_device>(RAM_TAG)->pointer() + 0xc000);
+
+}
+
+WRITE8_MEMBER(llc_state::llc2_rom_disable_w)
+{
+ address_space *mem_space = machine().device("maincpu")->memory().space(AS_PROGRAM);
+ UINT8 *ram = machine().device<ram_device>(RAM_TAG)->pointer();
+
+ mem_space->install_write_bank(0x0000, 0xbfff, "bank1");
+ membank("bank1")->set_base(ram);
+
+ mem_space->install_write_bank(0x4000, 0x5fff, "bank2");
+ membank("bank2")->set_base(ram + 0x4000);
+
+ mem_space->install_write_bank(0x6000, 0xbfff, "bank3");
+ membank("bank3")->set_base(ram + 0x6000);
+
+ mem_space->install_write_bank(0xc000, 0xffff, "bank4");
+ membank("bank4")->set_base(ram + 0xc000);
+
+}
+
+WRITE8_MEMBER(llc_state::llc2_basic_enable_w)
+{
+ address_space *mem_space = machine().device("maincpu")->memory().space(AS_PROGRAM);
+ if (data & 0x02)
+ {
+ mem_space->unmap_write(0x4000, 0x5fff);
+ membank("bank2")->set_base(machine().root_device().memregion("maincpu")->base() + 0x10000);
+ }
+ else
+ {
+ mem_space->install_write_bank(0x4000, 0x5fff, "bank2");
+ membank("bank2")->set_base(machine().device<ram_device>(RAM_TAG)->pointer() + 0x4000);
+ }
+
+}
+
+READ8_MEMBER(llc_state::llc2_port1_b_r)
+{
+ return 0;
+}
+
+WRITE8_MEMBER(llc_state::llc2_port1_b_w)
+{
+ speaker_level_w(m_speaker, BIT(data, 6) );
+ m_rv = BIT(data, 5);
+}
+
+Z80PIO_INTERFACE( llc2_z80pio1_intf )
+{
+ DEVCB_NULL, /* callback when change interrupt status */
+ DEVCB_DEVICE_MEMBER(K7659_KEYBOARD_TAG, k7659_keyboard_device, read),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DRIVER_MEMBER(llc_state, llc2_port1_b_r),
+ DEVCB_DRIVER_MEMBER(llc_state, llc2_port1_b_w),
+ DEVCB_NULL
+};
+
+READ8_MEMBER(llc_state::llc2_port2_a_r)
+{
+ return 0; // bit 2 low or hangs on ^Z^X^C sequence
+}
+
+Z80PIO_INTERFACE( llc2_z80pio2_intf )
+{
+ DEVCB_NULL, /* callback when change interrupt status */
+ DEVCB_DRIVER_MEMBER(llc_state, llc2_port2_a_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
diff --git a/src/mess/machine/lux10828.c b/src/mess/machine/lux10828.c
new file mode 100644
index 00000000000..72b2f1d8346
--- /dev/null
+++ b/src/mess/machine/lux10828.c
@@ -0,0 +1,734 @@
+/**********************************************************************
+
+ Luxor 55-10828 "slow" floppy disk controller emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+/*
+
+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 FD1791_TAG "7a"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type LUXOR_55_10828 = &device_creator<luxor_55_10828_device>;
+
+
+//-------------------------------------------------
+// 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_INTERFACE( pio_intf )
+//-------------------------------------------------
+
+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 = ioport("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 |= wd17xx_hdld_r(device) << 6;
+ data |= 0x40;
+
+ // 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
+ wd17xx_dden_w(m_fdc, BIT(data, 3));
+
+ // head load timing
+// wd17xx_hlt_w(m_fdc, BIT(data, 5));
+}
+
+static Z80PIO_INTERFACE( pio_intf )
+{
+ DEVCB_CPU_INPUT_LINE(Z80_TAG, INPUT_LINE_IRQ0),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, luxor_55_10828_device, pio_pa_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, luxor_55_10828_device, pio_pa_w),
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, luxor_55_10828_device, pio_pb_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, luxor_55_10828_device, pio_pb_w),
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// z80_daisy_config daisy_chain
+//-------------------------------------------------
+
+static const z80_daisy_config daisy_chain[] =
+{
+ { Z80PIO_TAG },
+ { NULL }
+};
+
+
+//-------------------------------------------------
+// wd17xx_interface fdc_intf
+//-------------------------------------------------
+
+static const floppy_interface lux10828_floppy_interface =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ FLOPPY_STANDARD_5_25_DSDD,
+ LEGACY_FLOPPY_OPTIONS_NAME(default),
+ "floppy_5_25",
+ NULL
+};
+
+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);
+}
+
+static const wd17xx_interface fdc_intf =
+{
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, luxor_55_10828_device, fdc_intrq_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, luxor_55_10828_device, fdc_drq_w),
+ { FLOPPY_0, FLOPPY_1, NULL, NULL }
+};
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( luxor_55_10828 )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( luxor_55_10828 )
+ // main CPU
+ 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)
+
+ // devices
+ MCFG_Z80PIO_ADD(Z80PIO_TAG, XTAL_4MHz/2, pio_intf)
+ MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(lux10828_floppy_interface)
+ MCFG_FD1791_ADD(FD1791_TAG, fdc_intf)
+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),
+ device_abcbus_card_interface(mconfig, *this),
+ m_maincpu(*this, Z80_TAG),
+ m_pio(*this, Z80PIO_TAG),
+ m_fdc(*this, FD1791_TAG),
+ m_image0(*this, FLOPPY_0),
+ m_image1(*this, FLOPPY_1),
+ 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(ioport("S1")->read(), 0);
+
+ m_cs = (data == address);
+}
+
+
+//-------------------------------------------------
+// abcbus_rst -
+//-------------------------------------------------
+
+void luxor_55_10828_device::abcbus_rst(int state)
+{
+ if (!state)
+ {
+ device_reset();
+ }
+}
+
+
+//-------------------------------------------------
+// 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_utp -
+//-------------------------------------------------
+
+void luxor_55_10828_device::abcbus_utp(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
+ if (BIT(data, 0)) wd17xx_set_drive(m_fdc, 0);
+ if (BIT(data, 1)) wd17xx_set_drive(m_fdc, 1);
+// if (BIT(data, 2)) wd17xx_set_drive(m_fdc, 2);
+ m_sel0 = BIT(data, 0);
+ m_sel1 = BIT(data, 1);
+
+ // motor enable
+ int moton = BIT(data, 3);
+ floppy_mon_w(m_image0, moton);
+ floppy_mon_w(m_image1, moton);
+ floppy_drive_set_ready_state(m_image0, !moton, 1);
+ floppy_drive_set_ready_state(m_image1, !moton, 1);
+
+ // side selection
+ //wd17xx_set_side(m_fdc, BIT(data, 4));
+
+ // wait enable
+ m_wait_enable = BIT(data, 6);
+
+ // FDC master reset
+ wd17xx_mr_w(m_fdc, BIT(data, 7));
+}
+
+
+//-------------------------------------------------
+// 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
+
+ */
+
+ // interrupt
+// abcbus_int_w(m_bus, BIT(data, 0) ? CLEAR_LINE : ASSERT_LINE);
+
+ m_status = data & 0xfe;
+}
+
+
+//-------------------------------------------------
+// fdc_r -
+//-------------------------------------------------
+
+READ8_MEMBER( luxor_55_10828_device::fdc_r )
+{
+ UINT8 data = 0xff;
+
+ if (!m_wait_enable && !m_fdc_irq && !m_fdc_drq)
+ {
+ logerror("WAIT\n");
+ m_maincpu->set_input_line(Z80_INPUT_LINE_WAIT, ASSERT_LINE);
+ }
+
+ switch (offset & 0x03)
+ {
+ case 0: data = wd17xx_status_r(m_fdc, 0); break;
+ case 1: data = wd17xx_track_r(m_fdc, 0); break;
+ case 2: data = wd17xx_sector_r(m_fdc, 0); break;
+ case 3: data = wd17xx_data_r(m_fdc, 0); break;
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// fdc_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( luxor_55_10828_device::fdc_w )
+{
+ if (!m_wait_enable && !m_fdc_irq && !m_fdc_drq)
+ {
+ logerror("WAIT\n");
+ m_maincpu->set_input_line(Z80_INPUT_LINE_WAIT, ASSERT_LINE);
+ }
+
+ switch (offset & 0x03)
+ {
+ case 0: wd17xx_command_w(m_fdc, 0, data); break;
+ case 1: wd17xx_track_w(m_fdc, 0, data); break;
+ case 2: wd17xx_sector_w(m_fdc, 0, data); break;
+ case 3: wd17xx_data_w(m_fdc, 0, data); break;
+ }
+}
+
+
+
+//**************************************************************************
+// LUXOR 55 10828 DEVICE INPUT DEFAULTS
+//**************************************************************************
+
+//-------------------------------------------------
+// DEVICE_INPUT_DEFAULTS( abc830_slow )
+//-------------------------------------------------
+
+DEVICE_INPUT_DEFAULTS_START( abc830_slow )
+ DEVICE_INPUT_DEFAULTS("SW1", 0x0f, 0x03)
+ DEVICE_INPUT_DEFAULTS("S1", 0x01, 0x01)
+DEVICE_INPUT_DEFAULTS_END
diff --git a/src/mess/machine/lux10828.h b/src/mess/machine/lux10828.h
new file mode 100644
index 00000000000..5f4b46cbce1
--- /dev/null
+++ b/src/mess/machine/lux10828.h
@@ -0,0 +1,130 @@
+/**********************************************************************
+
+ Luxor 55-10828 "slow" floppy disk controller emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#pragma once
+
+#ifndef __LUXOR_55_10828__
+#define __LUXOR_55_10828__
+
+
+#include "emu.h"
+#include "cpu/z80/z80.h"
+#include "cpu/z80/z80daisy.h"
+#include "formats/basicdsk.h"
+#include "imagedev/flopdrv.h"
+#include "machine/abcbus.h"
+#include "machine/devhelpr.h"
+#include "machine/wd17xx.h"
+#include "machine/z80pio.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LUXOR_55_10828_TAG "luxor_55_10828"
+
+
+#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 );
+
+ // 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();
+ virtual void device_config_complete() { m_shortname = "lux10828"; }
+
+ // device_abcbus_interface overrides
+ virtual void abcbus_cs(UINT8 data);
+ virtual void abcbus_rst(int state);
+ virtual UINT8 abcbus_inp();
+ virtual void abcbus_utp(UINT8 data);
+ virtual UINT8 abcbus_stat();
+ virtual void abcbus_c1(UINT8 data);
+ virtual void abcbus_c3(UINT8 data);
+
+private:
+ required_device<cpu_device> m_maincpu;
+ required_device<z80pio_device> m_pio;
+ required_device<device_t> m_fdc;
+ required_device<legacy_floppy_image_device> m_image0;
+ required_device<legacy_floppy_image_device> m_image1;
+
+ bool m_cs; // card selected
+ UINT8 m_status; // ABC BUS status
+ UINT8 m_data; // ABC BUS data
+ int m_fdc_irq; // floppy interrupt
+ int m_fdc_drq; // floppy data request
+ int m_wait_enable; // wait enable
+ int m_sel0; // drive select 0
+ int m_sel1; // drive select 1
+
+ UINT8 m_sw1; // single/double sided/density
+ UINT8 m_drive_type; // drive type
+ UINT8 m_s1; // ABC bus address
+};
+
+
+// device type definition
+extern const device_type LUXOR_55_10828;
+
+
+// default input ports
+extern const input_device_default DEVICE_INPUT_DEFAULTS_NAME( abc830_slow )[];
+
+
+
+#endif
diff --git a/src/mess/machine/lux21046.c b/src/mess/machine/lux21046.c
new file mode 100644
index 00000000000..de30bb01ce6
--- /dev/null
+++ b/src/mess/machine/lux21046.c
@@ -0,0 +1,792 @@
+/**********************************************************************
+
+ Luxor 55-21046 "fast" floppy disk controller emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+/*
+
+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 |
+| S1 LS240 |
+| |
+| LS244 SW3 DM8131 |
+| |
+| |
+|--|-----------------------------|--|
+ |------------CON1-------------|
+
+Notes:
+ All IC's shown.
+
+ ROM - Toshiba TMM27128D-20 16Kx8 EPROM "CNTR 1.07 6490318-07"
+ 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:? B:ABCBUS)
+ S3 - Interface type (A:? B:ABCBUS)
+ S5 - Interface type (A:? 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
+
+*/
+
+/*
+
+ TODO:
+
+ - 8" floppy is not supported, but there are no dumps available either
+
+*/
+
+#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<luxor_55_21046_device>;
+
+
+//-------------------------------------------------
+// ROM( luxor_55_21046 )
+//-------------------------------------------------
+
+ROM_START( luxor_55_21046 )
+ ROM_REGION( 0x4000, Z80_TAG, 0 ) // A13 is always high, thus loading at 0x2000
+ ROM_LOAD_OPTIONAL( "cntr 108.6cd", 0x2000, 0x2000, CRC(229764cb) SHA1(a2e2f6f49c31b827efc62f894de9a770b65d109d) ) // 1986-03-12
+ ROM_LOAD_OPTIONAL( "diab 207.6cd", 0x2000, 0x2000, CRC(86622f52) SHA1(61ad271de53152c1640c0b364fce46d1b0b4c7e2) ) // 1987-06-24
+ ROM_LOAD( "cntr 1.07 6490318-07.6cd", 0x0000, 0x4000, CRC(db8c1c0e) SHA1(8bccd5bc72124984de529ee058df779f06d2c1d5) ) // 1985-07-03
+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)
+ 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(0x00, 0x00) AM_MIRROR(0xff0f) AM_READ(_3d_r)
+ AM_RANGE(0x10, 0x10) AM_MIRROR(0xff0f) AM_WRITE(_4d_w)
+ AM_RANGE(0x20, 0x20) AM_MIRROR(0xff0f) AM_WRITE(_4b_w)
+ AM_RANGE(0x30, 0x30) AM_MIRROR(0xff0f) AM_WRITE(_9b_w)
+ AM_RANGE(0x40, 0x40) AM_MIRROR(0xff0f) AM_WRITE(_8a_w)
+ AM_RANGE(0x50, 0x50) AM_MIRROR(0xff0f) AM_MASK(0xff00) AM_READ(_9a_r)
+ AM_RANGE(0x60, 0x63) AM_MIRROR(0xff0c) AM_DEVREAD_LEGACY(SAB1793_TAG, wd17xx_r)
+ AM_RANGE(0x70, 0x73) AM_MIRROR(0xff0c) AM_DEVWRITE_LEGACY(SAB1793_TAG, wd17xx_w)
+ AM_RANGE(0x80, 0x80) AM_MIRROR(0xff0f) AM_DEVREADWRITE_LEGACY(Z80DMA_TAG, z80dma_r, z80dma_w)
+ADDRESS_MAP_END
+
+
+//-------------------------------------------------
+// Z80DMA_INTERFACE( dma_intf )
+//-------------------------------------------------
+
+/*
+
+ 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);
+}
+
+static UINT8 memory_read_byte(address_space *space, offs_t address) { return space->read_byte(address); }
+static void memory_write_byte(address_space *space, offs_t address, UINT8 data) { space->write_byte(address, data); }
+
+static Z80DMA_INTERFACE( dma_intf )
+{
+ DEVCB_CPU_INPUT_LINE(Z80_TAG, INPUT_LINE_HALT),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, luxor_55_21046_device, dma_int_w),
+ DEVCB_NULL,
+ DEVCB_MEMORY_HANDLER(Z80_TAG, PROGRAM, memory_read_byte),
+ DEVCB_MEMORY_HANDLER(Z80_TAG, PROGRAM, memory_write_byte),
+ DEVCB_MEMORY_HANDLER(Z80_TAG, IO, memory_read_byte),
+ DEVCB_MEMORY_HANDLER(Z80_TAG, IO, memory_write_byte)
+};
+
+
+//-------------------------------------------------
+// wd17xx_interface fdc_intf
+//-------------------------------------------------
+
+static const floppy_interface lux21046_floppy_interface =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ FLOPPY_STANDARD_5_25_DSDD,
+ LEGACY_FLOPPY_OPTIONS_NAME(default),
+ "floppy_5_25",
+ NULL
+};
+
+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);
+}
+
+static const wd17xx_interface fdc_intf =
+{
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, luxor_55_21046_device, fdc_intrq_w),
+ DEVCB_DEVICE_LINE(Z80DMA_TAG, z80dma_rdy_w),
+ { FLOPPY_0, FLOPPY_1, NULL, NULL }
+};
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( luxor_55_21046 )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( luxor_55_21046 )
+ // main CPU
+ MCFG_CPU_ADD(Z80_TAG, Z80, XTAL_16MHz/4)
+ MCFG_CPU_PROGRAM_MAP(luxor_55_21046_mem)
+ MCFG_CPU_IO_MAP(luxor_55_21046_io)
+
+ // devices
+ MCFG_Z80DMA_ADD(Z80DMA_TAG, XTAL_16MHz/4, dma_intf)
+ MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(lux21046_floppy_interface)
+ MCFG_FD1793_ADD(SAB1793_TAG, fdc_intf)
+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 );
+}
+
+
+//-------------------------------------------------
+// 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, 0x00, "Drive 0 Sided" ) PORT_DIPLOCATION("SW1:1") PORT_CONDITION("SW3", 0x7f, EQUALS, 0x2d)
+ PORT_DIPSETTING( 0x00, DEF_STR( Single ) )
+ PORT_DIPSETTING( 0x01, "Double" )
+ PORT_DIPNAME( 0x02, 0x00, "Drive 1 Sided" ) PORT_DIPLOCATION("SW1:2") PORT_CONDITION("SW3", 0x7f, EQUALS, 0x2d)
+ PORT_DIPSETTING( 0x00, DEF_STR( Single ) )
+ PORT_DIPSETTING( 0x02, "Double" )
+ PORT_DIPNAME( 0x04, 0x00, "Drive 0 Density" ) PORT_DIPLOCATION("SW1:3") PORT_CONDITION("SW3", 0x7f, EQUALS, 0x2d)
+ PORT_DIPSETTING( 0x00, DEF_STR( Single ) )
+ PORT_DIPSETTING( 0x04, "Double" )
+ PORT_DIPNAME( 0x08, 0x00, "Drive 1 Density" ) PORT_DIPLOCATION("SW1:4") PORT_CONDITION("SW3", 0x7f, EQUALS, 0x2d)
+ PORT_DIPSETTING( 0x00, DEF_STR( Single ) )
+ PORT_DIPSETTING( 0x08, "Double" )
+ // ABC 832/834/850
+ PORT_DIPNAME( 0x01, 0x01, "Drive 0 Sided" ) PORT_DIPLOCATION("SW1:1") PORT_CONDITION("SW3", 0x7f, EQUALS, 0x2c)
+ PORT_DIPSETTING( 0x00, DEF_STR( Single ) )
+ PORT_DIPSETTING( 0x01, "Double" )
+ PORT_DIPNAME( 0x02, 0x02, "Drive 1 Sided" ) PORT_DIPLOCATION("SW1:2") PORT_CONDITION("SW3", 0x7f, EQUALS, 0x2c)
+ PORT_DIPSETTING( 0x00, DEF_STR( Single ) )
+ PORT_DIPSETTING( 0x02, "Double" )
+ PORT_DIPNAME( 0x04, 0x00, "Drive 0 Tracks" ) PORT_DIPLOCATION("SW1:3") PORT_CONDITION("SW3", 0x7f, EQUALS, 0x2c)
+ PORT_DIPSETTING( 0x00, "80" )
+ PORT_DIPSETTING( 0x04, "40" )
+ PORT_DIPNAME( 0x08, 0x00, "Drive 1 Tracks" ) PORT_DIPLOCATION("SW1:4") PORT_CONDITION("SW3", 0x7f, EQUALS, 0x2c)
+ PORT_DIPSETTING( 0x00, "80" )
+ PORT_DIPSETTING( 0x08, "40" )
+
+ 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)" )
+ PORT_DIPSETTING( 0x2d, "45 (ABC 830)" )
+ PORT_DIPSETTING( 0x2e, "46 (ABC 838)" )
+
+ PORT_START("S6")
+ PORT_DIPNAME( 0x01, 0x01, "RAM Size" ) PORT_DIPLOCATION("S6:1")
+ PORT_DIPSETTING( 0x00, "2 KB" )
+ PORT_DIPSETTING( 0x01, "8 KB" )
+
+ PORT_START("S8")
+ PORT_DIPNAME( 0x01, 0x01, "Drive Type" ) PORT_DIPLOCATION("S8:1")
+ PORT_DIPSETTING( 0x00, "8\"" )
+ PORT_DIPSETTING( 0x01, "5.25\"" )
+
+ PORT_START("S9")
+ PORT_DIPNAME( 0x01, 0x01, "RDY Pin" ) PORT_DIPLOCATION("S9:1")
+ 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 );
+}
+
+
+
+//**************************************************************************
+// 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),
+ device_abcbus_card_interface(mconfig, *this),
+ m_maincpu(*this, Z80_TAG),
+ m_dma(*this, Z80DMA_TAG),
+ m_fdc(*this, SAB1793_TAG),
+ m_image0(*this, FLOPPY_0),
+ m_image1(*this, FLOPPY_1),
+ m_cs(false),
+ m_fdc_irq(0),
+ m_dma_irq(0),
+ m_busy(0),
+ m_force_busy(0)
+{
+}
+
+
+//-------------------------------------------------
+// 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_data_in));
+ save_item(NAME(m_data_out));
+ save_item(NAME(m_fdc_irq));
+ save_item(NAME(m_dma_irq));
+ save_item(NAME(m_busy));
+ save_item(NAME(m_force_busy));
+
+ // patch out sector skew table
+/* UINT8 *rom = memregion(Z80_TAG)->base();
+
+ for (int i = 0; i < 16; i++)
+ rom[0x2dd3 + i] = i + 1;*/
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void luxor_55_21046_device::device_reset()
+{
+ m_cs = false;
+
+ floppy_mon_w(m_image0, ASSERT_LINE);
+ floppy_mon_w(m_image1, ASSERT_LINE);
+ floppy_drive_set_ready_state(m_image0, 1, 1);
+ floppy_drive_set_ready_state(m_image1, 1, 1);
+}
+
+
+
+//**************************************************************************
+// ABC BUS INTERFACE
+//**************************************************************************
+
+//-------------------------------------------------
+// abcbus_cs -
+//-------------------------------------------------
+
+void luxor_55_21046_device::abcbus_cs(UINT8 data)
+{
+ m_cs = (data == ioport("SW3")->read());
+}
+
+
+//-------------------------------------------------
+// abcbus_rst -
+//-------------------------------------------------
+
+void luxor_55_21046_device::abcbus_rst(int state)
+{
+ if (!state)
+ {
+ device_reset();
+ }
+}
+
+
+//-------------------------------------------------
+// abcbus_stat -
+//-------------------------------------------------
+
+UINT8 luxor_55_21046_device::abcbus_stat()
+{
+ UINT8 data = 0;
+
+ if (m_cs)
+ {
+ data = (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_data_out;
+ m_busy = 1;
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// abcbus_utp -
+//-------------------------------------------------
+
+void luxor_55_21046_device::abcbus_utp(UINT8 data)
+{
+ if (m_cs)
+ {
+ m_data_in = 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)
+ {
+ m_maincpu->reset();
+ }
+}
+
+
+
+//**************************************************************************
+// IMPLEMENTATION
+//**************************************************************************
+
+//-------------------------------------------------
+// 3d_r -
+//-------------------------------------------------
+
+READ8_MEMBER( luxor_55_21046_device::_3d_r )
+{
+ if (BIT(m_status, 0))
+ {
+ m_busy = 0;
+ }
+
+ return m_data_in;
+}
+
+
+//-------------------------------------------------
+// 4d_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( luxor_55_21046_device::_4d_w )
+{
+ if (BIT(m_status, 0))
+ {
+ m_busy = 0;
+ }
+
+ m_data_out = 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;
+
+ // busy
+ if (!BIT(m_status, 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
+ if (BIT(data, 0)) wd17xx_set_drive(m_fdc, 0);
+ if (BIT(data, 1)) wd17xx_set_drive(m_fdc, 1);
+ //if (BIT(data, 2)) wd17xx_set_drive(m_fdc, 2);
+
+ // motor enable
+ int mtron = BIT(data, 3);
+ floppy_mon_w(m_image0, !mtron);
+ floppy_mon_w(m_image1, !mtron);
+ floppy_drive_set_ready_state(m_image0, mtron, 1);
+ floppy_drive_set_ready_state(m_image1, mtron, 1);
+
+ // side select
+ wd17xx_set_side(m_fdc, 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 READY signal polarity (0=inverted)
+ 4 FDC9229 P2
+ 5 FDC9229 P1
+ 6
+ 7
+
+ FDC9229 P0 is grounded
+
+ */
+
+ // FDC master reset
+ wd17xx_mr_w(m_fdc, BIT(data, 0));
+
+ // density select
+ wd17xx_dden_w(m_fdc, BIT(data, 1));
+}
+
+
+//-------------------------------------------------
+// 9a_r -
+//-------------------------------------------------
+
+READ8_MEMBER( luxor_55_21046_device::_9a_r )
+{
+ /*
+
+ bit signal description
+
+ 0 busy controller busy
+ 1 _FD2S double-sided disk
+ 2 SW2
+ 3 _DCG ? disk changed
+ 4 SW1-1
+ 5 SW1-2
+ 6 SW1-3
+ 7 SW1-4
+
+ */
+
+ UINT8 data = 0;
+
+ // busy
+ data |= m_busy;
+
+ // SW1
+ UINT8 sw1 = ioport("SW1")->read() & 0x0f;
+
+ data |= sw1 << 4;
+
+ // SW2
+ UINT8 sw2 = ioport("SW2")->read() & 0x0f;
+
+ // TTL inputs float high so DIP switch in off position equals 1
+ 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;
+
+ return data ^ 0xff;
+}
+
+
+//**************************************************************************
+// LUXOR 55 21046 DEVICE INPUT DEFAULTS
+//**************************************************************************
+
+//-------------------------------------------------
+// DEVICE_INPUT_DEFAULTS( abc830_fast_intf )
+//-------------------------------------------------
+
+DEVICE_INPUT_DEFAULTS_START( abc830_fast )
+ DEVICE_INPUT_DEFAULTS("SW1", 0x0f, 0x03)
+ DEVICE_INPUT_DEFAULTS("SW2", 0x0f, DRIVE_BASF_6106_08)
+ DEVICE_INPUT_DEFAULTS("SW3", 0x7f, ADDRESS_ABC830)
+DEVICE_INPUT_DEFAULTS_END
+
+
+//-------------------------------------------------
+// DEVICE_INPUT_DEFAULTS( abc832_fast )
+//-------------------------------------------------
+
+DEVICE_INPUT_DEFAULTS_START( abc832_fast )
+ DEVICE_INPUT_DEFAULTS("SW1", 0x0f, 0x03)
+ DEVICE_INPUT_DEFAULTS("SW2", 0x0f, DRIVE_TEAC_FD55F)
+ DEVICE_INPUT_DEFAULTS("SW3", 0x7f, ADDRESS_ABC832)
+DEVICE_INPUT_DEFAULTS_END
+
+
+//-------------------------------------------------
+// DEVICE_INPUT_DEFAULTS( abc834_fast )
+//-------------------------------------------------
+
+DEVICE_INPUT_DEFAULTS_START( abc834_fast )
+ DEVICE_INPUT_DEFAULTS("SW1", 0x0f, 0x03)
+ DEVICE_INPUT_DEFAULTS("SW2", 0x0f, DRIVE_TEAC_FD55F)
+ DEVICE_INPUT_DEFAULTS("SW3", 0x7f, ADDRESS_ABC832)
+DEVICE_INPUT_DEFAULTS_END
+
+
+//-------------------------------------------------
+// DEVICE_INPUT_DEFAULTS( abc838_fast )
+//-------------------------------------------------
+
+DEVICE_INPUT_DEFAULTS_START( abc838_fast )
+ DEVICE_INPUT_DEFAULTS("SW1", 0x0f, 0x03)
+ DEVICE_INPUT_DEFAULTS("SW2", 0x0f, DRIVE_BASF_6105)
+ DEVICE_INPUT_DEFAULTS("SW3", 0x7f, ADDRESS_ABC838)
+DEVICE_INPUT_DEFAULTS_END
+
+
+//-------------------------------------------------
+// DEVICE_INPUT_DEFAULTS( abc850_fast )
+//-------------------------------------------------
+
+DEVICE_INPUT_DEFAULTS_START( abc850_fast )
+ DEVICE_INPUT_DEFAULTS("SW1", 0x0f, 0x03)
+ DEVICE_INPUT_DEFAULTS("SW2", 0x0f, DRIVE_BASF_6138)
+ DEVICE_INPUT_DEFAULTS("SW3", 0x7f, ADDRESS_ABC830)
+DEVICE_INPUT_DEFAULTS_END
diff --git a/src/mess/machine/lux21046.h b/src/mess/machine/lux21046.h
new file mode 100644
index 00000000000..6750b2aa47c
--- /dev/null
+++ b/src/mess/machine/lux21046.h
@@ -0,0 +1,126 @@
+/**********************************************************************
+
+ Luxor 55-21046 "fast" floppy disk controller emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#pragma once
+
+#ifndef __LUXOR_55_21046__
+#define __LUXOR_55_21046__
+
+
+#include "emu.h"
+#include "cpu/z80/z80.h"
+#include "cpu/z80/z80daisy.h"
+#include "formats/basicdsk.h"
+#include "imagedev/flopdrv.h"
+#include "machine/abcbus.h"
+#include "machine/devhelpr.h"
+#include "machine/wd17xx.h"
+#include "machine/z80dma.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LUXOR_55_21046_TAG "luxor_55_21046"
+
+
+#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, 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( _3d_r );
+ DECLARE_WRITE8_MEMBER( _4d_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_WRITE_LINE_MEMBER( fdc_intrq_w );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "lux21046"; }
+
+ // device_abcbus_interface overrides
+ virtual void abcbus_cs(UINT8 data);
+ virtual void abcbus_rst(int state);
+ virtual UINT8 abcbus_inp();
+ virtual void abcbus_utp(UINT8 data);
+ virtual UINT8 abcbus_stat();
+ virtual void abcbus_c1(UINT8 data);
+ virtual void abcbus_c3(UINT8 data);
+
+private:
+ required_device<cpu_device> m_maincpu;
+ required_device<z80dma_device> m_dma;
+ required_device<device_t> m_fdc;
+ required_device<legacy_floppy_image_device> m_image0;
+ required_device<legacy_floppy_image_device> m_image1;
+
+ bool m_cs; // card selected
+ UINT8 m_status; // ABC BUS status
+ UINT8 m_data_in; // ABC BUS data in
+ UINT8 m_data_out; // ABC BUS data out
+ int m_fdc_irq; // FDC interrupt
+ int m_dma_irq; // DMA interrupt
+ int m_busy; // busy bit
+ int m_force_busy; // force busy bit
+};
+
+
+// device type definition
+extern const device_type LUXOR_55_21046;
+
+
+// default input ports
+extern const input_device_default DEVICE_INPUT_DEFAULTS_NAME( abc830_fast )[];
+extern const input_device_default DEVICE_INPUT_DEFAULTS_NAME( abc832_fast )[];
+extern const input_device_default DEVICE_INPUT_DEFAULTS_NAME( abc834_fast )[];
+extern const input_device_default DEVICE_INPUT_DEFAULTS_NAME( abc838_fast )[];
+extern const input_device_default DEVICE_INPUT_DEFAULTS_NAME( abc850_fast )[];
+
+
+
+#endif
diff --git a/src/mess/machine/lux4105.c b/src/mess/machine/lux4105.c
new file mode 100644
index 00000000000..4891fa17d6f
--- /dev/null
+++ b/src/mess/machine/lux4105.c
@@ -0,0 +1,408 @@
+/**********************************************************************
+
+ Luxor 4105 SASI hard disk controller emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#include "lux4105.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define SASIBUS_TAG "sasi"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type LUXOR_4105 = &device_creator<luxor_4105_device>;
+
+
+//-------------------------------------------------
+// SCSIBus_interface sasi_intf
+//-------------------------------------------------
+
+static const SCSIConfigTable sasi_dev_table =
+{
+ 1,
+ {
+ { SCSI_ID_0, "harddisk0" }
+ }
+};
+
+WRITE_LINE_MEMBER( luxor_4105_device::sasi_bsy_w )
+{
+ if (!state)
+ {
+ scsi_sel_w(m_sasibus, 1);
+ }
+}
+
+WRITE_LINE_MEMBER( luxor_4105_device::sasi_io_w )
+{
+ if (!m_io && state)
+ {
+ scsi_data_w(m_sasibus, m_data);
+ }
+
+ m_io = state;
+
+ update_trrq_int();
+}
+
+WRITE_LINE_MEMBER( luxor_4105_device::sasi_req_w )
+{
+ if (state)
+ {
+ scsi_ack_w(m_sasibus, 1);
+ }
+
+ update_trrq_int();
+}
+
+static const SCSIBus_interface sasi_intf =
+{
+ &sasi_dev_table,
+ NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, luxor_4105_device, sasi_bsy_w),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, luxor_4105_device, sasi_io_w),
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, luxor_4105_device, sasi_req_w),
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( luxor_4105 )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( luxor_4105 )
+ MCFG_SCSIBUS_ADD(SASIBUS_TAG, sasi_intf)
+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 = scsi_cd_r(m_sasibus);
+ int req = scsi_req_r(m_sasibus);
+ int trrq = !(cd & !req);
+
+ if (BIT(m_dma, 5))
+ {
+ m_slot->int_w(trrq ? CLEAR_LINE : ASSERT_LINE);
+ }
+ else
+ {
+ m_slot->int_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),
+ device_abc1600bus_card_interface(mconfig, *this),
+ m_sasibus(*this, SASIBUS_TAG),
+ m_io(1)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void luxor_4105_device::device_start()
+{
+ m_slot = dynamic_cast<abc1600bus_slot_device *>(owner());
+
+ // state saving
+ save_item(NAME(m_cs));
+ save_item(NAME(m_io));
+ save_item(NAME(m_data));
+ save_item(NAME(m_dma));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void luxor_4105_device::device_reset()
+{
+ init_scsibus(m_sasibus, 512);
+
+ m_cs = 0;
+ m_data = 0;
+ m_dma = 0;
+
+ scsi_rst_w(m_sasibus, 0);
+ scsi_rst_w(m_sasibus, 1);
+
+ m_slot->trrq_w(1);
+}
+
+
+
+//**************************************************************************
+// ABC 1600 BUS INTERFACE
+//**************************************************************************
+
+//-------------------------------------------------
+// abc1600bus_cs -
+//-------------------------------------------------
+
+void luxor_4105_device::abc1600bus_cs(UINT8 data)
+{
+ m_cs = (data == ioport("5E")->read());
+}
+
+
+//-------------------------------------------------
+// abc1600bus_csb -
+//-------------------------------------------------
+
+int luxor_4105_device::abc1600bus_csb()
+{
+ return !m_cs;
+}
+
+
+//-------------------------------------------------
+// abc1600bus_rst -
+//-------------------------------------------------
+
+void luxor_4105_device::abc1600bus_brst()
+{
+ device_reset();
+}
+
+
+//-------------------------------------------------
+// abc1600bus_stat -
+//-------------------------------------------------
+
+UINT8 luxor_4105_device::abc1600bus_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 = !scsi_bsy_r(m_sasibus);
+ data |= !scsi_req_r(m_sasibus) << 2;
+ data |= !scsi_cd_r(m_sasibus) << 3;
+ data |= !scsi_io_r(m_sasibus) << 6;
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// abc1600bus_inp -
+//-------------------------------------------------
+
+UINT8 luxor_4105_device::abc1600bus_inp()
+{
+ UINT8 data = 0xff;
+
+ if (m_cs)
+ {
+ if (scsi_bsy_r(m_sasibus))
+ {
+ ioport("1E")->read();
+ }
+ else
+ {
+ if (!scsi_io_r(m_sasibus))
+ {
+ data = scsi_data_r(m_sasibus);
+
+ if (!scsi_req_r(m_sasibus))
+ {
+ scsi_ack_w(m_sasibus, 0);
+ }
+ }
+ }
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// abc1600bus_utp -
+//-------------------------------------------------
+
+void luxor_4105_device::abc1600bus_out(UINT8 data)
+{
+ if (m_cs)
+ {
+ m_data = data;
+
+ if (scsi_io_r(m_sasibus))
+ {
+ scsi_data_w(m_sasibus, m_data);
+
+ if (!scsi_req_r(m_sasibus))
+ {
+ scsi_ack_w(m_sasibus, 0);
+ }
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// abc1600bus_c1 -
+//-------------------------------------------------
+
+void luxor_4105_device::abc1600bus_c1(UINT8 data)
+{
+ if (m_cs)
+ {
+ scsi_sel_w(m_sasibus, 0);
+ }
+}
+
+
+//-------------------------------------------------
+// abc1600bus_c3 -
+//-------------------------------------------------
+
+void luxor_4105_device::abc1600bus_c3(UINT8 data)
+{
+ if (m_cs)
+ {
+ m_data = 0;
+ m_dma = 0;
+
+ scsi_rst_w(m_sasibus, 0);
+ scsi_rst_w(m_sasibus, 1);
+ }
+}
+
+
+//-------------------------------------------------
+// abc1600bus_c4 -
+//-------------------------------------------------
+
+void luxor_4105_device::abc1600bus_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/mess/machine/lux4105.h b/src/mess/machine/lux4105.h
new file mode 100644
index 00000000000..990ff49c03a
--- /dev/null
+++ b/src/mess/machine/lux4105.h
@@ -0,0 +1,88 @@
+/**********************************************************************
+
+ Luxor 4105 SASI hard disk controller emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#pragma once
+
+#ifndef __LUXOR_4105__
+#define __LUXOR_4105__
+
+
+#include "emu.h"
+#include "abc1600_bus.h"
+#include "machine/scsibus.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LUXOR_4105_TAG "luxor_4105"
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> luxor_4105_device
+
+class luxor_4105_device : public device_t,
+ public device_abc1600bus_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( sasi_bsy_w );
+ DECLARE_WRITE_LINE_MEMBER( sasi_io_w );
+ DECLARE_WRITE_LINE_MEMBER( sasi_req_w );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "luxor_4105"; }
+
+ // device_abc1600bus_interface overrides
+ virtual void abc1600bus_cs(UINT8 data);
+ virtual int abc1600bus_csb();
+ virtual void abc1600bus_brst();
+ virtual UINT8 abc1600bus_inp();
+ virtual void abc1600bus_out(UINT8 data);
+ virtual UINT8 abc1600bus_stat();
+ virtual void abc1600bus_c1(UINT8 data);
+ virtual void abc1600bus_c3(UINT8 data);
+ virtual void abc1600bus_c4(UINT8 data);
+
+private:
+ inline void update_trrq_int();
+
+ abc1600bus_slot_device *m_slot;
+
+ required_device<device_t> m_sasibus;
+
+ int m_cs;
+ int m_io;
+ UINT8 m_data;
+ UINT8 m_dma;
+};
+
+
+// device type definition
+extern const device_type LUXOR_4105;
+
+
+
+#endif
diff --git a/src/mess/machine/lviv.c b/src/mess/machine/lviv.c
new file mode 100644
index 00000000000..c628005c836
--- /dev/null
+++ b/src/mess/machine/lviv.c
@@ -0,0 +1,372 @@
+/***************************************************************************
+
+ machine.c
+
+ Functions to emulate general aspects of PK-01 Lviv (RAM, ROM, interrupts,
+ I/O ports)
+
+ Krzysztof Strzecha
+
+***************************************************************************/
+
+#include "emu.h"
+#include "imagedev/cassette.h"
+#include "imagedev/snapquik.h"
+#include "cpu/i8085/i8085.h"
+#include "machine/i8255.h"
+#include "includes/lviv.h"
+#include "sound/speaker.h"
+#include "machine/ram.h"
+
+#define LVIV_SNAPSHOT_SIZE 82219
+
+
+
+
+
+static void lviv_update_memory (running_machine &machine)
+{
+ lviv_state *state = machine.driver_data<lviv_state>();
+ UINT8 *ram = machine.device<ram_device>(RAM_TAG)->pointer();
+
+ if (state->m_ppi_port_outputs[0][2] & 0x02)
+ {
+ state->membank("bank1")->set_base(ram);
+ state->membank("bank2")->set_base(ram + 0x4000);
+ }
+ else
+ {
+ state->membank("bank1")->set_base(ram + 0x8000);
+ state->membank("bank2")->set_base(ram + 0xc000);
+ }
+}
+
+static TIMER_CALLBACK( lviv_reset )
+{
+ machine.schedule_soft_reset();
+}
+
+DIRECT_UPDATE_MEMBER(lviv_state::lviv_directoverride)
+{
+ if (ioport("RESET")->read() & 0x01)
+ machine().scheduler().timer_set(attotime::from_usec(10), FUNC(lviv_reset));
+ return address;
+}
+
+static READ8_DEVICE_HANDLER ( lviv_ppi_0_porta_r )
+{
+ return 0xff;
+}
+
+static READ8_DEVICE_HANDLER ( lviv_ppi_0_portb_r )
+{
+ return 0xff;
+}
+
+static READ8_DEVICE_HANDLER ( lviv_ppi_0_portc_r )
+{
+ lviv_state *state = device->machine().driver_data<lviv_state>();
+ UINT8 data = state->m_ppi_port_outputs[0][2] & 0x0f;
+ if (device->machine().device<cassette_image_device>(CASSETTE_TAG)->input() > 0.038)
+ data |= 0x10;
+ if (state->m_ppi_port_outputs[0][0] & state->ioport("JOY")->read())
+ data |= 0x80;
+ return data;
+}
+
+static WRITE8_DEVICE_HANDLER ( lviv_ppi_0_porta_w )
+{
+ lviv_state *state = device->machine().driver_data<lviv_state>();
+ state->m_ppi_port_outputs[0][0] = data;
+}
+
+static WRITE8_DEVICE_HANDLER ( lviv_ppi_0_portb_w )
+{
+ lviv_state *state = device->machine().driver_data<lviv_state>();
+ state->m_ppi_port_outputs[0][1] = data;
+ lviv_update_palette(device->machine(), data&0x7f);
+}
+
+static WRITE8_DEVICE_HANDLER ( lviv_ppi_0_portc_w ) /* tape in/out, video memory on/off */
+{
+ lviv_state *state = device->machine().driver_data<lviv_state>();
+ device_t *speaker = device->machine().device(SPEAKER_TAG);
+ state->m_ppi_port_outputs[0][2] = data;
+ if (state->m_ppi_port_outputs[0][1]&0x80)
+ speaker_level_w(speaker, data&0x01);
+ device->machine().device<cassette_image_device>(CASSETTE_TAG)->output((data & 0x01) ? -1.0 : 1.0);
+ lviv_update_memory(device->machine());
+}
+
+static READ8_DEVICE_HANDLER ( lviv_ppi_1_porta_r )
+{
+ return 0xff;
+}
+
+static READ8_DEVICE_HANDLER ( lviv_ppi_1_portb_r ) /* keyboard reading */
+{
+ lviv_state *state = device->machine().driver_data<lviv_state>();
+ return ((state->m_ppi_port_outputs[1][0] & 0x01) ? 0xff : device->machine().root_device().ioport("KEY0")->read()) &
+ ((state->m_ppi_port_outputs[1][0] & 0x02) ? 0xff : device->machine().root_device().ioport("KEY1")->read()) &
+ ((state->m_ppi_port_outputs[1][0] & 0x04) ? 0xff : device->machine().root_device().ioport("KEY2")->read()) &
+ ((state->m_ppi_port_outputs[1][0] & 0x08) ? 0xff : device->machine().root_device().ioport("KEY3")->read()) &
+ ((state->m_ppi_port_outputs[1][0] & 0x10) ? 0xff : device->machine().root_device().ioport("KEY4")->read()) &
+ ((state->m_ppi_port_outputs[1][0] & 0x20) ? 0xff : device->machine().root_device().ioport("KEY5")->read()) &
+ ((state->m_ppi_port_outputs[1][0] & 0x40) ? 0xff : device->machine().root_device().ioport("KEY6")->read()) &
+ ((state->m_ppi_port_outputs[1][0] & 0x80) ? 0xff : state->ioport("KEY7")->read());
+}
+
+static READ8_DEVICE_HANDLER ( lviv_ppi_1_portc_r ) /* keyboard reading */
+{
+ lviv_state *state = device->machine().driver_data<lviv_state>();
+ return ((state->m_ppi_port_outputs[1][2] & 0x01) ? 0xff : device->machine().root_device().ioport("KEY8")->read()) &
+ ((state->m_ppi_port_outputs[1][2] & 0x02) ? 0xff : device->machine().root_device().ioport("KEY9" )->read()) &
+ ((state->m_ppi_port_outputs[1][2] & 0x04) ? 0xff : device->machine().root_device().ioport("KEY10")->read()) &
+ ((state->m_ppi_port_outputs[1][2] & 0x08) ? 0xff : state->ioport("KEY11")->read());
+}
+
+static WRITE8_DEVICE_HANDLER ( lviv_ppi_1_porta_w ) /* kayboard scaning */
+{
+ lviv_state *state = device->machine().driver_data<lviv_state>();
+ state->m_ppi_port_outputs[1][0] = data;
+}
+
+static WRITE8_DEVICE_HANDLER ( lviv_ppi_1_portb_w )
+{
+ lviv_state *state = device->machine().driver_data<lviv_state>();
+ state->m_ppi_port_outputs[1][1] = data;
+}
+
+static WRITE8_DEVICE_HANDLER ( lviv_ppi_1_portc_w ) /* kayboard scaning */
+{
+ lviv_state *state = device->machine().driver_data<lviv_state>();
+ state->m_ppi_port_outputs[1][2] = data;
+}
+
+
+/* I/O */
+READ8_MEMBER(lviv_state::lviv_io_r)
+{
+ if (m_startup_mem_map)
+ {
+ return 0; /* ??? */
+ }
+ else
+ {
+ switch ((offset >> 4) & 0x3)
+ {
+ case 0:
+ return machine().device<i8255_device>("ppi8255_0")->read(space, offset & 3);
+
+ case 1:
+ return machine().device<i8255_device>("ppi8255_1")->read(space, offset & 3);
+
+ case 2:
+ case 3:
+ default:
+ /* reserved for extension? */
+ return 0; /* ??? */
+ }
+ }
+}
+
+WRITE8_MEMBER(lviv_state::lviv_io_w)
+{
+ address_space *cpuspace = machine().device("maincpu")->memory().space(AS_PROGRAM);
+ if (m_startup_mem_map)
+ {
+ UINT8 *ram = machine().device<ram_device>(RAM_TAG)->pointer();
+
+ m_startup_mem_map = 0;
+
+ cpuspace->install_write_bank(0x0000, 0x3fff, "bank1");
+ cpuspace->install_write_bank(0x4000, 0x7fff, "bank2");
+ cpuspace->install_write_bank(0x8000, 0xbfff, "bank3");
+ cpuspace->unmap_write(0xC000, 0xffff);
+
+ membank("bank1")->set_base(ram);
+ membank("bank2")->set_base(ram + 0x4000);
+ membank("bank3")->set_base(ram + 0x8000);
+ membank("bank4")->set_base(machine().root_device().memregion("maincpu")->base() + 0x010000);
+ }
+ else
+ {
+ switch ((offset >> 4) & 0x3)
+ {
+ case 0:
+ machine().device<i8255_device>("ppi8255_0")->write(space, offset & 3, data);
+ break;
+
+ case 1:
+ machine().device<i8255_device>("ppi8255_1")->write(space, offset & 3, data);
+ break;
+
+ case 2:
+ case 3:
+ /* reserved for extension? */
+ break;
+ }
+ }
+}
+
+
+I8255A_INTERFACE( lviv_ppi8255_interface_0 )
+{
+ DEVCB_HANDLER(lviv_ppi_0_porta_r),
+ DEVCB_HANDLER(lviv_ppi_0_porta_w),
+ DEVCB_HANDLER(lviv_ppi_0_portb_r),
+ DEVCB_HANDLER(lviv_ppi_0_portb_w),
+ DEVCB_HANDLER(lviv_ppi_0_portc_r),
+ DEVCB_HANDLER(lviv_ppi_0_portc_w)
+};
+
+I8255A_INTERFACE( lviv_ppi8255_interface_1 )
+{
+ DEVCB_HANDLER(lviv_ppi_1_porta_r),
+ DEVCB_HANDLER(lviv_ppi_1_porta_w),
+ DEVCB_HANDLER(lviv_ppi_1_portb_r),
+ DEVCB_HANDLER(lviv_ppi_1_portb_w),
+ DEVCB_HANDLER(lviv_ppi_1_portc_r),
+ DEVCB_HANDLER(lviv_ppi_1_portc_w)
+};
+
+MACHINE_RESET( lviv )
+{
+ lviv_state *state = machine.driver_data<lviv_state>();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ UINT8 *mem;
+
+ space->set_direct_update_handler(direct_update_delegate(FUNC(lviv_state::lviv_directoverride), state));
+
+ state->m_video_ram = machine.device<ram_device>(RAM_TAG)->pointer() + 0xc000;
+
+ state->m_startup_mem_map = 1;
+
+ space->unmap_write(0x0000, 0x3fff);
+ space->unmap_write(0x4000, 0x7fff);
+ space->unmap_write(0x8000, 0xbfff);
+ space->unmap_write(0xC000, 0xffff);
+
+ mem = state->memregion("maincpu")->base();
+ state->membank("bank1")->set_base(mem + 0x010000);
+ state->membank("bank2")->set_base(mem + 0x010000);
+ state->membank("bank3")->set_base(mem + 0x010000);
+ state->membank("bank4")->set_base(mem + 0x010000);
+
+ /*machine.scheduler().timer_pulse(TIME_IN_NSEC(200), FUNC(lviv_draw_pixel));*/
+
+ /*memset(machine.device<ram_device>(RAM_TAG)->pointer(), 0, sizeof(unsigned char)*0xffff);*/
+}
+
+
+/*******************************************************************************
+Lviv snapshot files (SAV)
+-------------------------
+
+00000 - 0000D: 'LVOV/DUMP/2.0/' (like LVT-header)
+0000E - 0000F: 'H+' (something additional)
+00010 00h
+00011 - 0C010: RAM (0000 - BFFF)
+0C011 - 10010: ROM (C000 - FFFF)
+10011 - 14010: Video RAM (4000 - 7FFF)
+14011 - 14110: Ports map (00 - FF)
+14111 - 1411C: Registers (B,C,D,E,H,L,A,F,SP,PC)
+1411D - 1412A: ??? (something additional)
+*******************************************************************************/
+
+static void lviv_setup_snapshot (running_machine &machine,UINT8 * data)
+{
+ lviv_state *state = machine.driver_data<lviv_state>();
+ unsigned char lo,hi;
+
+ /* Set registers */
+ lo = data[0x14112] & 0x0ff;
+ hi = data[0x14111] & 0x0ff;
+ cpu_set_reg(machine.device("maincpu"), I8085_BC, (hi << 8) | lo);
+ lo = data[0x14114] & 0x0ff;
+ hi = data[0x14113] & 0x0ff;
+ cpu_set_reg(machine.device("maincpu"), I8085_DE, (hi << 8) | lo);
+ lo = data[0x14116] & 0x0ff;
+ hi = data[0x14115] & 0x0ff;
+ cpu_set_reg(machine.device("maincpu"), I8085_HL, (hi << 8) | lo);
+ lo = data[0x14118] & 0x0ff;
+ hi = data[0x14117] & 0x0ff;
+ cpu_set_reg(machine.device("maincpu"), I8085_AF, (hi << 8) | lo);
+ lo = data[0x14119] & 0x0ff;
+ hi = data[0x1411a] & 0x0ff;
+ cpu_set_reg(machine.device("maincpu"), I8085_SP, (hi << 8) | lo);
+ lo = data[0x1411b] & 0x0ff;
+ hi = data[0x1411c] & 0x0ff;
+ cpu_set_reg(machine.device("maincpu"), I8085_PC, (hi << 8) | lo);
+
+ /* Memory dump */
+ memcpy (machine.device<ram_device>(RAM_TAG)->pointer(), data+0x0011, 0xc000);
+ memcpy (machine.device<ram_device>(RAM_TAG)->pointer()+0xc000, data+0x10011, 0x4000);
+
+ /* Ports */
+ state->m_ppi_port_outputs[0][0] = data[0x14011+0xc0];
+ state->m_ppi_port_outputs[0][1] = data[0x14011+0xc1];
+ lviv_update_palette(machine, state->m_ppi_port_outputs[0][1]&0x7f);
+ state->m_ppi_port_outputs[0][2] = data[0x14011+0xc2];
+ lviv_update_memory(machine);
+}
+
+static void dump_registers(running_machine &machine)
+{
+ logerror("PC = %04x\n", (unsigned) cpu_get_reg(machine.device("maincpu"), I8085_PC));
+ logerror("SP = %04x\n", (unsigned) cpu_get_reg(machine.device("maincpu"), I8085_SP));
+ logerror("AF = %04x\n", (unsigned) cpu_get_reg(machine.device("maincpu"), I8085_AF));
+ logerror("BC = %04x\n", (unsigned) cpu_get_reg(machine.device("maincpu"), I8085_BC));
+ logerror("DE = %04x\n", (unsigned) cpu_get_reg(machine.device("maincpu"), I8085_DE));
+ logerror("HL = %04x\n", (unsigned) cpu_get_reg(machine.device("maincpu"), I8085_HL));
+}
+
+static int lviv_verify_snapshot (UINT8 * data, UINT32 size)
+{
+ const char* tag = "LVOV/DUMP/2.0/";
+
+ if( strncmp( tag, (char*)data, strlen(tag) ) )
+ {
+ logerror("Not a Lviv snapshot\n");
+ return IMAGE_VERIFY_FAIL;
+ }
+
+ if (size != LVIV_SNAPSHOT_SIZE)
+ {
+ logerror ("Incomplete snapshot file\n");
+ return IMAGE_VERIFY_FAIL;
+ }
+
+ logerror("returning ID_OK\n");
+ return IMAGE_VERIFY_PASS;
+}
+
+SNAPSHOT_LOAD( lviv )
+{
+ UINT8 *lviv_snapshot_data;
+
+ lviv_snapshot_data = (UINT8*)malloc(LVIV_SNAPSHOT_SIZE);
+ if (!lviv_snapshot_data)
+ {
+ logerror ("Unable to load snapshot file\n");
+ return IMAGE_INIT_FAIL;
+ }
+
+ image.fread( lviv_snapshot_data, LVIV_SNAPSHOT_SIZE);
+
+ if( lviv_verify_snapshot(lviv_snapshot_data, snapshot_size) == IMAGE_VERIFY_FAIL)
+ {
+ free(lviv_snapshot_data);
+ return IMAGE_INIT_FAIL;
+ }
+
+ lviv_setup_snapshot (image.device().machine(),lviv_snapshot_data);
+
+ dump_registers(image.device().machine());
+
+ free(lviv_snapshot_data);
+
+ logerror("Snapshot file loaded\n");
+ return IMAGE_INIT_PASS;
+}
+
diff --git a/src/mess/machine/lynx.c b/src/mess/machine/lynx.c
new file mode 100644
index 00000000000..63403ea9d48
--- /dev/null
+++ b/src/mess/machine/lynx.c
@@ -0,0 +1,2137 @@
+/******************************************************************************
+ PeT mess@utanet.at 2000,2001
+******************************************************************************/
+
+#include "emu.h"
+#include "includes/lynx.h"
+#include "cpu/m6502/m6502.h"
+#include "imagedev/cartslot.h"
+
+
+#define PAD_UP 0x80
+#define PAD_DOWN 0x40
+#define PAD_LEFT 0x20
+#define PAD_RIGHT 0x10
+
+
+/****************************************
+
+ Graphics Drawing
+
+****************************************/
+
+/*
+2008-10 FP:
+Current implementation: lynx_blitter reads what will be drawn and sets which line_functions to use.
+It then calls lynx_blit_lines which sets the various flip bits (horizontal and vertical) and calls
+the chosen line_function. These functions (available in various versions, depending on how many
+color bits are to be used) finally call lynx_plot_pixel which draws the sprite.
+
+Notice however that, based on the problems in Electrocop, Jimmy Connors Tennis and Switchblade II
+(among the others), it clearly seems that something is being lost in some of the passages. From
+my partial understanding while comparing the code with the manual, I would suspect the loops in
+the line_functions to be not completely correct.
+
+This whole part will be eventually moved to video/ once I'm satisfied (or I give up).
+*/
+
+/* modes from blitter command */
+enum {
+ BACKGROUND = 0,
+ BACKGROUND_NO_COLL,
+ BOUNDARY_SHADOW,
+ BOUNDARY,
+ NORMAL_SPRITE,
+ NO_COLL,
+ XOR_SPRITE,
+ SHADOW
+};
+
+static UINT8 lynx_read_ram(lynx_state *state, UINT16 address)
+{
+ UINT8 result = 0x00;
+ if (address <= 0xfbff)
+ result = state->m_mem_0000[address - 0x0000];
+ else if (address <= 0xfcff)
+ result = state->m_mem_fc00[address - 0xfc00];
+ else if (address <= 0xfdff)
+ result = state->m_mem_fd00[address - 0xfd00];
+ else if (address <= 0xfff7)
+ result = state->m_mem_fe00[address - 0xfe00];
+ else if (address >= 0xfffa)
+ result = state->m_mem_fffa[address - 0xfffa];
+ return result;
+}
+
+static void lynx_write_ram(lynx_state *state, UINT16 address, UINT8 data)
+{
+ if (address <= 0xfbff)
+ state->m_mem_0000[address - 0x0000] = data;
+ else if (address <= 0xfcff)
+ state->m_mem_fc00[address - 0xfc00] = data;
+ else if (address <= 0xfdff)
+ state->m_mem_fd00[address - 0xfd00] = data;
+ else if (address <= 0xfff7)
+ state->m_mem_fe00[address - 0xfe00] = data;
+ else if (address >= 0xfffa)
+ state->m_mem_fffa[address - 0xfffa] = data;
+}
+
+/* The pen numbers range from '0' to 'F. Pen numbers '1' through 'D' are always collidable and opaque. The other
+ones have different behavior depending on the sprite type: there are 8 types of sprites, each has different
+characteristics relating to some or all of their pen numbers.
+
+* Shadow Error: The hardware is missing an inverter in the 'shadow' generator. This causes sprite types that
+did not invoke shadow to now invoke it and vice versa. The only actual functionality loss is that 'exclusive or'
+sprites and 'background' sprites will have shadow enabled.
+
+The sprite types relate to specific hardware functions according to the following table:
+
+
+ -------------------------- SHADOW
+ | ----------------------- BOUNDARY_SHADOW
+ | | -------------------- NORMAL_SPRITE
+ | | | ----------------- BOUNDARY
+ | | | | -------------- BACKGROUND (+ shadow, due to bug in 'E' pen)
+ | | | | | ----------- BACKGROUND_NO_COLL
+ | | | | | | -------- NO_COLL
+ | | | | | | | ----- XOR_SPRITE (+ shadow, due to bug in 'E' pen)
+ | | | | | | | |
+ 1 0 1 0 1 1 1 1 F is opaque
+ 0 0 1 1 0 0 0 0 E is collideable
+ 0 0 1 1 0 0 0 0 0 is opaque and collideable
+ 1 1 1 1 0 0 0 1 allow collision detect
+ 1 1 1 1 1 0 0 1 allow coll. buffer access
+ 0 0 0 0 0 0 0 1 exclusive-or the data
+*/
+
+INLINE void lynx_plot_pixel(lynx_state *state, const int mode, const INT16 x, const int y, const int color)
+{
+ UINT8 back;
+ UINT16 screen;
+ UINT16 colbuf;
+
+ state->m_blitter.everon = TRUE;
+ screen = state->m_blitter.screen + y * 80 + x / 2;
+ colbuf = state->m_blitter.colbuf + y * 80 + x / 2;
+
+ /* a note on timing: The hardware packs the pixel data and updates the screen and collision buffer a byte at a time.
+ Thus the buffer update for two pixels takes 3 memory accesses for a normal sprite (write to screen buffer, read/write to collision buffer).
+ +1 memory access for palette fetch?
+ */
+
+ switch (mode&0x7)
+ {
+ case NORMAL_SPRITE:
+ /* A sprite may be set to 'normal'. This means that pen number '0' will be transparent and
+ non-collideable. All other pens will be opaque and collideable */
+ if (color == 0)
+ break;
+ if (!(x & 0x01)) /* Upper nibble */
+ {
+ back = lynx_read_ram(state, screen);
+ lynx_write_ram(state, screen, (back & 0x0f) | (color << 4));
+ state->m_blitter.memory_accesses++;
+
+ if(state->m_blitter.sprite_collide && !(state->m_blitter.no_collide))
+ {
+ back = lynx_read_ram(state, colbuf);
+ lynx_write_ram(state, colbuf, (back & ~0xf0) | (state->m_blitter.spritenr << 4));
+ state->m_blitter.memory_accesses += 2;
+ if ((back >> 4) > state->m_blitter.fred)
+ state->m_blitter.fred = back >> 4;
+ }
+ state->m_blitter.memory_accesses++;
+ }
+ else /* Lower nibble */
+ {
+ back = lynx_read_ram(state, screen);
+ lynx_write_ram(state, screen, (back & 0xf0) | color);
+
+ if(state->m_blitter.sprite_collide && !(state->m_blitter.no_collide))
+ {
+ back = lynx_read_ram(state, colbuf);
+ lynx_write_ram(state, colbuf, (back & ~0x0f) | (state->m_blitter.spritenr));
+ if ((back & 0x0f) > state->m_blitter.fred)
+ state->m_blitter.fred = back >> 4;
+ }
+ }
+ break;
+
+ case BOUNDARY:
+ /* A sprite may be set to 'boundary'. This is a 'normal' sprite with the exception that pen
+ number 'F' is transparent (and still collideable). */
+ if (color == 0)
+ break;
+ if (!(x & 0x01)) /* Upper nibble */
+ {
+ if (color != 0x0f)
+ {
+ back = lynx_read_ram(state, screen);
+ lynx_write_ram(state, screen, (back & 0x0f) | (color << 4));
+ state->m_blitter.memory_accesses++;
+ }
+ if(state->m_blitter.sprite_collide && !(state->m_blitter.no_collide))
+ {
+ back = lynx_read_ram(state, colbuf);
+ lynx_write_ram(state, colbuf, (back & ~0xf0) | (state->m_blitter.spritenr << 4));
+ if ((back >> 4) > state->m_blitter.fred)
+ state->m_blitter.fred = back >> 4;
+ state->m_blitter.memory_accesses += 2;
+ }
+ state->m_blitter.memory_accesses++;
+ }
+ else /* Lower nibble */
+ {
+ if (color != 0x0f)
+ {
+ back = lynx_read_ram(state, screen);
+ lynx_write_ram(state, screen, (back & 0xf0) | color);
+ }
+ if(state->m_blitter.sprite_collide && !(state->m_blitter.no_collide))
+ {
+ back = lynx_read_ram(state, colbuf);
+ lynx_write_ram(state, colbuf, (back & ~0x0f) | (state->m_blitter.spritenr));
+ if ((back & 0x0f) > state->m_blitter.fred)
+ state->m_blitter.fred = back >> 4;
+ }
+ }
+ break;
+
+ case SHADOW:
+ /* A sprite may be set to 'shadow'. This is a 'normal' sprite with the exception that pen
+ number 'E' is non-collideable (but still opaque) */
+ if (color == 0)
+ break;
+ if (!(x & 0x01)) /* Upper nibble */
+ {
+ back = lynx_read_ram(state, screen);
+ lynx_write_ram(state, screen, (back & 0x0f) | (color << 4));
+ state->m_blitter.memory_accesses++;
+
+ if (state->m_blitter.sprite_collide && (color != 0x0e) && !(state->m_blitter.no_collide))
+ {
+ back = lynx_read_ram(state, colbuf);
+ lynx_write_ram(state, colbuf, (back & ~0xf0) | (state->m_blitter.spritenr << 4));
+ if ((back >> 4) > state->m_blitter.fred)
+ state->m_blitter.fred = back >> 4;
+ state->m_blitter.memory_accesses += 2;
+ }
+ state->m_blitter.memory_accesses++;
+ }
+ else /* Lower nibble */
+ {
+ back = lynx_read_ram(state, screen);
+ lynx_write_ram(state, screen, (back & 0xf0) | color);
+
+ if (state->m_blitter.sprite_collide && (color != 0x0e) && !(state->m_blitter.no_collide))
+ {
+ back = lynx_read_ram(state, colbuf);
+ lynx_write_ram(state, colbuf, (back & ~0x0f) | (state->m_blitter.spritenr));
+ if ((back & 0x0f) > state->m_blitter.fred)
+ state->m_blitter.fred = back >> 4;
+ }
+ }
+ break;
+
+ case BOUNDARY_SHADOW:
+ /* This sprite is a 'normal' sprite with the characteristics of both 'boundary'
+ and 'shadow'. That is, pen number 'F' is transparent (and still collideable) and
+ pen number 'E' is non-collideable (but still opaque). */
+ if (color == 0)
+ break;
+ if (!(x & 0x01)) /* Upper nibble */
+ {
+ if (color != 0x0f)
+ {
+ back = lynx_read_ram(state, screen);
+ lynx_write_ram(state, screen, (back & 0x0f) | (color << 4));
+ state->m_blitter.memory_accesses++;
+ }
+ if (state->m_blitter.sprite_collide && (color != 0x0e) && !(state->m_blitter.no_collide))
+ {
+ back = lynx_read_ram(state, colbuf);
+ lynx_write_ram(state, colbuf, (back & ~0xf0) | (state->m_blitter.spritenr << 4));
+ if ((back >> 4) > state->m_blitter.fred)
+ state->m_blitter.fred = back >> 4;
+ state->m_blitter.memory_accesses += 2;
+ }
+ state->m_blitter.memory_accesses++;
+ }
+ else /* Lower nibble */
+ {
+ if (color != 0x0f)
+ {
+ back = lynx_read_ram(state, screen);
+ lynx_write_ram(state, screen, (back & 0xf0) | color);
+ }
+ if (state->m_blitter.sprite_collide && (color != 0x0e) && !(state->m_blitter.no_collide))
+ {
+ back = lynx_read_ram(state, colbuf);
+ lynx_write_ram(state, colbuf, (back & ~0x0f) | (state->m_blitter.spritenr));
+ if ((back & 0x0f) > state->m_blitter.fred)
+ state->m_blitter.fred = back >> 4;
+ }
+ }
+ break;
+
+ case BACKGROUND:
+ /* A sprite may be set to 'background'. This sprite will overwrite the contents of the video and
+ collision buffers. Pens '0' and 'F' are no longer transparent. This sprite is used to initialize
+ the buffers at the start of a 'painting'. Additionally, no collision detection is done, and no write
+ to the collision depository occurs. The 'E' error will cause the pen number 'E' to be non-collideable
+ and therefore not clear the collision buffer */
+ if (!(x & 0x01)) /* Upper nibble */
+ {
+ back = lynx_read_ram(state, screen);
+ lynx_write_ram(state, screen, (back & 0x0f) | (color << 4));
+ state->m_blitter.memory_accesses++;
+
+ if (state->m_blitter.sprite_collide && (color != 0x0e) && !(state->m_blitter.no_collide))
+ {
+ back = lynx_read_ram(state, colbuf);
+ lynx_write_ram(state, colbuf, (back & ~0xf0) | (state->m_blitter.spritenr << 4));
+ state->m_blitter.memory_accesses++;
+ }
+ state->m_blitter.memory_accesses++;
+ }
+ else /* Lower nibble */
+ {
+ back = lynx_read_ram(state, screen);
+ lynx_write_ram(state, screen, (back & 0xf0) | color);
+
+ if (state->m_blitter.sprite_collide && (color != 0x0e) && !(state->m_blitter.no_collide))
+ {
+ back = lynx_read_ram(state, colbuf);
+ lynx_write_ram(state, colbuf, (back & ~0x0f) | (state->m_blitter.spritenr));
+ }
+ }
+ break;
+
+ case BACKGROUND_NO_COLL:
+ /* This is a 'background' sprite with the exception that no activity occurs in the collision buffer */
+ if (!(x & 0x01)) /* Upper nibble */
+ {
+ back = lynx_read_ram(state, screen);
+ lynx_write_ram(state, screen, (back & 0x0f) | (color << 4));
+ state->m_blitter.memory_accesses++;
+ state->m_blitter.memory_accesses++;
+ }
+ else /* Lower nibble */
+ {
+ back = lynx_read_ram(state, screen);
+ lynx_write_ram(state, screen, (back & 0xf0) | color);
+ }
+ break;
+
+ case NO_COLL:
+ /* A sprite may be set to 'non-collideable'. This means that it will have no affect on the contents of
+ the collision buffer and all other collision activities are overridden (pen 'F' is not collideable). */
+ if (color == 0)
+ break;
+ if (!(x & 0x01)) /* Upper nibble */
+ {
+ back = lynx_read_ram(state, screen);
+ lynx_write_ram(state, screen, (back & 0x0f) | (color << 4));
+ state->m_blitter.memory_accesses++;
+ state->m_blitter.memory_accesses++;
+ }
+ else /* Lower nibble */
+ {
+ back = lynx_read_ram(state, screen);
+ lynx_write_ram(state, screen, (back & 0xf0) | color);
+ }
+ break;
+
+ case XOR_SPRITE:
+ /* This is a 'normal' sprite with the exception that the data from the video buffer is exclusive-ored
+ with the sprite data and written back out to the video buffer. Collision activity is 'normal'. The 'E'
+ error will cause the pen number 'E' to be non-collideable and therefore not react with the collision
+ buffer */
+ if (color == 0)
+ break;
+ if (!(x & 0x01)) /* Upper nibble */
+ {
+ back = lynx_read_ram(state, screen);
+ lynx_write_ram(state, screen, back^(color << 4));
+ state->m_blitter.memory_accesses += 2;
+ if (state->m_blitter.sprite_collide && (color != 0x0e) && !(state->m_blitter.no_collide))
+ {
+ back = lynx_read_ram(state, colbuf);
+ lynx_write_ram(state, colbuf, (back & ~0xf0) | (state->m_blitter.spritenr << 4));
+ if ((back >> 4) > state->m_blitter.fred)
+ state->m_blitter.fred = back >> 4;
+ state->m_blitter.memory_accesses += 2;
+ }
+ state->m_blitter.memory_accesses++;
+ }
+ else /* Lower nibble */
+ {
+ back = lynx_read_ram(state, screen);
+ lynx_write_ram(state, screen, back^color);
+ if (state->m_blitter.sprite_collide && (color != 0x0e) && !(state->m_blitter.no_collide))
+ {
+ back = lynx_read_ram(state, colbuf);
+ lynx_write_ram(state, colbuf, (back & ~0x0f) | (state->m_blitter.spritenr));
+ if ((back & 0x0f) > state->m_blitter.fred)
+ state->m_blitter.fred = back >> 4;
+ }
+ }
+ break;
+ }
+}
+
+static void lynx_blit_do_work( lynx_state *state, const int y, const int xdir, const int bits_per_pixel, const int mask )
+{
+ int next_line_addr,i,j;
+ int xi, bits, color;
+ UINT16 width_accum, buffer;
+
+ next_line_addr = lynx_read_ram(state, state->m_blitter.bitmap); // offset to second sprite line
+ width_accum = (xdir == 1) ? state->m_blitter.width_offset : 0;
+ state->m_blitter.memory_accesses++;
+
+ for (xi = state->m_blitter.x_pos - state->m_blitter.xoff, bits = 0, buffer = 0, j = 1; j < next_line_addr;j++)
+ {
+ buffer = (buffer << 8) | lynx_read_ram(state, state->m_blitter.bitmap + j);
+ bits += 8; // current bits in buffer
+ state->m_blitter.memory_accesses++;
+
+ for ( ; bits > bits_per_pixel; bits -= bits_per_pixel) // last data packet at end of scanline is not rendered (qix, blulght)
+ {
+ color = state->m_blitter.color[(buffer >> (bits - bits_per_pixel)) & mask];
+ width_accum += state->m_blitter.width;
+ for (i = 0; i < (width_accum>>8); i++, xi += xdir)
+ {
+ if ((xi >= 0) && (xi < 160))
+ {
+ lynx_plot_pixel(state, state->m_blitter.mode, xi, y, color);
+ }
+ }
+ width_accum &= 0xff;
+ }
+ }
+}
+
+static void lynx_blit_2color_line(lynx_state *state, const int y, const int xdir) {lynx_blit_do_work(state, y, xdir, 1, 0x01);}
+static void lynx_blit_4color_line(lynx_state *state, const int y, const int xdir) {lynx_blit_do_work(state, y, xdir, 2, 0x03);}
+static void lynx_blit_8color_line(lynx_state *state, const int y, const int xdir) {lynx_blit_do_work(state, y, xdir, 3, 0x07);}
+static void lynx_blit_16color_line(lynx_state *state, const int y, const int xdir) {lynx_blit_do_work(state, y, xdir, 4, 0x0f);}
+
+static void lynx_blit_rle_do_work( lynx_state *state, const INT16 y, const int xdir, const int bits_per_pixel, const int mask )
+{
+ int i;
+ int xi;
+ int buffer, bits, j;
+ int literal_data, count, color;
+ UINT16 width_accum;
+
+ width_accum = (xdir == 1) ? state->m_blitter.width_offset : 0;
+ for( bits = 0, j = 0, buffer = 0, xi = state->m_blitter.x_pos - state->m_blitter.xoff; ; ) /* through the rle entries */
+ {
+ if (bits < 5 + bits_per_pixel) /* under 7 bits no complete entry */
+ {
+ j++;
+ if (j >= lynx_read_ram(state, state->m_blitter.bitmap))
+ return;
+
+ bits += 8;
+ buffer = (buffer << 8) | lynx_read_ram(state,state->m_blitter.bitmap + j);
+ state->m_blitter.memory_accesses++;
+ }
+
+ literal_data = (buffer >> (bits - 1)) & 0x01;
+ bits--;
+ count = (buffer >> (bits - 4)) & 0x0f; // repeat count (packed) or pixel count (literal)
+ bits -= 4;
+
+ if (literal_data) /* count of different pixels */
+ {
+ for ( ; count >= 0; count--)
+ {
+ if (bits < bits_per_pixel)
+ {
+ j++;
+ if (j >= lynx_read_ram(state, state->m_blitter.bitmap))
+ return;
+ bits += 8;
+ buffer = (buffer << 8) | lynx_read_ram(state, state->m_blitter.bitmap + j);
+ state->m_blitter.memory_accesses++;
+ }
+
+ color = state->m_blitter.color[(buffer >> (bits - bits_per_pixel)) & mask];
+ bits -= bits_per_pixel;
+ width_accum += state->m_blitter.width;
+ for (i = 0; i < (width_accum>>8); i++, xi += xdir)
+ {
+ if ((xi >= 0) && (xi < 160))
+ lynx_plot_pixel(state, state->m_blitter.mode, xi, y, color);
+ }
+ width_accum &= 0xff;
+ }
+ }
+ else /* count of same pixels */
+ {
+ if (count == 0) // 4 bit count value of zero indicates end-of-line in a packed sprite
+ return;
+
+ if (bits < bits_per_pixel)
+ {
+ j++;
+ if (j >= lynx_read_ram(state, state->m_blitter.bitmap))
+ return;
+ bits += 8;
+ buffer = (buffer << 8) | lynx_read_ram(state, state->m_blitter.bitmap + j);
+ state->m_blitter.memory_accesses++;
+ }
+
+ color = state->m_blitter.color[(buffer >> (bits - bits_per_pixel)) & mask];
+ bits -= bits_per_pixel;
+
+ for ( ; count>=0; count--)
+ {
+ width_accum += state->m_blitter.width;
+ for (i = 0; i < (width_accum>>8); i++, xi += xdir)
+ {
+ if ((xi >= 0) && (xi < 160))
+ lynx_plot_pixel(state, state->m_blitter.mode, xi, y, color);
+ }
+ width_accum &= 0xff;
+ }
+ }
+ }
+}
+
+static void lynx_blit_2color_rle_line(lynx_state *state, const int y, const int xdir) {lynx_blit_rle_do_work(state, y, xdir, 1, 0x01);}
+static void lynx_blit_4color_rle_line(lynx_state *state, const int y, const int xdir) {lynx_blit_rle_do_work(state, y, xdir, 2, 0x03);}
+static void lynx_blit_8color_rle_line(lynx_state *state, const int y, const int xdir) {lynx_blit_rle_do_work(state, y, xdir, 3, 0x07);}
+static void lynx_blit_16color_rle_line(lynx_state *state, const int y, const int xdir) {lynx_blit_rle_do_work(state, y, xdir, 4, 0x0f);}
+
+static void lynx_blit_lines(lynx_state *state)
+{
+ int i;
+ INT16 y;
+ int ydir = 0, xdir = 0;
+ int flip = 0;
+
+ state->m_blitter.everon = FALSE;
+
+ switch (state->m_blitter.spr_ctl1 & 0x03) /* Initial drawing direction */
+ {
+ case 0: // Down/Right (quadrant 0)
+ xdir = 1;
+ ydir = 1;
+ flip = 0;
+ break;
+ case 1: // Down/Left (blockout) (quadrant 3)
+ xdir = -1;
+ ydir = 1;
+ flip = 3;
+ break;
+ case 2: // Up/Right (fat bobby) (quadrant 1)
+ xdir = 1;
+ ydir = -1;
+ flip = 1;
+ break;
+ case 3: // Up/Left (quadrant 2)
+ xdir = -1;
+ ydir = -1;
+ flip = 2;
+ break;
+ }
+
+ if (state->m_blitter.spr_ctl0 & 0x20) /* Horizontal Flip */
+ {
+ xdir *= -1;
+ }
+
+ if (state->m_blitter.spr_ctl0 & 0x10) /* Vertical Flip */
+ {
+ ydir *= -1;
+ }
+
+ // Set height accumulator based on drawing direction
+ state->m_blitter.height_accumulator = (ydir == 1) ? state->m_blitter.height_offset : 0x00;
+
+ // loop through lines, next line offset of zero indicates end of sprite
+ for (y = state->m_blitter.y_pos - state->m_blitter.yoff; (i = lynx_read_ram(state, state->m_blitter.bitmap)); state->m_blitter.bitmap += i)
+ {
+ state->m_blitter.memory_accesses++;
+
+ if (i == 1) // draw next quadrant
+ {
+ // centered sprites sprdemo3, fat bobby, blockout
+ switch (flip & 0x03)
+ {
+ case 0:
+ case 2:
+ ydir *= -1;
+ state->m_blitter.y_pos += ydir;
+ break;
+ case 1:
+ case 3:
+ xdir *= -1;
+ state->m_blitter.x_pos += xdir;
+ break;
+ }
+ flip++;
+ y = state->m_blitter.y_pos - state->m_blitter.yoff;
+ state->m_blitter.height_accumulator = (ydir == 1) ? state->m_blitter.height_offset : 0x00;
+ continue;
+ }
+
+
+ state->m_blitter.height_accumulator += state->m_blitter.height;
+ for (int i=0; i < (state->m_blitter.height_accumulator>>8); i++, y += ydir)
+ {
+ if (y >= 0 && y < 102)
+ state->m_blitter.line_function(state, y, xdir);
+ state->m_blitter.width += (INT16)state->m_blitter.stretch;
+ if (state->m_blitter.vstretch) // doesn't seem to be used
+ {
+ state->m_blitter.height += (INT16)state->m_blitter.stretch;
+ logerror("vertical stretch enabled");
+ }
+ state->m_blitter.tilt_accumulator += state->m_blitter.tilt;
+ state->m_blitter.x_pos += (state->m_blitter.tilt_accumulator>>8);
+ state->m_blitter.tilt_accumulator &= 0xff;
+ }
+ state->m_blitter.height_accumulator &= 0xff;
+ }
+}
+
+static TIMER_CALLBACK(lynx_blitter_timer)
+{
+ lynx_state *state = machine.driver_data<lynx_state>();
+ state->m_blitter.busy=0; // blitter finished
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_HALT, CLEAR_LINE);
+}
+
+/*
+ control 0
+ bit 7,6: 00 2 color
+ 01 4 color
+ 11 8 colors?
+ 11 16 color
+ bit 5,4: 00 right down
+ 01 right up
+ 10 left down
+ 11 left up
+
+#define SHADOW (0x07)
+#define XORSHADOW (0x06)
+#define NONCOLLIDABLE (0x05)
+#define NORMAL (0x04)
+#define BOUNDARY (0x03)
+#define BOUNDARYSHADOW (0x02)
+#define BKGRNDNOCOL (0x01)
+#define BKGRND (0x00)
+
+ control 1
+ bit 7: 0 bitmap rle encoded
+ 1 not encoded
+ bit 3: 0 color info with command
+ 1 no color info with command
+
+#define RELHVST (0x30)
+#define RELHVS (0x20)
+#define RELHV (0x10)
+
+#define SKIPSPRITE (0x04)
+
+#define DUP (0x02)
+#define DDOWN (0x00)
+#define DLEFT (0x01)
+#define DRIGHT (0x00)
+
+
+ coll
+#define DONTCOLLIDE (0x20)
+
+ word next
+ word data
+ word x
+ word y
+ word width
+ word height
+
+ pixel c0 90 20 0000 datapointer x y 0100 0100 color (8 colorbytes)
+ 4 bit direct?
+ datapointer 2 10 0
+ 98 (0 colorbytes)
+
+ box c0 90 20 0000 datapointer x y width height color
+ datapointer 2 10 0
+
+ c1 98 00 4 bit direct without color bytes (raycast)
+
+ 40 10 20 4 bit rle (sprdemo2)
+
+ line c1 b0 20 0000 datapointer x y 0100 0100 stretch tilt:x/y color (8 color bytes)
+ or
+ line c0 b0 20 0000 datapointer x y 0100 0100 stretch tilt:x/y color
+ datapointer 2 11 0
+
+ text ?(04) 90 20 0000 datapointer x y width height color
+ datapointer 2 10 0
+
+ stretch: hsize adder
+ tilt: hpos adder
+
+*/
+
+static void lynx_blitter(running_machine &machine)
+{
+ lynx_state *state = machine.driver_data<lynx_state>();
+ static const int lynx_colors[4]={2,4,8,16};
+ UINT8 palette_offset;
+ UINT8 coldep;
+
+ static void (* const blit_line[4])(lynx_state *state, const int y, const int xdir)= {
+ lynx_blit_2color_line,
+ lynx_blit_4color_line,
+ lynx_blit_8color_line,
+ lynx_blit_16color_line
+ };
+
+ static void (* const blit_rle_line[4])(lynx_state *state, const int y, const int xdir)= {
+ lynx_blit_2color_rle_line,
+ lynx_blit_4color_rle_line,
+ lynx_blit_8color_rle_line,
+ lynx_blit_16color_rle_line
+ };
+
+ int i; int colors;
+
+ state->m_blitter.mem = (UINT8*)machine.device("maincpu")->memory().space(AS_PROGRAM)->get_read_ptr(0x0000);
+
+ state->m_blitter.busy = 1; // blitter working
+ state->m_blitter.memory_accesses = 0;
+
+ // Last SCB is indicated by zero in the high byte of SCBNEXT
+ while (state->m_blitter.scb_next & 0xff00)
+ {
+ state->m_blitter.stretch = 0;
+ state->m_blitter.tilt = 0;
+ state->m_blitter.tilt_accumulator = 0;
+
+ state->m_blitter.scb = state->m_blitter.scb_next; // current scb
+ state->m_blitter.scb_next = lynx_read_ram(state, state->m_blitter.scb + SCB_SCBNEXT) | (lynx_read_ram(state, state->m_blitter.scb + SCB_SCBNEXT + 1) << 8); // next scb
+ state->m_blitter.spr_ctl0 = lynx_read_ram(state, state->m_blitter.scb + SCB_SPRCTL0);
+ state->m_blitter.spr_ctl1 = lynx_read_ram(state, state->m_blitter.scb + SCB_SPRCTL1);
+ state->m_blitter.spr_coll = lynx_read_ram(state, state->m_blitter.scb + SCB_SPRCOLL);
+ state->m_blitter.memory_accesses += 5;
+
+ if(!(state->m_blitter.spr_ctl1 & 0x04)) // sprite will be processed (if sprite is skipped first 5 bytes are still copied to suzy)
+ {
+ state->m_blitter.bitmap = lynx_read_ram(state, state->m_blitter.scb + SCB_SPRDLINE) | (lynx_read_ram(state, state->m_blitter.scb + SCB_SPRDLINE + 1) << 8);
+ state->m_blitter.x_pos = lynx_read_ram(state, state->m_blitter.scb + SCB_HPOSSTRT) | (lynx_read_ram(state, state->m_blitter.scb + SCB_HPOSSTRT + 1) << 8);
+ state->m_blitter.y_pos = lynx_read_ram(state, state->m_blitter.scb + SCB_VPOSSTRT) | (lynx_read_ram(state, state->m_blitter.scb + SCB_VPOSSTRT + 1) << 8);
+ state->m_blitter.memory_accesses += 6;
+
+ switch(state->m_blitter.spr_ctl1 & 0x30) // reload sprite scaling
+ {
+ case 0x30: // width, height, tilt, stretch
+ state->m_blitter.tilt = lynx_read_ram(state, state->m_blitter.scb + SCB_TILT) | (lynx_read_ram(state, state->m_blitter.scb + SCB_TILT + 1) << 8);
+ state->m_blitter.memory_accesses+=2;
+ case 0x20: // width, height, stretch
+ state->m_blitter.stretch = lynx_read_ram(state, state->m_blitter.scb + SCB_STRETCH) | (lynx_read_ram(state, state->m_blitter.scb + SCB_STRETCH + 1) << 8);
+ state->m_blitter.memory_accesses+=2;
+ case 0x10: // width, height
+ state->m_blitter.width = lynx_read_ram(state, state->m_blitter.scb + SCB_SPRHSIZ) | (lynx_read_ram(state, state->m_blitter.scb + SCB_SPRHSIZ + 1) << 8);
+ state->m_blitter.height = lynx_read_ram(state, state->m_blitter.scb + SCB_SPRVSIZ) | (lynx_read_ram(state, state->m_blitter.scb + SCB_SPRVSIZ + 1) << 8);
+ state->m_blitter.memory_accesses+=4;
+ }
+
+ if(!(state->m_blitter.spr_ctl1 & 0x08)) // reload palette
+ {
+ if (state->m_blitter.spr_ctl1 & 0x30)
+ palette_offset = 0x0b + 2*(((state->m_blitter.spr_ctl1 & 0x30)>>4) + 1); // palette data offset depends on width, height, etc. reloading
+ else
+ palette_offset = 0x0b;
+
+ colors = lynx_colors[state->m_blitter.spr_ctl0 >> 6];
+
+ for (i = 0; i < colors / 2; i++)
+ {
+ state->m_blitter.color[i * 2] = lynx_read_ram(state, state->m_blitter.scb + palette_offset + i) >> 4;
+ state->m_blitter.color[i * 2 + 1 ] = lynx_read_ram(state, state->m_blitter.scb + palette_offset + i) & 0x0f;
+ state->m_blitter.memory_accesses++;
+ }
+ }
+ }
+
+
+ if (!(state->m_blitter.spr_ctl1 & 0x04)) // if 0, we skip this sprite
+ {
+ state->m_blitter.colpos = state->m_blitter.scb + (state->m_suzy.data[COLLOFFL] | (state->m_suzy.data[COLLOFFH]<<8));
+ state->m_blitter.mode = state->m_blitter.spr_ctl0 & 0x07;
+
+ if (state->m_blitter.spr_ctl1 & 0x80) // totally literal sprite
+ state->m_blitter.line_function = blit_line[state->m_blitter.spr_ctl0 >> 6];
+ else
+ state->m_blitter.line_function = blit_rle_line[state->m_blitter.spr_ctl0 >> 6];
+
+ state->m_blitter.sprite_collide = !(state->m_blitter.spr_coll & 0x20);
+ state->m_blitter.spritenr = state->m_blitter.spr_coll & 0x0f;
+ state->m_blitter.fred = 0;
+
+ /* Draw Sprite */
+ lynx_blit_lines(state);
+
+ if (state->m_blitter.sprite_collide && !(state->m_blitter.no_collide))
+ {
+ switch (state->m_blitter.mode)
+ {
+ case BOUNDARY_SHADOW:
+ case BOUNDARY:
+ case NORMAL_SPRITE:
+ case XOR_SPRITE:
+ case SHADOW:
+ lynx_write_ram(state, state->m_blitter.colpos, state->m_blitter.fred);
+ break;
+ }
+ }
+
+ if (state->m_suzy.data[SPRGO] & 0x04) // Everon enabled
+ {
+ coldep = lynx_read_ram(state, state->m_blitter.colpos);
+ if (!state->m_blitter.everon)
+ coldep |= 0x80;
+ else
+ coldep &= 0x7f;
+ lynx_write_ram(state, state->m_blitter.colpos, coldep);
+ }
+ }
+ }
+
+ machine.scheduler().timer_set(machine.device<cpu_device>("maincpu")->cycles_to_attotime(state->m_blitter.memory_accesses), FUNC(lynx_blitter_timer));
+}
+
+
+/****************************************
+
+ Suzy Emulation
+
+****************************************/
+
+
+/* Math bugs of the original hardware:
+
+- in signed multiply, the hardware thinks that 8000 is a positive number
+- in signed multiply, the hardware thinks that 0 is a negative number. This is not an immediate
+problem for a multiply by zero, since the answer will be re-negated to the correct polarity of
+zero. However, since it will set the sign flag, you can not depend on the sign flag to be correct
+if you just load the lower byte after a multiply by zero.
+- in divide, the remainder will have 2 possible errors, depending on its actual value (no further
+notes on these errors available) */
+
+void lynx_state::lynx_divide()
+{
+ UINT32 left;
+ UINT16 right;
+ UINT32 res, mod;
+ /*
+ Hardware divide:
+ EFGH
+ * NP
+ ----------------
+ ABCD
+ Remainder (JK)LM
+ */
+
+ left = m_suzy.data[MATH_H] | (m_suzy.data[MATH_G] << 8) | (m_suzy.data[MATH_F] << 16) | (m_suzy.data[MATH_E] << 24);
+ right = m_suzy.data[MATH_P] | (m_suzy.data[MATH_N] << 8);
+
+ m_suzy.accumulate_overflow = FALSE;
+ if (right == 0)
+ {
+ m_suzy.accumulate_overflow = TRUE; /* during divisions, this bit is used to detect denominator = 0 */
+ res = 0xffffffff;
+ mod = 0; //?
+ }
+ else
+ {
+ res = left / right;
+ mod = left % right;
+ }
+// logerror("coprocessor %8x / %8x = %4x\n", left, right, res);
+ m_suzy.data[MATH_D] = res & 0xff;
+ m_suzy.data[MATH_C] = res >> 8;
+ m_suzy.data[MATH_B] = res >> 16;
+ m_suzy.data[MATH_A] = res >> 24;
+
+ m_suzy.data[MATH_M] = mod & 0xff;
+ m_suzy.data[MATH_L] = mod >> 8;
+ m_suzy.data[MATH_K] = 0; // documentation states the hardware sets these to zero on divides
+ m_suzy.data[MATH_J] = 0;
+}
+
+void lynx_state::lynx_multiply()
+{
+ UINT16 left, right;
+ UINT32 res, accu;
+ /*
+ Hardware multiply:
+ AB
+ * CD
+ ----------------
+ EFGH
+ Accumulate JKLM
+ */
+ m_suzy.accumulate_overflow = FALSE;
+
+ left = m_suzy.data[MATH_B] | (m_suzy.data[MATH_A] << 8);
+ right = m_suzy.data[MATH_D] | (m_suzy.data[MATH_C] << 8);
+
+ res = left * right;
+
+ if (m_suzy.signed_math)
+ {
+ if (!(m_sign_AB + m_sign_CD)) /* different signs */
+ res = (res ^ 0xffffffff) + 1;
+ }
+
+ m_suzy.data[MATH_H] = res & 0xff;
+ m_suzy.data[MATH_G] = res >> 8;
+ m_suzy.data[MATH_F] = res >> 16;
+ m_suzy.data[MATH_E] = res >> 24;
+
+ if (m_suzy.accumulate)
+ {
+ accu = m_suzy.data[MATH_M] | m_suzy.data[MATH_L] << 8 | m_suzy.data[MATH_K] << 16 | m_suzy.data[MATH_J] << 24;
+ accu += res;
+
+ if (accu < res)
+ m_suzy.accumulate_overflow = TRUE;
+
+ m_suzy.data[MATH_M] = accu;
+ m_suzy.data[MATH_L] = accu >> 8;
+ m_suzy.data[MATH_K] = accu >> 16;
+ m_suzy.data[MATH_J] = accu >> 24;
+ }
+}
+
+READ8_MEMBER(lynx_state::suzy_read)
+{
+ UINT8 value = 0, input;
+
+ switch (offset)
+ {
+ case TILTACUML:
+ return m_blitter.tilt_accumulator & 0xff;
+ case TILTACUMH:
+ return m_blitter.tilt_accumulator>>8;
+ case HOFFL:
+ return m_blitter.xoff & 0xff;
+ case HOFFH:
+ return m_blitter.xoff>>8;
+ case VOFFL:
+ return m_blitter.yoff & 0xff;
+ case VOFFH:
+ return m_blitter.yoff>>8;
+ case VIDBASL:
+ return m_blitter.screen & 0xff;
+ case VIDBASH:
+ return m_blitter.screen>>8;
+ case COLLBASL:
+ return m_blitter.colbuf & 0xff;
+ case COLLBASH:
+ return m_blitter.colbuf>>8;
+ case SCBNEXTL:
+ return m_blitter.scb_next & 0xff;
+ case SCBNEXTH:
+ return m_blitter.scb_next>>8;
+ case SPRDLINEL:
+ return m_blitter.bitmap & 0xff;
+ case SPRDLINEH:
+ return m_blitter.bitmap>>8;
+ case HPOSSTRTL:
+ return m_blitter.x_pos & 0xff;
+ case HPOSSTRTH:
+ return m_blitter.x_pos>>8;
+ case VPOSSTRTL:
+ return m_blitter.y_pos & 0xff;
+ case VPOSSTRTH:
+ return m_blitter.y_pos>>8;
+ case SPRHSIZL:
+ return m_blitter.width & 0xff;
+ case SPRHSIZH:
+ return m_blitter.width>>8;
+ case SPRVSIZL:
+ return m_blitter.height & 0xff;
+ case SPRVSIZH:
+ return m_blitter.height>>8;
+ case STRETCHL:
+ return m_blitter.stretch & 0xff;
+ case STRETCHH:
+ return m_blitter.stretch>>8;
+ case TILTL:
+ return m_blitter.tilt & 0xff;
+ case TILTH:
+ return m_blitter.tilt>>8;
+ // case SPRDOFFL:
+ // case SPRVPOSL:
+ // case COLLOFFL:
+ case VSIZACUML:
+ return m_blitter.height_accumulator & 0xff;
+ case VSIZACUMH:
+ return m_blitter.height_accumulator>>8;
+ case HSIZOFFL:
+ return m_blitter.width_offset & 0xff;
+ case HSIZOFFH:
+ return m_blitter.width_offset>>8;
+ case VSIZOFFL:
+ return m_blitter.height_offset & 0xff;
+ case VSIZOFFH:
+ return m_blitter.height_offset>>8;
+ case SCBADRL:
+ return m_blitter.scb & 0xff;
+ case SCBADRH:
+ return m_blitter.scb>>8;
+ //case PROCADRL:
+ case SUZYHREV:
+ return 0x01; // must not be 0 for correct power up
+ case SPRSYS:
+ // math busy, last carry, unsafe access, and stop on current sprite bits not implemented.
+ if (m_suzy.accumulate_overflow)
+ value |= 0x40;
+ if (m_blitter.vstretch)
+ value |= 0x10;
+ if (m_blitter.lefthanded)
+ value |= 0x08;
+ if (m_blitter.busy)
+ value |= 0x01;
+ break;
+ case JOYSTICK:
+ input = ioport("JOY")->read();
+ switch (m_rotate)
+ {
+ case 1:
+ value = input;
+ input &= 0x0f;
+ if (value & PAD_UP) input |= PAD_LEFT;
+ if (value & PAD_LEFT) input |= PAD_DOWN;
+ if (value & PAD_DOWN) input |= PAD_RIGHT;
+ if (value & PAD_RIGHT) input |= PAD_UP;
+ break;
+ case 2:
+ value = input;
+ input &= 0x0f;
+ if (value & PAD_UP) input |= PAD_RIGHT;
+ if (value & PAD_RIGHT) input |= PAD_DOWN;
+ if (value & PAD_DOWN) input |= PAD_LEFT;
+ if (value & PAD_LEFT) input |= PAD_UP;
+ break;
+ }
+ if (m_blitter.lefthanded)
+ {
+ value = input & 0x0f;
+ if (input & PAD_UP) value |= PAD_DOWN;
+ if (input & PAD_DOWN) value |= PAD_UP;
+ if (input & PAD_LEFT) value |= PAD_RIGHT;
+ if (input & PAD_RIGHT) value |= PAD_LEFT;
+ }
+ else
+ value = input;
+ break;
+ case SWITCHES:
+ value = ioport("PAUSE")->read();
+ break;
+ case RCART:
+ value = *(machine().root_device().memregion("user1")->base() + (m_suzy.high * m_granularity) + m_suzy.low);
+ m_suzy.low = (m_suzy.low + 1) & (m_granularity - 1);
+ break;
+ //case RCART_BANK1: /* we need bank 1 emulation!!! */
+ case SPRCTL0:
+ case SPRCTL1:
+ case SPRCOLL:
+ case SPRINIT:
+ case SUZYBUSEN:
+ case SPRGO:
+ logerror("read from write only register %x\n", offset);
+ value = 0;
+ break;
+ default:
+ value = m_suzy.data[offset];
+ }
+ //logerror("suzy read %.2x %.2x\n",offset,value);
+ return value;
+}
+
+WRITE8_MEMBER(lynx_state::suzy_write)
+{
+ m_suzy.data[offset] = data;
+ //logerror("suzy write %.2x %.2x\n",offset,data);
+ /* Additional effects of a write */
+ /* Even addresses are the LSB. Any CPU write to an LSB in 0x00-0x7f will set the MSB to 0. */
+ /* This in particular holds for math quantities: Writing to B (0x54), D (0x52),
+ F (0x62), H (0x60), K (0x6e) or M (0x6c) will force a '0' to be written to A (0x55),
+ C (0x53), E (0x63), G (0x61), J (0x6f) or L (0x6d) respectively */
+ if ((offset < 0x80) && !(offset & 0x01))
+ m_suzy.data[offset + 1] = 0;
+
+ switch(offset)
+ {
+ //case TMPADRL:
+ //case TMPADRH:
+ case TILTACUML:
+ m_blitter.tilt_accumulator = data; // upper byte forced to zero see above.
+ break;
+ case TILTACUMH:
+ m_blitter.tilt_accumulator &= 0xff;
+ m_blitter.tilt_accumulator |= data<<8;
+ break;
+ case HOFFL:
+ m_blitter.xoff = data;
+ break;
+ case HOFFH:
+ m_blitter.xoff &= 0xff;
+ m_blitter.xoff |= data<<8;
+ break;
+ case VOFFL:
+ m_blitter.yoff = data;
+ break;
+ case VOFFH:
+ m_blitter.yoff &= 0xff;
+ m_blitter.yoff |= data<<8;
+ break;
+ case VIDBASL:
+ m_blitter.screen = data;
+ break;
+ case VIDBASH:
+ m_blitter.screen &= 0xff;
+ m_blitter.screen |= data<<8;
+ break;
+ case COLLBASL:
+ m_blitter.colbuf = data;
+ break;
+ case COLLBASH:
+ m_blitter.colbuf &= 0xff;
+ m_blitter.colbuf |= data<<8;
+ break;
+ case SCBNEXTL:
+ m_blitter.scb_next = data;
+ break;
+ case SCBNEXTH:
+ m_blitter.scb_next &= 0xff;
+ m_blitter.scb_next |= data<<8;
+ break;
+ case SPRDLINEL:
+ m_blitter.bitmap = data;
+ break;
+ case SPRDLINEH:
+ m_blitter.bitmap &= 0xff;
+ m_blitter.bitmap |= data<<8;
+ break;
+ case HPOSSTRTL:
+ m_blitter.x_pos = data;
+ case HPOSSTRTH:
+ m_blitter.x_pos &= 0xff;
+ m_blitter.x_pos |= data<<8;
+ case VPOSSTRTL:
+ m_blitter.y_pos = data;
+ case VPOSSTRTH:
+ m_blitter.y_pos &= 0xff;
+ m_blitter.y_pos |= data<<8;
+ case SPRHSIZL:
+ m_blitter.width = data;
+ break;
+ case SPRHSIZH:
+ m_blitter.width &= 0xff;
+ m_blitter.width |= data<<8;
+ break;
+ case SPRVSIZL:
+ m_blitter.height = data;
+ break;
+ case SPRVSIZH:
+ m_blitter.height &= 0xff;
+ m_blitter.height |= data<<8;
+ break;
+ case STRETCHL:
+ m_blitter.stretch = data;
+ break;
+ case STRETCHH:
+ m_blitter.stretch &= 0xff;
+ m_blitter.stretch |= data<<8;
+ break;
+ case TILTL:
+ m_blitter.tilt = data;
+ break;
+ case TILTH:
+ m_blitter.tilt &= 0xff;
+ m_blitter.tilt |= data<<8;
+ break;
+ // case SPRDOFFL:
+ // case SPRVPOSL:
+ // case COLLOFFL:
+ case VSIZACUML:
+ m_blitter.height_accumulator = data;
+ break;
+ case VSIZACUMH:
+ m_blitter.height_accumulator &= 0xff;
+ m_blitter.height_accumulator |= data<<8;
+ break;
+ case HSIZOFFL:
+ m_blitter.width_offset = data;
+ break;
+ case HSIZOFFH:
+ m_blitter.width_offset &= 0xff;
+ m_blitter.width_offset |= data<<8;
+ break;
+ case VSIZOFFL:
+ m_blitter.height_offset = data;
+ break;
+ case VSIZOFFH:
+ m_blitter.height_offset &= 0xff;
+ m_blitter.height_offset |= data<<8;
+ break;
+ case SCBADRL:
+ m_blitter.scb = data;
+ break;
+ case SCBADRH:
+ m_blitter.scb &= 0xff;
+ m_blitter.scb |= data<<8;
+ break;
+ //case PROCADRL:
+
+ /* Writing to M (0x6c) will also clear the accumulator overflow bit */
+ case MATH_M:
+ m_suzy.accumulate_overflow = FALSE;
+ break;
+ case MATH_C:
+ /* If we are going to perform a signed multiplication, we store the sign and convert the number
+ to an unsigned one */
+ if (m_suzy.signed_math)
+ {
+ UINT16 factor, temp;
+ factor = m_suzy.data[MATH_D] | (m_suzy.data[MATH_C] << 8);
+ if ((factor - 1) & 0x8000) /* here we use -1 to cover the math bugs on the sign of 0 and 0x8000 */
+ {
+ temp = (factor ^ 0xffff) + 1;
+ m_sign_CD = - 1;
+ m_suzy.data[MATH_D] = temp & 0xff;
+ m_suzy.data[MATH_C] = temp >> 8;
+ }
+ else
+ m_sign_CD = 1;
+ }
+ break;
+ case MATH_D:
+ /* Documentation states that writing to the MATH_D will set MATH_C to zero but not update the sign flag.
+ Implementing the sign detection as described in the documentation causes Stun Runners to not work.
+ Either the sign error in the docs is not as described or writing to the lower byte does update the sign flag.
+ Here I assume the sign flag gets updated. */
+ if (data)
+ m_sign_CD = 1;
+ break;
+ /* Writing to A will start a 16 bit multiply */
+ /* If we are going to perform a signed multiplication, we also store the sign and convert the
+ number to an unsigned one */
+ case MATH_A:
+ if (m_suzy.signed_math)
+ {
+ UINT16 factor, temp;
+ factor = m_suzy.data[MATH_B] | (m_suzy.data[MATH_A] << 8);
+ if ((factor - 1) & 0x8000) /* here we use -1 to cover the math bugs on the sign of 0 and 0x8000 */
+ {
+ temp = (factor ^ 0xffff) + 1;
+ m_sign_AB = - 1;
+ m_suzy.data[MATH_B] = temp & 0xff;
+ m_suzy.data[MATH_A] = temp >> 8;
+ }
+ else
+ m_sign_AB = 1;
+ }
+ lynx_multiply();
+ break;
+ /* Writing to E will start a 16 bit divide */
+ case MATH_E:
+ lynx_divide();
+ break;
+ case SPRCTL0:
+ m_blitter.spr_ctl0 = data;
+ break;
+ case SPRCTL1:
+ m_blitter.spr_ctl1 = data;
+ break;
+ case SPRCOLL:
+ m_blitter.spr_coll = data;
+ break;
+ case SUZYBUSEN:
+ logerror("write to SUSYBUSEN %x \n", data);
+ break;
+ case SPRSYS:
+ m_suzy.signed_math = (data & 0x80) ? 1:0;
+ m_suzy.accumulate = (data & 0x40) ? 1:0;
+ m_blitter.no_collide = (data & 0x20) ? 1:0;
+ m_blitter.vstretch = (data & 0x10) ? 1:0;
+ m_blitter.lefthanded = (data & 0x08) ? 1:0;
+ // unsafe access clear and sprite engine stop request are not enabled
+ if (data & 0x02) logerror("sprite engine stop request\n");
+ break;
+ case SPRGO:
+ if ((data & 0x01) && m_suzy.data[SUZYBUSEN])
+ {
+ //m_blitter.time = machine().time();
+ lynx_blitter(machine());
+ }
+ break;
+ case JOYSTICK:
+ case SWITCHES:
+ logerror("warning: write to read-only button registers\n");
+ break;
+ }
+}
+
+
+/****************************************
+
+ Mikey emulation
+
+****************************************/
+
+/*
+ 0xfd0a r sync signal?
+ 0xfd81 r interrupt source bit 2 vertical refresh
+ 0xfd80 w interrupt quit
+ 0xfd87 w bit 1 !clr bit 0 blocknumber clk
+ 0xfd8b w bit 1 blocknumber hi B
+ 0xfd94 w 0
+ 0xfd95 w 4
+ 0xfda0-f rw farben 0..15
+ 0xfdb0-f rw bit0..3 farben 0..15
+*/
+
+
+/*
+DISPCTL EQU $FD92 ; set to $D by INITMIKEY
+
+; B7..B4 0
+; B3 1 EQU color
+; B2 1 EQU 4 bit mode
+; B1 1 EQU flip screen
+; B0 1 EQU video DMA enabled
+*/
+
+static void lynx_draw_line(running_machine &machine)
+{
+ lynx_state *state = machine.driver_data<lynx_state>();
+ int x, y;
+ UINT16 j; // clipping needed!
+ UINT8 byte;
+ UINT16 *line;
+
+
+ // calculate y: first three lines are vblank,
+ y = 101-state->m_timer[2].counter;
+ // Documentation states lower two bits of buffer address are ignored (thus 0xfffc mask)
+ j = (state->m_mikey.disp_addr & 0xfffc) + y * 160 / 2;
+
+ if (state->m_mikey.data[0x92] & 0x02)
+ {
+ j -= 160 * 102 / 2 - 1;
+ line = &state->m_bitmap_temp.pix16(102 - 1 - y);
+ for (x = 160 - 2; x >= 0; j++, x -= 2)
+ {
+ byte = lynx_read_ram(state, j);
+ line[x + 1] = state->m_palette[(byte >> 4) & 0x0f];
+ line[x + 0] = state->m_palette[(byte >> 0) & 0x0f];
+ }
+ }
+ else
+ {
+ line = &state->m_bitmap_temp.pix16(y);
+ for (x = 0; x < 160; j++, x += 2)
+ {
+ byte = lynx_read_ram(state, j);
+ line[x + 0] = state->m_palette[(byte >> 4) & 0x0f];
+ line[x + 1] = state->m_palette[(byte >> 0) & 0x0f];
+ }
+ }
+}
+
+/****************************************
+
+ Timers
+
+****************************************/
+
+/*
+HCOUNTER EQU TIMER0
+VCOUNTER EQU TIMER2
+SERIALRATE EQU TIMER4
+
+TIM_BAKUP EQU 0 ; backup-value (count+1)
+TIM_CNTRL1 EQU 1 ; timer-control register
+TIM_CNT EQU 2 ; current counter
+TIM_CNTRL2 EQU 3 ; dynamic control
+
+; TIM_CNTRL1
+TIM_IRQ EQU %10000000 ; enable interrupt (not TIMER4 !)
+TIM_RESETDONE EQU %01000000 ; reset timer done
+TIM_MAGMODE EQU %00100000 ; nonsense in Lynx !!
+TIM_RELOAD EQU %00010000 ; enable reload
+TIM_COUNT EQU %00001000 ; enable counter
+TIM_LINK EQU %00000111
+; link timers (0->2->4 / 1->3->5->7->Aud0->Aud1->Aud2->Aud3->1
+TIM_64us EQU %00000110
+TIM_32us EQU %00000101
+TIM_16us EQU %00000100
+TIM_8us EQU %00000011
+TIM_4us EQU %00000010
+TIM_2us EQU %00000001
+TIM_1us EQU %00000000
+
+;TIM_CNTRL2 (read-only)
+; B7..B4 unused
+TIM_DONE EQU %00001000 ; set if timer's done; reset with TIM_RESETDONE
+TIM_LAST EQU %00000100 ; last clock (??)
+TIM_BORROWIN EQU %00000010
+TIM_BORROWOUT EQU %00000001
+*/
+
+#define NR_LYNX_TIMERS 8
+
+
+static TIMER_CALLBACK(lynx_timer_shot);
+
+static void lynx_timer_init(running_machine &machine, int which)
+{
+ lynx_state *state = machine.driver_data<lynx_state>();
+ memset( &state->m_timer[which], 0, sizeof(LYNX_TIMER) );
+ state->m_timer[which].timer = machine.scheduler().timer_alloc(FUNC(lynx_timer_shot));
+}
+
+static void lynx_timer_signal_irq(running_machine &machine, int which)
+{
+ lynx_state *state = machine.driver_data<lynx_state>();
+ if ( ( state->m_timer[which].cntrl1 & 0x80 ) && ( which != 4 ) ) // if interrupts are enabled and timer != 4
+ {
+ state->m_mikey.data[0x81] |= ( 1 << which ); // set interupt poll register
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_HALT, CLEAR_LINE);
+ cputag_set_input_line(machine, "maincpu", M65SC02_IRQ_LINE, ASSERT_LINE);
+ }
+ switch ( which ) // count down linked timers
+ {
+ case 0:
+ switch (state->m_timer[2].counter)
+ {
+ case 104:
+ break;
+ case 103:
+ state->m_mikey.vb_rest = 1;
+ break;
+ case 102:
+ state->m_mikey.disp_addr = state->m_mikey.data[0x94] | (state->m_mikey.data[0x95] << 8);
+ break;
+ case 101:
+ state->m_mikey.vb_rest = 0;
+ lynx_draw_line( machine );
+ break;
+ default:
+ lynx_draw_line( machine );
+ }
+ lynx_timer_count_down( machine, 2 );
+ break;
+ case 2:
+ copybitmap(state->m_bitmap, state->m_bitmap_temp, 0, 0, 0, 0, machine.primary_screen->cliprect());
+ lynx_timer_count_down( machine, 4 );
+ break;
+ case 1:
+ lynx_timer_count_down( machine, 3 );
+ break;
+ case 3:
+ lynx_timer_count_down( machine, 5 );
+ break;
+ case 5:
+ lynx_timer_count_down( machine, 7 );
+ break;
+ case 7:
+ lynx_audio_count_down( state->m_audio, 0 );
+ break;
+ }
+}
+
+void lynx_timer_count_down(running_machine &machine, int which)
+{
+ lynx_state *state = machine.driver_data<lynx_state>();
+ if ( ( state->m_timer[which].cntrl1 & 0x0f ) == 0x0f ) // count and linking enabled
+ {
+ if ( state->m_timer[which].counter > 0 )
+ {
+ state->m_timer[which].counter--;
+ //state->m_timer[which].borrow_in = 1;
+ return;
+ }
+ if ( state->m_timer[which].counter == 0 )
+ {
+ if (state->m_timer[which].cntrl2 & 0x01) // borrow out
+ {
+ lynx_timer_signal_irq(machine, which);
+ if ( state->m_timer[which].cntrl1 & 0x10 ) // if reload enabled
+ {
+ state->m_timer[which].counter = state->m_timer[which].bakup;
+ }
+ else
+ {
+ state->m_timer[which].cntrl2 |= 8; // set timer done
+ }
+ state->m_timer[which].cntrl2 &= ~0x01; // clear borrow out
+ }
+ else
+ state->m_timer[which].cntrl2 |= 0x01; // set borrow out
+ return;
+ }
+ }
+ else
+ {
+ //state->m_timer[which].borrow_in = 0;
+ state->m_timer[which].cntrl2 &= ~0x01;
+ }
+}
+
+static UINT32 lynx_time_factor(int val)
+{
+ switch(val)
+ {
+ case 0: return 1000000;
+ case 1: return 500000;
+ case 2: return 250000;
+ case 3: return 125000;
+ case 4: return 62500;
+ case 5: return 31250;
+ case 6: return 15625;
+ default: fatalerror("invalid value");
+ }
+}
+
+static TIMER_CALLBACK(lynx_timer_shot)
+{
+ lynx_state *state = machine.driver_data<lynx_state>();
+ lynx_timer_signal_irq( machine, param );
+ if ( ! ( state->m_timer[param].cntrl1 & 0x10 ) ) // if reload not enabled
+ {
+ state->m_timer[param].timer_active = 0;
+ state->m_timer[param].cntrl2 |= 8; // set timer done
+ }
+ else
+ {
+ attotime t = (attotime::from_hz(lynx_time_factor(state->m_timer[param].cntrl1 & 0x07)) * (state->m_timer[param].bakup + 1));
+ state->m_timer[param].timer->adjust(t, param);
+ }
+}
+
+UINT8 lynx_state::lynx_timer_read(int which, int offset)
+{
+ UINT8 value = 0;
+
+ switch (offset)
+ {
+ case 0:
+ value = m_timer[which].bakup;
+ break;
+ case 1:
+ value = m_timer[which].cntrl1;
+ break;
+ case 2:
+ if ((m_timer[which].cntrl1 & 0x07) == 0x07) // linked timer
+ {
+ value = m_timer[which].counter;
+ }
+ else
+ {
+ if ( m_timer[which].timer_active )
+ {
+ value = (UINT8) (m_timer[which].timer->remaining().as_ticks(1000000>>(m_timer[which].cntrl1 & 0x07)));
+ value -= value ? 1 : 0;
+ }
+ }
+ break;
+
+ case 3:
+ value = m_timer[which].cntrl2;
+ break;
+ }
+ // logerror("timer %d read %x %.2x\n", which, offset, value);
+ return value;
+}
+
+void lynx_state::lynx_timer_write(int which, int offset, UINT8 data)
+{
+ //logerror("timer %d write %x %.2x\n", which, offset, data);
+ attotime t;
+
+ if ( m_timer[which].timer_active && ((m_timer[which].cntrl1 & 0x07) != 0x07))
+ {
+ m_timer[which].counter = (UINT8) (m_timer[which].timer->remaining().as_ticks(1000000>>(m_timer[which].cntrl1 & 0x07)));
+ m_timer[which].counter -= (m_timer[which].counter) ? 1 : 0;
+ }
+
+ switch (offset)
+ {
+ case 0:
+ m_timer[which].bakup = data;
+ break;
+ case 1:
+ m_timer[which].cntrl1 = data;
+ if (data & 0x40) // reset timer done
+ m_timer[which].cntrl2 &= ~0x08;
+ break;
+ case 2:
+ m_timer[which].counter = data;
+ break;
+ case 3:
+ m_timer[which].cntrl2 = (m_timer[which].cntrl2 & ~0x08) | (data & 0x08);
+ break;
+ }
+
+ /* Update timers */
+ //if ( offset < 3 )
+ //{
+ m_timer[which].timer->reset();
+ m_timer[which].timer_active = 0;
+ if ((m_timer[which].cntrl1 & 0x08) && !(m_timer[which].cntrl2 & 0x08)) // if enable count
+ {
+ if ((m_timer[which].cntrl1 & 0x07) != 0x07) // if not set to link mode
+ {
+ t = (attotime::from_hz(lynx_time_factor(m_timer[which].cntrl1 & 0x07)) * (m_timer[which].counter + 1));
+ m_timer[which].timer->adjust(t, which);
+ m_timer[which].timer_active = 1;
+ }
+ }
+ //}
+}
+
+
+/****************************************
+
+ UART Emulation
+
+****************************************/
+
+
+static void lynx_uart_reset(lynx_state *state)
+{
+ memset(&state->m_uart, 0, sizeof(state->m_uart));
+}
+
+static TIMER_CALLBACK(lynx_uart_loopback_timer)
+{
+ lynx_state *state = machine.driver_data<lynx_state>();
+ state->m_uart.received = FALSE;
+}
+
+static TIMER_CALLBACK(lynx_uart_timer)
+{
+ lynx_state *state = machine.driver_data<lynx_state>();
+ if (state->m_uart.buffer_loaded)
+ {
+ state->m_uart.data_to_send = state->m_uart.buffer;
+ state->m_uart.buffer_loaded = FALSE;
+ machine.scheduler().timer_set(attotime::from_usec(11*16), FUNC(lynx_uart_timer));
+ }
+ else
+ {
+ state->m_uart.sending = FALSE;
+ state->m_uart.received = TRUE;
+ state->m_uart.data_received = state->m_uart.data_to_send;
+ machine.scheduler().timer_set(attotime::from_usec(11*16), FUNC(lynx_uart_loopback_timer));
+ if (state->m_uart.serctl & 0x40)
+ {
+ state->m_mikey.data[0x81] |= 0x10;
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_HALT, CLEAR_LINE);
+ cputag_set_input_line(machine, "maincpu", M65SC02_IRQ_LINE, ASSERT_LINE);
+ }
+ }
+
+ if (state->m_uart.serctl & 0x80)
+ {
+ state->m_mikey.data[0x81] |= 0x10;
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_HALT, CLEAR_LINE);
+ cputag_set_input_line(machine, "maincpu", M65SC02_IRQ_LINE, ASSERT_LINE);
+ }
+}
+
+static READ8_HANDLER(lynx_uart_r)
+{
+ lynx_state *state = space->machine().driver_data<lynx_state>();
+ UINT8 value = 0x00;
+ switch (offset)
+ {
+ case 0x8c:
+ if (!state->m_uart.buffer_loaded)
+ value |= 0x80;
+ if (state->m_uart.received)
+ value |= 0x40;
+ if (!state->m_uart.sending)
+ value |= 0x20;
+ break;
+
+ case 0x8d:
+ value = state->m_uart.data_received;
+ break;
+ }
+ logerror("uart read %.2x %.2x\n", offset, value);
+ return value;
+}
+
+WRITE8_MEMBER(lynx_state::lynx_uart_w)
+{
+ logerror("uart write %.2x %.2x\n", offset, data);
+ switch (offset)
+ {
+ case 0x8c:
+ m_uart.serctl = data;
+ break;
+
+ case 0x8d:
+ if (m_uart.sending)
+ {
+ m_uart.buffer = data;
+ m_uart.buffer_loaded = TRUE;
+ }
+ else
+ {
+ m_uart.sending = TRUE;
+ m_uart.data_to_send = data;
+ // timing not accurate, baude rate should be calculated from timer 4 backup value and clock rate
+ machine().scheduler().timer_set(attotime::from_usec(11*16), FUNC(lynx_uart_timer));
+ }
+ break;
+ }
+}
+
+
+/****************************************
+
+ Mikey memory handlers
+
+****************************************/
+
+
+READ8_MEMBER(lynx_state::mikey_read)
+{
+ UINT8 direction, value = 0x00;
+
+ switch (offset)
+ {
+ 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 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:
+ value = lynx_timer_read(offset >> 2, offset & 0x03);
+ 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:
+ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
+ case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
+ case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x50:
+ value = lynx_audio_read(m_audio, offset);
+ break;
+
+ case 0x80:
+ case 0x81:
+ value = m_mikey.data[0x81]; // both registers access the same interupt status byte
+ // logerror( "mikey read %.2x %.2x\n", offset, value );
+ break;
+
+ case 0x84:
+ case 0x85:
+ value = 0x00;
+ break;
+
+ case 0x86:
+ value = 0x80;
+ break;
+
+ case 0x88:
+ value = 0x01;
+ break;
+
+ case 0x8b:
+ direction = m_mikey.data[0x8a];
+ value |= (direction & 0x01) ? (m_mikey.data[offset] & 0x01) : 0x01; // External Power input
+ value |= (direction & 0x02) ? (m_mikey.data[offset] & 0x02) : 0x00; // Cart Address Data output (0 turns cart power on)
+ value |= (direction & 0x04) ? (m_mikey.data[offset] & 0x04) : 0x04; // noexp input
+ // REST read returns actual rest state anded with rest output bit
+ value |= (direction & 0x08) ? (((m_mikey.data[offset] & 0x08) && (m_mikey.vb_rest)) ? 0x00 : 0x08) : 0x00; // rest output
+ value |= (direction & 0x10) ? (m_mikey.data[offset] & 0x10) : 0x10; // audin input
+ /* Hack: we disable COMLynx */
+ value |= 0x04;
+ /* B5, B6 & B7 are not used */
+ break;
+
+ case 0x8c:
+ case 0x8d:
+ value = lynx_uart_r(&space, offset);
+ break;
+
+ default:
+ value = m_mikey.data[offset];
+ //logerror( "mikey read %.2x %.2x\n", offset, value );
+ }
+ return value;
+}
+
+WRITE8_MEMBER(lynx_state::mikey_write)
+{
+ switch (offset)
+ {
+ 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 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:
+ lynx_timer_write(offset >> 2, offset & 3, data);
+ return;
+
+ 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: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
+ case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
+ case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x50:
+ lynx_audio_write(m_audio, offset, data);
+ return;
+
+ case 0x80:
+ m_mikey.data[0x81] &= ~data; // clear interrupt source
+ // logerror("mikey write %.2x %.2x\n", offset, data);
+ if (!m_mikey.data[0x81])
+ cputag_set_input_line(machine(), "maincpu", M65SC02_IRQ_LINE, CLEAR_LINE);
+ break;
+
+ /* Is this correct? */ // Notes say writing to register will result in interupt being triggered.
+ case 0x81:
+ m_mikey.data[0x81] |= data;
+ if (data)
+ {
+ cputag_set_input_line(machine(), "maincpu", INPUT_LINE_HALT, CLEAR_LINE);
+ cputag_set_input_line(machine(), "maincpu", M65SC02_IRQ_LINE, ASSERT_LINE);
+ logerror("direct write to interupt register\n");
+ }
+ break;
+
+ case 0x87:
+ m_mikey.data[offset] = data;
+ if (data & 0x02) // Power (1 = on)
+ {
+ if (data & 0x01) // Cart Address Strobe
+ {
+ m_suzy.high <<= 1;
+ if (m_mikey.data[0x8b] & 0x02)
+ m_suzy.high |= 1;
+ m_suzy.high &= 0xff;
+ m_suzy.low = 0;
+ }
+ }
+ else
+ {
+ m_suzy.high = 0;
+ m_suzy.low = 0;
+ }
+ break;
+
+ case 0x8c: case 0x8d:
+ lynx_uart_w(space, offset, data);
+ 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:
+ m_mikey.data[offset] = data;
+
+ /* RED = 0xb- & 0x0f, GREEN = 0xa- & 0x0f, BLUE = (0xb- & 0xf0) >> 4 */
+ m_palette[offset & 0x0f] = machine().pens[
+ ((m_mikey.data[0xb0 + (offset & 0x0f)] & 0x0f)) |
+ ((m_mikey.data[0xa0 + (offset & 0x0f)] & 0x0f) << 4) |
+ ((m_mikey.data[0xb0 + (offset & 0x0f)] & 0xf0) << 4)];
+ break;
+
+ /* TODO: properly implement these writes */
+ case 0x8b:
+ m_mikey.data[offset] = data;
+ if (m_mikey.data[0x8a] & 0x10)
+ logerror("Trying to enable bank 1 write. %d\n", m_mikey.data[offset] & 0x10);
+ break;
+
+ //case 0x90: // SDONEACK - Suzy Done Acknowledge
+ case 0x91: // CPUSLEEP - CPU Bus Request Disable
+ m_mikey.data[offset] = data;
+ if (!data && m_blitter.busy)
+ {
+ cputag_set_input_line(machine(), "maincpu", INPUT_LINE_HALT, ASSERT_LINE);
+ /* A write of '0' to this address will reset the CPU bus request flip flop */
+ }
+ break;
+ case 0x94: case 0x95:
+ m_mikey.data[offset]=data;
+ break;
+ case 0x9c: case 0x9d: case 0x9e:
+ m_mikey.data[offset]=data;
+ logerror("Mtest%d write: %x\n", offset&0x3, data);
+ break;
+
+ default:
+ m_mikey.data[offset]=data;
+ //logerror("mikey write %.2x %.2x\n",offset,data);
+ break;
+ }
+}
+
+/****************************************
+
+ Init / Config
+
+****************************************/
+
+READ8_MEMBER(lynx_state::lynx_memory_config_r)
+{
+ return m_memory_config;
+}
+
+WRITE8_MEMBER(lynx_state::lynx_memory_config_w)
+{
+ /* bit 7: hispeed, uses page mode accesses (4 instead of 5 cycles )
+ * when these are safe in the cpu */
+ m_memory_config = data;
+
+ if (data & 1) {
+ space.install_readwrite_bank(0xfc00, 0xfcff, "bank1");
+ } else {
+ space.install_readwrite_handler(0xfc00, 0xfcff, read8_delegate(FUNC(lynx_state::suzy_read),this), write8_delegate(FUNC(lynx_state::suzy_write),this));
+ }
+ if (data & 2) {
+ space.install_readwrite_bank(0xfd00, 0xfdff, "bank2");
+ } else {
+ space.install_readwrite_handler(0xfd00, 0xfdff, read8_delegate(FUNC(lynx_state::mikey_read),this), write8_delegate(FUNC(lynx_state::mikey_write),this));
+ }
+
+ if (data & 1)
+ membank("bank1")->set_base(m_mem_fc00);
+ if (data & 2)
+ membank("bank2")->set_base(m_mem_fd00);
+ membank("bank3")->set_entry((data & 4) ? 1 : 0);
+ membank("bank4")->set_entry((data & 8) ? 1 : 0);
+}
+
+static void lynx_reset(running_machine &machine)
+{
+ lynx_state *state = machine.driver_data<lynx_state>();
+ state->lynx_memory_config_w(*machine.device("maincpu")->memory().space(AS_PROGRAM), 0, 0);
+
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_HALT, CLEAR_LINE);
+ cputag_set_input_line(machine, "maincpu", M65SC02_IRQ_LINE, CLEAR_LINE);
+
+ memset(&state->m_suzy, 0, sizeof(state->m_suzy));
+ memset(&state->m_mikey, 0, sizeof(state->m_mikey));
+
+ state->m_suzy.data[0x88] = 0x01;
+ state->m_suzy.data[0x90] = 0x00;
+ state->m_suzy.data[0x91] = 0x00;
+ state->m_mikey.data[0x80] = 0x00;
+ state->m_mikey.data[0x81] = 0x00;
+ state->m_mikey.data[0x88] = 0x01;
+ state->m_mikey.data[0x8a] = 0x00;
+ state->m_mikey.data[0x8c] = 0x00;
+ state->m_mikey.data[0x90] = 0x00;
+ state->m_mikey.data[0x92] = 0x00;
+
+ lynx_uart_reset(state);
+
+ // hack to allow current object loading to work
+#if 0
+ lynx_timer_write( state, 0, 0, 160 ); // set backup value (hpos) = 160
+ lynx_timer_write( state, 0, 1, 0x10 | 0x8 | 0 ); // enable count, enable reload, 1us period
+ lynx_timer_write( state, 2, 0, 105 ); // set backup value (vpos) = 102
+ lynx_timer_write( state, 2, 1, 0x10 | 0x8 | 7 ); // enable count, enable reload, link
+#endif
+}
+
+static void lynx_postload(lynx_state *state)
+{
+ state->lynx_memory_config_w( *state->machine().device("maincpu")->memory().space(AS_PROGRAM), 0, state->m_memory_config);
+}
+
+MACHINE_START( lynx )
+{
+ lynx_state *state = machine.driver_data<lynx_state>();
+ state->m_bitmap_temp.allocate(160,102,0,0);
+
+ int i;
+ state->save_item(NAME(state->m_memory_config));
+ state->save_pointer(NAME(state->m_mem_fe00.target()), state->m_mem_fe00.bytes());
+ machine.save().register_postload(save_prepost_delegate(FUNC(lynx_postload), state));
+
+ state->membank("bank3")->configure_entry(0, machine.root_device().memregion("maincpu")->base() + 0x0000);
+ state->membank("bank3")->configure_entry(1, state->m_mem_fe00);
+ state->membank("bank4")->configure_entry(0, state->memregion("maincpu")->base() + 0x01fa);
+ state->membank("bank4")->configure_entry(1, state->m_mem_fffa);
+
+ state->m_audio = machine.device("custom");
+
+ memset(&state->m_suzy, 0, sizeof(state->m_suzy));
+
+ machine.add_notifier(MACHINE_NOTIFY_RESET, machine_notify_delegate(FUNC(lynx_reset),&machine));
+
+ for (i = 0; i < NR_LYNX_TIMERS; i++)
+ lynx_timer_init(machine, i);
+}
+
+MACHINE_RESET( lynx )
+{
+ lynx_state *state = machine.driver_data<lynx_state>();
+ render_target *target = machine.render().first_target();
+ target->set_view(state->m_rotate);
+}
+
+/****************************************
+
+ Image handling
+
+****************************************/
+
+
+static void lynx_partialhash(hash_collection &dest, const unsigned char *data,
+ unsigned long length, const char *functions)
+{
+ if (length <= 64)
+ return;
+ dest.compute(&data[64], length - 64, functions);
+}
+
+int lynx_verify_cart (char *header, int kind)
+{
+ if (kind)
+ {
+ if (strncmp("BS93", &header[6], 4))
+ {
+ logerror("This is not a valid Lynx image\n");
+ return IMAGE_VERIFY_FAIL;
+ }
+ }
+ else
+ {
+ if (strncmp("LYNX",&header[0],4))
+ {
+ if (!strncmp("BS93", &header[6], 4))
+ {
+ logerror("This image is probably a Quickload image with .lnx extension\n");
+ logerror("Try to load it with -quickload\n");
+ }
+ else
+ logerror("This is not a valid Lynx image\n");
+ return IMAGE_VERIFY_FAIL;
+ }
+ }
+
+ return IMAGE_VERIFY_PASS;
+}
+
+static DEVICE_IMAGE_LOAD( lynx_cart )
+{
+ /* Lynx carts have 19 address lines, the upper 8 used for bank select. The lower
+ 11 bits are used to address data within the selected bank. Valid bank sizes are 256,
+ 512, 1024 or 2048 bytes. Commercial roms use all 256 banks.*/
+
+ lynx_state *state = image.device().machine().driver_data<lynx_state>();
+ UINT8 *rom = state->memregion("user1")->base();
+ UINT32 size;
+ UINT8 header[0x40];
+
+ if (image.software_entry() == NULL)
+ {
+ const char *filetype;
+ size = image.length();
+/* 64 byte header
+ LYNX
+ intelword lower counter size
+ 0 0 1 0
+ 32 chars name
+ 22 chars manufacturer
+*/
+
+ filetype = image.filetype();
+
+ if (!mame_stricmp (filetype, "lnx"))
+ {
+ if (image.fread( header, 0x40) != 0x40)
+ return IMAGE_INIT_FAIL;
+
+ /* Check the image */
+ if (lynx_verify_cart((char*)header, LYNX_CART) == IMAGE_VERIFY_FAIL)
+ return IMAGE_INIT_FAIL;
+
+ /* 2008-10 FP: According to Handy source these should be page_size_bank0. Are we using
+ it correctly in MESS? Moreover, the next two values should be page_size_bank1. We should
+ implement this as well */
+ state->m_granularity = header[4] | (header[5] << 8);
+
+ logerror ("%s %dkb cartridge with %dbyte granularity from %s\n",
+ header + 10, size / 1024, state->m_granularity, header + 42);
+
+ size -= 0x40;
+ }
+ else if (!mame_stricmp (filetype, "lyx"))
+ {
+ /* 2008-10 FP: FIXME: .lyx file don't have an header, hence they miss "lynx_granularity"
+ (see above). What if bank 0 has to be loaded elsewhere? And what about bank 1?
+ These should work with most .lyx files, but we need additional info on raw cart images */
+ if (size == 0x20000)
+ state->m_granularity = 0x0200;
+ else if (size == 0x80000)
+ state->m_granularity = 0x0800;
+ else
+ state->m_granularity = 0x0400;
+ }
+
+ if (image.fread( rom, size) != size)
+ return IMAGE_INIT_FAIL;
+ }
+ else
+ {
+ size = image.get_software_region_length("rom");
+ if (size > 0xffff) // 64,128,256,512k cartridges
+ state->m_granularity = size >> 8;
+ else
+ state->m_granularity = 0x400; // Homebrew roms not using all 256 banks (T-Tris) (none currently in softlist)
+
+ memcpy(rom, image.get_software_region("rom"), size);
+
+ const char *rotate = image.get_feature("rotation");
+ state->m_rotate = 0;
+ if (rotate)
+ {
+ if(strcmp(rotate, "RIGHT") == 0) {
+ state->m_rotate = 1;
+ }
+ else if (strcmp(rotate, "LEFT") == 0) {
+ state->m_rotate = 2;
+ }
+ }
+
+ }
+
+ return IMAGE_INIT_PASS;
+}
+
+MACHINE_CONFIG_FRAGMENT(lynx_cartslot)
+ MCFG_CARTSLOT_ADD("cart")
+ MCFG_CARTSLOT_EXTENSION_LIST("lnx,lyx")
+ MCFG_CARTSLOT_MANDATORY
+ MCFG_CARTSLOT_INTERFACE("lynx_cart")
+ MCFG_CARTSLOT_LOAD(lynx_cart)
+ MCFG_CARTSLOT_PARTIALHASH(lynx_partialhash)
+
+ /* Software lists */
+ MCFG_SOFTWARE_LIST_ADD("cart_list","lynx")
+MACHINE_CONFIG_END
diff --git a/src/mess/machine/mac.c b/src/mess/machine/mac.c
new file mode 100644
index 00000000000..06e66d4631c
--- /dev/null
+++ b/src/mess/machine/mac.c
@@ -0,0 +1,3283 @@
+/****************************************************************************
+
+ machine/mac.c
+
+ Mac hardware - Mac 128k, 512k, 512ke, Plus, SE, Classic, II, PowerBook (SCSI, SCC, ADB, etc)
+
+ Nate Woods
+ Ernesto Corvi
+ Raphael Nabet
+ R. Belmont
+
+ Mac Model Feature Summary:
+ CPU FDC Kbd/Mouse PRAM Video
+ - Mac 128k 68k IWM orig orig Original
+ - Mac 512k 68k IWM orig orig Original
+ - Mac 512ke 68k IWM orig orig Original
+ - Mac Plus 68k IWM orig ext Original
+ - Mac SE 68k IWM MacII ADB ext Original
+ - Mac Classic 68k SWIM MacII ADB ext Original
+ - Mac Portable 68k (16 MHz) SWIM ADB-PMU PMU 640x400 B&W
+ - PowerBook 100 68k (16 MHz) SWIM ADB-PMU PMU 640x400 B&W
+ - Mac II 020 IWM MacII ADB ext NuBus card
+ - Mac IIx 030 SWIM MacII ADB ext NuBus card
+ - Mac IIfx 030 SWIM IOP ADB ext NuBus card
+ - Mac SE/30 030 SWIM MacII ADB ext Internal fake NuBus card
+ - Mac IIcx 030 SWIM MacII ADB ext NuBus card
+ - Mac IIci 030 SWIM MacII ADB ext Internal "RBV" type
+ - Mac IIsi 030 SWIM Egret ADB n/a Internal "RBV" type
+ - PowerBook 140/145(B) 030 (16/25 MHz) SWIM ADB-PMU PMU 640x400 B&W (passive matrix)
+ - PowerBook 170 030 (25 MHz) SWIM ADB-PMU PMU 640x400 B&W (active matrix)
+ - Mac IIvx/IIvi 030 SWIM Egret ADB n/a Internal "VASP" type
+ - Mac LC 020 SWIM Egret ADB n/a Internal "V8" type
+ - Mac LC II 030 SWIM Egret ADB n/a Internal "V8" type
+ - Mac LC III 030 SWIM Egret ADB n/a Internal "Sonora" type
+ - Mac Classic II 030 SWIM Egret ADB n/a Internal "Eagle" type (V8 clone)
+ - Mac Color Classic 030 SWIM Cuda ADB n/a Internal "Spice" type (V8 clone)
+ - Mac Quadra 700 040 (25 MHz) SWIM II MacII ADB ext Internal "DAFB" type
+ - Mac Quadra 900 040 (33 MHz) SWIM II IOP ADB ext Internal "DAFB" type
+
+ Notes:
+ - The Mac Plus boot code seems to check to see the extent of ROM
+ mirroring to determine if SCSI is available. If the ROM is mirrored,
+ then SCSI is not available. Thanks to R. Belmont for making this
+ discovery.
+ - On the SE and most later Macs, the first access to ROM turns off the overlay.
+ However, the Mac II/IIx/IIcx (and others?) have the old-style VIA overlay control bit!
+ - The Mac II can have either a 68551 PMMU fitted or an Apple custom that handles 24 vs. 32
+ bit addressing mode. The ROM is *not* 32-bit clean so Mac OS normally runs in 24 bit mode,
+ but A/UX can run 32.
+ - There are 5 known kinds of host-side ADB hardware:
+ * "Mac II ADB" used in the SE, II, IIx, IIcx, SE/30, IIci, Quadra 610, Quadra 650, Quadra 700,
+ Quadra 800, Centris 610 and Centris 650. This is a bit-banger using the VIA and a simple PIC.
+ * "PMU ADB" used in the Mac Portable and all 680x0-based PowerBooks.
+ * "Egret ADB" used in the IIsi, IIvi, IIvx, Classic II, LC, LC II, LC III, Performa 460,
+ and Performa 600. This is a 68HC05 with a different internal ROM than CUDA.
+ * "IOP ADB" (ADB driven by a 6502 coprocessor, similar to Lisa) used in the IIfx,
+ Quadra 900, and Quadra 950.
+ * "Cuda ADB" (Apple's CUDA chip, which is a 68HC05 MCU) used in the Color Classic, LC 520,
+ LC 55x, LC 57x, LC 58x, Quadra 630, Quadra 660AV, Quadra 840AV, PowerMac 6100/7100/8100,
+ IIci, and PowerMac 5200.
+
+ TODO:
+ - Call the RTC timer
+
+ Egret version spotting:
+ 341S0850 - 0x???? (1.01, earlier) - LC, LC II
+ 341S0851 - 0x0101 (1.01, later) - Classic II, IIsi, IIvx/IIvi, LC III
+ 344S0100 - 0x0100 (1.00) - Some (early production?) IIsi
+
+ Cuda version spotting:
+ 341S0262 - 0x0003f200 (3.02) - some PMac 6500, Bondi blue iMac
+ 341S0285 - No version (x.xx) - PMac 4400 + Mac clones ("Cuda Lite" with 768 bytes more ROM + PS/2 keyboard/mouse support)
+ 341S0060 - 0x00020028 (2.40) - Performa/Quadra 6xx, PMac 6200, x400, some x500, Pippin, "Gossamer" G3, others?
+ (verified found in PMac 5500-225, G3-333)
+ 341S0788 - 0x00020025 (2.37) - LC 475/575/Quadra 605, Quadra 660AV/840AV, PMac 7200
+ 341S0417 - 0x00020023 (2.35) - Color Classic
+
+ Caboose version spotting:
+ 341S0853 - 0x0100 (1.00) - Quadra 950
+
+ PG&E (68HC05 PMU) version spotting:
+ (find the text "BORG" in the system ROM, the next 32768 bytes are the PG&E image.
+ offset +4 in the image is the version byte).
+ 01 - PowerBook Duo 210/230/250
+ 02 - PowerBook 540c, PBDuo 270C, PBDuo 280/280C
+ 03 - PowerBook 150
+ 08 - PB190cs, PowerBook 540c PPC update, all PowerPC PowerBooks through WallStreet G3s
+
+****************************************************************************/
+
+
+#include <time.h>
+
+#include "emu.h"
+#include "machine/6522via.h"
+#include "machine/8530scc.h"
+#include "cpu/m68000/m68000.h"
+#include "machine/applefdc.h"
+#include "devices/sonydriv.h"
+#include "machine/ncr5380.h"
+#include "sound/asc.h"
+#include "includes/mac.h"
+#include "debug/debugcpu.h"
+#include "machine/ram.h"
+#include "debugger.h"
+
+#define AUDIO_IS_CLASSIC (mac->m_model <= MODEL_MAC_CLASSIC)
+#define MAC_HAS_VIA2 ((m_model >= MODEL_MAC_II) && (m_model != MODEL_MAC_IIFX))
+
+#define ASC_INTS_RBV ((mac->m_model >= MODEL_MAC_IICI) && (mac->m_model <= MODEL_MAC_IIVI)) || ((mac->m_model >= MODEL_MAC_LC) && (mac->m_model <= MODEL_MAC_COLOR_CLASSIC))
+
+#ifdef MAME_DEBUG
+#define LOG_ADB 0
+#define LOG_VIA 0
+#define LOG_MAC_IWM 0
+#define LOG_GENERAL 0
+#define LOG_KEYBOARD 0
+#define LOG_MEMORY 0
+#else
+#define LOG_ADB 0
+#define LOG_VIA 0
+#define LOG_MAC_IWM 0
+#define LOG_GENERAL 0
+#define LOG_KEYBOARD 0
+#define LOG_MEMORY 0
+#endif
+
+extern TIMER_CALLBACK(mac_adb_tick); // macadb.c
+extern TIMER_CALLBACK(mac_pmu_tick); // macadb.c
+static TIMER_CALLBACK(mac_scanline_tick);
+static TIMER_CALLBACK(mac_6015_tick);
+static int scan_keyboard(running_machine &machine);
+static TIMER_CALLBACK(inquiry_timeout_func);
+static void keyboard_receive(running_machine &machine, int val);
+static READ8_DEVICE_HANDLER(mac_via_in_a);
+static READ8_DEVICE_HANDLER(mac_via_in_b);
+static READ8_DEVICE_HANDLER(mac_adb_via_in_cb2);
+static WRITE8_DEVICE_HANDLER(mac_via_out_a);
+static WRITE8_DEVICE_HANDLER(mac_via_out_b);
+static WRITE8_DEVICE_HANDLER(mac_adb_via_out_cb2);
+static WRITE8_DEVICE_HANDLER(mac_via_out_cb2);
+static READ8_DEVICE_HANDLER(mac_via2_in_a);
+static READ8_DEVICE_HANDLER(mac_via2_in_b);
+static WRITE8_DEVICE_HANDLER(mac_via2_out_a);
+static WRITE8_DEVICE_HANDLER(mac_via2_out_b);
+static void mac_via_irq(device_t *device, int state);
+static void mac_via2_irq(device_t *device, int state);
+static offs_t mac_dasm_override(device_t &device, char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, int options);
+
+const via6522_interface mac_via6522_intf =
+{
+ DEVCB_HANDLER(mac_via_in_a), DEVCB_HANDLER(mac_via_in_b),
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_HANDLER(mac_via_out_a), DEVCB_HANDLER(mac_via_out_b),
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_NULL, DEVCB_HANDLER(mac_via_out_cb2),
+ DEVCB_LINE(mac_via_irq)
+};
+
+const via6522_interface mac_via6522_adb_intf =
+{
+ DEVCB_HANDLER(mac_via_in_a), DEVCB_HANDLER(mac_via_in_b),
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_NULL, DEVCB_HANDLER(mac_adb_via_in_cb2),
+ DEVCB_HANDLER(mac_via_out_a), DEVCB_HANDLER(mac_via_out_b),
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_NULL, DEVCB_HANDLER(mac_adb_via_out_cb2),
+ DEVCB_LINE(mac_via_irq)
+};
+
+const via6522_interface mac_via6522_2_intf =
+{
+ DEVCB_HANDLER(mac_via2_in_a), DEVCB_HANDLER(mac_via2_in_b),
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_HANDLER(mac_via2_out_a), DEVCB_HANDLER(mac_via2_out_b),
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_LINE(mac_via2_irq)
+};
+
+// returns non-zero if this Mac has ADB
+int mac_state::has_adb()
+{
+ return m_model >= MODEL_MAC_SE;
+}
+
+// handle disk enable lines
+void mac_fdc_set_enable_lines(device_t *device, int enable_mask)
+{
+ mac_state *mac = device->machine().driver_data<mac_state>();
+
+ if (mac->m_model != MODEL_MAC_SE)
+ {
+ sony_set_enable_lines(device, enable_mask);
+ }
+ else
+ {
+ if (enable_mask)
+ {
+ sony_set_enable_lines(device, mac->m_drive_select ? 1 : 2);
+ }
+ else
+ {
+ sony_set_enable_lines(device, enable_mask);
+ }
+ }
+}
+
+static void mac_install_memory(running_machine &machine, offs_t memory_begin, offs_t memory_end,
+ offs_t memory_size, void *memory_data, int is_rom, const char *bank)
+{
+ mac_state *state = machine.driver_data<mac_state>();
+ address_space* space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ offs_t memory_mask;
+
+ memory_size = MIN(memory_size, (memory_end + 1 - memory_begin));
+ memory_mask = memory_size - 1;
+
+ if (!is_rom)
+ {
+ space->install_readwrite_bank(memory_begin, memory_end, memory_mask, 0, bank);
+ }
+ else
+ {
+ space->unmap_write(memory_begin, memory_end, memory_mask, 0);
+ space->install_read_bank(memory_begin, memory_end, memory_mask, 0, bank);
+ }
+
+ state->membank(bank)->set_base(memory_data);
+
+ if (LOG_MEMORY)
+ {
+ printf("mac_install_memory(): bank=%s range=[0x%06x...0x%06x] mask=0x%06x ptr=0x%p\n",
+ bank, memory_begin, memory_end, memory_mask, memory_data);
+ }
+}
+
+
+
+/*
+ Interrupt handling
+*/
+
+void mac_state::field_interrupts()
+{
+ int take_interrupt = -1;
+
+ if (m_model < MODEL_MAC_PORTABLE)
+ {
+ if ((m_scc_interrupt) || (m_scsi_interrupt))
+ {
+ take_interrupt = 2;
+ }
+ else if (m_via_interrupt)
+ {
+ take_interrupt = 1;
+ }
+ }
+ else if ((m_model == MODEL_MAC_PORTABLE) || (m_model == MODEL_MAC_PB100))
+ {
+ if ((m_scc_interrupt) || (m_asc_interrupt))
+ {
+ take_interrupt = 2;
+ }
+ else if (m_via_interrupt)
+ {
+ take_interrupt = 1;
+ }
+ }
+ else if ((m_model < MODEL_MAC_POWERMAC_6100) && (m_model != MODEL_MAC_IIFX))
+ {
+ if (m_scc_interrupt)
+ {
+ take_interrupt = 4;
+ }
+ else if (m_via2_interrupt)
+ {
+ take_interrupt = 2;
+ }
+ else if (m_via_interrupt)
+ {
+ take_interrupt = 1;
+ }
+ }
+ else
+ {
+ return; // no interrupts for PowerPC yet
+ }
+
+ if (m_last_taken_interrupt > -1)
+ {
+ cputag_set_input_line(machine(), "maincpu", m_last_taken_interrupt, CLEAR_LINE);
+ m_last_taken_interrupt = -1;
+ }
+
+ if (take_interrupt > -1)
+ {
+ cputag_set_input_line(machine(), "maincpu", take_interrupt, ASSERT_LINE);
+ m_last_taken_interrupt = take_interrupt;
+ }
+}
+
+void mac_state::set_scc_interrupt(bool value)
+{
+ m_scc_interrupt = value;
+ this->field_interrupts();
+}
+
+void mac_state::set_via_interrupt(int value)
+{
+ m_via_interrupt = value;
+ this->field_interrupts();
+}
+
+
+void mac_state::set_via2_interrupt(int value)
+{
+ m_via2_interrupt = value;
+ this->field_interrupts();
+}
+
+void mac_asc_irq(device_t *device, int state)
+{
+ mac_state *mac = device->machine().driver_data<mac_state>();
+
+ if (ASC_INTS_RBV)
+ {
+ if (state)
+ {
+ mac->m_rbv_regs[3] |= 0x10; // any VIA 2 interrupt | sound interrupt
+ mac->rbv_recalc_irqs();
+ }
+ else
+ {
+ mac->m_rbv_regs[3] &= ~0x10;
+ mac->rbv_recalc_irqs();
+ }
+ }
+ else if ((mac->m_model == MODEL_MAC_PORTABLE) || (mac->m_model == MODEL_MAC_PB100))
+ {
+// m_asc_interrupt = state;
+// mac->field_interrupts();
+ }
+ else if ((mac->m_model >= MODEL_MAC_II) && (mac->m_model != MODEL_MAC_IIFX))
+ {
+ mac->m_via2->write_cb1(state^1);
+ }
+}
+
+WRITE16_MEMBER ( mac_state::mac_autovector_w )
+{
+ if (LOG_GENERAL)
+ logerror("mac_autovector_w: offset=0x%08x data=0x%04x\n", offset, data);
+
+ /* This should throw an exception */
+
+ /* Not yet implemented */
+}
+
+READ16_MEMBER ( mac_state::mac_autovector_r )
+{
+ if (LOG_GENERAL)
+ logerror("mac_autovector_r: offset=0x%08x\n", offset);
+
+ /* This should throw an exception */
+
+ /* Not yet implemented */
+ return 0;
+}
+
+static void set_scc_waitrequest(int waitrequest)
+{
+ if (LOG_GENERAL)
+ logerror("set_scc_waitrequest: waitrequest=%i\n", waitrequest);
+
+ /* Not Yet Implemented */
+}
+
+void mac_state::v8_resize()
+{
+ offs_t memory_size;
+ UINT8 *memory_data;
+ int is_rom;
+
+ is_rom = (m_overlay) ? 1 : 0;
+
+ // get what memory we're going to map
+ if (is_rom)
+ {
+ /* ROM mirror */
+ memory_size = memregion("bootrom")->bytes();
+ memory_data = memregion("bootrom")->base();
+ is_rom = TRUE;
+ }
+ else
+ {
+ /* RAM */
+ memory_size = m_ram->size();
+ memory_data = m_ram->pointer();
+ is_rom = FALSE;
+ }
+
+// printf("mac_v8_resize: memory_size = %x, ctrl bits %02x (overlay %d = %s)\n", memory_size, m_rbv_regs[1] & 0xe0, m_overlay, is_rom ? "ROM" : "RAM");
+
+ if (is_rom)
+ {
+ mac_install_memory(machine(), 0x00000000, memory_size-1, memory_size, memory_data, is_rom, "bank1");
+ }
+ else
+ {
+ address_space* space = machine().device("maincpu")->memory().space(AS_PROGRAM);
+ UINT32 onboard_amt, simm_amt, simm_size;
+ static const UINT32 simm_sizes[4] = { 0, 2*1024*1024, 4*1024*1024, 8*1024*1024 };
+
+ // force unmap of entire RAM region
+ space->unmap_write(0, 0x9fffff, 0x9fffff, 0);
+
+ // LC and Classic II have 2 MB built-in, all other V8-style machines have 4 MB
+ // we reserve the first 2 or 4 MB of mess_ram for the onboard,
+ // RAM above that mark is the SIMM
+ onboard_amt = ((m_model == MODEL_MAC_LC) || (m_model == MODEL_MAC_CLASSIC_II)) ? 2*1024*1024 : 4*1024*1024;
+ simm_amt = (m_rbv_regs[1]>>6) & 3; // size of SIMM RAM window
+ simm_size = memory_size - onboard_amt; // actual amount of RAM available for SIMMs
+
+ // installing SIMM RAM?
+ if (simm_amt != 0)
+ {
+// printf("mac_v8_resize: SIMM region size is %x, SIMM size is %x, onboard size is %x\n", simm_sizes[simm_amt], simm_size, onboard_amt);
+
+ if ((simm_amt > 0) && (simm_size > 0))
+ {
+// mac_install_memory(machine(), 0x000000, simm_sizes[simm_amt]-1, simm_sizes[simm_amt], memory_data + onboard_amt, is_rom, "bank1");
+ mac_install_memory(machine(), 0x000000, simm_size-1, simm_size, memory_data + onboard_amt, is_rom, "bank1");
+ }
+
+ // onboard RAM sits immediately above the SIMM, if any
+ if (simm_sizes[simm_amt] + onboard_amt <= 0x800000)
+ {
+ mac_install_memory(machine(), simm_sizes[simm_amt], simm_sizes[simm_amt] + onboard_amt - 1, onboard_amt, memory_data, is_rom, "bank2");
+ }
+
+ // a mirror of the first 2 MB of on board RAM always lives at 0x800000
+ mac_install_memory(machine(), 0x800000, 0x9fffff, 0x200000, memory_data, is_rom, "bank3");
+ }
+ else
+ {
+// printf("mac_v8_resize: SIMM off, mobo RAM at 0 and top\n");
+
+ mac_install_memory(machine(), 0x000000, onboard_amt-1, onboard_amt, memory_data, is_rom, "bank1");
+ mac_install_memory(machine(), 0x900000, 0x9fffff, 0x200000, memory_data+0x100000, is_rom, "bank3");
+ }
+ }
+}
+
+void mac_state::set_memory_overlay(int overlay)
+{
+ offs_t memory_size;
+ UINT8 *memory_data;
+ int is_rom;
+
+ /* normalize overlay */
+ overlay = overlay ? TRUE : FALSE;
+
+ if (overlay != m_overlay)
+ {
+ /* set up either main RAM area or ROM mirror at 0x000000-0x3fffff */
+ if (overlay)
+ {
+ /* ROM mirror */
+ memory_size = memregion("bootrom")->bytes();
+ memory_data = memregion("bootrom")->base();
+ is_rom = TRUE;
+ }
+ else
+ {
+ /* RAM */
+ memory_size = m_ram->size();
+ memory_data = m_ram->pointer();
+ is_rom = FALSE;
+ }
+
+ /* install the memory */
+ if (((m_model >= MODEL_MAC_LC) && (m_model <= MODEL_MAC_COLOR_CLASSIC) && ((m_model != MODEL_MAC_LC_III) && (m_model != MODEL_MAC_LC_III_PLUS))) || (m_model == MODEL_MAC_CLASSIC_II))
+ {
+ m_overlay = overlay;
+ v8_resize();
+ }
+ else if ((m_model == MODEL_MAC_IICI) || (m_model == MODEL_MAC_IISI))
+ {
+ // ROM is OK to flood to 3fffffff
+ if (is_rom)
+ {
+ mac_install_memory(machine(), 0x00000000, 0x3fffffff, memory_size, memory_data, is_rom, "bank1");
+ }
+ else // RAM: be careful not to populate ram B with a mirror or the ROM will get confused
+ {
+ mac_install_memory(machine(), 0x00000000, memory_size-1, memory_size, memory_data, is_rom, "bank1");
+ }
+ }
+ else if ((m_model == MODEL_MAC_PORTABLE) || (m_model == MODEL_MAC_PB100) || (m_model == MODEL_MAC_IIVX) || (m_model == MODEL_MAC_IIFX))
+ {
+ address_space* space = machine().device("maincpu")->memory().space(AS_PROGRAM);
+ space->unmap_write(0x000000, 0x9fffff, 0x9fffff, 0);
+ mac_install_memory(machine(), 0x000000, memory_size-1, memory_size, memory_data, is_rom, "bank1");
+ }
+ else if ((m_model == MODEL_MAC_PB140) || (m_model == MODEL_MAC_PB160) || ((m_model >= MODEL_MAC_PBDUO_210) && (m_model <= MODEL_MAC_PBDUO_270c)))
+ {
+ address_space* space = machine().device("maincpu")->memory().space(AS_PROGRAM);
+ space->unmap_write(0x000000, 0xffffff, 0xffffff, 0);
+ mac_install_memory(machine(), 0x000000, memory_size-1, memory_size, memory_data, is_rom, "bank1");
+ }
+ else if ((m_model >= MODEL_MAC_II) && (m_model <= MODEL_MAC_SE30))
+ {
+ mac_install_memory(machine(), 0x00000000, 0x3fffffff, memory_size, memory_data, is_rom, "bank1");
+ }
+ else if ((m_model == MODEL_MAC_LC_III) || (m_model == MODEL_MAC_LC_III_PLUS) || (m_model >= MODEL_MAC_LC_475 && m_model <= MODEL_MAC_LC_580)) // up to 36 MB
+ {
+ mac_install_memory(machine(), 0x00000000, memory_size-1, memory_size, memory_data, is_rom, "bank1");
+ }
+ else if (m_model == MODEL_MAC_QUADRA_700)
+ {
+ mac_install_memory(machine(), 0x00000000, memory_size-1, memory_size, memory_data, is_rom, "bank1");
+ }
+ else
+ {
+ mac_install_memory(machine(), 0x00000000, 0x003fffff, memory_size, memory_data, is_rom, "bank1");
+ }
+
+ m_overlay = overlay;
+
+ if (LOG_GENERAL)
+ logerror("mac_set_memory_overlay: overlay=%i\n", overlay);
+ }
+}
+
+
+
+/*
+ R Nabet 000531 : added keyboard code
+*/
+
+/* *************************************************************************
+ * non-ADB keyboard support
+ *
+ * The keyboard uses a i8021 (?) microcontroller.
+ * It uses a bidirectional synchonous serial line, connected to the VIA (SR feature)
+ *
+ * Our emulation is more a hack than anything else - the keyboard controller is
+ * not emulated, instead we interpret keyboard commands directly. I made
+ * many guesses, which may be wrong
+ *
+ * todo :
+ * * find the correct model number for the Mac Plus keyboard ?
+ * * emulate original Macintosh keyboards (2 layouts : US and international)
+ *
+ * references :
+ * * IM III-29 through III-32 and III-39 through III-42
+ * * IM IV-250
+ * *************************************************************************/
+
+/*
+ scan_keyboard()
+
+ scan the keyboard, and returns key transition code (or NULL ($7B) if none)
+*/
+
+static int scan_keyboard(running_machine &machine)
+{
+ int i, j;
+ int keybuf;
+ int keycode;
+ static const char *const keynames[] = { "KEY0", "KEY1", "KEY2", "KEY3", "KEY4", "KEY5", "KEY6" };
+ mac_state *mac = machine.driver_data<mac_state>();
+
+ if (mac->m_keycode_buf_index)
+ {
+ return mac->m_keycode_buf[--mac->m_keycode_buf_index];
+ }
+
+ for (i=0; i<7; i++)
+ {
+ keybuf = machine.root_device().ioport(keynames[i])->read();
+
+ if (keybuf != mac->m_key_matrix[i])
+ {
+ /* if state has changed, find first bit which has changed */
+ if (LOG_KEYBOARD)
+ logerror("keyboard state changed, %d %X\n", i, keybuf);
+
+ for (j=0; j<16; j++)
+ {
+ if (((keybuf ^ mac->m_key_matrix[i]) >> j) & 1)
+ {
+ /* update mac->m_key_matrix */
+ mac->m_key_matrix[i] = (mac->m_key_matrix[i] & ~ (1 << j)) | (keybuf & (1 << j));
+
+ if (i < 4)
+ {
+ /* create key code */
+ keycode = (i << 5) | (j << 1) | 0x01;
+ if (! (keybuf & (1 << j)))
+ {
+ /* key up */
+ keycode |= 0x80;
+ }
+ return keycode;
+ }
+ else if (i < 6)
+ {
+ /* create key code */
+ keycode = ((i & 3) << 5) | (j << 1) | 0x01;
+
+ if ((keycode == 0x05) || (keycode == 0x0d) || (keycode == 0x11) || (keycode == 0x1b))
+ {
+ /* these keys cause shift to be pressed (for compatibility with mac 128/512) */
+ if (keybuf & (1 << j))
+ {
+ /* key down */
+ if (! (mac->m_key_matrix[3] & 0x0100))
+ {
+ /* shift key is really up */
+ mac->m_keycode_buf[0] = keycode;
+ mac->m_keycode_buf[1] = 0x79;
+ mac->m_keycode_buf_index = 2;
+ return 0x71; /* "presses" shift down */
+ }
+ }
+ else
+ { /* key up */
+ if (! (mac->m_key_matrix[3] & 0x0100))
+ {
+ /* shift key is really up */
+ mac->m_keycode_buf[0] = keycode | 0x80;
+ mac->m_keycode_buf[1] = 0x79;
+ mac->m_keycode_buf_index = 2;
+ return 0xF1; /* "releases" shift */
+ }
+ }
+ }
+
+ if (! (keybuf & (1 << j)))
+ {
+ /* key up */
+ keycode |= 0x80;
+ }
+ mac->m_keycode_buf[0] = keycode;
+ mac->m_keycode_buf_index = 1;
+ return 0x79;
+ }
+ else /* i == 6 */
+ {
+ /* create key code */
+ keycode = (j << 1) | 0x01;
+ if (! (keybuf & (1 << j)))
+ {
+ /* key up */
+ keycode |= 0x80;
+ }
+ mac->m_keycode_buf[0] = keycode;
+ mac->m_keycode_buf_index = 1;
+ return 0x79;
+ }
+ }
+ }
+ }
+ }
+
+ return 0x7B; /* return NULL */
+}
+
+/*
+ power-up init
+*/
+static void keyboard_init(mac_state *mac)
+{
+ int i;
+
+ /* init flag */
+ mac->m_kbd_comm = FALSE;
+ mac->m_kbd_receive = FALSE;
+ mac->m_kbd_shift_reg=0;
+ mac->m_kbd_shift_count=0;
+
+ /* clear key matrix */
+ for (i=0; i<7; i++)
+ {
+ mac->m_key_matrix[i] = 0;
+ }
+
+ /* purge transmission buffer */
+ mac->m_keycode_buf_index = 0;
+}
+
+/******************* Keyboard <-> VIA communication ***********************/
+
+static TIMER_CALLBACK(kbd_clock)
+{
+ int i;
+ mac_state *mac = machine.driver_data<mac_state>();
+
+ if (mac->m_kbd_comm == TRUE)
+ {
+ for (i=0; i<8; i++)
+ {
+ /* Put data on CB2 if we are sending*/
+ if (mac->m_kbd_receive == FALSE)
+ mac->m_via1->write_cb2(mac->m_kbd_shift_reg&0x80?1:0);
+ mac->m_kbd_shift_reg <<= 1;
+ mac->m_via1->write_cb1(0);
+ mac->m_via1->write_cb1(1);
+ }
+ if (mac->m_kbd_receive == TRUE)
+ {
+ mac->m_kbd_receive = FALSE;
+ /* Process the command received from mac */
+ keyboard_receive(machine, mac->m_kbd_shift_reg & 0xff);
+ }
+ else
+ {
+ /* Communication is over */
+ mac->m_kbd_comm = FALSE;
+ }
+ }
+}
+
+static void kbd_shift_out(running_machine &machine, int data)
+{
+ mac_state *mac = machine.driver_data<mac_state>();
+
+ if (mac->m_kbd_comm == TRUE)
+ {
+ mac->m_kbd_shift_reg = data;
+ machine.scheduler().timer_set(attotime::from_msec(1), FUNC(kbd_clock));
+ }
+}
+
+static WRITE8_DEVICE_HANDLER(mac_via_out_cb2)
+{
+ mac_state *mac = device->machine().driver_data<mac_state>();
+
+ if (mac->m_kbd_comm == FALSE && data == 0)
+ {
+ /* Mac pulls CB2 down to initiate communication */
+ mac->m_kbd_comm = TRUE;
+ mac->m_kbd_receive = TRUE;
+ device->machine().scheduler().timer_set(attotime::from_usec(100), FUNC(kbd_clock));
+ }
+ if (mac->m_kbd_comm == TRUE && mac->m_kbd_receive == TRUE)
+ {
+ /* Shift in what mac is sending */
+ mac->m_kbd_shift_reg = (mac->m_kbd_shift_reg & ~1) | data;
+ }
+}
+
+/*
+ called when inquiry times out (1/4s)
+*/
+static TIMER_CALLBACK(inquiry_timeout_func)
+{
+ if (LOG_KEYBOARD)
+ logerror("keyboard enquiry timeout\n");
+ kbd_shift_out(machine, 0x7B); /* always send NULL */
+}
+
+/*
+ called when a command is received from the mac
+*/
+static void keyboard_receive(running_machine &machine, int val)
+{
+ mac_state *mac = machine.driver_data<mac_state>();
+
+ switch (val)
+ {
+ case 0x10:
+ /* inquiry - returns key transition code, or NULL ($7B) if time out (1/4s) */
+ if (LOG_KEYBOARD)
+ logerror("keyboard command : inquiry\n");
+
+ mac->m_keyboard_reply = scan_keyboard(machine);
+ if (mac->m_keyboard_reply == 0x7B)
+ {
+ /* if NULL, wait until key pressed or timeout */
+ mac->m_inquiry_timeout->adjust(
+ attotime(0, DOUBLE_TO_ATTOSECONDS(0.25)), 0);
+ }
+ break;
+
+ case 0x14:
+ /* instant - returns key transition code, or NULL ($7B) */
+ if (LOG_KEYBOARD)
+ logerror("keyboard command : instant\n");
+
+ kbd_shift_out(machine, scan_keyboard(machine));
+ break;
+
+ case 0x16:
+ /* model number - resets keyboard, return model number */
+ if (LOG_KEYBOARD)
+ logerror("keyboard command : model number\n");
+
+ { /* reset */
+ int i;
+
+ /* clear key matrix */
+ for (i=0; i<7; i++)
+ {
+ mac->m_key_matrix[i] = 0;
+ }
+
+ /* purge transmission buffer */
+ mac->m_keycode_buf_index = 0;
+ }
+
+ /* format : 1 if another device (-> keypad ?) connected | next device (-> keypad ?) number 1-8
+ | keyboard model number 1-8 | 1 */
+ /* keyboards :
+ 3 : mac 512k, US and international layout ? Mac plus ???
+ other values : Apple II keyboards ?
+ */
+ /* keypads :
+ ??? : standard keypad (always available on Mac Plus) ???
+ */
+ kbd_shift_out(machine, 0x17); /* probably wrong */
+ break;
+
+ case 0x36:
+ /* test - resets keyboard, return ACK ($7D) or NAK ($77) */
+ if (LOG_KEYBOARD)
+ logerror("keyboard command : test\n");
+
+ kbd_shift_out(machine, 0x7D); /* ACK */
+ break;
+
+ default:
+ if (LOG_KEYBOARD)
+ logerror("unknown keyboard command 0x%X\n", val);
+
+ kbd_shift_out(machine, 0);
+ break;
+ }
+}
+
+/* *************************************************************************
+ * Mouse
+ * *************************************************************************/
+
+void mac_state::mouse_callback()
+{
+ int new_mx, new_my;
+ int x_needs_update = 0, y_needs_update = 0;
+ mac_state *mac = machine().driver_data<mac_state>();
+
+ new_mx = ioport("MOUSE1")->read();
+ new_my = ioport("MOUSE2")->read();
+
+ /* see if it moved in the x coord */
+ 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;
+ }
+ /* see if it moved in the y coord */
+ 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;
+ }
+
+ /* update any remaining count and then return */
+ if (count_x)
+ {
+ if (count_x < 0)
+ {
+ count_x++;
+ mac->m_mouse_bit_x = 0;
+ }
+ else
+ {
+ count_x--;
+ mac->m_mouse_bit_x = 1;
+ }
+ x_needs_update = 1;
+ }
+ else if (count_y)
+ {
+ if (count_y < 0)
+ {
+ count_y++;
+ mac->m_mouse_bit_y = 1;
+ }
+ else
+ {
+ count_y--;
+ mac->m_mouse_bit_y = 0;
+ }
+ y_needs_update = 1;
+ }
+
+ if (x_needs_update || y_needs_update)
+ /* assert Port B External Interrupt on the SCC */
+ mac->scc_mouse_irq(x_needs_update, y_needs_update );
+}
+
+/* *************************************************************************
+ * SCSI
+ * *************************************************************************/
+
+/*
+
+From http://www.mac.m68k-linux.org/devel/plushw.php
+
+The address of each register is computed as follows:
+
+ $580drn
+
+ where r represents the register number (from 0 through 7),
+ n determines whether it a read or write operation
+ (0 for reads, or 1 for writes), and
+ d determines whether the DACK signal to the NCR 5380 is asserted.
+ (0 for not asserted, 1 is for asserted)
+
+Here's an example of the address expressed in binary:
+
+ 0101 1000 0000 00d0 0rrr 000n
+
+Note: Asserting the DACK signal applies only to write operations to
+ the output data register and read operations from the input
+ data register.
+
+ Symbolic Memory
+ Location Location NCR 5380 Internal Register
+
+ scsiWr+sODR+dackWr $580201 Output Data Register with DACK
+ scsiWr+sODR $580001 Output Data Register
+ scsiWr+sICR $580011 Initiator Command Register
+ scsiWr+sMR $580021 Mode Register
+ scsiWr+sTCR $580031 Target Command Register
+ scsiWr+sSER $580041 Select Enable Register
+ scsiWr+sDMAtx $580051 Start DMA Send
+ scsiWr+sTDMArx $580061 Start DMA Target Receive
+ scsiWr+sIDMArx $580071 Start DMA Initiator Receive
+
+ scsiRd+sIDR+dackRd $580260 Current SCSI Data with DACK
+ scsiRd+sCDR $580000 Current SCSI Data
+ scsiRd+sICR $580010 Initiator Command Register
+ scsiRd+sMR $580020 Mode Registor
+ scsiRd+sTCR $580030 Target Command Register
+ scsiRd+sCSR $580040 Current SCSI Bus Status
+ scsiRd+sBSR $580050 Bus and Status Register
+ scsiRd+sIDR $580060 Input Data Register
+ scsiRd+sRESET $580070 Reset Parity/Interrupt
+ */
+
+READ16_MEMBER ( mac_state::macplus_scsi_r )
+{
+ int reg = (offset>>3) & 0xf;
+ device_t *ncr = space.machine().device("ncr5380");
+
+// logerror("macplus_scsi_r: offset %x mask %x\n", offset, mem_mask);
+
+ if ((reg == 6) && (offset == 0x130))
+ {
+ reg = R5380_CURDATA_DTACK;
+ }
+
+ return ncr5380_read_reg(ncr, reg)<<8;
+}
+
+READ32_MEMBER (mac_state::macii_scsi_drq_r)
+{
+ device_t *ncr = space.machine().device("ncr5380");
+
+ switch (mem_mask)
+ {
+ case 0xff000000:
+ return ncr5380_read_reg(ncr, R5380_CURDATA_DTACK)<<24;
+
+ case 0xffff0000:
+ return (ncr5380_read_reg(ncr, R5380_CURDATA_DTACK)<<24) | (ncr5380_read_reg(ncr, R5380_CURDATA_DTACK)<<16);
+
+ case 0xffffffff:
+ return (ncr5380_read_reg(ncr, R5380_CURDATA_DTACK)<<24) | (ncr5380_read_reg(ncr, R5380_CURDATA_DTACK)<<16) | (ncr5380_read_reg(ncr, R5380_CURDATA_DTACK)<<8) | ncr5380_read_reg(ncr, R5380_CURDATA_DTACK);
+
+ default:
+ logerror("macii_scsi_drq_r: unknown mem_mask %08x\n", mem_mask);
+ }
+
+ return 0;
+}
+
+WRITE32_MEMBER (mac_state::macii_scsi_drq_w)
+{
+ device_t *ncr = space.machine().device("ncr5380");
+
+ switch (mem_mask)
+ {
+ case 0xff000000:
+ ncr5380_write_reg(ncr, R5380_OUTDATA_DTACK, data>>24);
+ break;
+
+ case 0xffff0000:
+ ncr5380_write_reg(ncr, R5380_OUTDATA_DTACK, data>>24);
+ ncr5380_write_reg(ncr, R5380_OUTDATA_DTACK, data>>16);
+ break;
+
+ case 0xffffffff:
+ ncr5380_write_reg(ncr, R5380_OUTDATA_DTACK, data>>24);
+ ncr5380_write_reg(ncr, R5380_OUTDATA_DTACK, data>>16);
+ ncr5380_write_reg(ncr, R5380_OUTDATA_DTACK, data>>8);
+ ncr5380_write_reg(ncr, R5380_OUTDATA_DTACK, data&0xff);
+ break;
+
+ default:
+ logerror("macii_scsi_drq_w: unknown mem_mask %08x\n", mem_mask);
+ break;
+ }
+}
+
+WRITE16_MEMBER ( mac_state::macplus_scsi_w )
+{
+ int reg = (offset>>3) & 0xf;
+ device_t *ncr = space.machine().device("ncr5380");
+
+// logerror("macplus_scsi_w: data %x offset %x mask %x\n", data, offset, mem_mask);
+
+ if ((reg == 0) && (offset == 0x100))
+ {
+ reg = R5380_OUTDATA_DTACK;
+ }
+
+ ncr5380_write_reg(ncr, reg, data);
+}
+
+WRITE16_MEMBER ( mac_state::macii_scsi_w )
+{
+ int reg = (offset>>3) & 0xf;
+ device_t *ncr = space.machine().device("ncr5380");
+
+// logerror("macplus_scsi_w: data %x offset %x mask %x (PC=%x)\n", data, offset, mem_mask, cpu_get_pc(&space->device()));
+
+ if ((reg == 0) && (offset == 0x100))
+ {
+ reg = R5380_OUTDATA_DTACK;
+ }
+
+ ncr5380_write_reg(ncr, reg, data>>8);
+}
+
+void mac_scsi_irq(running_machine &machine, int state)
+{
+/* mac_state *mac = machine.driver_data<mac_state>();
+
+ if ((mac->m_scsiirq_enable) && ((mac->m_model == MODEL_MAC_SE) || (mac->m_model == MODEL_MAC_CLASSIC)))
+ {
+ mac->m_scsi_interrupt = state;
+ mac->field_interrupts();
+ }*/
+}
+
+WRITE_LINE_MEMBER(mac_state::irq_539x_1_w)
+{
+ if (state) // make sure a CB1 transition occurs
+ {
+ m_via2->write_cb2(0);
+ m_via2->write_cb2(1);
+ }
+}
+
+WRITE_LINE_MEMBER(mac_state::drq_539x_1_w)
+{
+ m_dafb_scsi1_drq = state;
+}
+
+/* *************************************************************************
+ * SCC
+ *
+ * Serial Communications Controller
+ * *************************************************************************/
+
+void mac_state::scc_mouse_irq(int x, int y)
+{
+ scc8530_t *scc = machine().device<scc8530_t>("scc");
+ if (x && y)
+ {
+ if (m_last_was_x)
+ scc->set_status(0x0a);
+ else
+ scc->set_status(0x02);
+
+ m_last_was_x ^= 1;
+ }
+ else
+ {
+ if (x)
+ scc->set_status(0x0a);
+ else
+ scc->set_status(0x02);
+ }
+
+ this->set_scc_interrupt(1);
+}
+
+
+
+READ16_MEMBER ( mac_state::mac_scc_r )
+{
+ scc8530_t *scc = space.machine().device<scc8530_t>("scc");
+ UINT16 result;
+
+ result = scc->reg_r(space, offset);
+ return (result << 8) | result;
+}
+
+
+
+WRITE16_MEMBER ( mac_state::mac_scc_w )
+{
+ scc8530_t *scc = space.machine().device<scc8530_t>("scc");
+ scc->reg_w(space, offset, data);
+}
+
+WRITE16_MEMBER ( mac_state::mac_scc_2_w )
+{
+ scc8530_t *scc = space.machine().device<scc8530_t>("scc");
+ scc->reg_w(space, offset, data >> 8);
+}
+
+/* ********************************** *
+ * IWM Code specific to the Mac Plus *
+ * ********************************** */
+
+READ16_MEMBER ( mac_state::mac_iwm_r )
+{
+ /* The first time this is called is in a floppy test, which goes from
+ * $400104 to $400126. After that, all access to the floppy goes through
+ * the disk driver in the MacOS
+ *
+ * I just thought this would be on interest to someone trying to further
+ * this driver along
+ */
+
+ UINT16 result = 0;
+ device_t *fdc = space.machine().device("fdc");
+
+ result = applefdc_r(fdc, (offset >> 8));
+
+ if (LOG_MAC_IWM)
+ printf("mac_iwm_r: offset=0x%08x mem_mask %04x = %02x (PC %x)\n", offset, mem_mask, result, cpu_get_pc(m_maincpu));
+
+ return (result << 8) | result;
+}
+
+WRITE16_MEMBER ( mac_state::mac_iwm_w )
+{
+ device_t *fdc = space.machine().device("fdc");
+
+ if (LOG_MAC_IWM)
+ printf("mac_iwm_w: offset=0x%08x data=0x%04x mask %04x (PC=%x)\n", offset, data, mem_mask, cpu_get_pc(m_maincpu));
+
+ if (ACCESSING_BITS_0_7)
+ applefdc_w(fdc, (offset >> 8), data & 0xff);
+ else
+ applefdc_w(fdc, (offset >> 8), data>>8);
+}
+
+static READ8_DEVICE_HANDLER(mac_adb_via_in_cb2)
+{
+ UINT8 ret;
+ mac_state *mac = device->machine().driver_data<mac_state>();
+
+ if (ADB_IS_EGRET)
+ {
+ ret = mac->m_egret->get_via_data();
+ #if LOG_ADB
+ printf("68K: Read VIA_DATA %x\n", ret);
+ #endif
+ }
+ else if (ADB_IS_CUDA)
+ {
+ ret = mac->m_cuda->get_via_data();
+ #if LOG_ADB
+ printf("68K: Read VIA_DATA %x\n", ret);
+ #endif
+ }
+ else
+ {
+ ret = (mac->m_adb_send & 0x80)>>7;
+ mac->m_adb_send <<= 1;
+ }
+
+// printf("VIA IN CB2 = %x\n", ret);
+
+ return ret;
+}
+
+static WRITE8_DEVICE_HANDLER(mac_adb_via_out_cb2)
+{
+ mac_state *mac = device->machine().driver_data<mac_state>();
+
+// printf("VIA OUT CB2 = %x\n", data);
+ if (ADB_IS_EGRET)
+ {
+ mac->m_egret->set_via_data(data & 1);
+ }
+ else if (ADB_IS_CUDA)
+ {
+ mac->m_cuda->set_via_data(data & 1);
+ }
+ else
+ {
+ mac->m_adb_command <<= 1;
+ mac->m_adb_command |= data & 1;
+ }
+}
+
+/* *************************************************************************
+ * VIA
+ * *************************************************************************
+ *
+ *
+ * PORT A
+ *
+ * bit 7 R SCC Wait/Request
+ * bit 6 W Main/Alternate screen buffer select
+ * bit 5 W Floppy Disk Line Selection
+ * bit 4 W Overlay/Normal memory mapping
+ * bit 3 W Main/Alternate sound buffer
+ * bit 2-0 W Sound Volume
+ *
+ *
+ * PORT B
+ *
+ * bit 7 W Sound enable
+ * bit 6 R Video beam in display
+ * bit 5 (pre-ADB) R Mouse Y2
+ * (ADB) W ADB ST1
+ * bit 4 (pre-ADB) R Mouse X2
+ * (ADB) W ADB ST0
+ * bit 3 (pre-ADB) R Mouse button (active low)
+ * (ADB) R ADB INT
+ * bit 2 W Real time clock enable
+ * bit 1 W Real time clock data clock
+ * bit 0 RW Real time clock data
+ *
+ */
+
+#define PA6 0x40
+#define PA4 0x10
+#define PA2 0x04
+#define PA1 0x02
+
+static READ8_DEVICE_HANDLER(mac_via_in_a)
+{
+ mac_state *mac = device->machine().driver_data<mac_state>();
+
+// printf("VIA1 IN_A (PC %x)\n", cpu_get_pc(device->machine().device("maincpu")));
+
+ switch (mac->m_model)
+ {
+ case MODEL_MAC_PORTABLE:
+ case MODEL_MAC_PB100:
+ #if LOG_ADB
+// printf("Read PM data %x\n", mac->m_pm_data_recv);
+ #endif
+ return mac->m_pm_data_recv;
+
+ case MODEL_MAC_CLASSIC:
+ case MODEL_MAC_II:
+ case MODEL_MAC_II_FDHD:
+ case MODEL_MAC_IIX:
+ case MODEL_MAC_POWERMAC_6100:
+ case MODEL_MAC_POWERMAC_7100:
+ case MODEL_MAC_POWERMAC_8100:
+ return 0x81; // bit 0 must be set on most Macs to avoid attempting to boot from AppleTalk
+
+ case MODEL_MAC_SE30:
+ return 0x81 | PA6;
+
+ case MODEL_MAC_LC:
+ case MODEL_MAC_LC_II:
+ case MODEL_MAC_IIVX:
+ return 0x81 | PA6 | PA4 | PA2;
+
+ case MODEL_MAC_IICI:
+ return 0x81 | PA6 | PA2 | PA1;
+
+ case MODEL_MAC_IISI:
+ return 0x81 | PA4 | PA2 | PA1;
+
+ case MODEL_MAC_IIFX:
+ return 0x81 | PA6 | PA4 | PA1;
+
+ case MODEL_MAC_IICX:
+ return 0x81 | PA6;
+
+ case MODEL_MAC_PB140: // since the ASICs are different, these are allowed to "collide"
+ case MODEL_MAC_PB160:
+ case MODEL_MAC_CLASSIC_II:
+ case MODEL_MAC_QUADRA_800:
+ return 0x81 | PA4 | PA1;
+
+ case MODEL_MAC_QUADRA_700:
+ return 0x81 | PA6;
+
+ case MODEL_MAC_QUADRA_900:
+ return 0x81 | PA6 | PA4;
+
+ case MODEL_MAC_COLOR_CLASSIC:
+ return 0x81 | PA1;
+
+ default:
+ return 0x80;
+
+ }
+
+ return 0x80;
+}
+
+static READ8_DEVICE_HANDLER(mac_via_in_b)
+{
+ int val = 0;
+ mac_state *mac = device->machine().driver_data<mac_state>();
+
+ // portable/PB100 is pretty different
+ if (mac->m_model >= MODEL_MAC_PORTABLE && mac->m_model <= MODEL_MAC_PB100)
+ {
+// printf("Read VIA B: PM_ACK %x\n", mac->m_pm_ack);
+ val = 0x80 | 0x04 | mac->m_pm_ack; // SCC wait/request (bit 2 must be set at 900c1a or startup tests always fail)
+ }
+ else
+ {
+ /* video beam in display (! VBLANK && ! HBLANK basically) */
+ if (device->machine().primary_screen->vpos() >= MAC_V_VIS)
+ val |= 0x40;
+
+ if (ADB_IS_BITBANG)
+ {
+ val |= mac->m_adb_state<<4;
+
+ if (!mac->m_adb_irq_pending)
+ {
+ val |= 0x08;
+ }
+ }
+ else if (ADB_IS_EGRET)
+ {
+ val |= mac->m_egret->get_xcvr_session()<<3;
+ }
+ else if (ADB_IS_CUDA)
+ {
+ val |= mac->m_cuda->get_treq()<<3;
+ }
+ else
+ {
+ if (mac->m_mouse_bit_y) /* Mouse Y2 */
+ val |= 0x20;
+ if (mac->m_mouse_bit_x) /* Mouse X2 */
+ val |= 0x10;
+ if ((device->machine().root_device().ioport("MOUSE0")->read() & 0x01) == 0)
+ val |= 0x08;
+ }
+ if (mac->m_rtc_data_out)
+ val |= 1;
+ }
+
+// printf("VIA1 IN_B = %02x (PC %x)\n", val, cpu_get_pc(device->machine().device("maincpu")));
+
+ return val;
+}
+
+static WRITE8_DEVICE_HANDLER(mac_via_out_a)
+{
+ device_t *sound = device->machine().device("custom");
+ device_t *fdc = device->machine().device("fdc");
+ mac_state *mac = device->machine().driver_data<mac_state>();
+
+// printf("VIA1 OUT A: %02x (PC %x)\n", data, cpu_get_pc(device->machine().device("maincpu")));
+
+ if (ADB_IS_PM_VIA1)
+ {
+ #if LOG_ADB
+// printf("%02x to PM\n", data);
+ #endif
+ mac->m_pm_data_send = data;
+ return;
+ }
+
+ set_scc_waitrequest((data & 0x80) >> 7);
+ mac->m_screen_buffer = (data & 0x40) >> 6;
+ sony_set_sel_line(fdc,(data & 0x20) >> 5);
+ if (mac->m_model == MODEL_MAC_SE) // on SE this selects which floppy drive (0 = upper, 1 = lower)
+ {
+ mac->m_drive_select = ((data & 0x10) >> 4);
+ }
+
+ if (mac->m_model < MODEL_MAC_SE) // SE no longer has dual buffers
+ {
+ mac_set_sound_buffer(sound, (data & 0x08) >> 3);
+ }
+
+ if (mac->m_model < MODEL_MAC_II)
+ {
+ mac_set_volume(sound, data & 0x07);
+ }
+
+ /* Early Mac models had VIA A4 control overlaying. In the Mac SE (and
+ * possibly later models), overlay was set on reset, but cleared on the
+ * first access to the ROM. */
+ if (mac->m_model < MODEL_MAC_SE)
+ {
+ mac->set_memory_overlay((data & 0x10) >> 4);
+ }
+}
+
+static WRITE8_DEVICE_HANDLER(mac_via_out_b)
+{
+ device_t *sound = device->machine().device("custom");
+ int new_rtc_rTCClk;
+ mac_state *mac = device->machine().driver_data<mac_state>();
+
+// printf("VIA1 OUT B: %02x (PC %x)\n", data, cpu_get_pc(device->machine().device("maincpu")));
+
+ if (ADB_IS_PM_VIA1)
+ {
+ device_t *fdc = device->machine().device("fdc");
+
+ sony_set_sel_line(fdc,(data & 0x20) >> 5);
+ mac->m_drive_select = ((data & 0x10) >> 4);
+
+ if ((data & 1) && !(mac->m_pm_req & 1))
+ {
+ #if LOG_ADB
+ printf("PM: 68k dropping /REQ\n");
+ #endif
+
+ if (mac->m_pm_state == 0) // do this in receive state only
+ {
+ mac->m_pm_data_recv = 0xff;
+ mac->m_pm_ack |= 2;
+
+ // check if length byte matches
+ if ((mac->m_pm_dptr >= 2) && (mac->m_pm_cmd[1] == (mac->m_pm_dptr-2)))
+ {
+ mac->pmu_exec();
+ #if LOG_ADB
+ printf("PMU exec: command %02x length %d\n", mac->m_pm_cmd[0], mac->m_pm_cmd[1]);
+ #endif
+ }
+ }
+ }
+ else if (!(data & 1) && (mac->m_pm_req & 1))
+ {
+ if (mac->m_pm_state == 0)
+ {
+ #if LOG_ADB
+ printf("PM: 68k asserting /REQ, clocking in byte [%d] = %02x\n", mac->m_pm_dptr, mac->m_pm_data_send);
+ #endif
+ mac->m_pm_ack &= ~2; // clear, we're waiting for more bytes
+ mac->m_pm_cmd[mac->m_pm_dptr++] = mac->m_pm_data_send;
+ }
+ else // receiving, so this is different
+ {
+ mac->m_pm_data_recv = mac->m_pm_out[mac->m_pm_sptr++];
+ mac->m_pm_slen--;
+ mac->m_pm_ack |= 2; // raise ACK to indicate available byte
+ #if LOG_ADB
+ printf("PM: 68k asserted /REQ, sending byte %02x\n", mac->m_pm_data_recv);
+ #endif
+
+ // another byte to send?
+ if (mac->m_pm_slen)
+ {
+ mac->m_pmu_send_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(100)));
+ }
+ else
+ {
+ mac->m_pm_state = 0; // back to receive state
+ mac->m_pmu_send_timer->adjust(attotime::never);
+ }
+ }
+ }
+
+ mac->m_pm_req = data & 1;
+ return;
+ }
+
+ if (AUDIO_IS_CLASSIC)
+ {
+ mac_enable_sound(sound, (data & 0x80) == 0);
+ }
+
+ // SE and Classic have SCSI enable/disable here
+ if ((mac->m_model == MODEL_MAC_SE) || (mac->m_model == MODEL_MAC_CLASSIC))
+ {
+ mac->m_scsiirq_enable = (data & 0x40) ? 0 : 1;
+// printf("VIAB & 0x40 = %02x, IRQ enable %d\n", data & 0x40, mac->m_scsiirq_enable);
+ }
+
+ if (mac->m_model == MODEL_MAC_SE30)
+ {
+ // 0x40 = 0 means enable vblank on SE/30
+ mac->m_se30_vbl_enable = (data & 0x40) ? 0 : 1;
+
+ // clear the interrupt if we disabled it
+ if (!mac->m_se30_vbl_enable)
+ {
+ mac->nubus_slot_interrupt(0xe, 0);
+ }
+ }
+
+ mac->rtc_write_rTCEnb(data & 0x04);
+ new_rtc_rTCClk = (data >> 1) & 0x01;
+ if ((! new_rtc_rTCClk) && (mac->m_rtc_rTCClk))
+ mac->rtc_shift_data(data & 0x01);
+ mac->m_rtc_rTCClk = new_rtc_rTCClk;
+
+ if (ADB_IS_BITBANG)
+ {
+ mac->mac_adb_newaction((data & 0x30) >> 4);
+ }
+ else if (ADB_IS_EGRET)
+ {
+ #if LOG_ADB
+ printf("68K: New Egret state: SS %d VF %d (PC %x)\n", (data>>5)&1, (data>>4)&1, cpu_get_pc(mac->m_maincpu));
+ #endif
+ mac->m_egret->set_via_full((data&0x10) ? 1 : 0);
+ mac->m_egret->set_sys_session((data&0x20) ? 1 : 0);
+ }
+ else if (ADB_IS_CUDA)
+ {
+ #if LOG_ADB
+ printf("68K: New Cuda state: TIP %d BYTEACK %d (PC %x)\n", (data>>5)&1, (data>>4)&1, cpu_get_pc(mac->m_maincpu));
+ #endif
+ mac->m_cuda->set_byteack((data&0x10) ? 1 : 0);
+ mac->m_cuda->set_tip((data&0x20) ? 1 : 0);
+ }
+}
+
+static void mac_via_irq(device_t *device, int state)
+{
+ mac_state *mac = device->machine().driver_data<mac_state>();
+
+ /* interrupt the 68k (level 1) */
+ mac->set_via_interrupt(state);
+}
+
+READ16_MEMBER ( mac_state::mac_via_r )
+{
+ UINT16 data;
+
+ offset >>= 8;
+ offset &= 0x0f;
+
+ if (LOG_VIA)
+ logerror("mac_via_r: offset=0x%02x\n", offset);
+ data = m_via1->read(space, offset);
+
+ device_adjust_icount(m_maincpu, m_via_cycles);
+
+ return (data & 0xff) | (data << 8);
+}
+
+WRITE16_MEMBER ( mac_state::mac_via_w )
+{
+ offset >>= 8;
+ offset &= 0x0f;
+
+ if (LOG_VIA)
+ logerror("mac_via_w: offset=0x%02x data=0x%08x\n", offset, data);
+
+ if (ACCESSING_BITS_0_7)
+ m_via1->write(space, offset, data & 0xff);
+ if (ACCESSING_BITS_8_15)
+ m_via1->write(space, offset, (data >> 8) & 0xff);
+
+ device_adjust_icount(m_maincpu, m_via_cycles);
+}
+
+/* *************************************************************************
+ * VIA 2 (on Mac IIs and PowerMacs)
+ * *************************************************************************/
+
+static void mac_via2_irq(device_t *device, int state)
+{
+ mac_state *mac = device->machine().driver_data<mac_state>();
+ mac->set_via2_interrupt(state);
+}
+
+READ16_MEMBER ( mac_state::mac_via2_r )
+{
+ int data;
+
+ offset >>= 8;
+ offset &= 0x0f;
+
+ data = m_via2->read(space, offset);
+
+ if (LOG_VIA)
+ logerror("mac_via2_r: offset=0x%02x = %02x (PC=%x)\n", offset*2, data, cpu_get_pc(space.machine().device("maincpu")));
+
+ return (data & 0xff) | (data << 8);
+}
+
+WRITE16_MEMBER ( mac_state::mac_via2_w )
+{
+ offset >>= 8;
+ offset &= 0x0f;
+
+ if (LOG_VIA)
+ logerror("mac_via2_w: offset=%x data=0x%08x mask=%x (PC=%x)\n", offset, data, mem_mask, cpu_get_pc(space.machine().device("maincpu")));
+
+ if (ACCESSING_BITS_0_7)
+ m_via2->write(space, offset, data & 0xff);
+ if (ACCESSING_BITS_8_15)
+ m_via2->write(space, offset, (data >> 8) & 0xff);
+}
+
+
+static READ8_DEVICE_HANDLER(mac_via2_in_a)
+{
+ UINT8 result;
+ mac_state *mac = device->machine().driver_data<mac_state>();
+
+ if (ADB_IS_PM_VIA2)
+ {
+ result = mac->m_pm_data_recv;
+ }
+ else if ((mac->m_model == MODEL_MAC_QUADRA_700) || (mac->m_model == MODEL_MAC_QUADRA_900) || (mac->m_model == MODEL_MAC_QUADRA_950))
+ {
+ result = 0x80 | mac->m_nubus_irq_state;
+ }
+ else
+ {
+ result = 0xc0 | mac->m_nubus_irq_state;
+ }
+
+ return result;
+}
+
+static READ8_DEVICE_HANDLER(mac_via2_in_b)
+{
+ mac_state *mac =device->machine().driver_data<mac_state>();
+
+// logerror("VIA2 IN B (PC %x)\n", cpu_get_pc(device->machine().device("maincpu")));
+
+ if (ADB_IS_PM_VIA2)
+ {
+ if (mac->m_pm_ack == 2)
+ {
+ return 0xcf;
+ }
+ else
+ {
+ return 0xcd;
+ }
+ }
+
+ if ((mac->m_model == MODEL_MAC_LC) || (mac->m_model == MODEL_MAC_LC_II) || (mac->m_model == MODEL_MAC_CLASSIC_II))
+ {
+ return 0x4f;
+ }
+
+ if ((mac->m_model == MODEL_MAC_SE30) || (mac->m_model == MODEL_MAC_IIX))
+ {
+ return 0x87; // bits 3 and 6 are tied low on SE/30
+ }
+
+ return 0xcf; // indicate no NuBus transaction error
+}
+
+static WRITE8_DEVICE_HANDLER(mac_via2_out_a)
+{
+ mac_state *mac = device->machine().driver_data<mac_state>();
+
+// logerror("VIA2 OUT A: %02x (PC %x)\n", data, cpu_get_pc(device->machine().device("maincpu")));
+ if (ADB_IS_PM_VIA2)
+ {
+ mac->m_pm_data_send = data;
+ return;
+ }
+}
+
+static WRITE8_DEVICE_HANDLER(mac_via2_out_b)
+{
+ mac_state *mac = device->machine().driver_data<mac_state>();
+
+// logerror("VIA2 OUT B: %02x (PC %x)\n", data, cpu_get_pc(device->machine().device("maincpu")));
+
+ if (ADB_IS_PM_VIA2)
+ {
+ if ((data & 4) && !(mac->m_pm_req & 4))
+ {
+ #if LOG_ADB
+ printf("PM: 68k dropping /REQ\n");
+ #endif
+
+ if (mac->m_pm_state == 0) // do this in receive state only
+ {
+ mac->m_pm_data_recv = 0xff;
+ mac->m_pm_ack |= 2;
+
+ // check if length byte matches
+ if ((mac->m_pm_dptr >= 2) && (mac->m_pm_cmd[1] == (mac->m_pm_dptr-2)))
+ {
+ mac->pmu_exec();
+ #if LOG_ADB
+ printf("PMU exec: command %02x length %d\n", mac->m_pm_cmd[0], mac->m_pm_cmd[1]);
+ #endif
+ }
+ }
+ }
+ else if (!(data & 4) && (mac->m_pm_req & 4))
+ {
+ if (mac->m_pm_state == 0)
+ {
+ #if LOG_ADB
+ printf("PM: 68k asserting /REQ, clocking in byte [%d] = %02x\n", mac->m_pm_dptr, mac->m_pm_data_send);
+ #endif
+ mac->m_pm_ack &= ~2; // clear, we're waiting for more bytes
+ mac->m_pm_cmd[mac->m_pm_dptr++] = mac->m_pm_data_send;
+ }
+ else // receiving, so this is different
+ {
+ mac->m_pm_data_recv = mac->m_pm_out[mac->m_pm_sptr++];
+ mac->m_pm_slen--;
+ mac->m_pm_ack |= 2; // raise ACK to indicate available byte
+ #if LOG_ADB
+ printf("PM: 68k asserted /REQ, sending byte %02x\n", mac->m_pm_data_recv);
+ #endif
+
+ // another byte to send?
+ if (mac->m_pm_slen)
+ {
+ mac->m_pmu_send_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(100)));
+ }
+ else
+ {
+ mac->m_pm_state = 0; // back to receive state
+ mac->m_pmu_send_timer->adjust(attotime::never);
+ }
+ }
+ }
+
+ mac->m_pm_req = data & 4;
+ return;
+ }
+ else
+ {
+ // chain 60.15 Hz to VIA1
+ mac->m_via1->write_ca1(data>>7);
+ }
+
+ if (mac->m_model == MODEL_MAC_II)
+ {
+ m68k_set_hmmu_enable(mac->m_maincpu, (data & 0x8) ? M68K_HMMU_DISABLE : M68K_HMMU_ENABLE_II);
+ }
+}
+
+// This signal is generated internally on RBV, V8, Sonora, VASP, Eagle, etc.
+static TIMER_CALLBACK(mac_6015_tick)
+{
+ mac_state *mac = machine.driver_data<mac_state>();
+
+ mac->m_via1->write_ca1(0);
+ mac->m_via1->write_ca1(1);
+}
+
+/* *************************************************************************
+ * Main
+ * *************************************************************************/
+
+void mac_state::machine_start()
+{
+ if (has_adb())
+ {
+ this->m_adb_timer = machine().scheduler().timer_alloc(FUNC(mac_adb_tick));
+ this->m_adb_timer->adjust(attotime::never);
+
+ // also allocate PMU timer
+ if (ADB_IS_PM_CLASS)
+ {
+ m_pmu_send_timer = machine().scheduler().timer_alloc(FUNC(mac_pmu_tick));
+ this->m_adb_timer->adjust(attotime::never);
+ m_pmu_int_status = 0;
+ }
+
+ }
+ this->m_scanline_timer = machine().scheduler().timer_alloc(FUNC(mac_scanline_tick));
+ this->m_scanline_timer->adjust(machine().primary_screen->time_until_pos(0, 0));
+
+ m_6015_timer = machine().scheduler().timer_alloc(FUNC(mac_6015_tick));
+ m_6015_timer->adjust(attotime::never);
+}
+
+void mac_state::machine_reset()
+{
+ // stop 60.15 Hz timer
+ m_6015_timer->adjust(attotime::never);
+
+ m_rbv_vbltime = 0;
+
+ if (m_model >= MODEL_MAC_POWERMAC_6100 && m_model <= MODEL_MAC_POWERMAC_8100)
+ {
+ m_awacs->set_dma_base(m_maincpu->memory().space(AS_PROGRAM), 0x10000, 0x12000);
+ }
+
+ // start 60.15 Hz timer for most systems
+ if (((m_model >= MODEL_MAC_IICI) && (m_model <= MODEL_MAC_IIVI)) || (m_model >= MODEL_MAC_LC))
+ {
+ m_6015_timer->adjust(attotime::from_hz(60.15), 0, attotime::from_hz(60.15));
+ }
+
+ // we use the CPU clock divided by the VIA clock (783360 Hz) rounded up as
+ // an approximation for the right number of wait states. this yields good
+ // results - it's towards the end of the worst-case delay on h/w.
+ switch (m_maincpu->clock())
+ {
+ case 7833600: // C7M on classic Macs
+ m_via_cycles = -10;
+ break;
+
+ case 7833600*2: // "16 MHz" Macs
+ m_via_cycles = -30;
+ break;
+
+ case 20000000: // 20 MHz Macs
+ m_via_cycles = -40;
+ break;
+
+ case 25000000: // 25 MHz Macs
+ m_via_cycles = -50;
+ break;
+
+ case 7833600*4: // 32 MHz Macs (these are C7M * 4 like IIvx)
+ m_via_cycles = -60;
+ break;
+
+ case 33000000: // 33 MHz Macs ('040s)
+ m_via_cycles = -64;
+ break;
+
+ case 40000000: // 40 MHz Macs
+ m_via_cycles = -80;
+ break;
+
+ case 60000000: // 60 MHz PowerMac
+ m_via_cycles = -120;
+ break;
+
+ case 66000000: // 66 MHz PowerMac
+ m_via_cycles = -128;
+ break;
+
+ default:
+ fatalerror("mac: unknown clock\n");
+ break;
+ }
+
+ // clear PMU response timer
+ if (ADB_IS_PM_CLASS)
+ {
+ this->m_adb_timer->adjust(attotime::never);
+ }
+
+ // default to 32-bit mode on LC
+ if (m_model == MODEL_MAC_LC)
+ {
+ m68k_set_hmmu_enable(m_maincpu, M68K_HMMU_DISABLE);
+ }
+
+ m_last_taken_interrupt = -1;
+
+ /* initialize real-time clock */
+ rtc_init();
+
+ /* setup the memory overlay */
+ if (m_model < MODEL_MAC_POWERMAC_6100) // no overlay for PowerPC
+ {
+ m_overlay = -1; // insure no match
+ this->set_memory_overlay(1);
+ }
+
+ /* setup videoram */
+ this->m_screen_buffer = 1;
+
+ /* setup 'classic' sound */
+ if (machine().device("custom") != NULL)
+ {
+ mac_set_sound_buffer(machine().device("custom"), 0);
+ }
+ else if (MAC_HAS_VIA2) // prime CB1 for ASC and slot interrupts
+ {
+ m_via2->write_ca1(1);
+ m_via2->write_cb1(1);
+ }
+
+ if (has_adb())
+ {
+ this->adb_reset();
+ }
+
+ if ((m_model == MODEL_MAC_SE) || (m_model == MODEL_MAC_CLASSIC))
+ {
+ mac_set_sound_buffer(machine().device("custom"), 1);
+
+ // classic will fail RAM test and try to boot appletalk if RAM is not all zero
+ memset(m_ram->pointer(), 0, m_ram->size());
+ }
+
+ m_scsi_interrupt = 0;
+ if (machine().device<cpu_device>("maincpu")->debug())
+ {
+ machine().device<cpu_device>("maincpu")->debug()->set_dasm_override(mac_dasm_override);
+ }
+
+ m_drive_select = 0;
+ m_scsiirq_enable = 0;
+ m_via2_vbl = 0;
+ m_se30_vbl_enable = 0;
+ m_nubus_irq_state = 0xff;
+ m_keyboard_reply = 0;
+ m_kbd_comm = 0;
+ m_kbd_receive = 0;
+ m_kbd_shift_reg = 0;
+ m_kbd_shift_count = 0;
+ m_mouse_bit_x = m_mouse_bit_y = 0;
+ m_rtc_rTCEnb = 0;
+ m_rtc_rTCClk = 0;
+ m_rtc_bit_count = 0;
+ m_rtc_data_dir = 0;
+ m_rtc_data_out = 0;
+ m_rtc_cmd = 0;
+ m_rtc_write_protect = 0;
+ m_rtc_state = 0;
+ m_pm_data_send = m_pm_data_recv = m_pm_ack = m_pm_req = m_pm_dptr = 0;
+ m_pm_state = 0;
+ m_last_taken_interrupt = 0;
+}
+
+WRITE_LINE_MEMBER(mac_state::cuda_reset_w)
+{
+ if (state == ASSERT_LINE)
+ {
+ set_memory_overlay(0);
+ set_memory_overlay(1);
+ }
+
+ cputag_set_input_line(machine(), "maincpu", INPUT_LINE_RESET, state);
+}
+
+static void mac_state_load(mac_state *mac)
+{
+ int overlay;
+ overlay = mac->m_overlay;
+ if (mac->m_model < MODEL_MAC_POWERMAC_6100) // no overlay for PowerPC
+ {
+ mac->m_overlay = -1;
+ mac->set_memory_overlay(overlay);
+ }
+}
+
+
+DIRECT_UPDATE_MEMBER(mac_state::overlay_opbaseoverride)
+{
+ if (m_overlay != -1)
+ {
+ if ((m_model == MODEL_MAC_PORTABLE) || (m_model == MODEL_MAC_PB100))
+ {
+ if ((address >= 0x900000) && (address <= 0x9fffff))
+ {
+ set_memory_overlay(0); // kill the overlay
+ }
+ }
+ else if ((m_model == MODEL_MAC_SE) || (m_model == MODEL_MAC_CLASSIC))
+ {
+ if ((address >= 0x400000) && (address <= 0x4fffff))
+ {
+ set_memory_overlay(0); // kill the overlay
+ }
+ }
+ else if ((m_model == MODEL_MAC_LC) || (m_model == MODEL_MAC_LC_II) || (m_model == MODEL_MAC_CLASSIC_II) || (m_model == MODEL_MAC_COLOR_CLASSIC))
+ {
+ if (((address >= 0xa00000) && (address <= 0xafffff)) || ((address >= 0x40a00000) && (address <= 0x40afffff)))
+ {
+ set_memory_overlay(0); // kill the overlay
+ }
+ }
+ else
+ {
+ if ((address >= 0x40000000) && (address <= 0x4fffffff))
+ {
+ set_memory_overlay(0); // kill the overlay
+ }
+ }
+ }
+
+ return address;
+}
+
+READ32_MEMBER(mac_state::mac_read_id)
+{
+// printf("Mac read ID reg @ PC=%x\n", cpu_get_pc(m_maincpu));
+
+ switch (m_model)
+ {
+ case MODEL_MAC_LC_III:
+ return 0xa55a0001; // 25 MHz LC III
+
+ case MODEL_MAC_LC_III_PLUS:
+ return 0xa55a0003; // 33 MHz LC III+
+
+ case MODEL_MAC_LC_475:
+ return 0xa55a2221;
+
+ case MODEL_MAC_LC_520:
+ return 0xa55a0100;
+
+ case MODEL_MAC_LC_550:
+ return 0xa55a0101;
+
+ case MODEL_MAC_LC_575:
+ return 0xa55a222e;
+
+ case MODEL_MAC_POWERMAC_6100:
+ return 0xa55a3011;
+
+ case MODEL_MAC_POWERMAC_7100:
+ return 0xa55a3012;
+
+ case MODEL_MAC_POWERMAC_8100:
+ return 0xa55a3013;
+
+ case MODEL_MAC_PBDUO_210:
+ return 0xa55a1004;
+
+ case MODEL_MAC_PBDUO_230:
+ return 0xa55a1005;
+
+ case MODEL_MAC_PBDUO_250:
+ return 0xa55a1006;
+
+ case MODEL_MAC_QUADRA_605:
+ return 0xa55a2225;
+
+ case MODEL_MAC_QUADRA_610:
+ case MODEL_MAC_QUADRA_650:
+ case MODEL_MAC_QUADRA_800:
+ return 0xa55a2bad;
+
+ case MODEL_MAC_QUADRA_660AV:
+ case MODEL_MAC_QUADRA_840AV:
+ return 0xa55a2830;
+
+ default:
+ return 0;
+ }
+}
+
+static void mac_driver_init(running_machine &machine, model_t model)
+{
+ mac_state *mac = machine.driver_data<mac_state>();
+
+ mac->m_overlay = 1;
+ mac->m_scsi_interrupt = 0;
+ mac->m_model = model;
+
+ if (model < MODEL_MAC_PORTABLE)
+ {
+ /* set up RAM mirror at 0x600000-0x6fffff (0x7fffff ???) */
+ mac_install_memory(machine, 0x600000, 0x6fffff, mac->m_ram->size(), mac->m_ram->pointer(), FALSE, "bank2");
+
+ /* set up ROM at 0x400000-0x43ffff (-0x5fffff for mac 128k/512k/512ke) */
+ mac_install_memory(machine, 0x400000, (model >= MODEL_MAC_PLUS) ? 0x43ffff : 0x5fffff,
+ machine.root_device().memregion("bootrom")->bytes(), machine.root_device().memregion("bootrom")->base(), TRUE, "bank3");
+ }
+
+ mac->m_overlay = -1;
+ if (mac->m_model < MODEL_MAC_POWERMAC_6100) // no overlay for PowerPC
+ {
+ mac->set_memory_overlay(1);
+ }
+
+ memset(mac->m_ram->pointer(), 0, mac->m_ram->size());
+
+ if ((model == MODEL_MAC_SE) || (model == MODEL_MAC_CLASSIC) || (model == MODEL_MAC_CLASSIC_II) || (model == MODEL_MAC_LC) || (model == MODEL_MAC_COLOR_CLASSIC) || (model >= MODEL_MAC_LC_475 && model <= MODEL_MAC_LC_580) ||
+ (model == MODEL_MAC_LC_II) || (model == MODEL_MAC_LC_III) || (model == MODEL_MAC_LC_III_PLUS) || ((mac->m_model >= MODEL_MAC_II) && (mac->m_model <= MODEL_MAC_SE30)) ||
+ (model == MODEL_MAC_PORTABLE) || (model == MODEL_MAC_PB100) || (model == MODEL_MAC_PB140) || (model == MODEL_MAC_PB160) || (model == MODEL_MAC_PBDUO_210) || (model >= MODEL_MAC_QUADRA_700 && model <= MODEL_MAC_QUADRA_800))
+ {
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->set_direct_update_handler(direct_update_delegate(FUNC(mac_state::overlay_opbaseoverride), mac));
+ }
+
+ /* setup keyboard */
+ keyboard_init(mac);
+
+ mac->m_inquiry_timeout = machine.scheduler().timer_alloc(FUNC(inquiry_timeout_func));
+
+ /* save state stuff */
+ machine.save().register_postload(save_prepost_delegate(FUNC(mac_state_load), mac));
+}
+
+#define MAC_DRIVER_INIT(label, model) \
+DRIVER_INIT_MEMBER(mac_state,label) \
+{ \
+ mac_driver_init(machine(), model ); \
+}
+
+MAC_DRIVER_INIT(mac128k512k, MODEL_MAC_128K512K)
+MAC_DRIVER_INIT(mac512ke, MODEL_MAC_512KE)
+MAC_DRIVER_INIT(macplus, MODEL_MAC_PLUS)
+MAC_DRIVER_INIT(macse, MODEL_MAC_SE)
+MAC_DRIVER_INIT(macclassic, MODEL_MAC_CLASSIC)
+MAC_DRIVER_INIT(maclc, MODEL_MAC_LC)
+MAC_DRIVER_INIT(maclc2, MODEL_MAC_LC_II)
+MAC_DRIVER_INIT(maclc3, MODEL_MAC_LC_III)
+MAC_DRIVER_INIT(maclc3plus, MODEL_MAC_LC_III_PLUS)
+MAC_DRIVER_INIT(maciici, MODEL_MAC_IICI)
+MAC_DRIVER_INIT(maciisi, MODEL_MAC_IISI)
+MAC_DRIVER_INIT(macii, MODEL_MAC_II)
+MAC_DRIVER_INIT(macse30, MODEL_MAC_SE30)
+MAC_DRIVER_INIT(macclassic2, MODEL_MAC_CLASSIC_II)
+MAC_DRIVER_INIT(maclrcclassic, MODEL_MAC_COLOR_CLASSIC)
+MAC_DRIVER_INIT(macpm6100, MODEL_MAC_POWERMAC_6100)
+MAC_DRIVER_INIT(macpm7100, MODEL_MAC_POWERMAC_7100)
+MAC_DRIVER_INIT(macpm8100, MODEL_MAC_POWERMAC_8100)
+MAC_DRIVER_INIT(macprtb, MODEL_MAC_PORTABLE)
+MAC_DRIVER_INIT(macpb100, MODEL_MAC_PB100)
+MAC_DRIVER_INIT(macpb140, MODEL_MAC_PB140)
+MAC_DRIVER_INIT(macpb160, MODEL_MAC_PB160)
+MAC_DRIVER_INIT(maciivx, MODEL_MAC_IIVX)
+MAC_DRIVER_INIT(maciifx, MODEL_MAC_IIFX)
+MAC_DRIVER_INIT(macpd210, MODEL_MAC_PBDUO_210)
+MAC_DRIVER_INIT(macquadra700, MODEL_MAC_QUADRA_700)
+MAC_DRIVER_INIT(maciicx, MODEL_MAC_IICX)
+MAC_DRIVER_INIT(maciifdhd, MODEL_MAC_II_FDHD)
+MAC_DRIVER_INIT(maciix, MODEL_MAC_IIX);
+MAC_DRIVER_INIT(maclc520, MODEL_MAC_LC_520)
+
+void mac_state::nubus_slot_interrupt(UINT8 slot, UINT32 state)
+{
+ static const UINT8 masks[8] = { 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80 };
+ mac_state *mac = machine().driver_data<mac_state>();
+ UINT8 mask = 0x3f;
+
+ // quadra 700/900/950 use the top 2 bits of the interrupt register for ethernet and video
+ if ((mac->m_model == MODEL_MAC_QUADRA_700) || (mac->m_model == MODEL_MAC_QUADRA_900) || (mac->m_model == MODEL_MAC_QUADRA_950))
+ {
+ mask = 0xff;
+ }
+
+ slot -= 9;
+
+ if (state)
+ {
+ mac->m_nubus_irq_state &= ~masks[slot];
+ }
+ else
+ {
+ mac->m_nubus_irq_state |= masks[slot];
+ }
+
+ if ((mac->m_model != MODEL_MAC_IIFX) && (mac->m_model != MODEL_MAC_IICI) && (mac->m_model != MODEL_MAC_IISI))
+ {
+ if ((mac->m_nubus_irq_state & mask) != mask)
+ {
+ // HACK: sometimes we miss an ack (possible misbehavior in the VIA?)
+ if (m_via2->read_ca1() == 0)
+ {
+ m_via2->write_ca1(1);
+ }
+ m_via2->write_ca1(0);
+ }
+ else
+ {
+ m_via2->write_ca1(1);
+ }
+ }
+
+ if ((mac->m_model == MODEL_MAC_IICI) || (mac->m_model == MODEL_MAC_IISI) || (mac->m_model == MODEL_MAC_IIVX) || (mac->m_model == MODEL_MAC_IIVI))
+ {
+ mac->m_rbv_regs[2] &= ~0x38;
+ mac->m_rbv_regs[2] |= (mac->m_nubus_irq_state & 0x38);
+ mac->rbv_recalc_irqs();
+ }
+}
+
+void mac_state::vblank_irq()
+{
+ /* handle ADB keyboard/mouse */
+ if (has_adb())
+ {
+ this->adb_vblank();
+ }
+
+ /* handle keyboard */
+ if (m_kbd_comm == TRUE)
+ {
+ int keycode = scan_keyboard(machine());
+
+ if (keycode != 0x7B)
+ {
+ /* if key pressed, send the code */
+
+ logerror("keyboard enquiry successful, keycode %X\n", keycode);
+
+ m_inquiry_timeout->reset();
+ kbd_shift_out(machine(), keycode);
+ }
+ }
+
+ /* signal VBlank on CA1 input on the VIA */
+ if ((m_model < MODEL_MAC_II) || (m_model == MODEL_MAC_PB140) || (m_model == MODEL_MAC_PB160) || (m_model == MODEL_MAC_QUADRA_700))
+ {
+ ca1_data ^= 1;
+ m_via1->write_ca1(ca1_data);
+ }
+
+ if (++irq_count == 60)
+ {
+ irq_count = 0;
+
+ ca2_data ^= 1;
+ /* signal 1 Hz irq on CA2 input on the VIA */
+ m_via1->write_ca2(ca2_data);
+ rtc_incticks();
+ }
+
+ // handle SE/30 vblank IRQ
+ if (m_model == MODEL_MAC_SE30)
+ {
+ if (m_se30_vbl_enable)
+ {
+ m_via2_vbl ^= 1;
+ if (!m_via2_vbl)
+ {
+ this->nubus_slot_interrupt(0xe, 1);
+ }
+ }
+ }
+}
+
+static TIMER_CALLBACK(mac_scanline_tick)
+{
+ int scanline;
+ mac_state *mac = machine.driver_data<mac_state>();
+
+ if (machine.device("custom") != NULL)
+ {
+ mac_sh_updatebuffer(machine.device("custom"));
+ }
+
+ if (mac->m_rbv_vbltime > 0)
+ {
+ mac->m_rbv_vbltime--;
+
+ if (mac->m_rbv_vbltime == 0)
+ {
+ mac->m_rbv_regs[2] |= 0x40;
+ mac->rbv_recalc_irqs();
+ }
+ }
+
+ scanline = machine.primary_screen->vpos();
+ if (scanline == MAC_V_VIS)
+ mac->vblank_irq();
+
+ /* check for mouse changes at 10 irqs per frame */
+ if (mac->m_model <= MODEL_MAC_PLUS)
+ {
+ if (!(scanline % 10))
+ mac->mouse_callback();
+ }
+
+ mac->m_scanline_timer->adjust(machine.primary_screen->time_until_pos((scanline+1) % MAC_V_TOTAL, 0));
+}
+
+WRITE_LINE_MEMBER(mac_state::nubus_irq_9_w)
+{
+ nubus_slot_interrupt(9, state);
+}
+
+WRITE_LINE_MEMBER(mac_state::nubus_irq_a_w)
+{
+ nubus_slot_interrupt(0xa, state);
+}
+
+WRITE_LINE_MEMBER(mac_state::nubus_irq_b_w)
+{
+ nubus_slot_interrupt(0xb, state);
+}
+
+WRITE_LINE_MEMBER(mac_state::nubus_irq_c_w)
+{
+ nubus_slot_interrupt(0xc, state);
+}
+
+WRITE_LINE_MEMBER(mac_state::nubus_irq_d_w)
+{
+ nubus_slot_interrupt(0xd, state);
+}
+
+WRITE_LINE_MEMBER(mac_state::nubus_irq_e_w)
+{
+ nubus_slot_interrupt(0xe, state);
+}
+
+/* *************************************************************************
+ * Trap Tracing
+ *
+ * This is debug code that will output diagnostics regarding OS traps called
+ * *************************************************************************/
+
+static const char *lookup_trap(UINT16 opcode)
+{
+ static const struct
+ {
+ UINT16 trap;
+ const char *name;
+ } traps[] =
+ {
+ { 0xA000, "_Open" },
+ { 0xA001, "_Close" },
+ { 0xA002, "_Read" },
+ { 0xA003, "_Write" },
+ { 0xA004, "_Control" },
+ { 0xA005, "_Status" },
+ { 0xA006, "_KillIO" },
+ { 0xA007, "_GetVolInfo" },
+ { 0xA008, "_Create" },
+ { 0xA009, "_Delete" },
+ { 0xA00A, "_OpenRF" },
+ { 0xA00B, "_Rename" },
+ { 0xA00C, "_GetFileInfo" },
+ { 0xA00D, "_SetFileInfo" },
+ { 0xA00E, "_UnmountVol" },
+ { 0xA00F, "_MountVol" },
+ { 0xA010, "_Allocate" },
+ { 0xA011, "_GetEOF" },
+ { 0xA012, "_SetEOF" },
+ { 0xA013, "_FlushVol" },
+ { 0xA014, "_GetVol" },
+ { 0xA015, "_SetVol" },
+ { 0xA016, "_FInitQueue" },
+ { 0xA017, "_Eject" },
+ { 0xA018, "_GetFPos" },
+ { 0xA019, "_InitZone" },
+ { 0xA01B, "_SetZone" },
+ { 0xA01C, "_FreeMem" },
+ { 0xA01F, "_DisposePtr" },
+ { 0xA020, "_SetPtrSize" },
+ { 0xA021, "_GetPtrSize" },
+ { 0xA023, "_DisposeHandle" },
+ { 0xA024, "_SetHandleSize" },
+ { 0xA025, "_GetHandleSize" },
+ { 0xA027, "_ReallocHandle" },
+ { 0xA029, "_HLock" },
+ { 0xA02A, "_HUnlock" },
+ { 0xA02B, "_EmptyHandle" },
+ { 0xA02C, "_InitApplZone" },
+ { 0xA02D, "_SetApplLimit" },
+ { 0xA02E, "_BlockMove" },
+ { 0xA02F, "_PostEvent" },
+ { 0xA030, "_OSEventAvail" },
+ { 0xA031, "_GetOSEvent" },
+ { 0xA032, "_FlushEvents" },
+ { 0xA033, "_VInstall" },
+ { 0xA034, "_VRemove" },
+ { 0xA035, "_OffLine" },
+ { 0xA036, "_MoreMasters" },
+ { 0xA038, "_WriteParam" },
+ { 0xA039, "_ReadDateTime" },
+ { 0xA03A, "_SetDateTime" },
+ { 0xA03B, "_Delay" },
+ { 0xA03C, "_CmpString" },
+ { 0xA03D, "_DrvrInstall" },
+ { 0xA03E, "_DrvrRemove" },
+ { 0xA03F, "_InitUtil" },
+ { 0xA040, "_ResrvMem" },
+ { 0xA041, "_SetFilLock" },
+ { 0xA042, "_RstFilLock" },
+ { 0xA043, "_SetFilType" },
+ { 0xA044, "_SetFPos" },
+ { 0xA045, "_FlushFile" },
+ { 0xA047, "_SetTrapAddress" },
+ { 0xA049, "_HPurge" },
+ { 0xA04A, "_HNoPurge" },
+ { 0xA04B, "_SetGrowZone" },
+ { 0xA04C, "_CompactMem" },
+ { 0xA04D, "_PurgeMem" },
+ { 0xA04E, "_AddDrive" },
+ { 0xA04F, "_RDrvrInstall" },
+ { 0xA050, "_CompareString" },
+ { 0xA051, "_ReadXPRam" },
+ { 0xA052, "_WriteXPRam" },
+ { 0xA054, "_UprString" },
+ { 0xA055, "_StripAddress" },
+ { 0xA056, "_LowerText" },
+ { 0xA057, "_SetAppBase" },
+ { 0xA058, "_InsTime" },
+ { 0xA059, "_RmvTime" },
+ { 0xA05A, "_PrimeTime" },
+ { 0xA05B, "_PowerOff" },
+ { 0xA05C, "_MemoryDispatch" },
+ { 0xA05D, "_SwapMMUMode" },
+ { 0xA05E, "_NMInstall" },
+ { 0xA05F, "_NMRemove" },
+ { 0xA060, "_FSDispatch" },
+ { 0xA061, "_MaxBlock" },
+ { 0xA063, "_MaxApplZone" },
+ { 0xA064, "_MoveHHi" },
+ { 0xA065, "_StackSpace" },
+ { 0xA067, "_HSetRBit" },
+ { 0xA068, "_HClrRBit" },
+ { 0xA069, "_HGetState" },
+ { 0xA06A, "_HSetState" },
+ { 0xA06C, "_InitFS" },
+ { 0xA06D, "_InitEvents" },
+ { 0xA06E, "_SlotManager" },
+ { 0xA06F, "_SlotVInstall" },
+ { 0xA070, "_SlotVRemove" },
+ { 0xA071, "_AttachVBL" },
+ { 0xA072, "_DoVBLTask" },
+ { 0xA075, "_SIntInstall" },
+ { 0xA076, "_SIntRemove" },
+ { 0xA077, "_CountADBs" },
+ { 0xA078, "_GetIndADB" },
+ { 0xA079, "_GetADBInfo" },
+ { 0xA07A, "_SetADBInfo" },
+ { 0xA07B, "_ADBReInit" },
+ { 0xA07C, "_ADBOp" },
+ { 0xA07D, "_GetDefaultStartup" },
+ { 0xA07E, "_SetDefaultStartup" },
+ { 0xA07F, "_InternalWait" },
+ { 0xA080, "_GetVideoDefault" },
+ { 0xA081, "_SetVideoDefault" },
+ { 0xA082, "_DTInstall" },
+ { 0xA083, "_SetOSDefault" },
+ { 0xA084, "_GetOSDefault" },
+ { 0xA085, "_PMgrOp" },
+ { 0xA086, "_IOPInfoAccess" },
+ { 0xA087, "_IOPMsgRequest" },
+ { 0xA088, "_IOPMoveData" },
+ { 0xA089, "_SCSIAtomic" },
+ { 0xA08A, "_Sleep" },
+ { 0xA08B, "_CommToolboxDispatch" },
+ { 0xA08D, "_DebugUtil" },
+ { 0xA08F, "_DeferUserFn" },
+ { 0xA090, "_SysEnvirons" },
+ { 0xA092, "_EgretDispatch" },
+ { 0xA094, "_ServerDispatch" },
+ { 0xA09E, "_PowerMgrDispatch" },
+ { 0xA09F, "_PowerDispatch" },
+ { 0xA0A4, "_HeapDispatch" },
+ { 0xA0AC, "_FSMDispatch" },
+ { 0xA0AE, "_VADBProc" },
+ { 0xA0DD, "_PPC" },
+ { 0xA0FE, "_TEFindWord" },
+ { 0xA0FF, "_TEFindLine" },
+ { 0xA11A, "_GetZone" },
+ { 0xA11D, "_MaxMem" },
+ { 0xA11E, "_NewPtr" },
+ { 0xA122, "_NewHandle" },
+ { 0xA126, "_HandleZone" },
+ { 0xA128, "_RecoverHandle" },
+ { 0xA12F, "_PPostEvent" },
+ { 0xA146, "_GetTrapAddress" },
+ { 0xA148, "_PtrZone" },
+ { 0xA162, "_PurgeSpace" },
+ { 0xA166, "_NewEmptyHandle" },
+ { 0xA193, "_Microseconds" },
+ { 0xA198, "_HWPriv" },
+ { 0xA1AD, "_Gestalt" },
+ { 0xA200, "_HOpen" },
+ { 0xA207, "_HGetVInfo" },
+ { 0xA208, "_HCreate" },
+ { 0xA209, "_HDelete" },
+ { 0xA20A, "_HOpenRF" },
+ { 0xA20B, "_HRename" },
+ { 0xA20C, "_HGetFileInfo" },
+ { 0xA20D, "_HSetFileInfo" },
+ { 0xA20E, "_HUnmountVol" },
+ { 0xA210, "_AllocContig" },
+ { 0xA214, "_HGetVol" },
+ { 0xA215, "_HSetVol" },
+ { 0xA22E, "_BlockMoveData" },
+ { 0xA241, "_HSetFLock" },
+ { 0xA242, "_HRstFLock" },
+ { 0xA247, "_SetOSTrapAddress" },
+ { 0xA256, "_StripText" },
+ { 0xA260, "_HFSDispatch" },
+ { 0xA285, "_IdleUpdate" },
+ { 0xA28A, "_SlpQInstall" },
+ { 0xA31E, "_NewPtrClear" },
+ { 0xA322, "_NewHandleClear" },
+ { 0xA346, "_GetOSTrapAddress" },
+ { 0xA3AD, "_NewGestalt" },
+ { 0xA456, "_UpperText" },
+ { 0xA458, "_InsXTime" },
+ { 0xA485, "_IdleState" },
+ { 0xA48A, "_SlpQRemove" },
+ { 0xA51E, "_NewPtrSys" },
+ { 0xA522, "_NewHandleSys" },
+ { 0xA562, "_PurgeSpaceSys" },
+ { 0xA5AD, "_ReplaceGestalt" },
+ { 0xA647, "_SetToolBoxTrapAddress" },
+ { 0xA656, "_StripUpperText" },
+ { 0xA685, "_SerialPower" },
+ { 0xA71E, "_NewPtrSysClear" },
+ { 0xA722, "_NewHandleSysClear" },
+ { 0xA746, "_GetToolBoxTrapAddress" },
+ { 0xA7AD, "_GetGestaltProcPtr" },
+ { 0xA800, "_SoundDispatch" },
+ { 0xA801, "_SndDisposeChannel" },
+ { 0xA802, "_SndAddModifier" },
+ { 0xA803, "_SndDoCommand" },
+ { 0xA804, "_SndDoImmediate" },
+ { 0xA805, "_SndPlay" },
+ { 0xA806, "_SndControl" },
+ { 0xA807, "_SndNewChannel" },
+ { 0xA808, "_InitProcMenu" },
+ { 0xA809, "_GetControlVariant" },
+ { 0xA80A, "_GetWVariant" },
+ { 0xA80B, "_PopUpMenuSelect" },
+ { 0xA80C, "_RGetResource" },
+ { 0xA811, "_TESelView" },
+ { 0xA812, "_TEPinScroll" },
+ { 0xA813, "_TEAutoView" },
+ { 0xA814, "_SetFractEnable" },
+ { 0xA815, "_SCSIDispatch" },
+ { 0xA817, "_CopyMask" },
+ { 0xA819, "_XMunger" },
+ { 0xA81A, "_HOpenResFile" },
+ { 0xA81B, "_HCreateResFile" },
+ { 0xA81D, "_InvalMenuBar" },
+ { 0xA821, "_MaxSizeRsrc" },
+ { 0xA822, "_ResourceDispatch" },
+ { 0xA823, "_AliasDispatch" },
+ { 0xA824, "_HFSUtilDispatch" },
+ { 0xA825, "_MenuDispatch" },
+ { 0xA826, "_InsertMenuItem" },
+ { 0xA827, "_HideDialogItem" },
+ { 0xA828, "_ShowDialogItem" },
+ { 0xA82A, "_ComponentDispatch" },
+ { 0xA833, "_ScrnBitMap" },
+ { 0xA834, "_SetFScaleDisable" },
+ { 0xA835, "_FontMetrics" },
+ { 0xA836, "_GetMaskTable" },
+ { 0xA837, "_MeasureText" },
+ { 0xA838, "_CalcMask" },
+ { 0xA839, "_SeedFill" },
+ { 0xA83A, "_ZoomWindow" },
+ { 0xA83B, "_TrackBox" },
+ { 0xA83C, "_TEGetOffset" },
+ { 0xA83D, "_TEDispatch" },
+ { 0xA83E, "_TEStyleNew" },
+ { 0xA847, "_FracCos" },
+ { 0xA848, "_FracSin" },
+ { 0xA849, "_FracSqrt" },
+ { 0xA84A, "_FracMul" },
+ { 0xA84B, "_FracDiv" },
+ { 0xA84D, "_FixDiv" },
+ { 0xA84E, "_GetItemCmd" },
+ { 0xA84F, "_SetItemCmd" },
+ { 0xA850, "_InitCursor" },
+ { 0xA851, "_SetCursor" },
+ { 0xA852, "_HideCursor" },
+ { 0xA853, "_ShowCursor" },
+ { 0xA854, "_FontDispatch" },
+ { 0xA855, "_ShieldCursor" },
+ { 0xA856, "_ObscureCursor" },
+ { 0xA858, "_BitAnd" },
+ { 0xA859, "_BitXOr" },
+ { 0xA85A, "_BitNot" },
+ { 0xA85B, "_BitOr" },
+ { 0xA85C, "_BitShift" },
+ { 0xA85D, "_BitTst" },
+ { 0xA85E, "_BitSet" },
+ { 0xA85F, "_BitClr" },
+ { 0xA860, "_WaitNextEvent" },
+ { 0xA861, "_Random" },
+ { 0xA862, "_ForeColor" },
+ { 0xA863, "_BackColor" },
+ { 0xA864, "_ColorBit" },
+ { 0xA865, "_GetPixel" },
+ { 0xA866, "_StuffHex" },
+ { 0xA867, "_LongMul" },
+ { 0xA868, "_FixMul" },
+ { 0xA869, "_FixRatio" },
+ { 0xA86A, "_HiWord" },
+ { 0xA86B, "_LoWord" },
+ { 0xA86C, "_FixRound" },
+ { 0xA86D, "_InitPort" },
+ { 0xA86E, "_InitGraf" },
+ { 0xA86F, "_OpenPort" },
+ { 0xA870, "_LocalToGlobal" },
+ { 0xA871, "_GlobalToLocal" },
+ { 0xA872, "_GrafDevice" },
+ { 0xA873, "_SetPort" },
+ { 0xA874, "_GetPort" },
+ { 0xA875, "_SetPBits" },
+ { 0xA876, "_PortSize" },
+ { 0xA877, "_MovePortTo" },
+ { 0xA878, "_SetOrigin" },
+ { 0xA879, "_SetClip" },
+ { 0xA87A, "_GetClip" },
+ { 0xA87B, "_ClipRect" },
+ { 0xA87C, "_BackPat" },
+ { 0xA87D, "_ClosePort" },
+ { 0xA87E, "_AddPt" },
+ { 0xA87F, "_SubPt" },
+ { 0xA880, "_SetPt" },
+ { 0xA881, "_EqualPt" },
+ { 0xA882, "_StdText" },
+ { 0xA883, "_DrawChar" },
+ { 0xA884, "_DrawString" },
+ { 0xA885, "_DrawText" },
+ { 0xA886, "_TextWidth" },
+ { 0xA887, "_TextFont" },
+ { 0xA888, "_TextFace" },
+ { 0xA889, "_TextMode" },
+ { 0xA88A, "_TextSize" },
+ { 0xA88B, "_GetFontInfo" },
+ { 0xA88C, "_StringWidth" },
+ { 0xA88D, "_CharWidth" },
+ { 0xA88E, "_SpaceExtra" },
+ { 0xA88F, "_OSDispatch" },
+ { 0xA890, "_StdLine" },
+ { 0xA891, "_LineTo" },
+ { 0xA892, "_Line" },
+ { 0xA893, "_MoveTo" },
+ { 0xA894, "_Move" },
+ { 0xA895, "_ShutDown" },
+ { 0xA896, "_HidePen" },
+ { 0xA897, "_ShowPen" },
+ { 0xA898, "_GetPenState" },
+ { 0xA899, "_SetPenState" },
+ { 0xA89A, "_GetPen" },
+ { 0xA89B, "_PenSize" },
+ { 0xA89C, "_PenMode" },
+ { 0xA89D, "_PenPat" },
+ { 0xA89E, "_PenNormal" },
+ { 0xA89F, "_Moof" },
+ { 0xA8A0, "_StdRect" },
+ { 0xA8A1, "_FrameRect" },
+ { 0xA8A2, "_PaintRect" },
+ { 0xA8A3, "_EraseRect" },
+ { 0xA8A4, "_InverRect" },
+ { 0xA8A5, "_FillRect" },
+ { 0xA8A6, "_EqualRect" },
+ { 0xA8A7, "_SetRect" },
+ { 0xA8A8, "_OffsetRect" },
+ { 0xA8A9, "_InsetRect" },
+ { 0xA8AA, "_SectRect" },
+ { 0xA8AB, "_UnionRect" },
+ { 0xA8AD, "_PtInRect" },
+ { 0xA8AE, "_EmptyRect" },
+ { 0xA8AF, "_StdRRect" },
+ { 0xA8B0, "_FrameRoundRect" },
+ { 0xA8B1, "_PaintRoundRect" },
+ { 0xA8B2, "_EraseRoundRect" },
+ { 0xA8B3, "_InverRoundRect" },
+ { 0xA8B4, "_FillRoundRect" },
+ { 0xA8B5, "_ScriptUtil" },
+ { 0xA8B6, "_StdOval" },
+ { 0xA8B7, "_FrameOval" },
+ { 0xA8B8, "_PaintOval" },
+ { 0xA8B9, "_EraseOval" },
+ { 0xA8BA, "_InvertOval" },
+ { 0xA8BB, "_FillOval" },
+ { 0xA8BC, "_SlopeFromAngle" },
+ { 0xA8BD, "_StdArc" },
+ { 0xA8BE, "_FrameArc" },
+ { 0xA8BF, "_PaintArc" },
+ { 0xA8C0, "_EraseArc" },
+ { 0xA8C1, "_InvertArc" },
+ { 0xA8C2, "_FillArc" },
+ { 0xA8C3, "_PtToAngle" },
+ { 0xA8C4, "_AngleFromSlope" },
+ { 0xA8C5, "_StdPoly" },
+ { 0xA8C6, "_FramePoly" },
+ { 0xA8C7, "_PaintPoly" },
+ { 0xA8C8, "_ErasePoly" },
+ { 0xA8C9, "_InvertPoly" },
+ { 0xA8CA, "_FillPoly" },
+ { 0xA8CB, "_OpenPoly" },
+ { 0xA8CC, "_ClosePoly" },
+ { 0xA8CD, "_KillPoly" },
+ { 0xA8CE, "_OffsetPoly" },
+ { 0xA8CF, "_PackBits" },
+ { 0xA8D0, "_UnpackBits" },
+ { 0xA8D1, "_StdRgn" },
+ { 0xA8D2, "_FrameRgn" },
+ { 0xA8D3, "_PaintRgn" },
+ { 0xA8D4, "_EraseRgn" },
+ { 0xA8D5, "_InverRgn" },
+ { 0xA8D6, "_FillRgn" },
+ { 0xA8D7, "_BitMapToRegion" },
+ { 0xA8D8, "_NewRgn" },
+ { 0xA8D9, "_DisposeRgn" },
+ { 0xA8DA, "_OpenRgn" },
+ { 0xA8DB, "_CloseRgn" },
+ { 0xA8DC, "_CopyRgn" },
+ { 0xA8DD, "_SetEmptyRgn" },
+ { 0xA8DE, "_SetRecRgn" },
+ { 0xA8DF, "_RectRgn" },
+ { 0xA8E0, "_OffsetRgn" },
+ { 0xA8E1, "_InsetRgn" },
+ { 0xA8E2, "_EmptyRgn" },
+ { 0xA8E3, "_EqualRgn" },
+ { 0xA8E4, "_SectRgn" },
+ { 0xA8E5, "_UnionRgn" },
+ { 0xA8E6, "_DiffRgn" },
+ { 0xA8E7, "_XOrRgn" },
+ { 0xA8E8, "_PtInRgn" },
+ { 0xA8E9, "_RectInRgn" },
+ { 0xA8EA, "_SetStdProcs" },
+ { 0xA8EB, "_StdBits" },
+ { 0xA8EC, "_CopyBits" },
+ { 0xA8ED, "_StdTxMeas" },
+ { 0xA8EE, "_StdGetPic" },
+ { 0xA8EF, "_ScrollRect" },
+ { 0xA8F0, "_StdPutPic" },
+ { 0xA8F1, "_StdComment" },
+ { 0xA8F2, "_PicComment" },
+ { 0xA8F3, "_OpenPicture" },
+ { 0xA8F4, "_ClosePicture" },
+ { 0xA8F5, "_KillPicture" },
+ { 0xA8F6, "_DrawPicture" },
+ { 0xA8F7, "_Layout" },
+ { 0xA8F8, "_ScalePt" },
+ { 0xA8F9, "_MapPt" },
+ { 0xA8FA, "_MapRect" },
+ { 0xA8FB, "_MapRgn" },
+ { 0xA8FC, "_MapPoly" },
+ { 0xA8FD, "_PrGlue" },
+ { 0xA8FE, "_InitFonts" },
+ { 0xA8FF, "_GetFName" },
+ { 0xA900, "_GetFNum" },
+ { 0xA901, "_FMSwapFont" },
+ { 0xA902, "_RealFont" },
+ { 0xA903, "_SetFontLock" },
+ { 0xA904, "_DrawGrowIcon" },
+ { 0xA905, "_DragGrayRgn" },
+ { 0xA906, "_NewString" },
+ { 0xA907, "_SetString" },
+ { 0xA908, "_ShowHide" },
+ { 0xA909, "_CalcVis" },
+ { 0xA90A, "_CalcVBehind" },
+ { 0xA90B, "_ClipAbove" },
+ { 0xA90C, "_PaintOne" },
+ { 0xA90D, "_PaintBehind" },
+ { 0xA90E, "_SaveOld" },
+ { 0xA90F, "_DrawNew" },
+ { 0xA910, "_GetWMgrPort" },
+ { 0xA911, "_CheckUpDate" },
+ { 0xA912, "_InitWindows" },
+ { 0xA913, "_NewWindow" },
+ { 0xA914, "_DisposeWindow" },
+ { 0xA915, "_ShowWindow" },
+ { 0xA916, "_HideWindow" },
+ { 0xA917, "_GetWRefCon" },
+ { 0xA918, "_SetWRefCon" },
+ { 0xA919, "_GetWTitle" },
+ { 0xA91A, "_SetWTitle" },
+ { 0xA91B, "_MoveWindow" },
+ { 0xA91C, "_HiliteWindow" },
+ { 0xA91D, "_SizeWindow" },
+ { 0xA91E, "_TrackGoAway" },
+ { 0xA91F, "_SelectWindow" },
+ { 0xA920, "_BringToFront" },
+ { 0xA921, "_SendBehind" },
+ { 0xA922, "_BeginUpDate" },
+ { 0xA923, "_EndUpDate" },
+ { 0xA924, "_FrontWindow" },
+ { 0xA925, "_DragWindow" },
+ { 0xA926, "_DragTheRgn" },
+ { 0xA927, "_InvalRgn" },
+ { 0xA928, "_InvalRect" },
+ { 0xA929, "_ValidRgn" },
+ { 0xA92A, "_ValidRect" },
+ { 0xA92B, "_GrowWindow" },
+ { 0xA92C, "_FindWindow" },
+ { 0xA92D, "_CloseWindow" },
+ { 0xA92E, "_SetWindowPic" },
+ { 0xA92F, "_GetWindowPic" },
+ { 0xA930, "_InitMenus" },
+ { 0xA931, "_NewMenu" },
+ { 0xA932, "_DisposeMenu" },
+ { 0xA933, "_AppendMenu" },
+ { 0xA934, "_ClearMenuBar" },
+ { 0xA935, "_InsertMenu" },
+ { 0xA936, "_DeleteMenu" },
+ { 0xA937, "_DrawMenuBar" },
+ { 0xA938, "_HiliteMenu" },
+ { 0xA939, "_EnableItem" },
+ { 0xA93A, "_DisableItem" },
+ { 0xA93B, "_GetMenuBar" },
+ { 0xA93C, "_SetMenuBar" },
+ { 0xA93D, "_MenuSelect" },
+ { 0xA93E, "_MenuKey" },
+ { 0xA93F, "_GetItmIcon" },
+ { 0xA940, "_SetItmIcon" },
+ { 0xA941, "_GetItmStyle" },
+ { 0xA942, "_SetItmStyle" },
+ { 0xA943, "_GetItmMark" },
+ { 0xA944, "_SetItmMark" },
+ { 0xA945, "_CheckItem" },
+ { 0xA946, "_GetMenuItemText" },
+ { 0xA947, "_SetMenuItemText" },
+ { 0xA948, "_CalcMenuSize" },
+ { 0xA949, "_GetMenuHandle" },
+ { 0xA94A, "_SetMFlash" },
+ { 0xA94B, "_PlotIcon" },
+ { 0xA94C, "_FlashMenuBar" },
+ { 0xA94D, "_AppendResMenu" },
+ { 0xA94E, "_PinRect" },
+ { 0xA94F, "_DeltaPoint" },
+ { 0xA950, "_CountMItems" },
+ { 0xA951, "_InsertResMenu" },
+ { 0xA952, "_DeleteMenuItem" },
+ { 0xA953, "_UpdtControl" },
+ { 0xA954, "_NewControl" },
+ { 0xA955, "_DisposeControl" },
+ { 0xA956, "_KillControls" },
+ { 0xA957, "_ShowControl" },
+ { 0xA958, "_HideControl" },
+ { 0xA959, "_MoveControl" },
+ { 0xA95A, "_GetControlReference" },
+ { 0xA95B, "_SetControlReference" },
+ { 0xA95C, "_SizeControl" },
+ { 0xA95D, "_HiliteControl" },
+ { 0xA95E, "_GetControlTitle" },
+ { 0xA95F, "_SetControlTitle" },
+ { 0xA960, "_GetControlValue" },
+ { 0xA961, "_GetControlMinimum" },
+ { 0xA962, "_GetControlMaximum" },
+ { 0xA963, "_SetControlValue" },
+ { 0xA964, "_SetControlMinimum" },
+ { 0xA965, "_SetControlMaximum" },
+ { 0xA966, "_TestControl" },
+ { 0xA967, "_DragControl" },
+ { 0xA968, "_TrackControl" },
+ { 0xA969, "_DrawControls" },
+ { 0xA96A, "_GetControlAction" },
+ { 0xA96B, "_SetControlAction" },
+ { 0xA96C, "_FindControl" },
+ { 0xA96E, "_Dequeue" },
+ { 0xA96F, "_Enqueue" },
+ { 0xA970, "_GetNextEvent" },
+ { 0xA971, "_EventAvail" },
+ { 0xA972, "_GetMouse" },
+ { 0xA973, "_StillDown" },
+ { 0xA974, "_Button" },
+ { 0xA975, "_TickCount" },
+ { 0xA976, "_GetKeys" },
+ { 0xA977, "_WaitMouseUp" },
+ { 0xA978, "_UpdtDialog" },
+ { 0xA97B, "_InitDialogs" },
+ { 0xA97C, "_GetNewDialog" },
+ { 0xA97D, "_NewDialog" },
+ { 0xA97E, "_SelectDialogItemText" },
+ { 0xA97F, "_IsDialogEvent" },
+ { 0xA980, "_DialogSelect" },
+ { 0xA981, "_DrawDialog" },
+ { 0xA982, "_CloseDialog" },
+ { 0xA983, "_DisposeDialog" },
+ { 0xA984, "_FindDialogItem" },
+ { 0xA985, "_Alert" },
+ { 0xA986, "_StopAlert" },
+ { 0xA987, "_NoteAlert" },
+ { 0xA988, "_CautionAlert" },
+ { 0xA98B, "_ParamText" },
+ { 0xA98C, "_ErrorSound" },
+ { 0xA98D, "_GetDialogItem" },
+ { 0xA98E, "_SetDialogItem" },
+ { 0xA98F, "_SetDialogItemText" },
+ { 0xA990, "_GetDialogItemText" },
+ { 0xA991, "_ModalDialog" },
+ { 0xA992, "_DetachResource" },
+ { 0xA993, "_SetResPurge" },
+ { 0xA994, "_CurResFile" },
+ { 0xA995, "_InitResources" },
+ { 0xA996, "_RsrcZoneInit" },
+ { 0xA997, "_OpenResFile" },
+ { 0xA998, "_UseResFile" },
+ { 0xA999, "_UpdateResFile" },
+ { 0xA99A, "_CloseResFile" },
+ { 0xA99B, "_SetResLoad" },
+ { 0xA99C, "_CountResources" },
+ { 0xA99D, "_GetIndResource" },
+ { 0xA99E, "_CountTypes" },
+ { 0xA99F, "_GetIndType" },
+ { 0xA9A0, "_GetResource" },
+ { 0xA9A1, "_GetNamedResource" },
+ { 0xA9A2, "_LoadResource" },
+ { 0xA9A3, "_ReleaseResource" },
+ { 0xA9A4, "_HomeResFile" },
+ { 0xA9A5, "_SizeRsrc" },
+ { 0xA9A6, "_GetResAttrs" },
+ { 0xA9A7, "_SetResAttrs" },
+ { 0xA9A8, "_GetResInfo" },
+ { 0xA9A9, "_SetResInfo" },
+ { 0xA9AA, "_ChangedResource" },
+ { 0xA9AB, "_AddResource" },
+ { 0xA9AC, "_AddReference" },
+ { 0xA9AD, "_RmveResource" },
+ { 0xA9AE, "_RmveReference" },
+ { 0xA9AF, "_ResError" },
+ { 0xA9B0, "_WriteResource" },
+ { 0xA9B1, "_CreateResFile" },
+ { 0xA9B2, "_SystemEvent" },
+ { 0xA9B3, "_SystemClick" },
+ { 0xA9B4, "_SystemTask" },
+ { 0xA9B5, "_SystemMenu" },
+ { 0xA9B6, "_OpenDeskAcc" },
+ { 0xA9B7, "_CloseDeskAcc" },
+ { 0xA9B8, "_GetPattern" },
+ { 0xA9B9, "_GetCursor" },
+ { 0xA9BA, "_GetString" },
+ { 0xA9BB, "_GetIcon" },
+ { 0xA9BC, "_GetPicture" },
+ { 0xA9BD, "_GetNewWindow" },
+ { 0xA9BE, "_GetNewControl" },
+ { 0xA9BF, "_GetRMenu" },
+ { 0xA9C0, "_GetNewMBar" },
+ { 0xA9C1, "_UniqueID" },
+ { 0xA9C2, "_SysEdit" },
+ { 0xA9C3, "_KeyTranslate" },
+ { 0xA9C4, "_OpenRFPerm" },
+ { 0xA9C5, "_RsrcMapEntry" },
+ { 0xA9C6, "_SecondsToDate" },
+ { 0xA9C7, "_DateToSeconds" },
+ { 0xA9C8, "_SysBeep" },
+ { 0xA9C9, "_SysError" },
+ { 0xA9CA, "_PutIcon" },
+ { 0xA9CB, "_TEGetText" },
+ { 0xA9CC, "_TEInit" },
+ { 0xA9CD, "_TEDispose" },
+ { 0xA9CE, "_TETextBox" },
+ { 0xA9CF, "_TESetText" },
+ { 0xA9D0, "_TECalText" },
+ { 0xA9D1, "_TESetSelect" },
+ { 0xA9D2, "_TENew" },
+ { 0xA9D3, "_TEUpdate" },
+ { 0xA9D4, "_TEClick" },
+ { 0xA9D5, "_TECopy" },
+ { 0xA9D6, "_TECut" },
+ { 0xA9D7, "_TEDelete" },
+ { 0xA9D8, "_TEActivate" },
+ { 0xA9D9, "_TEDeactivate" },
+ { 0xA9DA, "_TEIdle" },
+ { 0xA9DB, "_TEPaste" },
+ { 0xA9DC, "_TEKey" },
+ { 0xA9DD, "_TEScroll" },
+ { 0xA9DE, "_TEInsert" },
+ { 0xA9DF, "_TESetAlignment" },
+ { 0xA9E0, "_Munger" },
+ { 0xA9E1, "_HandToHand" },
+ { 0xA9E2, "_PtrToXHand" },
+ { 0xA9E3, "_PtrToHand" },
+ { 0xA9E4, "_HandAndHand" },
+ { 0xA9E5, "_InitPack" },
+ { 0xA9E6, "_InitAllPacks" },
+ { 0xA9EF, "_PtrAndHand" },
+ { 0xA9F0, "_LoadSeg" },
+ { 0xA9F1, "_UnLoadSeg" },
+ { 0xA9F2, "_Launch" },
+ { 0xA9F3, "_Chain" },
+ { 0xA9F4, "_ExitToShell" },
+ { 0xA9F5, "_GetAppParms" },
+ { 0xA9F6, "_GetResFileAttrs" },
+ { 0xA9F7, "_SetResFileAttrs" },
+ { 0xA9F8, "_MethodDispatch" },
+ { 0xA9F9, "_InfoScrap" },
+ { 0xA9FA, "_UnloadScrap" },
+ { 0xA9FB, "_LoadScrap" },
+ { 0xA9FC, "_ZeroScrap" },
+ { 0xA9FD, "_GetScrap" },
+ { 0xA9FE, "_PutScrap" },
+ { 0xA9FF, "_Debugger" },
+ { 0xAA00, "_OpenCPort" },
+ { 0xAA01, "_InitCPort" },
+ { 0xAA02, "_CloseCPort" },
+ { 0xAA03, "_NewPixMap" },
+ { 0xAA04, "_DisposePixMap" },
+ { 0xAA05, "_CopyPixMap" },
+ { 0xAA06, "_SetPortPix" },
+ { 0xAA07, "_NewPixPat" },
+ { 0xAA08, "_DisposePixPat" },
+ { 0xAA09, "_CopyPixPat" },
+ { 0xAA0A, "_PenPixPat" },
+ { 0xAA0B, "_BackPixPat" },
+ { 0xAA0C, "_GetPixPat" },
+ { 0xAA0D, "_MakeRGBPat" },
+ { 0xAA0E, "_FillCRect" },
+ { 0xAA0F, "_FillCOval" },
+ { 0xAA10, "_FillCRoundRect" },
+ { 0xAA11, "_FillCArc" },
+ { 0xAA12, "_FillCRgn" },
+ { 0xAA13, "_FillCPoly" },
+ { 0xAA14, "_RGBForeColor" },
+ { 0xAA15, "_RGBBackColor" },
+ { 0xAA16, "_SetCPixel" },
+ { 0xAA17, "_GetCPixel" },
+ { 0xAA18, "_GetCTable" },
+ { 0xAA19, "_GetForeColor" },
+ { 0xAA1A, "_GetBackColor" },
+ { 0xAA1B, "_GetCCursor" },
+ { 0xAA1C, "_SetCCursor" },
+ { 0xAA1D, "_AllocCursor" },
+ { 0xAA1E, "_GetCIcon" },
+ { 0xAA1F, "_PlotCIcon" },
+ { 0xAA20, "_OpenCPicture" },
+ { 0xAA21, "_OpColor" },
+ { 0xAA22, "_HiliteColor" },
+ { 0xAA23, "_CharExtra" },
+ { 0xAA24, "_DisposeCTable" },
+ { 0xAA25, "_DisposeCIcon" },
+ { 0xAA26, "_DisposeCCursor" },
+ { 0xAA27, "_GetMaxDevice" },
+ { 0xAA28, "_GetCTSeed" },
+ { 0xAA29, "_GetDeviceList" },
+ { 0xAA2A, "_GetMainDevice" },
+ { 0xAA2B, "_GetNextDevice" },
+ { 0xAA2C, "_TestDeviceAttribute" },
+ { 0xAA2D, "_SetDeviceAttribute" },
+ { 0xAA2E, "_InitGDevice" },
+ { 0xAA2F, "_NewGDevice" },
+ { 0xAA30, "_DisposeGDevice" },
+ { 0xAA31, "_SetGDevice" },
+ { 0xAA32, "_GetGDevice" },
+ { 0xAA35, "_InvertColor" },
+ { 0xAA36, "_RealColor" },
+ { 0xAA37, "_GetSubTable" },
+ { 0xAA38, "_UpdatePixMap" },
+ { 0xAA39, "_MakeITable" },
+ { 0xAA3A, "_AddSearch" },
+ { 0xAA3B, "_AddComp" },
+ { 0xAA3C, "_SetClientID" },
+ { 0xAA3D, "_ProtectEntry" },
+ { 0xAA3E, "_ReserveEntry" },
+ { 0xAA3F, "_SetEntries" },
+ { 0xAA40, "_QDError" },
+ { 0xAA41, "_SetWinColor" },
+ { 0xAA42, "_GetAuxWin" },
+ { 0xAA43, "_SetControlColor" },
+ { 0xAA44, "_GetAuxiliaryControlRecord" },
+ { 0xAA45, "_NewCWindow" },
+ { 0xAA46, "_GetNewCWindow" },
+ { 0xAA47, "_SetDeskCPat" },
+ { 0xAA48, "_GetCWMgrPort" },
+ { 0xAA49, "_SaveEntries" },
+ { 0xAA4A, "_RestoreEntries" },
+ { 0xAA4B, "_NewColorDialog" },
+ { 0xAA4C, "_DelSearch" },
+ { 0xAA4D, "_DelComp" },
+ { 0xAA4E, "_SetStdCProcs" },
+ { 0xAA4F, "_CalcCMask" },
+ { 0xAA50, "_SeedCFill" },
+ { 0xAA51, "_CopyDeepMask" },
+ { 0xAA52, "_HFSPinaforeDispatch" },
+ { 0xAA53, "_DictionaryDispatch" },
+ { 0xAA54, "_TextServicesDispatch" },
+ { 0xAA56, "_SpeechRecognitionDispatch" },
+ { 0xAA57, "_DockingDispatch" },
+ { 0xAA59, "_MixedModeDispatch" },
+ { 0xAA5A, "_CodeFragmentDispatch" },
+ { 0xAA5C, "_OCEUtils" },
+ { 0xAA5D, "_DigitalSignature" },
+ { 0xAA5E, "_TBDispatch" },
+ { 0xAA60, "_DeleteMCEntries" },
+ { 0xAA61, "_GetMCInfo" },
+ { 0xAA62, "_SetMCInfo" },
+ { 0xAA63, "_DisposeMCInfo" },
+ { 0xAA64, "_GetMCEntry" },
+ { 0xAA65, "_SetMCEntries" },
+ { 0xAA66, "_MenuChoice" },
+ { 0xAA67, "_ModalDialogMenuSetup" },
+ { 0xAA68, "_DialogDispatch" },
+ { 0xAA73, "_ControlDispatch" },
+ { 0xAA74, "_AppearanceDispatch" },
+ { 0xAA7E, "_SysDebugDispatch" },
+ { 0xAA80, "_AVLTreeDispatch" },
+ { 0xAA81, "_FileMappingDispatch" },
+ { 0xAA90, "_InitPalettes" },
+ { 0xAA91, "_NewPalette" },
+ { 0xAA92, "_GetNewPalette" },
+ { 0xAA93, "_DisposePalette" },
+ { 0xAA94, "_ActivatePalette" },
+ { 0xAA95, "_NSetPalette" },
+ { 0xAA96, "_GetPalette" },
+ { 0xAA97, "_PmForeColor" },
+ { 0xAA98, "_PmBackColor" },
+ { 0xAA99, "_AnimateEntry" },
+ { 0xAA9A, "_AnimatePalette" },
+ { 0xAA9B, "_GetEntryColor" },
+ { 0xAA9C, "_SetEntryColor" },
+ { 0xAA9D, "_GetEntryUsage" },
+ { 0xAA9E, "_SetEntryUsage" },
+ { 0xAAA1, "_CopyPalette" },
+ { 0xAAA2, "_PaletteDispatch" },
+ { 0xAAA3, "_CodecDispatch" },
+ { 0xAAA4, "_ALMDispatch" },
+ { 0xAADB, "_CursorDeviceDispatch" },
+ { 0xAAF2, "_ControlStripDispatch" },
+ { 0xAAF3, "_ExpansionManager" },
+ { 0xAB1D, "_QDExtensions" },
+ { 0xABC3, "_NQDMisc" },
+ { 0xABC9, "_IconDispatch" },
+ { 0xABCA, "_DeviceLoop" },
+ { 0xABEB, "_DisplayDispatch" },
+ { 0xABED, "_DragDispatch" },
+ { 0xABF1, "_GestaltValueDispatch" },
+ { 0xABF2, "_ThreadDispatch" },
+ { 0xABF6, "_CollectionMgr" },
+ { 0xABF8, "_StdOpcodeProc" },
+ { 0xABFC, "_TranslationDispatch" },
+ { 0xABFF, "_DebugStr" }
+ };
+
+ int i;
+
+ for (i = 0; i < ARRAY_LENGTH(traps); i++)
+ {
+ if (traps[i].trap == opcode)
+ return traps[i].name;
+ }
+ return NULL;
+}
+
+
+
+static offs_t mac_dasm_override(device_t &device, char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, int options)
+{
+ UINT16 opcode;
+ unsigned result = 0;
+ const char *trap;
+
+ opcode = oprom[0]<<8 | oprom[1];
+ if ((opcode & 0xF000) == 0xA000)
+ {
+ trap = lookup_trap(opcode);
+ if (trap)
+ {
+ strcpy(buffer, trap);
+ result = 2;
+ }
+ }
+ return result;
+}
+
+
+
+#ifdef MAC_TRACETRAP
+static void mac_tracetrap(const char *cpu_name_local, int addr, int trap)
+{
+ typedef struct
+ {
+ int csCode;
+ const char *name;
+ } sonycscodeentry;
+
+ static const sonycscodeentry cscodes[] =
+ {
+ { 1, "KillIO" },
+ { 5, "VerifyDisk" },
+ { 6, "FormatDisk" },
+ { 7, "EjectDisk" },
+ { 8, "SetTagBuffer" },
+ { 9, "TrackCacheControl" },
+ { 23, "ReturnDriveInfo" }
+ };
+
+ static const char *const scsisels[] =
+ {
+ "SCSIReset", /* $00 */
+ "SCSIGet", /* $01 */
+ "SCSISelect", /* $02 */
+ "SCSICmd", /* $03 */
+ "SCSIComplete", /* $04 */
+ "SCSIRead", /* $05 */
+ "SCSIWrite", /* $06 */
+ NULL, /* $07 */
+ "SCSIRBlind", /* $08 */
+ "SCSIWBlind", /* $09 */
+ "SCSIStat", /* $0A */
+ "SCSISelAtn", /* $0B */
+ "SCSIMsgIn", /* $0C */
+ "SCSIMsgOut", /* $0D */
+ };
+
+ int i, a0, a7, d0, d1;
+ int csCode, ioVRefNum, ioRefNum, ioCRefNum, ioCompletion, ioBuffer, ioReqCount, ioPosOffset;
+ char *s;
+ unsigned char *mem;
+ char buf[256];
+ const char *trapstr;
+
+ trapstr = lookup_trap(trap);
+ if (trapstr)
+ strcpy(buf, trapstr);
+ else
+ sprintf(buf, "Trap $%04x", trap);
+
+ s = &buf[strlen(buf)];
+ mem = mac_ram_ptr;
+ a0 = cpu_get_reg(M68K_A0);
+ a7 = cpu_get_reg(M68K_A7);
+ d0 = cpu_get_reg(M68K_D0);
+ d1 = cpu_get_reg(M68K_D1);
+
+ switch(trap)
+ {
+ case 0xa004: /* _Control */
+ ioVRefNum = *((INT16*) (mem + a0 + 22));
+ ioCRefNum = *((INT16*) (mem + a0 + 24));
+ csCode = *((UINT16*) (mem + a0 + 26));
+ sprintf(s, " ioVRefNum=%i ioCRefNum=%i csCode=%i", ioVRefNum, ioCRefNum, csCode);
+
+ for (i = 0; i < ARRAY_LENGTH(cscodes); i++)
+ {
+ if (cscodes[i].csCode == csCode)
+ {
+ strcat(s, "=");
+ strcat(s, cscodes[i].name);
+ break;
+ }
+ }
+ break;
+
+ case 0xa002: /* _Read */
+ ioCompletion = (*((INT16*) (mem + a0 + 12)) << 16) + *((INT16*) (mem + a0 + 14));
+ ioVRefNum = *((INT16*) (mem + a0 + 22));
+ ioRefNum = *((INT16*) (mem + a0 + 24));
+ ioBuffer = (*((INT16*) (mem + a0 + 32)) << 16) + *((INT16*) (mem + a0 + 34));
+ ioReqCount = (*((INT16*) (mem + a0 + 36)) << 16) + *((INT16*) (mem + a0 + 38));
+ ioPosOffset = (*((INT16*) (mem + a0 + 46)) << 16) + *((INT16*) (mem + a0 + 48));
+ sprintf(s, " ioCompletion=0x%08x ioVRefNum=%i ioRefNum=%i ioBuffer=0x%08x ioReqCount=%i ioPosOffset=%i",
+ ioCompletion, ioVRefNum, ioRefNum, ioBuffer, ioReqCount, ioPosOffset);
+ break;
+
+ case 0xa04e: /* _AddDrive */
+ sprintf(s, " drvrRefNum=%i drvNum=%i qEl=0x%08x", (int) (INT16) d0, (int) (INT16) d1, a0);
+ break;
+
+ case 0xa9a0: /* _GetResource */
+ /* HACKHACK - the 'type' output assumes that the host is little endian
+ * since this is just trace code it isn't much of an issue
+ */
+ sprintf(s, " type='%c%c%c%c' id=%i", (char) mem[a7+3], (char) mem[a7+2],
+ (char) mem[a7+5], (char) mem[a7+4], *((INT16*) (mem + a7)));
+ break;
+
+ case 0xa815: /* _SCSIDispatch */
+ i = *((UINT16*) (mem + a7));
+ if (i < ARRAY_LENGTH(scsisels))
+ if (scsisels[i])
+ sprintf(s, " (%s)", scsisels[i]);
+ break;
+ }
+
+ logerror("mac_trace_trap: %s at 0x%08x: %s\n",cpu_name_local, addr, buf);
+}
+#endif
diff --git a/src/mess/machine/macadb.c b/src/mess/machine/macadb.c
new file mode 100644
index 00000000000..fc29b71384e
--- /dev/null
+++ b/src/mess/machine/macadb.c
@@ -0,0 +1,987 @@
+/***************************************************************************
+
+ macadb.c - handles various aspects of ADB on the Mac.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/mac.h"
+
+#define LOG_ADB 0
+#define LOG_ADB_MCU_CMD 0
+#define LOG_ADB_TALK_LISTEN 0
+
+// ADB states
+#define ADB_STATE_NEW_COMMAND (0)
+#define ADB_STATE_XFER_EVEN (1)
+#define ADB_STATE_XFER_ODD (2)
+#define ADB_STATE_IDLE (3)
+#define ADB_STATE_NOTINIT (4)
+
+// ADB commands
+#define ADB_CMD_RESET (0)
+#define ADB_CMD_FLUSH (1)
+
+/* *************************************************************************
+ * ADB (Mac II-style)
+ * *************************************************************************/
+
+#if LOG_ADB
+static const char *const adb_statenames[4] = { "NEW", "EVEN", "ODD", "IDLE" };
+#endif
+
+int mac_state::adb_pollkbd(int update)
+{
+ int i, j, keybuf, report, codes[2], result;
+ static const char *const keynames[] = { "KEY0", "KEY1", "KEY2", "KEY3", "KEY4", "KEY5" };
+
+ codes[0] = codes[1] = 0xff; // key up
+ report = result = 0;
+
+ for (i = 0; i < 6; i++)
+ {
+ keybuf = ioport(keynames[i])->read();
+
+ // any changes in this row?
+ if ((keybuf != m_key_matrix[i]) && (report < 2))
+ {
+ // check each column bit
+ for (j=0; j<16; j++)
+ {
+ if (((keybuf ^ m_key_matrix[i]) >> j) & 1)
+ {
+ // update m_key_matrix
+ if (update)
+ {
+ m_key_matrix[i] = (m_key_matrix[i] & ~ (1 << j)) | (keybuf & (1 << j));
+ }
+
+ codes[report] = (i<<4)|j;
+
+ // key up?
+ if (!(keybuf & (1 << j)))
+ {
+ codes[report] |= 0x80;
+ }
+
+ // update modifier state
+ if (update)
+ {
+ if (((i<<4)|j) == 0x39)
+ {
+ if (codes[report] & 0x80)
+ {
+ m_adb_modifiers &= ~0x20;
+ }
+ else
+ {
+ m_adb_modifiers |= 0x20;
+ }
+ }
+ if (((i<<4)|j) == 0x36)
+ {
+ if (codes[report] & 0x80)
+ {
+ m_adb_modifiers &= ~0x8;
+ }
+ else
+ {
+ m_adb_modifiers |= 0x08;
+ }
+ }
+ if (((i<<4)|j) == 0x38)
+ {
+ if (codes[report] & 0x80)
+ {
+ m_adb_modifiers &= ~0x4;
+ }
+ else
+ {
+ m_adb_modifiers |= 0x04;
+ }
+ }
+ if (((i<<4)|j) == 0x3a)
+ {
+ if (codes[report] & 0x80)
+ {
+ m_adb_modifiers &= ~0x2;
+ }
+ else
+ {
+ m_adb_modifiers |= 0x02;
+ }
+ }
+ if (((i<<4)|j) == 0x37)
+ {
+ if (codes[report] & 0x80)
+ {
+ m_adb_modifiers &= ~0x1;
+ }
+ else
+ {
+ m_adb_modifiers |= 0x01;
+ }
+ }
+ }
+
+ // we run out of keys we can track?
+ report++;
+ if (report == 2)
+ {
+ break;
+ }
+ }
+ }
+
+ // we run out of keys we can track?
+ if (report == 2)
+ {
+ break;
+ }
+ }
+ }
+
+// printf("ADB keyboard: update %d keys %02x %02x\n", update, codes[0], codes[1]);
+
+ // figure out if there was a change
+ if ((m_adb_currentkeys[0] != codes[0]) || (m_adb_currentkeys[1] != codes[1]))
+ {
+ result = 1;
+
+ // if we want to update the current read, do so
+ if (update)
+ {
+ m_adb_currentkeys[0] = codes[0];
+ m_adb_currentkeys[1] = codes[1];
+ }
+ }
+
+ return result;
+}
+
+int mac_state::adb_pollmouse()
+{
+ int NewX, NewY, NewButton;
+
+ if (!m_adb_mouse_initialized)
+ {
+ return 0;
+ }
+
+ NewButton = ioport("MOUSE0")->read() & 0x01;
+ NewX = ioport("MOUSE2")->read();
+ NewY = ioport("MOUSE1")->read();
+
+ if ((NewX != m_adb_lastmousex) || (NewY != m_adb_lastmousey) || (NewButton != m_adb_lastbutton))
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+void mac_state::adb_accummouse( UINT8 *MouseX, UINT8 *MouseY )
+{
+ int MouseCountX = 0, MouseCountY = 0;
+ int NewX, NewY;
+
+ NewX = ioport("MOUSE2")->read();
+ NewY = ioport("MOUSE1")->read();
+
+ /* see if it moved in the x coord */
+ if (NewX != m_adb_lastmousex)
+ {
+ int diff = NewX - m_adb_lastmousex;
+
+ /* check for wrap */
+ if (diff > 0x80)
+ diff = 0x100-diff;
+ if (diff < -0x80)
+ diff = -0x100-diff;
+
+ MouseCountX += diff;
+ m_adb_lastmousex = NewX;
+ }
+
+ /* see if it moved in the y coord */
+ if (NewY != m_adb_lastmousey)
+ {
+ int diff = NewY - m_adb_lastmousey;
+
+ /* check for wrap */
+ if (diff > 0x80)
+ diff = 0x100-diff;
+ if (diff < -0x80)
+ diff = -0x100-diff;
+
+ MouseCountY += diff;
+ m_adb_lastmousey = NewY;
+ }
+
+ m_adb_lastbutton = ioport("MOUSE0")->read() & 0x01;
+
+ *MouseX = (UINT8)MouseCountX;
+ *MouseY = (UINT8)MouseCountY;
+}
+
+void mac_state::adb_talk()
+{
+ int addr, reg;
+
+ addr = (m_adb_command>>4);
+ reg = (m_adb_command & 3);
+
+// printf("Mac sent %x (cmd %d addr %d reg %d mr %d kr %d)\n", mac->m_adb_command, (mac->m_adb_command>>2)&3, addr, reg, m_adb_mouseaddr, m_adb_keybaddr);
+
+ if (m_adb_waiting_cmd)
+ {
+ switch ((m_adb_command>>2)&3)
+ {
+ case 0:
+ case 1:
+ switch (reg)
+ {
+ case ADB_CMD_RESET:
+ #if LOG_ADB || LOG_ADB_TALK_LISTEN
+ printf("ADB RESET: reg %x address %x\n", reg, addr);
+ #endif
+ m_adb_direction = 0;
+ m_adb_send = 0;
+ break;
+
+ case ADB_CMD_FLUSH:
+ #if LOG_ADB || LOG_ADB_TALK_LISTEN
+ printf("ADB FLUSH: reg %x address %x\n", reg, addr);
+ #endif
+
+ m_adb_direction = 0;
+ m_adb_send = 0;
+ break;
+
+ default: // reserved/unused
+ break;
+ }
+ break;
+
+ case 2: // listen
+ #if LOG_ADB || LOG_ADB_TALK_LISTEN
+ printf("ADB LISTEN: reg %x address %x\n", reg, addr);
+ #endif
+
+ m_adb_direction = 1; // input from Mac
+ m_adb_listenreg = reg;
+ m_adb_listenaddr = addr;
+ m_adb_command = 0;
+ break;
+
+ case 3: // talk
+ #if LOG_ADB || LOG_ADB_TALK_LISTEN
+ printf("ADB TALK: reg %x address %x\n", reg, addr);
+ #endif
+
+ // keep track of what device the Mac last TALKed to
+ m_adb_last_talk = addr;
+
+ m_adb_direction = 0; // output to Mac
+ if (addr == m_adb_mouseaddr)
+ {
+ UINT8 mouseX, mouseY;
+
+ #if LOG_ADB || LOG_ADB_TALK_LISTEN
+ printf("Talking to mouse, register %x\n", reg);
+ #endif
+
+ switch (reg)
+ {
+ // read mouse
+ case 0:
+ if (m_adb_srq_switch)
+ {
+ m_adb_srq_switch = 0;
+ mouseX = mouseY = 0;
+ }
+ else
+ {
+ this->adb_accummouse(&mouseX, &mouseY);
+ }
+ m_adb_buffer[0] = (m_adb_lastbutton & 0x01) ? 0x00 : 0x80;
+ m_adb_buffer[0] |= mouseX & 0x7f;
+ m_adb_buffer[1] = mouseY & 0x7f;
+ m_adb_datasize = 2;
+ break;
+
+ // get ID/handler
+ case 3:
+ m_adb_buffer[0] = 0x60 | ((m_adb_mouseaddr<<8)&0xf); // SRQ enable, no exceptional event
+ m_adb_buffer[1] = 0x01; // handler 1
+ m_adb_datasize = 2;
+
+ m_adb_mouse_initialized = 1;
+ break;
+
+ default:
+ break;
+ }
+ }
+ else if (addr == m_adb_keybaddr)
+ {
+ #if LOG_ADB || LOG_ADB_TALK_LISTEN
+ printf("Talking to keyboard, register %x\n", reg);
+ #endif
+
+ switch (reg)
+ {
+ // read keyboard
+ case 0:
+ if (m_adb_srq_switch)
+ {
+ m_adb_srq_switch = 0;
+ }
+ else
+ {
+ this->adb_pollkbd(1);
+ }
+// printf("keyboard = %02x %02x\n", m_adb_currentkeys[0], m_adb_currentkeys[1]);
+ m_adb_buffer[0] = m_adb_currentkeys[1];
+ m_adb_buffer[1] = m_adb_currentkeys[0];
+ m_adb_datasize = 2;
+ break;
+
+ // read modifier keys
+ case 2:
+ this->adb_pollkbd(1);
+ m_adb_buffer[0] = m_adb_modifiers; // nothing pressed
+ m_adb_buffer[1] = 0;
+ m_adb_datasize = 2;
+ break;
+
+ // get ID/handler
+ case 3:
+ m_adb_buffer[0] = 0x60 | ((m_adb_keybaddr<<8)&0xf); // SRQ enable, no exceptional event
+ m_adb_buffer[1] = 0x01; // handler 1
+ m_adb_datasize = 2;
+
+ m_adb_keybinitialized = 1;
+ break;
+
+ default:
+ break;
+ }
+ }
+ else
+ {
+ #if LOG_ADB || LOG_ADB_TALK_LISTEN
+ printf("ADB: talking to unconnected device %d (K %d M %d)\n", addr, m_adb_keybaddr, m_adb_mouseaddr);
+ #endif
+ m_adb_buffer[0] = m_adb_buffer[1] = 0;
+ m_adb_datasize = 0;
+ }
+ break;
+ }
+
+ m_adb_waiting_cmd = 0;
+ }
+ else
+ {
+ #if LOG_ADB || LOG_ADB_TALK_LISTEN
+ printf("Got LISTEN data %x for device %x reg %x\n", m_adb_command, m_adb_listenaddr, m_adb_listenreg);
+ #endif
+
+ if (m_adb_listenaddr == m_adb_mouseaddr)
+ {
+ if ((m_adb_listenreg == 3) && (m_adb_command > 0) && (m_adb_command < 16))
+ {
+ #if LOG_ADB || LOG_ADB_TALK_LISTEN
+ printf("MOUSE: moving to address %x\n", m_adb_command);
+ #endif
+ m_adb_mouseaddr = m_adb_command&0x0f;
+ }
+ }
+ else if (m_adb_listenaddr == m_adb_keybaddr)
+ {
+ if ((m_adb_listenreg == 3) && (m_adb_command > 0) && (m_adb_command < 16))
+ {
+ #if LOG_ADB || LOG_ADB_TALK_LISTEN
+ printf("KEYBOARD: moving to address %x\n", m_adb_command);
+ #endif
+ m_adb_keybaddr = m_adb_command&0x0f;
+ }
+ }
+ }
+}
+
+TIMER_CALLBACK(mac_adb_tick)
+{
+ mac_state *mac = machine.driver_data<mac_state>();
+
+ // do one clock transition on CB1 to advance the VIA shifter
+ mac->m_adb_extclock ^= 1;
+ mac->m_via1->write_cb1(mac->m_adb_extclock);
+ mac->m_adb_extclock ^= 1;
+ mac->m_via1->write_cb1(mac->m_adb_extclock);
+
+ mac->m_adb_timer_ticks--;
+ if (!mac->m_adb_timer_ticks)
+ {
+ mac->m_adb_timer->adjust(attotime::never);
+
+ if ((mac->m_adb_direction) && (ADB_IS_BITBANG))
+ {
+ mac->adb_talk();
+ }
+ }
+ else
+ {
+ mac->m_adb_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(200)));
+ }
+}
+
+void mac_state::mac_adb_newaction(int state)
+{
+ if (state != m_adb_state)
+ {
+ #if LOG_ADB
+ printf("New ADB state: %s\n", adb_statenames[state]);
+ #endif
+
+ m_adb_state = state;
+ m_adb_timer_ticks = 8;
+
+ switch (state)
+ {
+ case ADB_STATE_NEW_COMMAND:
+ m_adb_command = m_adb_send = 0;
+ m_adb_direction = 1; // Mac is shifting us a command
+ m_adb_waiting_cmd = 1; // we're going to get a command
+ m_adb_irq_pending = 0;
+ m_adb_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(100)));
+ break;
+
+ case ADB_STATE_XFER_EVEN:
+ case ADB_STATE_XFER_ODD:
+ if (m_adb_datasize > 0)
+ {
+ int i;
+
+ // is something trying to send to the Mac?
+ if (m_adb_direction == 0)
+ {
+ // set up the byte
+ m_adb_send = m_adb_buffer[0];
+ m_adb_datasize--;
+
+ // move down the rest of the buffer, if any
+ for (i = 0; i < m_adb_datasize; i++)
+ {
+ m_adb_buffer[i] = m_adb_buffer[i+1];
+ }
+ }
+
+ }
+ else
+ {
+ m_adb_send = 0;
+ m_adb_irq_pending = 1;
+ }
+
+ m_adb_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(100)));
+ break;
+
+ case ADB_STATE_IDLE:
+ m_adb_irq_pending = 0;
+ break;
+ }
+ }
+}
+
+TIMER_CALLBACK(mac_pmu_tick)
+{
+ mac_state *mac = machine.driver_data<mac_state>();
+
+ // state 10 means this is in response to an ADB command
+ if (mac->m_pm_state == 10)
+ {
+ #if LOG_ADB
+ printf("PM: was state 10, chunk-chunking CB1\n");
+ #endif
+ mac->m_pm_state = 0;
+
+ // tick CB1, which should cause a PMU interrupt on PMU machines
+ mac->m_adb_extclock ^= 1;
+ mac->m_via1->write_cb1(mac->m_adb_extclock);
+ mac->m_adb_extclock ^= 1;
+ mac->m_via1->write_cb1(mac->m_adb_extclock);
+ }
+ else
+ {
+ #if LOG_ADB
+ printf("PM: timer tick, lowering ACK\n");
+ #endif
+ mac->m_pm_ack &= ~2; // lower ACK to handshake next step
+ }
+}
+
+void mac_state::pmu_one_byte_reply(UINT8 result)
+{
+ m_pm_out[0] = m_pm_out[1] = 1; // length
+ m_pm_out[2] = result;
+ m_pm_slen = 3;
+ m_pmu_send_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(200)));
+}
+
+void mac_state::pmu_three_byte_reply(UINT8 result1, UINT8 result2, UINT8 result3)
+{
+ m_pm_out[0] = m_pm_out[1] = 3; // length
+ m_pm_out[2] = result1;
+ m_pm_out[3] = result2;
+ m_pm_out[4] = result3;
+ m_pm_slen = 5;
+ m_pmu_send_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(200)));
+}
+
+void mac_state::pmu_exec()
+{
+ m_pm_sptr = 0; // clear send pointer
+ m_pm_slen = 0; // and send length
+ m_pm_dptr = 0; // and receive pointer
+
+// printf("PMU: Command %02x\n", mac->m_pm_cmd[0]);
+ switch (m_pm_cmd[0])
+ {
+ case 0x10: // subsystem power and clock ctrl
+ break;
+
+ case 0x20: // send ADB command (PMU must issue an IRQ on completion)
+ #if 0
+ printf("PMU: Send ADB %02x %02x cmd %02x flag %02x data %02x %02x\n",
+ m_pm_cmd[0], // 0x20
+ m_pm_cmd[1], // ???
+ m_pm_cmd[2], // adb flags (2 for autopoll active, 3 to reset bus?)
+ m_pm_cmd[3], // length of ADB data
+ m_pm_cmd[4], // adb data
+ m_pm_cmd[5]);
+ #endif
+
+ #if 0
+ m_pm_state = 10;
+ m_pmu_send_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(200)));
+ if (ADB_IS_PM_VIA1_CLASS)
+ {
+ m_pmu_int_status = 0x1;
+ }
+ else if (ADB_IS_PM_VIA2_CLASS)
+ {
+ m_pmu_int_status = 0x10;
+ }
+ else
+ {
+ fatalerror("mac: unknown ADB PMU type\n");
+ }
+ m_pmu_last_adb_command = m_pm_cmd[2];
+ m_adb_command = m_pm_cmd[2];
+ m_adb_waiting_cmd = 1;
+ adb_talk();
+
+ if ((m_pm_cmd[2] & 0xf) == 0xb) // LISTEN register 3 (remap)
+ {
+ m_adb_waiting_cmd = 0;
+ m_adb_command = mac->m_pm_cmd[5];
+ adb_talk();
+ }
+ #else
+ if (((m_pm_cmd[2] == 0xfc) || (m_pm_cmd[2] == 0x2c)) && (m_pm_cmd[3] == 4))
+ {
+// printf("PMU: request to poll ADB, returning nothing\n");
+ m_pm_slen = 0;
+ m_pmu_int_status = 0;
+ }
+ else
+ {
+ m_pm_state = 10;
+ m_pmu_send_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(200)));
+ if (ADB_IS_PM_VIA1_CLASS)
+ {
+ m_pmu_int_status = 0x1;
+ }
+ else if (ADB_IS_PM_VIA2_CLASS)
+ {
+ m_pmu_int_status = 0x10;
+ }
+ else
+ {
+ fatalerror("mac: unknown ADB PMU type\n");
+ }
+ m_pmu_last_adb_command = m_pm_cmd[2];
+ }
+
+ m_adb_command = m_pm_cmd[2];
+ m_adb_waiting_cmd = 1;
+ adb_talk();
+ #endif
+ break;
+
+ case 0x21: // turn ADB auto-poll off (does this need a reply?)
+ break;
+
+ case 0x28: // read ADB
+ if (m_adb_datasize > 0)
+ {
+ m_adb_datasize = 1; // hack
+
+ m_pm_out[0] = m_pm_out[1] = 3 + m_adb_datasize;
+ m_pm_out[2] = 0;
+// m_pm_out[3] = m_pmu_last_adb_command;
+ m_pm_out[3] = 0;
+ m_pm_out[4] = m_adb_datasize;
+ for (int i = 0; i < m_adb_datasize; i++)
+ {
+ m_pm_out[5+i] = 0; //mac->m_adb_buffer[i];
+ }
+ m_pm_slen = 5 + m_adb_datasize;
+ }
+ else
+ {
+ m_pm_out[0] = m_pm_out[1] = 4;
+ m_pm_out[2] = 0;
+ m_pm_out[3] = 0;
+// m_pm_out[3] = m_pmu_last_adb_command;
+ m_pm_out[4] = 1; // length of following data
+ m_pm_out[5] = 0;
+ m_pm_slen = 6;
+ }
+/* printf("ADB packet: ");
+ for (int i = 0; i < m_pm_slen; i++)
+ {
+ printf("%02x ", m_pm_out[i]);
+ }
+ printf("\n");*/
+ m_pmu_send_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(1000)));
+ break;
+
+ case 0x31: // write first 20 bytes of PRAM
+ {
+ for (int i = 0; i < 20; i++)
+ {
+ m_rtc_ram[i] = m_pm_cmd[1+i];
+ }
+ }
+ break;
+
+ case 0x32: // write extended PRAM byte(s). cmd[2] = address, cmd[3] = length, cmd[4...] = data
+ if ((m_pm_cmd[2] + m_pm_cmd[3]) < 0x100)
+ {
+ int i;
+
+ for (i = 0; i < m_pm_cmd[3]; i++)
+ {
+ m_rtc_ram[m_pm_cmd[2] + i] = m_pm_cmd[4+i];
+ }
+ }
+ break;
+
+ case 0x38: // read time
+ {
+ m_pm_out[0] = m_pm_out[1] = 4;
+ m_pm_out[2] = m_rtc_seconds[0];
+ m_pm_out[3] = m_rtc_seconds[1];
+ m_pm_out[4] = m_rtc_seconds[2];
+ m_pm_out[5] = m_rtc_seconds[3];
+ m_pm_slen = 6;
+ m_pmu_send_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(200)));
+ }
+ break;
+
+ case 0x39: // read first 20 bytes of PRAM
+ {
+ int i;
+
+ m_pm_out[0] = m_pm_out[1] = 20;
+ for (i = 0; i < 20; i++)
+ {
+ m_pm_out[2 + i] = m_rtc_ram[i];
+ }
+ m_pm_slen = 22;
+ m_pmu_send_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(200)));
+ }
+ break;
+
+ case 0x3a: // read extended PRAM byte(s). cmd[2] = address, cmd[3] = length
+ if ((m_pm_cmd[2] + m_pm_cmd[3]) < 0x100)
+ {
+ int i;
+
+ m_pm_out[0] = m_pm_out[1] = m_pm_cmd[3];
+ for (i = 0; i < m_pm_cmd[3]; i++)
+ {
+ m_pm_out[2 + i] = m_rtc_ram[m_pm_cmd[2] + i];
+ }
+ m_pm_slen = m_pm_out[0] + 2;
+ m_pmu_send_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(200)));
+ }
+ break;
+
+ case 0x40: // set screen contrast
+ break;
+
+ case 0x41:
+ break;
+
+ case 0x58: // read internal modem status
+ pmu_one_byte_reply(0);
+ break;
+
+ case 0x60: // set low power warning and cutoff battery levels
+ break;
+
+ case 0x68: // read battery/charger level
+ pmu_three_byte_reply(255, 255, 255);
+ break;
+
+ case 0x69: // read battery/charger instantaneous level and status
+ pmu_three_byte_reply(255, 255, 255);
+ break;
+
+ case 0x6b: // read extended battery/charger level and status (wants an 8 byte reply)
+ m_pm_out[0] = m_pm_out[1] = 8; // length
+ m_pm_out[2] = 255;
+ m_pm_out[3] = 255;
+ m_pm_out[4] = 255;
+ m_pm_out[5] = 255;
+ m_pm_out[6] = 255;
+ m_pm_out[7] = 255;
+ m_pm_out[8] = 255;
+ m_pm_out[9] = 255;
+ m_pm_slen = 10;
+ m_pmu_send_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(200)));
+ break;
+
+ case 0x6c: // read battery ID
+ pmu_one_byte_reply(1);
+ break;
+
+ case 0x78: // read interrupt flag
+ if (ADB_IS_PM_VIA2_CLASS) // PB 140/170 use a "leaner" PMU protocol where you get the data for a PMU interrupt here
+ {
+ #if 0
+ if ((m_pmu_int_status&0xf0) == 0x10)
+ {
+ if (m_adb_datasize > 0)
+ {
+ m_adb_datasize = 1; // hack
+ m_pm_out[0] = m_pm_out[1] = 2 + m_adb_datasize;
+ m_pm_out[2] = m_pmu_int_status; // ADB status in low nibble
+ m_pm_out[3] = m_pmu_last_adb_command; // ADB command that was sent
+ for (int i = 0; i < m_adb_datasize; i++)
+ {
+ m_pm_out[4+i] = 0; //m_adb_buffer[i];
+ }
+ m_pm_slen = 4 + m_adb_datasize;
+ m_pmu_send_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(1500)));
+
+/* printf("ADB packet: ");
+ for (int i = 0; i < m_pm_slen; i++)
+ {
+ printf("%02x ", m_pm_out[i]);
+ }
+ printf("\n");*/
+ }
+ else
+ {
+ m_pm_out[0] = m_pm_out[1] = 2;
+ m_pm_out[2] = m_pmu_int_status; // ADB status in low nibble
+ m_pm_out[3] = m_pmu_last_adb_command; // ADB command that was sent OR 0x80 for extra error-ness
+ m_pm_out[4] = 0; // return data
+ m_pm_slen = 4;
+ m_pmu_send_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(1500)));
+ }
+ }
+ else
+ {
+ pmu_one_byte_reply(mac, m_pmu_int_status);
+ }
+ #else
+ if ((m_pmu_int_status&0xf0) == 0x10)
+ {
+ m_pm_out[0] = m_pm_out[1] = 2;
+ m_pm_out[2] = m_pmu_int_status; // ADB status in low nibble
+ m_pm_out[3] = m_pmu_last_adb_command; // ADB command that was sent OR 0x80 for extra error-ness
+ m_pm_out[4] = 0; // return data
+ m_pm_slen = 4;
+ m_pmu_send_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(1500)));
+ }
+ else
+ {
+ pmu_one_byte_reply(m_pmu_int_status);
+ }
+ #endif
+ }
+ else
+ {
+ pmu_one_byte_reply(m_pmu_int_status);
+ }
+
+ m_pmu_int_status = 0;
+ break;
+
+ case 0x90: // sound power control
+ break;
+
+ case 0x98: // read sound power state
+ pmu_one_byte_reply(1);
+ break;
+
+ case 0xd8: // read A/D converter (not sure what this does)
+ pmu_one_byte_reply(0);
+ break;
+
+ case 0xe0: // write PMU internal RAM
+ break;
+
+ case 0xe8: // read PMU internal RAM (just return zeroes)
+ {
+ int i;
+
+ m_pm_out[0] = m_pm_out[1] = m_pm_cmd[4];
+// printf("PMU read at %x\n", m_pm_cmd[2] | (m_pm_cmd[3]<<8));
+
+ // note: read at 0xEE00 0 = target disk mode, 0xff = normal bootup
+ // (actually 0x00EE, the 50753 port 6)
+
+ for (i = 0; i < m_pm_cmd[4]; i++)
+ {
+ m_pm_out[2 + i] = 0xff;
+ }
+ m_pm_slen = m_pm_out[0] + 2;
+ m_pmu_send_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(200)));
+ }
+ break;
+
+ case 0xec: // PMU self-test (send 1 count byte + reply)
+ pmu_one_byte_reply(0);
+ break;
+
+ default:
+ fatalerror("PMU: Unhandled command %02x\n", m_pm_cmd[0]);
+ break;
+ }
+
+ if (m_pm_slen > 0)
+ {
+ m_pm_state = 1;
+ }
+}
+
+void mac_state::adb_vblank()
+{
+ if ((m_adb_state == ADB_STATE_IDLE) || ((ADB_IS_PM_CLASS) && (m_pmu_poll)))
+ {
+ if (this->adb_pollmouse())
+ {
+ // if the mouse was the last TALK, we can just send the new data
+ // otherwise we need to pull SRQ
+ if ((m_adb_last_talk == m_adb_mouseaddr) && !(ADB_IS_PM_CLASS))
+ {
+ // repeat last TALK to get updated data
+ m_adb_waiting_cmd = 1;
+ this->adb_talk();
+
+ m_adb_timer_ticks = 8;
+ this->m_adb_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(100)));
+ }
+ #if 0
+ else if (ADB_IS_PM_CLASS)
+ {
+ m_adb_waiting_cmd = 1;
+ this->adb_talk();
+ m_pm_state = 10;
+ m_pmu_send_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(200)));
+ if (ADB_IS_PM_VIA1_CLASS)
+ {
+ m_pmu_int_status = 0x1;
+ }
+ else if (ADB_IS_PM_VIA2_CLASS)
+ {
+ m_pmu_int_status = 0x10;
+ }
+ }
+ #endif
+ else
+ {
+ m_adb_irq_pending = 1;
+ m_adb_command = m_adb_send = 0;
+ m_adb_timer_ticks = 1; // one tick should be sufficient to make it see the IRQ
+ this->m_adb_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(100)));
+ m_adb_srq_switch = 1;
+ }
+ }
+ else if (this->adb_pollkbd(0))
+ {
+ if ((m_adb_last_talk == m_adb_keybaddr) && !(ADB_IS_PM_CLASS))
+ {
+ // repeat last TALK to get updated data
+ m_adb_waiting_cmd = 1;
+ this->adb_talk();
+
+ m_adb_timer_ticks = 8;
+ this->m_adb_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(100)));
+ }
+ #if 0
+ else if (ADB_IS_PM_CLASS)
+ {
+ m_adb_waiting_cmd = 1;
+ this->adb_talk();
+ m_pm_state = 10;
+ m_pmu_send_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(200)));
+ m_pmu_int_status = 0x1;
+ }
+ #endif
+ else
+ {
+ m_adb_irq_pending = 1;
+ m_adb_command = m_adb_send = 0;
+ m_adb_timer_ticks = 1; // one tick should be sufficient to make it see the IRQ
+ this->m_adb_timer->adjust(attotime(0, ATTOSECONDS_IN_USEC(100)));
+ m_adb_srq_switch = 1;
+ }
+ }
+ }
+}
+
+void mac_state::adb_reset()
+{
+ int i;
+
+ m_adb_srq_switch = 0;
+ m_adb_irq_pending = 0; // no interrupt
+ m_adb_timer_ticks = 0;
+ m_adb_command = 0;
+ m_adb_extclock = 0;
+ m_adb_send = 0;
+ m_adb_waiting_cmd = 0;
+ m_adb_streaming = MCU_STREAMING_NONE;
+ m_adb_state = 0;
+ m_pmu_poll = 0;
+ if (ADB_IS_BITBANG_CLASS)
+ {
+ m_adb_state = ADB_STATE_NOTINIT;
+ }
+ m_adb_direction = 0;
+ m_adb_datasize = 0;
+ m_adb_last_talk = -1;
+
+ // mouse
+ m_adb_mouseaddr = 3;
+ m_adb_lastmousex = m_adb_lastmousey = m_adb_lastbutton = 0;
+ m_adb_mouse_initialized = 0;
+
+ // keyboard
+ m_adb_keybaddr = 2;
+ m_adb_keybinitialized = 0;
+ m_adb_currentkeys[0] = m_adb_currentkeys[1] = 0xff;
+ m_adb_modifiers = 0;
+ for (i=0; i<7; i++)
+ {
+ m_key_matrix[i] = 0;
+ }
+}
+
diff --git a/src/mess/machine/mackbd.c b/src/mess/machine/mackbd.c
new file mode 100644
index 00000000000..95093cee754
--- /dev/null
+++ b/src/mess/machine/mackbd.c
@@ -0,0 +1,142 @@
+/*
+ Apple Macintosh original/512/Plus keyboard
+ Emulation by R. Belmont
+
+ Port definitions from "IM Underground Volume 1"
+ http://bitsavers.org/pdf/apple/mac/IM_Underground_Vol_1_1985.pdf
+
+ Key matrix for keyboard:
+
+ Cols 0 1 2 3 4 5 6 7 8 Rows
+ G B T 5 0 P ; . n/a 0
+ H n/a Y 6 8 I K M Enter 1
+ F V R 4 - [ ' N Backsp 2
+ D C E 3 7 U J / ` 3
+ S X W 2 9 O L , Space 4
+ A Z Q 1 = ] Ret \ Tab 5
+
+ Port 0:
+
+ x------- Clock to Mac
+ -x------ Caps Lock
+ --x----- Row 5 (tied to Vcc for keypad)
+ ---x---- Row 4
+ ----x--- Row 3
+ -----x-- Row 2
+ ------x- Row 1
+ -------x Row 0
+
+ Port 1:
+
+ x------- Column 8
+ -x------ Column 7
+ --x----- Column 6
+ ---x---- Column 5
+ ----x--- Column 4
+ -----x-- Column 3
+ ------x- Column 2
+ -------x Column 1
+
+ Port 2:
+ x--- Command/Apple
+ -x-- Shift
+ --x- Column 0
+ ---x Data to Mac
+
+ The T1 line is "Option".
+*/
+
+
+#include "emu.h"
+#include "mackbd.h"
+#include "cpu/mcs48/mcs48.h"
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define MACKBD_CPU_TAG "mackbd"
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type MACKBD = &device_creator<mackbd_device>;
+
+// typed in from the listing in the above-cited "IM Underground", but the PDF on Bitsavers is missing a page :(
+ROM_START( mackbd )
+ ROM_REGION(0x400, MACKBD_CPU_TAG, 0)
+ ROM_LOAD( "mackbd.bin", 0x0000, 0x0400, BAD_DUMP CRC(c9af25a5) SHA1(4a6f81da036b071d2ea090cbde78e11c43a3b3b3) )
+ROM_END
+
+//-------------------------------------------------
+// ADDRESS_MAP
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( mackbd_map, AS_PROGRAM, 8, mackbd_device )
+// AM_RANGE(0x0000, 0x03ff) AM_ROM AM_REGION(MACKBD_CPU_TAG, 0)
+ADDRESS_MAP_END
+
+//-------------------------------------------------
+// MACHINE_CONFIG
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( mackbd )
+ MCFG_CPU_ADD(MACKBD_CPU_TAG, I8021, 100000) // "100,000 operations per second"?
+ MCFG_CPU_PROGRAM_MAP(mackbd_map)
+ MCFG_DEVICE_DISABLE()
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor mackbd_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( mackbd );
+}
+
+const rom_entry *mackbd_device::device_rom_region() const
+{
+ return ROM_NAME( mackbd );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// mackbd_device - constructor
+//-------------------------------------------------
+
+mackbd_device::mackbd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MACKBD, "Macintosh keyboard", tag, owner, clock),
+ m_maincpu(*this, MACKBD_CPU_TAG)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void mackbd_device::device_start()
+{
+// m_out_reset_func.resolve(m_out_reset_cb, *this);
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void mackbd_device::device_reset()
+{
+}
+
+void mackbd_device::device_config_complete()
+{
+ m_shortname = "mackbd";
+}
+
diff --git a/src/mess/machine/mackbd.h b/src/mess/machine/mackbd.h
new file mode 100644
index 00000000000..1e7ef3300c9
--- /dev/null
+++ b/src/mess/machine/mackbd.h
@@ -0,0 +1,59 @@
+#pragma once
+
+#ifndef __MACKBD_H__
+#define __MACKBD_H__
+
+#include "emu.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define MACKBD_TAG "mackbd"
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_MACKBD_ADD() \
+ MCFG_DEVICE_ADD(MACKBD_TAG, MACKBD, 0)
+
+#define MCFG_MACKBD_REPLACE() \
+ MCFG_DEVICE_REPLACE(MACKBD_TAG, MACKBD, 0)
+
+#define MCFG_MACKBD_REMOVE() \
+ MCFG_DEVICE_REMOVE(MACKBD_TAG)
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> mackbd_device
+
+class mackbd_device : public device_t
+{
+public:
+ // construction/destruction
+ mackbd_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_config_complete();
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+
+ required_device<cpu_device> m_maincpu;
+
+private:
+
+// devcb_resolved_write_line m_out_reset_func;
+};
+
+// device type definition
+extern const device_type MACKBD;
+
+#endif
diff --git a/src/mess/machine/macpci.c b/src/mess/machine/macpci.c
new file mode 100644
index 00000000000..0ee51aa6328
--- /dev/null
+++ b/src/mess/machine/macpci.c
@@ -0,0 +1,256 @@
+/****************************************************************************
+
+ machine/pcimac.c
+
+ PCI-based Power Macintosh hardware
+
+ R. Belmont
+
+****************************************************************************/
+
+#include "emu.h"
+#include "machine/6522via.h"
+#include "machine/8530scc.h"
+#include "cpu/m68000/m68000.h"
+#include "machine/applefdc.h"
+#include "devices/sonydriv.h"
+#include "includes/macpci.h"
+#include "debug/debugcpu.h"
+#include "machine/ram.h"
+#include "debugger.h"
+
+#define LOG_ADB 0
+#define LOG_VIA 0
+
+static TIMER_CALLBACK(mac_6015_tick);
+
+/* VIA1 Handlers */
+
+static READ8_DEVICE_HANDLER(mac_via_in_a);
+static READ8_DEVICE_HANDLER(mac_via_in_b);
+static READ8_DEVICE_HANDLER(mac_adb_via_in_cb2);
+static WRITE8_DEVICE_HANDLER(mac_via_out_a);
+static WRITE8_DEVICE_HANDLER(mac_via_out_b);
+static WRITE8_DEVICE_HANDLER(mac_adb_via_out_cb2);
+static void mac_via_irq(device_t *device, int state);
+
+const via6522_interface pcimac_via6522_intf =
+{
+ DEVCB_HANDLER(mac_via_in_a), DEVCB_HANDLER(mac_via_in_b),
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_NULL, DEVCB_HANDLER(mac_adb_via_in_cb2),
+ DEVCB_HANDLER(mac_via_out_a), DEVCB_HANDLER(mac_via_out_b),
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_NULL, DEVCB_HANDLER(mac_adb_via_out_cb2),
+ DEVCB_LINE(mac_via_irq)
+};
+
+static void mac_via_irq(device_t *device, int state)
+{
+}
+
+static READ8_DEVICE_HANDLER(mac_via_in_a)
+{
+// macpci_state *mac = device->machine().driver_data<macpci_state>();
+
+// printf("VIA1 IN_A (PC %x)\n", cpu_get_pc(mac->m_maincpu));
+
+ return 0x80;
+}
+
+static READ8_DEVICE_HANDLER(mac_via_in_b)
+{
+ int val = 0;
+ macpci_state *mac = device->machine().driver_data<macpci_state>();
+
+ val |= mac->m_cuda->get_treq()<<3;
+
+// printf("VIA1 IN B = %02x (PC %x)\n", val, cpu_get_pc(mac->m_maincpu));
+
+ return val;
+}
+
+static WRITE8_DEVICE_HANDLER(mac_via_out_a)
+{
+// macpci_state *mac = device->machine().driver_data<macpci_state>();
+
+// printf("VIA1 OUT A: %02x (PC %x)\n", data, cpu_get_pc(mac->m_maincpu));
+}
+
+static WRITE8_DEVICE_HANDLER(mac_via_out_b)
+{
+ macpci_state *mac = device->machine().driver_data<macpci_state>();
+
+// printf("VIA1 OUT B: %02x (PC %x)\n", data, cpu_get_pc(mac->m_maincpu));
+
+ #if LOG_ADB
+ printf("PPC: New Cuda state: TIP %d BYTEACK %d (PC %x)\n", (data>>5)&1, (data>>4)&1, cpu_get_pc(mac->m_maincpu));
+ #endif
+ mac->m_cuda->set_byteack((data&0x10) ? 1 : 0);
+ mac->m_cuda->set_tip((data&0x20) ? 1 : 0);
+}
+
+READ16_MEMBER ( macpci_state::mac_via_r )
+{
+ UINT16 data;
+
+ offset >>= 8;
+ offset &= 0x0f;
+
+ if (LOG_VIA)
+ printf("mac_via_r: offset=0x%02x (PC=%x)\n", offset, cpu_get_pc(m_maincpu));
+ data = m_via1->read(space, offset);
+
+ device_adjust_icount(m_maincpu, m_via_cycles);
+
+ return data | (data<<8);
+}
+
+WRITE16_MEMBER ( macpci_state::mac_via_w )
+{
+ offset >>= 8;
+ offset &= 0x0f;
+
+ if (LOG_VIA)
+ printf("mac_via_w: offset=0x%02x data=0x%08x (PC=%x)\n", offset, data, cpu_get_pc(m_maincpu));
+
+ if (ACCESSING_BITS_0_7)
+ m_via1->write(space, offset, data & 0xff);
+ if (ACCESSING_BITS_8_15)
+ m_via1->write(space, offset, (data >> 8) & 0xff);
+
+ device_adjust_icount(m_maincpu, m_via_cycles);
+}
+
+static READ8_DEVICE_HANDLER(mac_adb_via_in_cb2)
+{
+ UINT8 ret;
+ macpci_state *mac = device->machine().driver_data<macpci_state>();
+
+ ret = mac->m_cuda->get_via_data();
+ #if LOG_ADB
+ printf("PPC: Read VIA_DATA %x\n", ret);
+ #endif
+
+ return ret;
+}
+
+static WRITE8_DEVICE_HANDLER(mac_adb_via_out_cb2)
+{
+ macpci_state *mac = device->machine().driver_data<macpci_state>();
+
+ mac->m_cuda->set_via_data(data & 1);
+}
+
+void macpci_state::machine_start()
+{
+ m_6015_timer = machine().scheduler().timer_alloc(FUNC(mac_6015_tick));
+ m_6015_timer->adjust(attotime::never);
+}
+
+void macpci_state::machine_reset()
+{
+ m_6015_timer->adjust(attotime::from_hz(60.15), 0, attotime::from_hz(60.15));
+
+ m_via_cycles = -256; // for a 66 MHz PowerMac
+
+ cputag_set_input_line(machine(), "maincpu", INPUT_LINE_RESET, ASSERT_LINE);
+}
+
+WRITE_LINE_MEMBER(macpci_state::cuda_reset_w)
+{
+ cputag_set_input_line(machine(), "maincpu", INPUT_LINE_RESET, state);
+}
+
+static void mac_driver_init(running_machine &machine, model_t model)
+{
+ macpci_state *mac = machine.driver_data<macpci_state>();
+
+ mac->m_model = model;
+
+ memset(mac->m_ram->pointer(), 0, mac->m_ram->size());
+}
+
+#define MAC_DRIVER_INIT(label, model) \
+DRIVER_INIT_MEMBER(macpci_state,label) \
+{ \
+ mac_driver_init(machine(), model ); \
+}
+
+MAC_DRIVER_INIT(pippin, PCIMODEL_MAC_PIPPIN)
+
+READ32_MEMBER(macpci_state::mac_read_id)
+{
+ printf("Mac read ID reg @ PC=%x\n", cpu_get_pc(m_maincpu));
+
+ switch (m_model)
+ {
+ case PCIMODEL_MAC_PIPPIN:
+ return 0xa55a7001;
+
+ default:
+ return 0;
+ }
+}
+
+/* 8530 SCC interface */
+
+READ16_MEMBER ( macpci_state::mac_scc_r )
+{
+ scc8530_t *scc = space.machine().device<scc8530_t>("scc");
+ UINT16 result;
+
+ result = scc->reg_r(space, offset);
+ return (result << 8) | result;
+}
+
+WRITE16_MEMBER ( macpci_state::mac_scc_w )
+{
+ scc8530_t *scc = space.machine().device<scc8530_t>("scc");
+ scc->reg_w(space, offset, data);
+}
+
+WRITE16_MEMBER ( macpci_state::mac_scc_2_w )
+{
+ scc8530_t *scc = space.machine().device<scc8530_t>("scc");
+ scc->reg_w(space, offset, data >> 8);
+}
+
+READ8_MEMBER(macpci_state::mac_5396_r)
+{
+ if (offset < 0x100)
+ {
+ return m_539x_1->read(space, offset>>4);
+ }
+ else // pseudo-DMA: read from the FIFO
+ {
+ return m_539x_1->read(space, 2);
+ }
+
+ return 0;
+}
+
+WRITE8_MEMBER(macpci_state::mac_5396_w)
+{
+ if (offset < 0x100)
+ {
+ m_539x_1->write(space, offset>>4, data);
+ }
+ else // pseudo-DMA: write to the FIFO
+ {
+ m_539x_1->write(space, 2, data);
+ }
+}
+
+WRITE_LINE_MEMBER(macpci_state::irq_539x_1_w)
+{
+}
+
+WRITE_LINE_MEMBER(macpci_state::drq_539x_1_w)
+{
+}
+
+static TIMER_CALLBACK(mac_6015_tick)
+{
+// macpci_state *mac = machine.driver_data<macpci_state>();
+}
diff --git a/src/mess/machine/macrtc.c b/src/mess/machine/macrtc.c
new file mode 100644
index 00000000000..d4d3e3914d6
--- /dev/null
+++ b/src/mess/machine/macrtc.c
@@ -0,0 +1,371 @@
+/***************************************************************************
+
+ macrtc.c - the real-time clock & NVRAM chip used in Macs and the Apple IIgs.
+
+ TODO: convert to a device, share between Mac and IIgs
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/mac.h"
+
+#ifdef MAME_DEBUG
+#define LOG_RTC 0
+#else
+#define LOG_RTC 0
+#endif
+
+enum
+{
+ RTC_STATE_NORMAL,
+ RTC_STATE_WRITE,
+ RTC_STATE_XPCOMMAND,
+ RTC_STATE_XPWRITE
+};
+
+/* init the rtc core */
+void mac_state::rtc_init()
+{
+ m_rtc_rTCClk = 0;
+
+ m_rtc_write_protect = 0;
+ m_rtc_rTCEnb = 0;
+ rtc_write_rTCEnb(1);
+ m_rtc_state = RTC_STATE_NORMAL;
+}
+
+/* write the rTCEnb state */
+void mac_state::rtc_write_rTCEnb(int val)
+{
+ if (val && (! m_rtc_rTCEnb))
+ {
+ /* rTCEnb goes high (inactive) */
+ m_rtc_rTCEnb = 1;
+ /* abort current transmission */
+ m_rtc_data_byte = m_rtc_bit_count = m_rtc_data_dir = m_rtc_data_out = 0;
+ m_rtc_state = RTC_STATE_NORMAL;
+ }
+ else if ((! val) && m_rtc_rTCEnb)
+ {
+ /* rTCEnb goes low (active) */
+ m_rtc_rTCEnb = 0;
+ /* abort current transmission */
+ m_rtc_data_byte = m_rtc_bit_count = m_rtc_data_dir = m_rtc_data_out = 0;
+ m_rtc_state = RTC_STATE_NORMAL;
+ }
+}
+
+/* shift data (called on rTCClk high-to-low transition (?)) */
+void mac_state::rtc_shift_data(int data)
+{
+ if (m_rtc_rTCEnb)
+ /* if enable line inactive (high), do nothing */
+ return;
+
+ if (m_rtc_data_dir)
+ { /* RTC -> VIA transmission */
+ m_rtc_data_out = (m_rtc_data_byte >> --m_rtc_bit_count) & 0x01;
+ if (LOG_RTC)
+ logerror("RTC shifted new data %d\n", m_rtc_data_out);
+ }
+ else
+ { /* VIA -> RTC transmission */
+ m_rtc_data_byte = (m_rtc_data_byte << 1) | (data ? 1 : 0);
+
+ if (++m_rtc_bit_count == 8)
+ { /* if one byte received, send to command interpreter */
+ rtc_execute_cmd(m_rtc_data_byte);
+ }
+ }
+}
+
+/* called every second, to increment the Clock count */
+void mac_state::rtc_incticks()
+{
+ if (LOG_RTC)
+ logerror("rtc_incticks called\n");
+
+ if (++m_rtc_seconds[0] == 0)
+ if (++m_rtc_seconds[1] == 0)
+ if (++m_rtc_seconds[2] == 0)
+ ++m_rtc_seconds[3];
+
+ /*if (++m_rtc_seconds[4] == 0)
+ if (++m_rtc_seconds[5] == 0)
+ if (++m_rtc_seconds[6] == 0)
+ ++m_rtc_seconds[7];*/
+}
+
+/* Executes a command.
+Called when the first byte after "enable" is received, and when the data byte after a write command
+is received. */
+void mac_state::rtc_execute_cmd(int data)
+{
+ int i;
+
+ if (LOG_RTC)
+ printf("rtc_execute_cmd: data=%x, state=%x\n", data, m_rtc_state);
+
+ if (m_rtc_state == RTC_STATE_XPCOMMAND)
+ {
+ m_rtc_xpaddr = ((m_rtc_cmd & 7)<<5) | ((data&0x7c)>>2);
+ if ((m_rtc_cmd & 0x80) != 0)
+ {
+ // read command
+ if (LOG_RTC)
+ printf("RTC: Reading extended address %x = %x\n", m_rtc_xpaddr, m_rtc_ram[m_rtc_xpaddr]);
+
+ m_rtc_data_dir = 1;
+ m_rtc_data_byte = m_rtc_ram[m_rtc_xpaddr];
+ m_rtc_state = RTC_STATE_NORMAL;
+ }
+ else
+ {
+ // write command
+ m_rtc_state = RTC_STATE_XPWRITE;
+ m_rtc_data_byte = 0;
+ m_rtc_bit_count = 0;
+ }
+ }
+ else if (m_rtc_state == RTC_STATE_XPWRITE)
+ {
+ if (LOG_RTC)
+ printf("RTC: writing %x to extended address %x\n", data, m_rtc_xpaddr);
+ m_rtc_ram[m_rtc_xpaddr] = data;
+ m_rtc_state = RTC_STATE_NORMAL;
+ }
+ else if (m_rtc_state == RTC_STATE_WRITE)
+ {
+ m_rtc_state = RTC_STATE_NORMAL;
+
+ /* Writing an RTC register */
+ i = (m_rtc_cmd >> 2) & 0x1f;
+ if (m_rtc_write_protect && (i != 13))
+ /* write-protection : only write-protect can be written again */
+ return;
+ switch(i)
+ {
+ case 0: case 1: case 2: case 3: /* seconds register */
+ case 4: case 5: case 6: case 7: /* ??? (not described in IM III) */
+ /* after various tries, I assumed m_rtc_seconds[4+i] is mapped to m_rtc_seconds[i] */
+ if (LOG_RTC)
+ logerror("RTC clock write, address = %X, data = %X\n", i, (int) m_rtc_data_byte);
+ m_rtc_seconds[i & 3] = m_rtc_data_byte;
+ break;
+
+ case 8: case 9: case 10: case 11: /* RAM address $10-$13 */
+ if (LOG_RTC)
+ printf("RTC RAM write, address = %X, data = %X\n", (i & 3) + 0x10, (int) m_rtc_data_byte);
+ m_rtc_ram[(i & 3) + 0x10] = m_rtc_data_byte;
+ break;
+
+ case 12:
+ /* Test register - do nothing */
+ if (LOG_RTC)
+ logerror("RTC write to test register, data = %X\n", (int) m_rtc_data_byte);
+ break;
+
+ case 13:
+ /* Write-protect register */
+ if (LOG_RTC)
+ printf("RTC write to write-protect register, data = %X\n", (int) m_rtc_data_byte&0x80);
+ m_rtc_write_protect = (m_rtc_data_byte & 0x80) ? TRUE : FALSE;
+ break;
+
+ case 16: case 17: case 18: case 19: /* RAM address $00-$0f */
+ case 20: case 21: case 22: case 23:
+ case 24: case 25: case 26: case 27:
+ case 28: case 29: case 30: case 31:
+ if (LOG_RTC)
+ printf("RTC RAM write, address = %X, data = %X\n", i & 15, (int) m_rtc_data_byte);
+ m_rtc_ram[i & 15] = m_rtc_data_byte;
+ break;
+
+ default:
+ printf("Unknown RTC write command : %X, data = %d\n", (int) m_rtc_cmd, (int) m_rtc_data_byte);
+ break;
+ }
+ }
+ else
+ {
+ // always save this byte to m_rtc_cmd
+ m_rtc_cmd = m_rtc_data_byte;
+
+ if ((m_rtc_cmd & 0x78) == 0x38) // extended command
+ {
+ m_rtc_state = RTC_STATE_XPCOMMAND;
+ m_rtc_data_byte = 0;
+ m_rtc_bit_count = 0;
+ }
+ else
+ {
+ if (m_rtc_cmd & 0x80)
+ {
+ m_rtc_state = RTC_STATE_NORMAL;
+
+ /* Reading an RTC register */
+ m_rtc_data_dir = 1;
+ i = (m_rtc_cmd >> 2) & 0x1f;
+ switch(i)
+ {
+ case 0: case 1: case 2: case 3:
+ case 4: case 5: case 6: case 7:
+ m_rtc_data_byte = m_rtc_seconds[i & 3];
+ if (LOG_RTC)
+ printf("RTC clock read, address = %X -> data = %X\n", i, m_rtc_data_byte);
+ break;
+
+ case 8: case 9: case 10: case 11:
+ if (LOG_RTC)
+ printf("RTC RAM read, address = %X data = %x\n", (i & 3) + 0x10, m_rtc_ram[(i & 3) + 0x10]);
+ m_rtc_data_byte = m_rtc_ram[(i & 3) + 0x10];
+ 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:
+ if (LOG_RTC)
+ printf("RTC RAM read, address = %X data = %x\n", i & 15, m_rtc_ram[i & 15]);
+ m_rtc_data_byte = m_rtc_ram[i & 15];
+ break;
+
+ default:
+ if (LOG_RTC)
+ logerror("Unknown RTC read command : %X\n", (int) m_rtc_cmd);
+ m_rtc_data_byte = 0;
+ break;
+ }
+ }
+ else
+ {
+ /* Writing an RTC register */
+ /* wait for extra data byte */
+ if (LOG_RTC)
+ logerror("RTC write, waiting for data byte : %X\n", (int) m_rtc_cmd);
+ m_rtc_state = RTC_STATE_WRITE;
+ m_rtc_data_byte = 0;
+ m_rtc_bit_count = 0;
+ }
+ }
+ }
+}
+
+/* should save PRAM to file */
+/* TODO : save write_protect flag, save time difference with host clock */
+NVRAM_HANDLER( mac )
+{
+ mac_state *mac = machine.driver_data<mac_state>();
+
+ if (read_or_write)
+ {
+ if (LOG_RTC)
+ logerror("Writing PRAM to file\n");
+ file->write(mac->m_rtc_ram, sizeof(mac->m_rtc_ram));
+ }
+ else
+ {
+ if (file)
+ {
+ if (LOG_RTC)
+ logerror("Reading PRAM from file\n");
+ file->read(mac->m_rtc_ram, sizeof(mac->m_rtc_ram));
+ }
+ else
+ {
+ UINT8 *pram = &mac->m_rtc_ram[0];
+
+ if (LOG_RTC)
+ logerror("trashing PRAM\n");
+
+ memset(mac->m_rtc_ram, 0, sizeof(mac->m_rtc_ram));
+
+ // some Mac ROMs are buggy in the presence of
+ // no NVRAM, so let's initialize it right
+ pram[0] = 0xa8; // valid
+ pram[4] = 0xcc;
+ pram[5] = 0x0a;
+ pram[6] = 0xcc;
+ pram[7] = 0x0a;
+ pram[0xc] = 0x42; // XPRAM valid for Plus/SE
+ pram[0xd] = 0x75;
+ pram[0xe] = 0x67;
+ pram[0xf] = 0x73;
+ pram[0x10] = 0x18;
+ pram[0x11] = 0x88;
+ pram[0x12] = 0x01;
+ pram[0x13] = 0x4c;
+
+ if (mac->m_model >= MODEL_MAC_II)
+ {
+ pram[0xc] = 0x4e; // XPRAM valid is different for these
+ pram[0xd] = 0x75;
+ pram[0xe] = 0x4d;
+ pram[0xf] = 0x63;
+ pram[0x77] = 0x01;
+ pram[0x78] = 0xff;
+ pram[0x79] = 0xff;
+ pram[0x7a] = 0xff;
+ pram[0x7b] = 0xdf;
+
+ if (mac->m_model == MODEL_MAC_IICI)
+ {
+ pram[0] = 0xa8;
+ pram[1] = 0x80;
+ pram[2] = 0x4f;
+ pram[3] = 0x48;
+ pram[4] = 0xcc;
+ pram[5] = 0x0a;
+ pram[6] = 0xcc;
+ pram[7] = 0x0a;
+ pram[0x10] = 0x18;
+ pram[0x11] = 0x88;
+ pram[0x12] = 0x03;
+ pram[0x13] = 0xec;
+ pram[0x57] = 0x1f;
+ pram[0x58] = 0x83;
+ pram[0x59] = 0x86;
+ pram[0x81] = 0x86;
+ pram[0x8a] = 0x05;
+ pram[0xb9] = 0xb0;
+ pram[0xf1] = 0x01;
+ pram[0xf3] = 0x02;
+ pram[0xf9] = 0x01;
+ pram[0xfb] = 0x8e;
+ }
+ }
+ }
+
+ {
+ /* Now we copy the host clock into the Mac clock */
+ /* Cool, isn't it ? :-) */
+ system_time systime;
+ struct tm mac_reference;
+ UINT32 seconds;
+
+ machine.base_datetime(systime);
+
+ /* The count starts on 1st January 1904 */
+ mac_reference.tm_sec = 0;
+ mac_reference.tm_min = 0;
+ mac_reference.tm_hour = 0;
+ mac_reference.tm_mday = 1;
+ mac_reference.tm_mon = 0;
+ mac_reference.tm_year = 4;
+ mac_reference.tm_isdst = 0;
+
+ seconds = difftime((time_t) systime.time, mktime(& mac_reference));
+
+ if (LOG_RTC)
+ logerror("second count 0x%lX\n", (unsigned long) seconds);
+
+ mac->m_rtc_seconds[0] = seconds & 0xff;
+ mac->m_rtc_seconds[1] = (seconds >> 8) & 0xff;
+ mac->m_rtc_seconds[2] = (seconds >> 16) & 0xff;
+ mac->m_rtc_seconds[3] = (seconds >> 24) & 0xff;
+ }
+ }
+}
+
+
+
diff --git a/src/mess/machine/mb8795.c b/src/mess/machine/mb8795.c
new file mode 100644
index 00000000000..fcc0ea89061
--- /dev/null
+++ b/src/mess/machine/mb8795.c
@@ -0,0 +1,333 @@
+
+#include "emu.h"
+#include "mb8795.h"
+
+const device_type MB8795 = &device_creator<mb8795_device>;
+
+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),
+ device_network_interface(mconfig, *this, 10)
+{
+}
+
+void mb8795_device::set_irq_cb(line_cb_t tx, line_cb_t rx)
+{
+ irq_tx_cb = tx;
+ irq_rx_cb = rx;
+}
+
+void mb8795_device::set_drq_cb(line_cb_t tx, line_cb_t rx)
+{
+ drq_tx_cb = tx;
+ drq_rx_cb = rx;
+}
+
+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()
+{
+ 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();
+}
+
+bool mb8795_device::mcast_chk(const UINT8 *buf, int len)
+{
+ return true;
+}
+
+READ8_MEMBER(mb8795_device::txstat_r)
+{
+ // fprintf(stderr, "mb8795: txstat_r %02x (%08x)\n", txstat, cpu_get_pc(&space.device()));
+ return txstat;
+}
+
+WRITE8_MEMBER(mb8795_device::txstat_w)
+{
+ txstat = txstat & (0xf0 | ~data);
+ check_irq();
+ fprintf(stderr, "mb8795: txstat_w %02x (%08x)\n", txstat, cpu_get_pc(&space.device()));
+}
+
+READ8_MEMBER(mb8795_device::txmask_r)
+{
+ fprintf(stderr, "mb8795: txmask_r %02x (%08x)\n", txmask, cpu_get_pc(&space.device()));
+ return txmask;
+}
+
+WRITE8_MEMBER(mb8795_device::txmask_w)
+{
+ txmask = data & 0xaf;
+ check_irq();
+ fprintf(stderr, "mb8795: txmask_w %02x (%08x)\n", txmask, cpu_get_pc(&space.device()));
+}
+
+READ8_MEMBER(mb8795_device::rxstat_r)
+{
+ fprintf(stderr, "mb8795: rxstat_r %02x (%08x)\n", rxstat, cpu_get_pc(&space.device()));
+ return rxstat;
+}
+
+WRITE8_MEMBER(mb8795_device::rxstat_w)
+{
+ rxstat = rxstat & (0x70 | ~data);
+ check_irq();
+ fprintf(stderr, "mb8795: rxstat_w %02x (%08x)\n", rxstat, cpu_get_pc(&space.device()));
+}
+
+READ8_MEMBER(mb8795_device::rxmask_r)
+{
+ fprintf(stderr, "mb8795: rxmask_r %02x (%08x)\n", rxmask, cpu_get_pc(&space.device()));
+ return rxmask;
+}
+
+WRITE8_MEMBER(mb8795_device::rxmask_w)
+{
+ rxmask = data & 0x9f;
+ check_irq();
+ fprintf(stderr, "mb8795: rxmask_w %02x (%08x)\n", rxmask, cpu_get_pc(&space.device()));
+}
+
+READ8_MEMBER(mb8795_device::txmode_r)
+{
+ fprintf(stderr, "mb8795: txmode_r %02x (%08x)\n", txmode, cpu_get_pc(&space.device()));
+ return txmode;
+}
+
+WRITE8_MEMBER(mb8795_device::txmode_w)
+{
+ txmode = data;
+ fprintf(stderr, "mb8795: txmode_w %02x (%08x)\n", txmode, cpu_get_pc(&space.device()));
+}
+
+READ8_MEMBER(mb8795_device::rxmode_r)
+{
+ fprintf(stderr, "mb8795: rxmode_r %02x (%08x)\n", rxmode, cpu_get_pc(&space.device()));
+ return rxmode;
+}
+
+WRITE8_MEMBER(mb8795_device::rxmode_w)
+{
+ rxmode = data;
+ fprintf(stderr, "mb8795: rxmode_w %02x (%08x)\n", rxmode, cpu_get_pc(&space.device()));
+}
+
+WRITE8_MEMBER(mb8795_device::reset_w)
+{
+ if(data & EN_RST_RESET)
+ device_reset();
+}
+
+READ8_MEMBER(mb8795_device::tdc_lsb_r)
+{
+ fprintf(stderr, "mb8795: tdc_lsb_r %02x (%08x)\n", txcount & 0xff, cpu_get_pc(&space.device()));
+ return txcount;
+}
+
+READ8_MEMBER(mb8795_device::mac_r)
+{
+ if(offset < 6)
+ return mac[offset];
+ if(offset == 7) {
+ fprintf(stderr, "mb8795: tdc_msb_r %02x (%08x)\n", txcount >> 8, cpu_get_pc(&space.device()));
+ 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) {
+ fprintf(stderr, "mb8795: send packet, dest=%02x.%02x.%02x.%02x.%02x.%02x len=%04x\n",
+ txbuf[0], txbuf[1], txbuf[2], txbuf[3], txbuf[4], txbuf[5],
+ txlen);
+ if(!(txmode & EN_TMD_LB_DISABLE))
+ fprintf(stderr, " -> loopback active\n");
+
+ 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()
+{
+ fprintf(stderr, "mb8975: received packet for %02x.%02x.%02x.%02x.%02x.%02x len=%04x, mode=%d\n",
+ rxbuf[0], rxbuf[1], rxbuf[2], rxbuf[3], rxbuf[4], rxbuf[5],
+ rxlen, rxmode & 3);
+ 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;
+ }
+ fprintf(stderr, " -> %s\n", keep ? "kept" : "dropped");
+ if(!keep)
+ rxlen = false;
+ else {
+ 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/mess/machine/mb8795.h b/src/mess/machine/mb8795.h
new file mode 100644
index 00000000000..a48751cdbb2
--- /dev/null
+++ b/src/mess/machine/mb8795.h
@@ -0,0 +1,109 @@
+#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<mb8795_device *>(device)->set_irq_cb(_tx_irq, _rx_irq); \
+ downcast<mb8795_device *>(device)->set_drq_cb(_tx_drq, _rx_drq);
+
+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);
+
+ void set_irq_cb(line_cb_t tx, line_cb_t rx);
+ void set_drq_cb(line_cb_t tx, line_cb_t rx);
+
+ 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);
+ virtual bool mcast_chk(const 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" - <? */
+ EN_RMD_RESETENABLE = 0x04, /* detect "reset" ethernet frames */
+ EN_RMD_WHATRECV = 0x03, /* controls what packets are received */
+ EN_RMD_RECV_PROMISC = 0x03, /* all packets */
+ EN_RMD_RECV_MULTI = 0x02, /* accept broad/multicasts */
+ EN_RMD_RECV_NORMAL = 0x01, /* accept broad/limited multicasts */
+ EN_RMD_RECV_NONE = 0x00, /* accept no packets */
+
+ EN_RST_RESET = 0x80 /* reset interface */
+ };
+
+ UINT8 mac[6];
+ UINT8 txbuf[2000], rxbuf[2000];
+ UINT8 txstat, txmask, rxstat, rxmask, txmode, rxmode;
+ UINT16 txlen, rxlen, txcount;
+ bool drq_tx, drq_rx, irq_tx, irq_rx;
+ emu_timer *timer_tx, *timer_rx;
+
+ line_cb_t irq_tx_cb, irq_rx_cb, drq_tx_cb, drq_rx_cb;
+
+ void check_irq();
+ void start_send();
+ void receive();
+ bool recv_is_broadcast();
+ bool recv_is_me();
+ bool recv_is_multicast();
+ bool recv_is_local_multicast();
+};
+
+extern const device_type MB8795;
+
+#endif
diff --git a/src/mess/machine/mb89352.c b/src/mess/machine/mb89352.c
new file mode 100644
index 00000000000..619bfd23b1e
--- /dev/null
+++ b/src/mess/machine/mb89352.c
@@ -0,0 +1,648 @@
+/*
+ * Fujitsu MB89352A SCSI Protocol Controller
+ *
+ * Should be compatible with the MB87030/31, and MB89351
+ *
+ * Used on the Sharp X68000 Super, X68000 XVI and X68030 (internal), and on SCSI expansion cards for any X680x0 (external)
+ *
+ * Registers (based on datasheet):
+ *
+ * 0: BDID (Bus Device ID)
+ * bit = device ID (ie: bit 2 = device 2) (read)
+ * bit 0 = ID1, bit 1 = ID2, bit 2 = ID4 (write)
+ *
+ * 1: SCTL (SPC Control)
+ * (all read/write)
+ * bit 0 = INT Enable
+ * bit 1 = Reselect Enable
+ * bit 2 = Select Enable
+ * bit 3 = Parity Enable
+ * bit 4 = Arbitration Phase Enable
+ * bit 5 = Diag Mode
+ * bit 6 = Control Reset
+ * bit 7 = Reset and Disable
+ *
+ * 2: SCMD (Command)
+ * bits 0-2 = Transfer Modifier (read)
+ * bit 0 = Term Mode (write)
+ * bit 2 = PRG Xfer (write)
+ * bit 3 = Intercept Xfer (read/write)
+ * bit 4 = RST Out (read/write)
+ * bits 5-7 = Command code (read/write) (would have been nice if these codes were mentioned in the datasheet...)
+ * 000 = Bus release
+ * 001 = Selection
+ * 010 = Reset ATN
+ * 011 = Set ATN
+ * 100 = Transfer
+ * 101 = Transfer Pause
+ * 110 = Reset ACK/REQ
+ * 111 = Set ACK/REQ
+ *
+ * 3: Unused
+ *
+ * 4: INTS (Interrupt Sense)
+ * on write, clear interrupt
+ * on read:
+ * bit 0 = Reset Condition
+ * bit 1 = SPC Hard Error
+ * bit 2 = Timeout
+ * bit 3 = Service Required
+ * bit 4 = Command Complete
+ * bit 5 = Disconnect
+ * bit 6 = Reselected
+ * bit 7 = Selected
+ *
+ * 5: PSNS (Phase Sense) (read-only)
+ * b7 b0
+ * | REQ | ACK | ATN | SEL | BSY | MSG | C/D | I/O |
+ * SDGC (SPC Diag. Control) (write-only)
+ * bit 5 = Xfer Enable
+ * bit 4 = Unused
+ * all other bits are Diag. of the matching inputs above.
+ *
+ * 6: SSTS (SPC Status) (read-only)
+ * bit 0 = DREG Empty
+ * bit 1 = DREG Full
+ * bit 2 = TC=0
+ * bit 3 = SCSI RST
+ * bit 4 = Xfer in progress
+ * bit 5 = SPC BSY
+ * bit 6 = Connected to Target
+ * bit 7 = Connected to Initiator
+ *
+ * 7: SERR (SCSI Error Status) (read-only)
+ * bit 1 = Short Transfer Period
+ * bit 3 = TC Parity Error
+ * bit 5 = Xfer Out (related to SDGC bit 5)
+ * bits 6,7 = Data error (10 = undefined, 00 = no error, 01 and 11 = parity error)
+ *
+ * 8: PCTL (Phase Control)
+ * (read/write)
+ * bits 0-2 = transfer phase ( | MSG | C/D | I/O | )
+ * bits 7 = Bus Free interrupt enable
+ * other bits read 0
+ *
+ * 9: MBC (Modified Byte Counter)
+ * (read-only)
+ * bits 0-3 = MBC bits 0-3
+ * other bits read 0
+ *
+ * A: DREG (Data Register)
+ * 8-bit FIFO
+ *
+ * B: TEMP (Temporary Register)
+ * on read, from SCSI
+ * on write, to SCSI
+ *
+ * C, D, E: TCH, TCM, TCL (Transfer Counter High, Mid, Low)
+ * 24-bit transfer counter
+ *
+ */
+
+#include "emu.h"
+#include "machine/devhelpr.h"
+#include "mb89352.h"
+
+/*
+ * Device config
+ */
+
+const device_type MB89352A = &device_creator<mb89352_device>;
+
+
+void mb89352_device::device_config_complete()
+{
+ // copy static configuration if present
+ const mb89352_interface *intf = reinterpret_cast<const mb89352_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<mb89352_interface *>(this) = *intf;
+
+ // otherwise, initialize it to defaults
+ else
+ {
+ scsidevs = NULL;
+ memset(&irq_callback,0,sizeof(irq_callback));
+ memset(&drq_callback,0,sizeof(drq_callback));
+ }
+}
+
+/*
+ * Device
+ */
+
+mb89352_device::mb89352_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MB89352A, "MB89352A", tag, owner, clock)
+{
+}
+
+void mb89352_device::device_start()
+{
+ int i;
+
+ 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;
+ if(m_transfer_count == 0)
+ m_spc_status |= SSTS_TC_ZERO;
+ m_ints = 0x00;
+
+ m_irq_func.resolve(irq_callback,*this);
+ m_drq_func.resolve(drq_callback,*this);
+
+ memset(m_SCSIdevices,0,sizeof(m_SCSIdevices));
+
+ // allocate read timer
+ m_transfer_timer = timer_alloc(TIMER_TRANSFER);
+
+ // try to open the devices
+ for (i = 0; i < scsidevs->devs_present; i++)
+ {
+ m_SCSIdevices[scsidevs->devices[i].scsiID] = machine().device<scsidev_device>( scsidevs->devices[i].tag );
+ }
+}
+
+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
+}
+
+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", group);
+
+ 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_func(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);
+}
+
+int mb89352_device::get_phase(void)
+{
+ return 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)
+ m_SCSIdevices[m_target]->ReadData(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_func(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_func(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;
+ }
+ 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_func(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
+ m_SCSIdevices[m_target]->ReadData(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
+ m_SCSIdevices[m_target]->SetCommand(m_command,m_command_index);
+ m_SCSIdevices[m_target]->ExecCommand(&m_result_length);
+ m_SCSIdevices[m_target]->GetPhase(&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<m_command_index;x++)
+ logerror(" %02x",m_command[x]);
+ logerror("\n");
+ }
+ return;
+ }
+ if(m_phase == SCSI_PHASE_STATUS)
+ {
+ void *image;
+ m_SCSIdevices[m_target]->GetDevice(&image);
+ if (image != NULL)
+ m_temp = 0x00;
+ else
+ m_temp = 0x02;
+ set_phase(SCSI_PHASE_MESSAGE_IN);
+ return;
+ }
+ if(m_phase == SCSI_PHASE_MESSAGE_IN)
+ {
+ m_temp = 0x00;
+ set_phase(SCSI_PHASE_BUS_FREE);
+ m_command_index = 0;
+ return;
+ }
+ break;
+ default:
+ logerror("mb89352: SCMD: Unimplemented command %02x\n",(data & 0xe0) >> 5);
+ break;
+ }
+ break;
+ case 0x04: // INTS - Interrupt Sense
+ m_ints &= ~data; // resets relevant status bits to zero
+ m_irq_func(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
+ m_SCSIdevices[m_target]->SetCommand(m_command,m_command_index);
+ m_SCSIdevices[m_target]->ExecCommand(&m_result_length);
+ m_SCSIdevices[m_target]->GetPhase(&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<m_command_index;x++)
+ logerror(" %02x",m_command[x]);
+ logerror("\n");
+ }
+ return;
+ }
+ if(m_spc_status & SSTS_XFER_IN_PROGRESS)
+ {
+ m_buffer[m_transfer_index % 512] = data;
+ m_spc_status |= SSTS_DREG_EMPTY; // DREG is empty once sent
+ m_transfer_index++;
+ m_transfer_count--;
+ if(m_transfer_index % 512 == 0)
+ m_SCSIdevices[m_target]->WriteData(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_func(1);
+ set_phase(SCSI_PHASE_STATUS);
+ }
+ }
+ break;
+ case 0x0b: // TEMP - Temporary
+ m_temp = data;
+ logerror("mb89352: Write %02x to temporary register\n",data);
+ break;
+ case 0x0c: // TCH - Transfer Counter High
+ m_transfer_count = (m_transfer_count & 0x0000ffff) | (data << 16);
+ if(m_transfer_count == 0)
+ m_spc_status |= SSTS_TC_ZERO;
+ else
+ m_spc_status &= ~SSTS_TC_ZERO;
+ logerror("mb89352: TCH: Write %02x [%06x]\n",data,m_transfer_count);
+ break;
+ case 0x0d: // TCM - Transfer Counter Mid
+ m_transfer_count = (m_transfer_count & 0x00ff00ff) | (data << 8);
+ if(m_transfer_count == 0)
+ m_spc_status |= SSTS_TC_ZERO;
+ else
+ m_spc_status &= ~SSTS_TC_ZERO;
+ logerror("mb89352: TCM: Write %02x [%06x]\n",data,m_transfer_count);
+ break;
+ case 0x0e: // TCL - Transfer Counter Low
+ m_transfer_count = (m_transfer_count & 0x00ffff00) | data;
+ if(m_transfer_count == 0)
+ m_spc_status |= SSTS_TC_ZERO;
+ else
+ m_spc_status &= ~SSTS_TC_ZERO;
+ logerror("mb89352: TCL: Write %02x [%06x]\n",data,m_transfer_count);
+ break;
+ default:
+ logerror("mb89352: write %02x to register %02x\n",data,offset & 0x0f);
+ }
+}
diff --git a/src/mess/machine/mb89352.h b/src/mess/machine/mb89352.h
new file mode 100644
index 00000000000..b1b397c27be
--- /dev/null
+++ b/src/mess/machine/mb89352.h
@@ -0,0 +1,129 @@
+/*
+ * mb89352.h
+ *
+ * Created on: 16/01/2011
+ */
+
+#ifndef MB89352_H_
+#define MB89352_H_
+
+#include "machine/scsi.h"
+#include "machine/scsidev.h"
+
+// SCSI lines readable via PSNS register (reg 5)
+#define MB89352_LINE_REQ 0x80
+#define MB89352_LINE_ACK 0x40
+#define MB89352_LINE_ATN 0x20
+#define MB89352_LINE_SEL 0x10
+#define MB89352_LINE_BSY 0x08
+#define MB89352_LINE_MSG 0x04
+#define MB89352_LINE_CD 0x02
+#define MB89352_LINE_IO 0x01
+
+// INTS bits
+#define INTS_RESET 0x01
+#define INTS_HARD_ERROR 0x02
+#define INTS_TIMEOUT 0x04
+#define INTS_SERVICE_REQUIRED 0x08
+#define INTS_COMMAND_COMPLETE 0x10
+#define INTS_DISCONNECTED 0x20
+#define INTS_RESELECTION 0x40
+#define INTS_SELECTION 0x80
+
+// SSTS status bits
+#define SSTS_DREG_EMPTY 0x01
+#define SSTS_DREG_FULL 0x02
+#define SSTS_TC_ZERO 0x04
+#define SSTS_SCSI_RST 0x08
+#define SSTS_XFER_IN_PROGRESS 0x10
+#define SSTS_SPC_BSY 0x20
+#define SSTS_TARG_CONNECTED 0x40
+#define SSTS_INIT_CONNECTED 0x80
+
+// SERR error status bits
+#define SERR_OFFSET 0x01
+#define SERR_SHORT_XFR 0x02
+#define SERR_PHASE_ERR 0x04
+#define SERR_TC_PAR 0x08
+#define SERR_SPC_PAR 0x40
+#define SERR_SCSI_PAR 0x80
+
+
+// these aren't defined in scsi.h
+#define SCSI_PHASE_BUS_FREE 8
+#define SCSI_PHASE_SELECT 9
+
+struct mb89352_interface
+{
+ const SCSIConfigTable *scsidevs; /* SCSI devices */
+ devcb_write_line irq_callback; /* irq callback */
+ devcb_write_line drq_callback; /* drq callback */
+};
+
+#define MCFG_MB89352A_ADD(_tag, _intrf) \
+ MCFG_DEVICE_ADD(_tag, MB89352A, 0) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+class mb89352_device : public device_t,
+ public mb89352_interface
+{
+public:
+ // construction/destruction
+ mb89352_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // any publically accessible interfaces needed for runtime
+ DECLARE_READ8_MEMBER( mb89352_r );
+ DECLARE_WRITE8_MEMBER( mb89352_w );
+
+ void set_phase(int phase);
+ int get_phase(void);
+
+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_config_complete();
+ 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_resolved_write_line m_irq_func;
+ devcb_resolved_write_line m_drq_func;
+
+ scsidev_device* m_SCSIdevices[8];
+
+ 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;
+ int m_result_length;
+ UINT8 m_buffer[512];
+
+ emu_timer* m_transfer_timer;
+};
+
+extern const device_type MB89352A;
+
+#endif /* MB89352_H_ */
diff --git a/src/mess/machine/mbc55x.c b/src/mess/machine/mbc55x.c
new file mode 100644
index 00000000000..b023b4a1eb4
--- /dev/null
+++ b/src/mess/machine/mbc55x.c
@@ -0,0 +1,480 @@
+/*
+ machine/mbc55x.c
+
+ Machine driver for the Sanyo MBC-550 and MBC-555.
+
+ Phill Harvey-Smith
+ 2011-01-29.
+*****************************************************************************/
+
+#include "includes/mbc55x.h"
+
+
+/*-------------------------------------------------------------------------*/
+/* Defines, constants, and global variables */
+/*-------------------------------------------------------------------------*/
+
+/* Debugging */
+
+#define DEBUG_SET(flags) ((state->m_debug_machine & (flags))==(flags))
+
+#define DEBUG_NONE 0x0000000
+#define DMA_BREAK 0x0000001
+#define DECODE_BIOS 0x0000002
+#define DECODE_BIOS_RAW 0x0000004
+#define DECODE_DOS21 0x0000008
+
+#define LOG_KEYBOARD 1
+
+static void decode_dos21(device_t *device,offs_t pc);
+//static void mbc55x_recalculate_ints(running_machine &machine);
+static void mbc55x_debug(running_machine &machine, int ref, int params, const char *param[]);
+static int instruction_hook(device_t &device, offs_t curpc);
+//static void fdc_reset(running_machine &machine);
+//static void set_disk_int(running_machine &machine, int state);
+
+
+/* Floppy drives WD2793 */
+
+const wd17xx_interface mbc55x_wd17xx_interface =
+{
+ DEVCB_LINE_GND,
+ DEVCB_DRIVER_LINE_MEMBER(mbc55x_state, mbc55x_fdc_intrq_w),
+ DEVCB_DRIVER_LINE_MEMBER(mbc55x_state, mbc55x_fdc_drq_w),
+ {FLOPPY_0, FLOPPY_1, FLOPPY_2, FLOPPY_3}
+};
+
+
+/* 8255 Configuration */
+
+READ8_MEMBER( mbc55x_state::ppi8255_r )
+{
+ return m_ppi->read(space, offset>>1);
+}
+
+WRITE8_MEMBER( mbc55x_state::ppi8255_w )
+{
+ m_ppi->write(space, offset>>1, data);
+}
+
+READ8_MEMBER( mbc55x_state::mbc55x_ppi_porta_r )
+{
+ return 0xff;
+}
+
+READ8_MEMBER( mbc55x_state::mbc55x_ppi_portb_r )
+{
+ return 0xff;
+}
+
+READ8_MEMBER( mbc55x_state::mbc55x_ppi_portc_r )
+{
+ return 0xff;
+}
+
+WRITE8_MEMBER( mbc55x_state::mbc55x_ppi_porta_w )
+{
+}
+
+WRITE8_MEMBER( mbc55x_state::mbc55x_ppi_portb_w )
+{
+}
+
+WRITE8_MEMBER( mbc55x_state::mbc55x_ppi_portc_w )
+{
+ wd17xx_set_drive(m_fdc,(data & 0x03));
+ wd17xx_set_side(m_fdc, BIT(data, 2));
+}
+
+I8255_INTERFACE( mbc55x_ppi8255_interface )
+{
+ DEVCB_DRIVER_MEMBER(mbc55x_state, mbc55x_ppi_porta_r),
+ DEVCB_DRIVER_MEMBER(mbc55x_state, mbc55x_ppi_porta_w),
+ DEVCB_DRIVER_MEMBER(mbc55x_state, mbc55x_ppi_portb_r),
+ DEVCB_DRIVER_MEMBER(mbc55x_state, mbc55x_ppi_portb_w),
+ DEVCB_DRIVER_MEMBER(mbc55x_state, mbc55x_ppi_portc_r),
+ DEVCB_DRIVER_MEMBER(mbc55x_state, mbc55x_ppi_portc_w)
+};
+
+/* Serial port USART, unimplemented as yet */
+
+READ8_MEMBER( mbc55x_state::mbc55x_usart_r )
+{
+ return 0;
+}
+
+WRITE8_MEMBER( mbc55x_state::mbc55x_usart_w )
+{
+}
+
+/* PIC 8259 Configuration */
+
+const struct pic8259_interface mbc55x_pic8259_config =
+{
+ DEVCB_CPU_INPUT_LINE(MAINCPU_TAG, INPUT_LINE_IRQ0),
+ DEVCB_LINE_VCC,
+ DEVCB_NULL
+};
+
+READ8_MEMBER(mbc55x_state::mbcpic8259_r)
+{
+ return pic8259_r(m_pic, offset>>1);
+}
+
+WRITE8_MEMBER(mbc55x_state::mbcpic8259_w)
+{
+ pic8259_w(m_pic, offset>>1, data);
+}
+
+static IRQ_CALLBACK(mbc55x_irq_callback)
+{
+ mbc55x_state *state = device->machine().driver_data<mbc55x_state>();
+ return pic8259_acknowledge( state->m_pic );
+}
+
+/* PIT8253 Configuration */
+
+const struct pit8253_config mbc55x_pit8253_config =
+{
+ {
+ {
+ PIT_C0_CLOCK,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE(PIC8259_TAG, pic8259_ir0_w)
+ },
+ {
+ PIT_C1_CLOCK,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE(PIC8259_TAG, pic8259_ir1_w)
+ },
+ {
+ PIT_C2_CLOCK,
+ DEVCB_NULL,
+ DEVCB_DRIVER_LINE_MEMBER(mbc55x_state, pit8253_t2)
+ }
+ }
+};
+
+READ8_MEMBER(mbc55x_state::mbcpit8253_r)
+{
+ return pit8253_r(m_pit, offset>>1);
+}
+
+WRITE8_MEMBER(mbc55x_state::mbcpit8253_w)
+{
+ pit8253_w(m_pit, offset>>1, data);
+}
+
+WRITE_LINE_MEMBER( mbc55x_state::pit8253_t2 )
+{
+ m_kb_uart->transmit_clock();
+ m_kb_uart->receive_clock();
+}
+
+/* Video ram page register */
+
+READ8_MEMBER( mbc55x_state::vram_page_r )
+{
+ return m_vram_page;
+}
+
+WRITE8_MEMBER( mbc55x_state::vram_page_w )
+{
+ logerror("%s : set vram page to %02X\n", machine().describe_context(),data);
+
+ m_vram_page=data;
+}
+
+READ8_MEMBER(mbc55x_state::mbc55x_disk_r)
+{
+ return wd17xx_r(m_fdc, offset>>1);
+}
+
+WRITE8_MEMBER(mbc55x_state::mbc55x_disk_w)
+{
+ wd17xx_w(m_fdc, offset>>1, data);
+}
+
+WRITE_LINE_MEMBER( mbc55x_state::mbc55x_fdc_intrq_w )
+{
+}
+
+WRITE_LINE_MEMBER( mbc55x_state::mbc55x_fdc_drq_w )
+{
+}
+
+/*
+ Keyboard emulation
+
+*/
+
+static void keyboard_reset(running_machine &machine)
+{
+ mbc55x_state *state = machine.driver_data<mbc55x_state>();
+ logerror("keyboard_reset()\n");
+
+ memset(state->m_keyboard.keyrows,0xFF,MBC55X_KEYROWS);
+ state->m_keyboard.key_special=0;
+
+ // Setup timer to scan keyboard.
+ state->m_keyboard.keyscan_timer->adjust(attotime::zero, 0, attotime::from_hz(50));
+}
+
+static void scan_keyboard(running_machine &machine)
+{
+ mbc55x_state *state = machine.driver_data<mbc55x_state>();
+ UINT8 keyrow;
+ UINT8 row;
+ UINT8 bitno;
+ UINT8 mask;
+
+ char key;
+ static const char *const keynames[] =
+ {
+ "KEY0", "KEY1", "KEY2", "KEY3", "KEY4",
+ "KEY5", "KEY6", "KEY7", "KEY8", "KEY9",
+ "KEY10"
+ };
+
+ static const char keyvalues_normal[MBC55X_KEYROWS][8] =
+ {
+ { '1', '2', '3', '4' , '5', '6', '7', '8' },
+ { '9', '0', '-', '=', '\\', 'q', 'w', 'e' },
+ { 'r', 't', 'y', 'u', 'i', 'o', 'p', '[' },
+ { ']', 'a', 's', 'd', 'f', 'g', 'h', 'j' },
+ { 'k', 'l', ';', '\'', '`', 0x0D, 'z', 'x' },
+ { 'c', 'v', 'b', 'n', 'm', ',', '.', '/', },
+ { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', }
+
+ };
+
+ static const char keyvalues_shift[MBC55X_KEYROWS][8] =
+ {
+ { '!', '@', '#', '$' , '%', '^', '&', '*' },
+ { '(', ')', '_', '+', '|', 'Q', 'W', 'E' },
+ { 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{' },
+ { '}', 'A', 'S', 'D', 'F', 'G', 'H', 'J' },
+ { 'K', 'L', ':', '"', '~', 0x0d, 'Z', 'X' },
+ { 'C', 'V', 'B', 'N', 'M', ',', '?', '/' },
+ { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' }
+ };
+
+ // First read shift, control and graph
+
+ state->m_keyboard.key_special = machine.root_device().ioport(KEY_SPECIAL_TAG)->read();
+
+ for(row=0; row<MBC55X_KEYROWS; row++)
+ {
+ keyrow = machine.root_device().ioport(keynames[row])->read();
+
+ for(mask=0x80, bitno=7;mask>0;mask=mask>>1, bitno-=1)
+ {
+ if(!(keyrow & mask) && (state->m_keyboard.keyrows[row] & mask))
+ {
+ if(state->m_keyboard.key_special & (KEY_BIT_LSHIFT | KEY_BIT_RSHIFT))
+ key=keyvalues_shift[row][bitno];
+ else
+ key=keyvalues_normal[row][bitno];
+
+ if (LOG_KEYBOARD) logerror("keypress %c\n",key);
+ state->m_kb_uart->receive_character(key);
+ }
+ }
+
+ state->m_keyboard.keyrows[row]=keyrow;
+ }
+}
+
+static TIMER_CALLBACK(keyscan_callback)
+{
+ scan_keyboard(machine);
+}
+
+/* i8251 serial */
+
+const i8251_interface mbc55x_i8251a_interface =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE(PIC8259_TAG, pic8259_ir3_w),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+READ8_MEMBER(mbc55x_state::mbc55x_kb_usart_r)
+{
+ UINT8 result = 0;
+ offset>>=1;
+
+ switch (offset)
+ {
+ case 0 : //logerror("%s read kb_uart\n",machine().describe_context());
+ result = m_kb_uart->data_r(space,0); break;
+
+ case 1 : result = m_kb_uart->status_r(space,0);
+
+ if (m_keyboard.key_special & KEY_BIT_CTRL) // Parity error used to flag control down
+ result |= I8251_STATUS_PARITY_ERROR;
+ break;
+ }
+
+ return result;
+}
+
+WRITE8_MEMBER(mbc55x_state::mbc55x_kb_usart_w)
+{
+ offset>>=1;
+
+ switch (offset)
+ {
+ case 0 : m_kb_uart->data_w(space, 0, data); break;
+ case 1 : m_kb_uart->control_w(space, 0, data); break;
+ }
+}
+
+static void set_ram_size(running_machine &machine)
+{
+ mbc55x_state *state = machine.driver_data<mbc55x_state>();
+ address_space *space = machine.device( MAINCPU_TAG)->memory().space( AS_PROGRAM );
+ int ramsize = state->m_ram->size();
+ int nobanks = ramsize / RAM_BANK_SIZE;
+ char bank[10];
+ int bankno;
+ UINT8 *ram = &state->m_ram->pointer()[0];
+ UINT8 *map_base;
+ int bank_base;
+
+
+ logerror("Ramsize is %d bytes\n",ramsize);
+ logerror("RAM_BANK_SIZE=%d, nobanks=%d\n",RAM_BANK_SIZE,nobanks);
+
+ // Main memory mapping
+
+ for(bankno=0; bankno<RAM_BANK_COUNT; bankno++)
+ {
+ sprintf(bank,"bank%x",bankno);
+ bank_base=bankno*RAM_BANK_SIZE;
+ map_base=&ram[bank_base];
+
+ if(bankno<nobanks)
+ {
+ state->membank(bank)->set_base(map_base);
+ space->install_readwrite_bank(bank_base, bank_base+(RAM_BANK_SIZE-1), bank);
+ logerror("Mapping bank %d at %05X to RAM\n",bankno,bank_base);
+ }
+ else
+ {
+ space->nop_readwrite(bank_base, bank_base+(RAM_BANK_SIZE-1));
+ logerror("Mapping bank %d at %05X to NOP\n",bankno,bank_base);
+ }
+ }
+
+ // Graphics red and blue plane memory mapping, green is in main memory
+ state->membank(RED_PLANE_TAG)->set_base(&state->m_video_mem[RED_PLANE_OFFSET]);
+ space->install_readwrite_bank(RED_PLANE_MEMBASE, RED_PLANE_MEMBASE+(COLOUR_PLANE_SIZE-1), RED_PLANE_TAG);
+ state->membank(BLUE_PLANE_TAG)->set_base(&state->m_video_mem[BLUE_PLANE_OFFSET]);
+ space->install_readwrite_bank(BLUE_PLANE_MEMBASE, BLUE_PLANE_MEMBASE+(COLOUR_PLANE_SIZE-1), BLUE_PLANE_TAG);
+}
+
+DRIVER_INIT_MEMBER(mbc55x_state,mbc55x)
+{
+}
+
+MACHINE_RESET( mbc55x )
+{
+ set_ram_size(machine);
+ keyboard_reset(machine);
+ device_set_irq_callback(machine.device(MAINCPU_TAG), mbc55x_irq_callback);
+}
+
+MACHINE_START( mbc55x )
+{
+ mbc55x_state *state = machine.driver_data<mbc55x_state>();
+ /* init cpu */
+// mbc55x_cpu_init(machine);
+
+
+ /* setup debug commands */
+ if (machine.debug_flags & DEBUG_FLAG_ENABLED)
+ {
+ debug_console_register_command(machine, "mbc55x_debug", CMDFLAG_NONE, 0, 0, 1, mbc55x_debug);
+
+ /* set up the instruction hook */
+ machine.device(MAINCPU_TAG)->debug()->set_instruction_hook(instruction_hook);
+ }
+
+ state->m_debug_machine=DEBUG_NONE;
+
+ // Allocate keyscan timer
+ state->m_keyboard.keyscan_timer=machine.scheduler().timer_alloc(FUNC(keyscan_callback));
+}
+
+
+static void mbc55x_debug(running_machine &machine, int ref, int params, const char *param[])
+{
+ mbc55x_state *state = machine.driver_data<mbc55x_state>();
+ if(params>0)
+ {
+ sscanf(param[0],"%d",&state->m_debug_machine);
+ }
+ else
+ {
+ debug_console_printf(machine,"Error usage : mbc55x_debug <debuglevel>\n");
+ debug_console_printf(machine,"Current debuglevel=%02X\n",state->m_debug_machine);
+ }
+}
+
+/*-----------------------------------------------
+ instruction_hook - per-instruction hook
+-----------------------------------------------*/
+
+static int instruction_hook(device_t &device, offs_t curpc)
+{
+ mbc55x_state *state = device.machine().driver_data<mbc55x_state>();
+ address_space *space = device.memory().space(AS_PROGRAM);
+ UINT8 *addr_ptr;
+
+ addr_ptr = (UINT8*)space->get_read_ptr(curpc);
+
+ if ((addr_ptr !=NULL) && (addr_ptr[0]==0xCD))
+ {
+// logerror("int %02X called\n",addr_ptr[1]);
+
+ if(DEBUG_SET(DECODE_DOS21) && (addr_ptr[1]==0x21))
+ decode_dos21(&device,curpc);
+ }
+
+ return 0;
+}
+
+static void decode_dos21(device_t *device,offs_t pc)
+{
+ device_t *cpu = device->machine().device(MAINCPU_TAG);
+
+ UINT16 ax = cpu_get_reg(cpu,I8086_AX);
+ UINT16 bx = cpu_get_reg(cpu,I8086_BX);
+ UINT16 cx = cpu_get_reg(cpu,I8086_CX);
+ UINT16 dx = cpu_get_reg(cpu,I8086_DX);
+ UINT16 cs = cpu_get_reg(cpu,I8086_CS);
+ UINT16 ds = cpu_get_reg(cpu,I8086_DS);
+ UINT16 es = cpu_get_reg(cpu,I8086_ES);
+ UINT16 ss = cpu_get_reg(cpu,I8086_SS);
+
+ UINT16 si = cpu_get_reg(cpu,I8086_SI);
+ UINT16 di = cpu_get_reg(cpu,I8086_DI);
+ UINT16 bp = cpu_get_reg(cpu,I8086_BP);
+
+ logerror("=======================================================================\n");
+ logerror("DOS Int 0x21 call at %05X\n",pc);
+ logerror("AX=%04X, BX=%04X, CX=%04X, DX=%04X\n",ax,bx,cx,dx);
+ logerror("CS=%04X, DS=%04X, ES=%04X, SS=%04X\n",cs,ds,es,ss);
+ logerror("SI=%04X, DI=%04X, BP=%04X\n",si,di,bp);
+ logerror("=======================================================================\n");
+
+ if((ax & 0xff00)==0x0900)
+ debugger_break(device->machine());
+}
diff --git a/src/mess/machine/mbee.c b/src/mess/machine/mbee.c
new file mode 100644
index 00000000000..948abcfc7ae
--- /dev/null
+++ b/src/mess/machine/mbee.c
@@ -0,0 +1,823 @@
+/***************************************************************************
+
+ microbee.c
+
+ machine driver
+ Juergen Buchmueller <pullmoll@t-online.de>, Jan 2000
+
+
+****************************************************************************/
+
+#include "emu.h"
+#include "includes/mbee.h"
+
+
+/***********************************************************
+
+ PIO
+
+************************************************************/
+
+WRITE_LINE_MEMBER( mbee_state::pio_ardy )
+{
+ m_printer->strobe_w((state) ? 0 : 1);
+}
+
+WRITE8_MEMBER( mbee_state::pio_port_a_w )
+{
+ /* hardware strobe driven by PIO ARDY, bit 7..0 = data */
+ m_pio->strobe_a(1); /* needed - otherwise nothing prints */
+ m_printer->write(space, 0, data);
+};
+
+WRITE8_MEMBER( mbee_state::pio_port_b_w )
+{
+/* PIO port B - d5..d2 not emulated
+ d7 network interrupt (microbee network for classrooms)
+ d6 speaker
+ d5 rs232 output (1=mark)
+ d4 rs232 input (0=mark)
+ d3 rs232 CTS (0=clear to send)
+ d2 rs232 clock or DTR
+ d1 cass out and (on 256tc) keyboard irq
+ d0 cass in */
+
+ m_cass->output((data & 0x02) ? -1.0 : +1.0);
+
+ speaker_level_w(m_speaker, BIT(data, 6));
+};
+
+READ8_MEMBER( mbee_state::pio_port_b_r )
+{
+ UINT8 data = 0;
+
+ if (m_cass->input() > 0.03) data |= 1;
+
+ data |= m_clock_pulse;
+ data |= m_mbee256_key_available;
+
+ m_clock_pulse = 0;
+
+ return data;
+};
+
+const z80pio_interface mbee_z80pio_intf =
+{
+ DEVCB_CPU_INPUT_LINE("maincpu", INPUT_LINE_IRQ0),
+ DEVCB_NULL,
+ DEVCB_DRIVER_MEMBER(mbee_state, pio_port_a_w),
+ DEVCB_DRIVER_LINE_MEMBER(mbee_state, pio_ardy),
+ DEVCB_DRIVER_MEMBER(mbee_state, pio_port_b_r),
+ DEVCB_DRIVER_MEMBER(mbee_state, pio_port_b_w),
+ DEVCB_NULL
+};
+
+/*************************************************************************************
+
+ Floppy DIsk
+
+ The callback is quite simple, no interrupts are used.
+ If either IRQ or DRQ activate, they set bit 7 of inport 0x48.
+
+*************************************************************************************/
+
+WRITE_LINE_MEMBER( mbee_state::mbee_fdc_intrq_w )
+{
+ m_fdc_intrq = state ? 0x80 : 0;
+}
+
+WRITE_LINE_MEMBER( mbee_state::mbee_fdc_drq_w )
+{
+ m_fdc_drq = state ? 0x80 : 0;
+}
+
+const wd17xx_interface mbee_wd17xx_interface =
+{
+ DEVCB_NULL,
+ DEVCB_DRIVER_LINE_MEMBER(mbee_state, mbee_fdc_intrq_w),
+ DEVCB_DRIVER_LINE_MEMBER(mbee_state, mbee_fdc_drq_w),
+ {FLOPPY_0, FLOPPY_1, NULL, NULL }
+};
+
+READ8_MEMBER( mbee_state::mbee_fdc_status_r )
+{
+/* d7 indicate if IRQ or DRQ is occuring (1=happening)
+ d6..d0 not used */
+
+ return 0x7f | m_fdc_intrq | m_fdc_drq;
+}
+
+WRITE8_MEMBER( mbee_state::mbee_fdc_motor_w )
+{
+/* d7..d4 not used
+ d3 density (1=MFM)
+ d2 side (1=side 1)
+ d1..d0 drive select (0 to 3) */
+
+ wd17xx_set_drive(m_fdc, data & 3);
+ wd17xx_set_side(m_fdc, BIT(data, 2));
+ wd17xx_dden_w(m_fdc, !BIT(data, 3));
+ /* no idea what turns the motors on & off, guessing it could be drive select
+ commented out because it prevents 128k and 256TC from booting up */
+ //floppy_mon_w(floppy_get_device(machine(), data & 3), CLEAR_LINE); // motor on
+}
+
+/***********************************************************
+
+ 256TC Keyboard
+
+************************************************************/
+
+
+static TIMER_CALLBACK( mbee256_kbd )
+{
+ mbee_state *state = machine.driver_data<mbee_state>();
+ /* Keyboard scanner is a Mostek M3870 chip. Its speed of operation is determined by a 15k resistor on
+ pin 2 (XTL2) and is therefore unknown. If a key change is detected (up or down), the /strobe
+ line activates, sending a high to bit 1 of port 2 (one of the pio input lines). The next read of
+ port 18 will clear this line, and read the key scancode. It will also signal the 3870 that the key
+ data has been read, on pin 38 (/extint). The 3870 can cache up to 9 keys. With no rom dump
+ available, the following is a guess.
+
+ The 3870 (MK3870) 8-bit microcontroller is a single chip implementation of Fairchild F8 (Mostek 3850).
+ It includes up to 4 KB of mask-programmable ROM, 64 bytes of scratchpad RAM and up to 64 bytes
+ of executable RAM. The MCU also integrates 32-bit I/O and a programmable timer. */
+
+ UINT8 i, j;
+ UINT8 pressed[15];
+ char kbdrow[6];
+
+
+ /* see what is pressed */
+ for (i = 0; i < 15; i++)
+ {
+ sprintf(kbdrow,"X%d",i);
+ pressed[i] = (machine.root_device().ioport(kbdrow)->read());
+ }
+
+ /* find what has changed */
+ for (i = 0; i < 15; i++)
+ {
+ if (pressed[i] != state->m_mbee256_was_pressed[i])
+ {
+ /* get scankey value */
+ for (j = 0; j < 8; j++)
+ {
+ if (BIT(pressed[i]^state->m_mbee256_was_pressed[i], j))
+ {
+ /* put it in the queue */
+ state->m_mbee256_q[state->m_mbee256_q_pos] = (i << 3) | j | (BIT(pressed[i], j) ? 0x80 : 0);
+ if (state->m_mbee256_q_pos < 19) state->m_mbee256_q_pos++;
+ }
+ }
+ state->m_mbee256_was_pressed[i] = pressed[i];
+ }
+ }
+
+ /* if anything queued, cause an interrupt */
+ if (state->m_mbee256_q_pos)
+ state->m_mbee256_key_available = 2; // set irq
+}
+
+READ8_MEMBER( mbee_state::mbee256_18_r )
+{
+ UINT8 i, data = m_mbee256_q[0]; // get oldest key
+
+ if (m_mbee256_q_pos)
+ {
+ m_mbee256_q_pos--;
+ for (i = 0; i < m_mbee256_q_pos; i++) m_mbee256_q[i] = m_mbee256_q[i+1]; // ripple queue
+ }
+
+ m_mbee256_key_available = 0; // clear irq
+ return data;
+}
+
+
+/***********************************************************
+
+ 256TC Change CPU speed
+
+************************************************************/
+
+READ8_MEMBER( mbee_state::mbee256_speed_low_r )
+{
+ machine().device("maincpu")->set_unscaled_clock(3375000);
+ return 0xff;
+}
+
+READ8_MEMBER( mbee_state::mbee256_speed_high_r )
+{
+ machine().device("maincpu")->set_unscaled_clock(6750000);
+ return 0xff;
+}
+
+
+
+/***********************************************************
+
+ 256TC Real Time Clock
+
+************************************************************/
+
+WRITE8_MEMBER( mbee_state::mbee_04_w ) // address
+{
+ address_space *mem = m_maincpu->memory().space(AS_IO);
+ machine().device<mc146818_device>("rtc")->write(*mem, 0, data);
+}
+
+WRITE8_MEMBER( mbee_state::mbee_06_w ) // write
+{
+ address_space *mem = m_maincpu->memory().space(AS_IO);
+ machine().device<mc146818_device>("rtc")->write(*mem, 1, data);
+}
+
+READ8_MEMBER( mbee_state::mbee_07_r ) // read
+{
+ address_space *mem = m_maincpu->memory().space(AS_IO);
+ return machine().device<mc146818_device>("rtc")->read(*mem, 1);
+}
+
+static TIMER_CALLBACK( mbee_rtc_irq )
+{
+ mbee_state *state = machine.driver_data<mbee_state>();
+ address_space *mem = machine.device("maincpu")->memory().space(AS_IO);
+ UINT8 data = machine.device<mc146818_device>("rtc")->read(*mem, 12);
+ if (data) state->m_clock_pulse = 0x80;
+}
+
+
+/***********************************************************
+
+ 256TC Memory Banking
+
+ Bits 0, 1 and 5 select which bank goes into 0000-7FFF.
+ Bit 2 disables ROM, replacing it with RAM.
+ Bit 3 disables Video, replacing it with RAM.
+ Bit 4 switches the video circuits between F000-FFFF and
+ 8000-8FFF.
+
+ In case of a clash, video overrides ROM which overrides RAM.
+
+************************************************************/
+
+WRITE8_MEMBER( mbee_state::mbee256_50_w )
+{
+ address_space *mem = m_maincpu->memory().space(AS_PROGRAM);
+
+ // primary low banks
+ membank("boot")->set_entry((data & 3) | ((data & 0x20) >> 3));
+ membank("bank1")->set_entry((data & 3) | ((data & 0x20) >> 3));
+
+ // 9000-EFFF
+ membank("bank9")->set_entry((data & 4) ? 1 : 0);
+
+ // 8000-8FFF, F000-FFFF
+ mem->unmap_readwrite (0x8000, 0x87ff);
+ mem->unmap_readwrite (0x8800, 0x8fff);
+ mem->unmap_readwrite (0xf000, 0xf7ff);
+ mem->unmap_readwrite (0xf800, 0xffff);
+
+ switch (data & 0x1c)
+ {
+ case 0x00:
+ mem->install_read_bank (0x8000, 0x87ff, "bank8l");
+ mem->install_read_bank (0x8800, 0x8fff, "bank8h");
+ mem->install_readwrite_handler (0xf000, 0xf7ff, read8_delegate(FUNC(mbee_state::mbeeppc_low_r), this), write8_delegate(FUNC(mbee_state::mbeeppc_low_w), this));
+ mem->install_readwrite_handler (0xf800, 0xffff, read8_delegate(FUNC(mbee_state::mbeeppc_high_r), this), write8_delegate(FUNC(mbee_state::mbeeppc_high_w), this));
+ membank("bank8l")->set_entry(0); // rom
+ membank("bank8h")->set_entry(0); // rom
+ break;
+ case 0x04:
+ mem->install_read_bank (0x8000, 0x87ff, "bank8l");
+ mem->install_read_bank (0x8800, 0x8fff, "bank8h");
+ mem->install_readwrite_handler (0xf000, 0xf7ff, read8_delegate(FUNC(mbee_state::mbeeppc_low_r), this), write8_delegate(FUNC(mbee_state::mbeeppc_low_w), this));
+ mem->install_readwrite_handler (0xf800, 0xffff, read8_delegate(FUNC(mbee_state::mbeeppc_high_r), this), write8_delegate(FUNC(mbee_state::mbeeppc_high_w), this));
+ membank("bank8l")->set_entry(1); // ram
+ membank("bank8h")->set_entry(1); // ram
+ break;
+ case 0x08:
+ case 0x18:
+ mem->install_read_bank (0x8000, 0x87ff, "bank8l");
+ mem->install_read_bank (0x8800, 0x8fff, "bank8h");
+ mem->install_read_bank (0xf000, 0xf7ff, "bankfl");
+ mem->install_read_bank (0xf800, 0xffff, "bankfh");
+ membank("bank8l")->set_entry(0); // rom
+ membank("bank8h")->set_entry(0); // rom
+ membank("bankfl")->set_entry(0); // ram
+ membank("bankfh")->set_entry(0); // ram
+ break;
+ case 0x0c:
+ case 0x1c:
+ mem->install_read_bank (0x8000, 0x87ff, "bank8l");
+ mem->install_read_bank (0x8800, 0x8fff, "bank8h");
+ mem->install_read_bank (0xf000, 0xf7ff, "bankfl");
+ mem->install_read_bank (0xf800, 0xffff, "bankfh");
+ membank("bank8l")->set_entry(1); // ram
+ membank("bank8h")->set_entry(1); // ram
+ membank("bankfl")->set_entry(0); // ram
+ membank("bankfh")->set_entry(0); // ram
+ break;
+ case 0x10:
+ case 0x14:
+ mem->install_readwrite_handler (0x8000, 0x87ff, read8_delegate(FUNC(mbee_state::mbeeppc_low_r), this), write8_delegate(FUNC(mbee_state::mbeeppc_low_w), this));
+ mem->install_readwrite_handler (0x8800, 0x8fff, read8_delegate(FUNC(mbee_state::mbeeppc_high_r), this), write8_delegate(FUNC(mbee_state::mbeeppc_high_w), this));
+ mem->install_read_bank (0xf000, 0xf7ff, "bankfl");
+ mem->install_read_bank (0xf800, 0xffff, "bankfh");
+ membank("bankfl")->set_entry(0); // ram
+ membank("bankfh")->set_entry(0); // ram
+ break;
+ }
+}
+
+/***********************************************************
+
+ 128k Memory Banking
+
+ The only difference to the 256TC is that bit 5 switches
+ between rom2 and rom3. Since neither of these is dumped,
+ this bit is not emulated. If it was, this scheme is used:
+
+ Low - rom2 occupies C000-FFFF
+ High - ram = C000-DFFF, rom3 = E000-FFFF.
+
+************************************************************/
+
+WRITE8_MEMBER( mbee_state::mbee128_50_w )
+{
+ address_space *mem = m_maincpu->memory().space(AS_PROGRAM);
+
+ // primary low banks
+ membank("boot")->set_entry((data & 3));
+ membank("bank1")->set_entry((data & 3));
+
+ // 9000-EFFF
+ membank("bank9")->set_entry((data & 4) ? 1 : 0);
+
+ // 8000-8FFF, F000-FFFF
+ mem->unmap_readwrite (0x8000, 0x87ff);
+ mem->unmap_readwrite (0x8800, 0x8fff);
+ mem->unmap_readwrite (0xf000, 0xf7ff);
+ mem->unmap_readwrite (0xf800, 0xffff);
+
+ switch (data & 0x1c)
+ {
+ case 0x00:
+ mem->install_read_bank (0x8000, 0x87ff, "bank8l");
+ mem->install_read_bank (0x8800, 0x8fff, "bank8h");
+ mem->install_readwrite_handler (0xf000, 0xf7ff, read8_delegate(FUNC(mbee_state::mbeeppc_low_r),this), write8_delegate(FUNC(mbee_state::mbeeppc_low_w),this));
+ mem->install_readwrite_handler (0xf800, 0xffff, read8_delegate(FUNC(mbee_state::mbeeppc_high_r),this), write8_delegate(FUNC(mbee_state::mbeeppc_high_w),this));
+ membank("bank8l")->set_entry(0); // rom
+ membank("bank8h")->set_entry(0); // rom
+ break;
+ case 0x04:
+ mem->install_read_bank (0x8000, 0x87ff, "bank8l");
+ mem->install_read_bank (0x8800, 0x8fff, "bank8h");
+ mem->install_readwrite_handler (0xf000, 0xf7ff, read8_delegate(FUNC(mbee_state::mbeeppc_low_r),this), write8_delegate(FUNC(mbee_state::mbeeppc_low_w),this));
+ mem->install_readwrite_handler (0xf800, 0xffff, read8_delegate(FUNC(mbee_state::mbeeppc_high_r),this), write8_delegate(FUNC(mbee_state::mbeeppc_high_w),this));
+ membank("bank8l")->set_entry(1); // ram
+ membank("bank8h")->set_entry(1); // ram
+ break;
+ case 0x08:
+ case 0x18:
+ mem->install_read_bank (0x8000, 0x87ff, "bank8l");
+ mem->install_read_bank (0x8800, 0x8fff, "bank8h");
+ mem->install_read_bank (0xf000, 0xf7ff, "bankfl");
+ mem->install_read_bank (0xf800, 0xffff, "bankfh");
+ membank("bank8l")->set_entry(0); // rom
+ membank("bank8h")->set_entry(0); // rom
+ membank("bankfl")->set_entry(0); // ram
+ membank("bankfh")->set_entry(0); // ram
+ break;
+ case 0x0c:
+ case 0x1c:
+ mem->install_read_bank (0x8000, 0x87ff, "bank8l");
+ mem->install_read_bank (0x8800, 0x8fff, "bank8h");
+ mem->install_read_bank (0xf000, 0xf7ff, "bankfl");
+ mem->install_read_bank (0xf800, 0xffff, "bankfh");
+ membank("bank8l")->set_entry(1); // ram
+ membank("bank8h")->set_entry(1); // ram
+ membank("bankfl")->set_entry(0); // ram
+ membank("bankfh")->set_entry(0); // ram
+ break;
+ case 0x10:
+ case 0x14:
+ mem->install_readwrite_handler (0x8000, 0x87ff, read8_delegate(FUNC(mbee_state::mbeeppc_low_r),this), write8_delegate(FUNC(mbee_state::mbeeppc_low_w),this));
+ mem->install_readwrite_handler (0x8800, 0x8fff, read8_delegate(FUNC(mbee_state::mbeeppc_high_r),this), write8_delegate(FUNC(mbee_state::mbeeppc_high_w),this));
+ mem->install_read_bank (0xf000, 0xf7ff, "bankfl");
+ mem->install_read_bank (0xf800, 0xffff, "bankfh");
+ membank("bankfl")->set_entry(0); // ram
+ membank("bankfh")->set_entry(0); // ram
+ break;
+ }
+}
+
+
+/***********************************************************
+
+ 64k Memory Banking
+
+ Bit 2 disables ROM, replacing it with RAM.
+
+ Due to lack of documentation, it is not possible to know
+ if other bits are used.
+
+************************************************************/
+
+WRITE8_MEMBER( mbee_state::mbee64_50_w )
+{
+ if BIT(data, 2)
+ {
+ membank("boot")->set_entry(0);
+ membank("bankl")->set_entry(0);
+ membank("bankh")->set_entry(0);
+ }
+ else
+ {
+ membank("bankl")->set_entry(1);
+ membank("bankh")->set_entry(1);
+ }
+}
+
+
+/***********************************************************
+
+ ROM Banking on older models
+
+ Set A to 0 or 1 then read the port to switch between the
+ halves of the Telcom ROM.
+
+ Output the PAK number to choose an optional PAK ROM.
+
+ The bios will support 256 PAKs, although normally only
+ 8 are available in hardware. Each PAK is normally a 4K
+ ROM. If 8K ROMs are used, the 2nd half becomes PAK+8,
+ thus 16 PAKs in total. This is used in the PC85 models.
+
+************************************************************/
+
+READ8_MEMBER( mbee_state::mbeeic_0a_r )
+{
+ return m_0a;
+}
+
+WRITE8_MEMBER( mbee_state::mbeeic_0a_w )
+{
+ m_0a = data;
+ membank("pak")->set_entry(data & 15);
+}
+
+READ8_MEMBER( mbee_state::mbeepc_telcom_low_r )
+{
+/* Read of port 0A - set Telcom rom to first half */
+ membank("telcom")->set_entry(0);
+ return m_0a;
+}
+
+READ8_MEMBER( mbee_state::mbeepc_telcom_high_r )
+{
+/* Read of port 10A - set Telcom rom to 2nd half */
+ membank("telcom")->set_entry(1);
+ return m_0a;
+}
+
+
+/***********************************************************
+
+ Machine
+
+************************************************************/
+
+/*
+ On reset or power on, a circuit forces rom 8000-8FFF to appear at 0000-0FFF, while ram is disabled.
+ It gets set back to normal on the first attempt to write to memory. (/WR line goes active).
+*/
+
+
+/* after the first 4 bytes have been read from ROM, switch the ram back in */
+static TIMER_CALLBACK( mbee_reset )
+{
+ mbee_state *state = machine.driver_data<mbee_state>();
+ state->membank("boot")->set_entry(0);
+}
+
+static void machine_reset_common_disk(running_machine &machine)
+{
+ mbee_state *state = machine.driver_data<mbee_state>();
+ /* These values need to be fine tuned or the fdc repaired */
+ wd17xx_set_pause_time(state->m_fdc, 45); /* default is 40 usec if not set */
+// wd17xx_set_complete_command_delay(state->m_fdc, 50); /* default is 12 usec if not set */
+}
+
+MACHINE_RESET( mbee )
+{
+ mbee_state *state = machine.driver_data<mbee_state>();
+ state->membank("boot")->set_entry(1);
+ machine.scheduler().timer_set(attotime::from_usec(4), FUNC(mbee_reset));
+}
+
+MACHINE_RESET( mbee56 )
+{
+ mbee_state *state = machine.driver_data<mbee_state>();
+ machine_reset_common_disk(machine);
+ state->membank("boot")->set_entry(1);
+ machine.scheduler().timer_set(attotime::from_usec(4), FUNC(mbee_reset));
+}
+
+MACHINE_RESET( mbee64 )
+{
+ mbee_state *state = machine.driver_data<mbee_state>();
+ machine_reset_common_disk(machine);
+ state->membank("boot")->set_entry(1);
+ state->membank("bankl")->set_entry(1);
+ state->membank("bankh")->set_entry(1);
+}
+
+MACHINE_RESET( mbee128 )
+{
+ mbee_state *state = machine.driver_data<mbee_state>();
+ address_space *mem = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ machine_reset_common_disk(machine);
+ state->mbee128_50_w(*mem,0,0); // set banks to default
+ state->membank("boot")->set_entry(4); // boot time
+}
+
+MACHINE_RESET( mbee256 )
+{
+ mbee_state *state = machine.driver_data<mbee_state>();
+ UINT8 i;
+ address_space *mem = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ machine_reset_common_disk(machine);
+ for (i = 0; i < 15; i++) state->m_mbee256_was_pressed[i] = 0;
+ state->m_mbee256_q_pos = 0;
+ state->mbee256_50_w(*mem,0,0); // set banks to default
+ state->membank("boot")->set_entry(8); // boot time
+ machine.scheduler().timer_set(attotime::from_usec(4), FUNC(mbee_reset));
+}
+
+MACHINE_RESET( mbeett )
+{
+ mbee_state *state = machine.driver_data<mbee_state>();
+ UINT8 i;
+ for (i = 0; i < 15; i++) state->m_mbee256_was_pressed[i] = 0;
+ state->m_mbee256_q_pos = 0;
+ state->membank("boot")->set_entry(1);
+ machine.scheduler().timer_set(attotime::from_usec(4), FUNC(mbee_reset));
+}
+
+INTERRUPT_GEN( mbee_interrupt )
+{
+// Due to the uncertainly and hackage here, this is commented out for now - Robbbert - 05-Oct-2010
+#if 0
+ mbee_state *state = device->machine().driver_data<mbee_state>();
+
+ //address_space *space = device->machine().device("maincpu")->memory().space(AS_PROGRAM);
+ /* The printer status connects to the pio ASTB pin, and the printer changing to not
+ busy should signal an interrupt routine at B61C, (next line) but this doesn't work.
+ The line below does what the interrupt should be doing. */
+ /* But it would break any program loaded to that area of memory, such as CP/M programs */
+
+ //state->m_z80pio->strobe_a(centronics_busy_r(state->m_printer)); /* signal int when not busy (L->H) */
+ //space->write_byte(0x109, centronics_busy_r(state->m_printer));
+
+
+ /* once per frame, pulse the PIO B bit 7 - it is in the schematic as an option,
+ but need to find out what it does */
+ state->m_clock_pulse = 0x80;
+ irq0_line_hold(device);
+
+#endif
+}
+
+DRIVER_INIT_MEMBER(mbee_state,mbee)
+{
+ UINT8 *RAM = memregion("maincpu")->base();
+ membank("boot")->configure_entries(0, 2, &RAM[0x0000], 0x8000);
+ m_size = 0x4000;
+}
+
+DRIVER_INIT_MEMBER(mbee_state,mbeeic)
+{
+ UINT8 *RAM = machine().root_device().memregion("maincpu")->base();
+ membank("boot")->configure_entries(0, 2, &RAM[0x0000], 0x8000);
+
+ RAM = memregion("pakrom")->base();
+ membank("pak")->configure_entries(0, 16, &RAM[0x0000], 0x2000);
+
+ membank("pak")->set_entry(0);
+ m_size = 0x8000;
+}
+
+DRIVER_INIT_MEMBER(mbee_state,mbeepc)
+{
+ UINT8 *RAM = machine().root_device().memregion("maincpu")->base();
+ membank("boot")->configure_entries(0, 2, &RAM[0x0000], 0x8000);
+
+ RAM = machine().root_device().memregion("telcomrom")->base();
+ membank("telcom")->configure_entries(0, 2, &RAM[0x0000], 0x1000);
+
+ RAM = memregion("pakrom")->base();
+ membank("pak")->configure_entries(0, 16, &RAM[0x0000], 0x2000);
+
+ membank("pak")->set_entry(0);
+ membank("telcom")->set_entry(0);
+ m_size = 0x8000;
+}
+
+DRIVER_INIT_MEMBER(mbee_state,mbeepc85)
+{
+ UINT8 *RAM = machine().root_device().memregion("maincpu")->base();
+ membank("boot")->configure_entries(0, 2, &RAM[0x0000], 0x8000);
+
+ RAM = machine().root_device().memregion("telcomrom")->base();
+ membank("telcom")->configure_entries(0, 2, &RAM[0x0000], 0x1000);
+
+ RAM = memregion("pakrom")->base();
+ membank("pak")->configure_entries(0, 16, &RAM[0x0000], 0x2000);
+
+ membank("pak")->set_entry(5);
+ membank("telcom")->set_entry(0);
+ m_size = 0x8000;
+}
+
+DRIVER_INIT_MEMBER(mbee_state,mbeeppc)
+{
+ UINT8 *RAM = machine().root_device().memregion("maincpu")->base();
+ membank("boot")->configure_entry(0, &RAM[0x0000]);
+
+ RAM = machine().root_device().memregion("basicrom")->base();
+ membank("basic")->configure_entries(0, 2, &RAM[0x0000], 0x2000);
+ membank("boot")->configure_entry(1, &RAM[0x0000]);
+
+ RAM = machine().root_device().memregion("telcomrom")->base();
+ membank("telcom")->configure_entries(0, 2, &RAM[0x0000], 0x1000);
+
+ RAM = memregion("pakrom")->base();
+ membank("pak")->configure_entries(0, 16, &RAM[0x0000], 0x2000);
+
+ membank("pak")->set_entry(5);
+ membank("telcom")->set_entry(0);
+ membank("basic")->set_entry(0);
+ m_size = 0x8000;
+}
+
+DRIVER_INIT_MEMBER(mbee_state,mbee56)
+{
+ UINT8 *RAM = memregion("maincpu")->base();
+ membank("boot")->configure_entries(0, 2, &RAM[0x0000], 0xe000);
+ m_size = 0xe000;
+}
+
+DRIVER_INIT_MEMBER(mbee_state,mbee64)
+{
+ UINT8 *RAM = machine().root_device().memregion("maincpu")->base();
+ membank("boot")->configure_entry(0, &RAM[0x0000]);
+ membank("bankl")->configure_entry(0, &RAM[0x1000]);
+ membank("bankl")->configure_entry(1, &RAM[0x9000]);
+ membank("bankh")->configure_entry(0, &RAM[0x8000]);
+
+ RAM = memregion("bootrom")->base();
+ membank("bankh")->configure_entry(1, &RAM[0x0000]);
+ membank("boot")->configure_entry(1, &RAM[0x0000]);
+
+ m_size = 0xf000;
+}
+
+DRIVER_INIT_MEMBER(mbee_state,mbee128)
+{
+ UINT8 *RAM = machine().root_device().memregion("maincpu")->base();
+ membank("boot")->configure_entries(0, 4, &RAM[0x0000], 0x8000); // standard banks 0000
+ membank("bank1")->configure_entries(0, 4, &RAM[0x1000], 0x8000); // standard banks 1000
+ membank("bank8l")->configure_entry(1, &RAM[0x0000]); // shadow ram
+ membank("bank8h")->configure_entry(1, &RAM[0x0800]); // shadow ram
+ membank("bank9")->configure_entry(1, &RAM[0x1000]); // shadow ram
+ membank("bankfl")->configure_entry(0, &RAM[0xf000]); // shadow ram
+ membank("bankfh")->configure_entry(0, &RAM[0xf800]); // shadow ram
+
+ RAM = memregion("bootrom")->base();
+ membank("bank9")->configure_entry(0, &RAM[0x1000]); // rom
+ membank("boot")->configure_entry(4, &RAM[0x0000]); // rom at boot for 4usec
+ membank("bank8l")->configure_entry(0, &RAM[0x0000]); // rom
+ membank("bank8h")->configure_entry(0, &RAM[0x0800]); // rom
+
+ m_size = 0x8000;
+}
+
+DRIVER_INIT_MEMBER(mbee_state,mbee256)
+{
+ UINT8 *RAM = machine().root_device().memregion("maincpu")->base();
+ membank("boot")->configure_entries(0, 8, &RAM[0x0000], 0x8000); // standard banks 0000
+ membank("bank1")->configure_entries(0, 8, &RAM[0x1000], 0x8000); // standard banks 1000
+ membank("bank8l")->configure_entry(1, &RAM[0x0000]); // shadow ram
+ membank("bank8h")->configure_entry(1, &RAM[0x0800]); // shadow ram
+ membank("bank9")->configure_entry(1, &RAM[0x1000]); // shadow ram
+ membank("bankfl")->configure_entry(0, &RAM[0xf000]); // shadow ram
+ membank("bankfh")->configure_entry(0, &RAM[0xf800]); // shadow ram
+
+ RAM = memregion("bootrom")->base();
+ membank("bank9")->configure_entry(0, &RAM[0x1000]); // rom
+ membank("boot")->configure_entry(8, &RAM[0x0000]); // rom at boot for 4usec
+ membank("bank8l")->configure_entry(0, &RAM[0x0000]); // rom
+ membank("bank8h")->configure_entry(0, &RAM[0x0800]); // rom
+
+ machine().scheduler().timer_pulse(attotime::from_hz(1), FUNC(mbee_rtc_irq)); /* timer for rtc */
+ machine().scheduler().timer_pulse(attotime::from_hz(25), FUNC(mbee256_kbd)); /* timer for kbd */
+
+ m_size = 0x8000;
+}
+
+DRIVER_INIT_MEMBER(mbee_state,mbeett)
+{
+ UINT8 *RAM = machine().root_device().memregion("maincpu")->base();
+ membank("boot")->configure_entries(0, 2, &RAM[0x0000], 0x8000);
+
+ RAM = machine().root_device().memregion("telcomrom")->base();
+ membank("telcom")->configure_entries(0, 2, &RAM[0x0000], 0x1000);
+
+ RAM = memregion("pakrom")->base();
+ membank("pak")->configure_entries(0, 16, &RAM[0x0000], 0x2000);
+
+ membank("pak")->set_entry(5);
+ membank("telcom")->set_entry(0);
+
+ machine().scheduler().timer_pulse(attotime::from_hz(1), FUNC(mbee_rtc_irq)); /* timer for rtc */
+ machine().scheduler().timer_pulse(attotime::from_hz(25), FUNC(mbee256_kbd)); /* timer for kbd */
+
+ m_size = 0x8000;
+}
+
+
+/***********************************************************
+
+ Quickload
+
+ These load the standard BIN format, as well
+ as COM and MWB files.
+
+************************************************************/
+
+QUICKLOAD_LOAD( mbee )
+{
+ mbee_state *state = image.device().machine().driver_data<mbee_state>();
+ device_t *cpu = image.device().machine().device("maincpu");
+ address_space *space = image.device().machine().device("maincpu")->memory().space(AS_PROGRAM);
+ UINT16 i, j;
+ UINT8 data, sw = image.device().machine().root_device().ioport("CONFIG")->read() & 1; /* reading the dipswitch: 1 = autorun */
+
+ if (!mame_stricmp(image.filetype(), "mwb"))
+ {
+ /* mwb files - standard basic files */
+ for (i = 0; i < quickload_size; i++)
+ {
+ j = 0x8c0 + i;
+
+ if (image.fread(&data, 1) != 1)
+ {
+ image.message("Unexpected EOF");
+ return IMAGE_INIT_FAIL;
+ }
+
+ if ((j < state->m_size) || (j > 0xefff))
+ space->write_byte(j, data);
+ else
+ {
+ image.message("Not enough memory in this microbee");
+ return IMAGE_INIT_FAIL;
+ }
+ }
+
+ if (sw)
+ {
+ space->write_word(0xa2,0x801e); /* fix warm-start vector to get around some copy-protections */
+ cpu_set_reg(cpu, STATE_GENPC, 0x801e);
+ }
+ else
+ space->write_word(0xa2,0x8517);
+ }
+ else if (!mame_stricmp(image.filetype(), "com"))
+ {
+ /* com files - most com files are just machine-language games with a wrapper and don't need cp/m to be present */
+ for (i = 0; i < quickload_size; i++)
+ {
+ j = 0x100 + i;
+
+ if (image.fread(&data, 1) != 1)
+ {
+ image.message("Unexpected EOF");
+ return IMAGE_INIT_FAIL;
+ }
+
+ if ((j < state->m_size) || (j > 0xefff))
+ space->write_byte(j, data);
+ else
+ {
+ image.message("Not enough memory in this microbee");
+ return IMAGE_INIT_FAIL;
+ }
+ }
+
+ if (sw) cpu_set_reg(cpu, STATE_GENPC, 0x100);
+ }
+
+ return IMAGE_INIT_PASS;
+}
diff --git a/src/mess/machine/mboard.c b/src/mess/machine/mboard.c
new file mode 100644
index 00000000000..8200153b1d7
--- /dev/null
+++ b/src/mess/machine/mboard.c
@@ -0,0 +1,557 @@
+/**********************************************************************
+
+ Mephisto Chess Computers
+
+**********************************************************************/
+#include "emu.h"
+#include "machine/mboard.h"
+
+static void set_artwork(running_machine &machine );
+static void check_board_buttons(running_machine &machine );
+
+UINT8 mboard_lcd_invert;
+UINT8 mboard_key_select;
+UINT8 mboard_key_selector;
+
+static const int start_board[64] =
+{
+ BR, BN, BB, BQ, BK, BB, BN, BR,
+ BP, BP, BP, BP, BP, BP, BP, BP,
+ EM, EM, EM, EM, EM, EM, EM, EM,
+ EM, EM, EM, EM, EM, EM, EM, EM,
+ EM, EM, EM, EM, EM, EM, EM, EM,
+ EM, EM, EM, EM, EM, EM, EM, EM,
+ WP, WP, WP, WP, WP, WP, WP, WP,
+ WR, WN, WB, WQ, WK, WB, WN, WR
+};
+
+static UINT8 border_pieces[12] = {WK,WQ,WR,WB,WN,WP,BK,BQ,BR,BB,BN,BP,};
+
+static int m_board[64];
+static int save_board[64];
+static UINT16 Line18_LED;
+static UINT16 Line18_REED;
+
+static MOUSE_HOLD mouse_hold;
+
+static int read_board_flag = TRUE;
+
+static int get_first_bit(UINT8 data)
+{
+ int i;
+
+ for (i = 0; i < 8; i++)
+ if (BIT(data, i))
+ return i;
+
+ return NOT_VALID;
+}
+
+static int get_first_cleared_bit(UINT8 data)
+{
+ int i;
+
+ for (i=0;i<8;i++)
+ if (!BIT(data, i))
+ return i;
+
+ return NOT_VALID;
+}
+
+static UINT8 read_board(void)
+{
+ UINT8 i_18, i_AH;
+ UINT8 data;
+
+ data = 0xff;
+
+/*
+
+Example board scan:
+Starting postion and pawn on E2 is lifted
+
+
+mask: 7f 0111 1111 Line 8
+data: 0 0000 0000 all fields occupied
+mask: bf 1011 1111 Line 7
+data: 0 0000 0000 all fields occupied
+mask: df 1101 1111 Line 6
+data: ff 1111 1111 all fields empty
+mask: ef 1110 1111 Line 5
+data: ff 1111 1111 all fields empty
+mask: f7 1111 0111 Line 4
+data: ff 1111 1111 all fields empty
+mask: fb 1111 1011 Line 3
+data: ff 1111 1111 all fields empty
+mask: fd 1111 1101 Line 2
+data: 10 0001 0000 E2 is empty rest is occupied
+mask: fe 1111 1110 Line 1
+data: 0 0000 0000 all fields occupied
+
+
+*/
+
+/* looking for cleared bit in mask Line18_REED => current line */
+
+ if (data && Line18_REED)
+ {
+ i_18=get_first_cleared_bit(Line18_REED);
+
+/* looking for a piece in this line and clear bit in data if found */
+
+ for ( i_AH = 0; i_AH < 8; i_AH = i_AH + 1)
+ if (IsPiece(64-(i_18*8 + 8-i_AH)))
+ data &= ~(1 << i_AH); // clear bit
+
+ read_board_flag = TRUE;
+ }
+
+ return data;
+}
+
+
+static void write_board( running_machine &machine, UINT8 data)
+{
+
+ Line18_REED=data;
+
+ if (read_board_flag && !strcmp(machine.system().name,"glasgow") ) //HACK
+ Line18_LED = 0;
+ else
+ Line18_LED = data;
+
+ read_board_flag = FALSE;
+
+ if (data == 0xff)
+ mboard_key_selector = 0;
+}
+
+
+
+static void write_LED(UINT8 data)
+{
+ int i;
+ UINT8 i_AH, i_18;
+ UINT8 LED;
+
+ mboard_lcd_invert = 1;
+/*
+
+Example: turn led E2 on
+
+mask: fd 1111 1101 Line 2
+data: 10 0001 0000 Line E
+
+*/
+
+ for (i=0; i < 64; i++) /* all LED's off */
+ output_set_led_value(i, 0);
+
+ if (Line18_LED)
+ {
+ for (i_AH = 0; i_AH < 8; i_AH++) /* turn LED on depending on bit masks */
+ {
+ if (BIT(data,i_AH))
+ {
+ for (i_18 = 0; i_18 < 8; i_18++)
+ {
+ LED = (i_18*8 + 8-i_AH-1);
+ if (!(Line18_LED & (1 << i_18))) /* cleared bit */
+ output_set_led_value(LED, 1);
+ //else
+ // output_set_led_value(LED, 0);
+ }
+ }
+ }
+ }
+
+}
+
+
+
+READ8_HANDLER( mboard_read_board_8 )
+{
+ UINT8 data;
+
+ data=read_board();
+ logerror("Read Board Port Data = %d\n ",data);
+ return data;
+}
+
+READ16_HANDLER( mboard_read_board_16 )
+{
+ UINT8 data;
+
+ data=read_board();
+ return data << 8;
+}
+
+READ32_HANDLER( mboard_read_board_32 )
+{
+ UINT8 data;
+
+ data=read_board();
+ return data<<24;
+}
+
+WRITE8_HANDLER( mboard_write_board_8 )
+{
+ write_board(space->machine(),data);
+ logerror("Write Board Port Data = %02x\n",data);
+}
+
+WRITE16_HANDLER( mboard_write_board_16 )
+{
+ if (data & 0xff) write_board(space->machine(),data);
+ logerror("write board 16 %08x\n",data);
+ write_board(space->machine(),data>>8);
+}
+
+WRITE32_HANDLER( mboard_write_board_32 )
+{
+// data |= data << 24;
+//printf("write board %08x %08x\n",offset,data);
+ logerror("write board 32 o: %08x d: %08x\n",offset,data);
+ if (offset) write_board(space->machine(),data);
+ else write_board(space->machine(),data>>24);
+}
+
+WRITE8_HANDLER( mboard_write_LED_8 )
+{
+ write_LED(data);
+ device_spin_until_time(&space->device(), attotime::from_usec(7));
+}
+
+WRITE16_HANDLER( mboard_write_LED_16 )
+{
+ write_LED(data >> 8);
+ device_spin_until_time(&space->device(), attotime::from_usec(9));
+}
+
+WRITE32_HANDLER( mboard_write_LED_32 )
+{
+// data = data | data << 24;
+//printf("write LED %08x %08x\n",offset,data);
+ if (offset) write_LED(data);
+ else write_LED(data >> 24);
+ logerror("write LED 32 o: %08x d: %08x\n",offset,data);
+// device_spin_until_time(&space->device(), ATTOTIME_IN_USEC(20));
+}
+
+
+/* save states callback */
+
+static void board_presave(running_machine *machine)
+{
+ int i;
+ for (i=0;i<64;i++)
+ save_board[i]=m_board[i];
+}
+
+static void board_postload(running_machine *machine)
+{
+ int i;
+ for (i=0;i<64;i++)
+ m_board[i]=save_board[i];
+
+}
+
+void mboard_savestate_register(running_machine &machine)
+{
+ state_save_register_global_array(machine,save_board);
+ machine.save().register_postload(save_prepost_delegate(FUNC(board_postload),&machine));
+ machine.save().register_presave(save_prepost_delegate(FUNC(board_presave),&machine));
+}
+
+void mboard_set_board( void )
+{
+ int i;
+ for (i=0;i<64;i++)
+ m_board[i]=start_board[i];
+}
+
+static void clear_board( void )
+{
+ int i;
+ for (i=0;i<64;i++)
+ m_board[i]=EM;
+}
+
+static void set_artwork ( running_machine &machine )
+{
+ int i;
+ for (i=0;i<64;i++)
+ output_set_indexed_value("P", i, m_board[i]);
+}
+
+void mboard_set_border_pieces (void)
+{
+ int i;
+ for (i=0;i<12;i++)
+ output_set_indexed_value("Q", i, border_pieces[i]);
+}
+
+TIMER_DEVICE_CALLBACK( mboard_update_artwork )
+{
+ check_board_buttons(timer.machine());
+ set_artwork(timer.machine());
+ mboard_set_border_pieces();
+}
+
+static void check_board_buttons ( running_machine &machine )
+{
+ int field;
+ int i;
+ UINT8 port_input=0;
+ UINT8 data = 0xff;
+ static const char *const keynames[] = { "LINE2", "LINE3", "LINE4", "LINE5", "LINE6", "LINE7", "LINE8", "LINE9" };
+ static UINT8 board_row = 0;
+ static UINT16 mouse_down = 0;
+ UINT8 pos2num_res = 0;
+ board_row++;
+ board_row &= 7;
+ int click_on_border_piece=FALSE;
+
+
+/* check click on border pieces */
+ i=0;
+ port_input=machine.root_device().ioport("B_BLACK")->read();
+ if (port_input)
+ {
+ i=get_first_bit(port_input)+6;
+ click_on_border_piece=TRUE;
+ }
+
+ port_input=machine.root_device().ioport("B_WHITE")->read();
+ if (port_input)
+ {
+ i=get_first_bit(port_input);
+ click_on_border_piece=TRUE;
+ }
+
+ if (click_on_border_piece)
+ {
+ if (!mouse_down)
+ {
+ if (border_pieces[i] > 12 ) /* second click on selected border piece */
+ {
+ mouse_hold.border_piece=FALSE;
+ border_pieces[i]=border_pieces[i]-12;
+ mouse_hold.from=0;
+ mouse_hold.piece=0;
+ }
+ else if (!mouse_hold.piece) /*select border piece */
+ {
+ if (mouse_hold.border_piece)
+ border_pieces[mouse_hold.from]=border_pieces[mouse_hold.from]-12;
+
+ mouse_hold.from=i;
+ mouse_hold.piece=border_pieces[i];
+ border_pieces[i]=border_pieces[i]+12;
+ mouse_hold.border_piece=TRUE;
+ }
+
+ mouse_down = board_row + 1;
+
+ }
+ return;
+ }
+
+
+/* check click on board */
+ data = machine.root_device().ioport(keynames[board_row])->read_safe(0xff);
+
+ if ((data != 0xff) && (!mouse_down) )
+ {
+
+ pos2num_res = pos_to_num(data);
+ field=64-(board_row*8+8-pos2num_res);
+
+
+ if (!(pos2num_res < 8))
+ logerror("Position out of bound!");
+
+ else if ((mouse_hold.piece) && (!IsPiece(field)))
+ {
+ /* Moving a piece onto a blank */
+ m_board[field] = mouse_hold.piece;
+
+ if (mouse_hold.border_piece)
+ {
+ border_pieces[mouse_hold.from]=border_pieces[mouse_hold.from]-12;
+ }else if ( field != mouse_hold.from ) /* Put a selected piece back to the source field */
+ m_board[mouse_hold.from] = 0;
+
+
+ mouse_hold.from = 0;
+ mouse_hold.piece = 0;
+ mouse_hold.border_piece=FALSE;
+ }
+ else if ((!mouse_hold.piece) )
+ {
+ /* Picking up a piece */
+
+ if (IsPiece(field))
+ {
+ mouse_hold.from = field;
+ mouse_hold.piece = m_board[field];
+ m_board[field] = m_board[field]+12;
+ }
+
+ }
+
+ mouse_down = board_row + 1;
+ }
+ else if ((data == 0xff) && (mouse_down == (board_row + 1))) /* Wait for mouse to be released */
+ mouse_down = 0;
+
+/* check click on border - remove selected piece*/
+ if (machine.root_device().ioport("LINE10")->read_safe(0x01))
+ {
+ if (mouse_hold.piece)
+ {
+ if (mouse_hold.border_piece)
+ border_pieces[mouse_hold.from]=border_pieces[mouse_hold.from]-12;
+ else
+ m_board[mouse_hold.from] = 0;
+
+ mouse_hold.from = 0;
+ mouse_hold.piece = 0;
+ mouse_hold.border_piece = FALSE;
+ }
+
+ return;
+ }
+
+/* check additional buttons */
+ if (data == 0xff)
+ {
+
+ port_input=machine.root_device().ioport("B_BUTTONS")->read();
+ if (port_input==0x01)
+ {
+ clear_board();
+ return;
+ }else if (port_input==0x02)
+ {
+ mboard_set_board();
+ return;
+ }
+
+
+ }
+
+}
+
+extern INPUT_PORTS_START( chessboard )
+
+ PORT_START("LINE2")
+ 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_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD)
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD)
+ PORT_START("LINE3")
+ 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_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD)
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD)
+ PORT_START("LINE4")
+ 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_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD)
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD)
+ PORT_START("LINE5")
+ 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_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD)
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD)
+ PORT_START("LINE6")
+ 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_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD)
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD)
+ PORT_START("LINE7")
+ 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_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD)
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD)
+ PORT_START("LINE8")
+ 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_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD)
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD)
+ PORT_START("LINE9")
+ 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_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD)
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD)
+
+ PORT_START("LINE10")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD)
+
+ PORT_START("B_WHITE")
+ 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_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD)
+ PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD)
+
+ PORT_START("B_BLACK")
+ 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_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD)
+ PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD)
+
+ PORT_START("B_BUTTONS")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD)
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD)
+
+ PORT_START("MOUSE_X")
+ PORT_BIT( 0xffff, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(100)
+
+ PORT_START("MOUSE_Y")
+ PORT_BIT( 0xffff, 0x00, IPT_MOUSE_Y ) PORT_SENSITIVITY(100)
+
+ PORT_START("BUTTON_L")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON2) PORT_CODE(MOUSECODE_BUTTON1) PORT_NAME("left button")
+
+ PORT_START("BUTTON_R")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_CODE(MOUSECODE_BUTTON2) PORT_NAME("right button")
+
+
+INPUT_PORTS_END
diff --git a/src/mess/machine/mboard.h b/src/mess/machine/mboard.h
new file mode 100644
index 00000000000..4aab4790f84
--- /dev/null
+++ b/src/mess/machine/mboard.h
@@ -0,0 +1,98 @@
+/**********************************************************************
+
+ Mephisto Chess Computers
+
+**********************************************************************/
+
+#ifndef __MBOARD_H__
+#define __MBOARD_H__
+
+#include "emu.h"
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+enum
+{
+ EM, /*No piece*/
+ BP,
+ BN,
+ BB,
+ BR,
+ BQ,
+ BK,
+ WP,
+ WN,
+ WB,
+ WR,
+ WQ,
+ WK
+};
+
+#define NOT_VALID 99
+#define BORDER_PIECE 64
+
+#define IsPiece(x) ((m_board[x] >=1) && (m_board[x] <=12))
+
+#define IsBitSet(x,y) ( y & (1<<x) ) //ersetzen durch BIT
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct {
+ int border_piece;
+ UINT8 from;
+ UINT8 piece;
+} MOUSE_HOLD;
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+READ8_HANDLER( mboard_read_board_8 );
+WRITE8_HANDLER( mboard_write_board_8 );
+WRITE8_HANDLER( mboard_write_LED_8 );
+
+READ16_HANDLER( mboard_read_board_16 );
+WRITE16_HANDLER( mboard_write_board_16 );
+WRITE16_HANDLER( mboard_write_LED_16 );
+
+READ32_HANDLER( mboard_read_board_32 );
+WRITE32_HANDLER( mboard_write_board_32 );
+WRITE32_HANDLER( mboard_write_LED_32 );
+
+TIMER_DEVICE_CALLBACK( mboard_update_artwork );
+
+void mboard_savestate_register(running_machine &machine);
+
+void mboard_set_board( void );
+void mboard_set_border_pieces (void);
+
+INLINE UINT8 pos_to_num(UINT8 val)
+{
+ switch (val)
+ {
+ case 0xfe: return 7;
+ case 0xfd: return 6;
+ case 0xfb: return 5;
+ case 0xf7: return 4;
+ case 0xef: return 3;
+ case 0xdf: return 2;
+ case 0xbf: return 1;
+ case 0x7f: return 0;
+ default: return 0xff;
+ }
+}
+
+/***************************************************************************
+ GLOBALS
+***************************************************************************/
+
+extern UINT8 mboard_lcd_invert;
+extern UINT8 mboard_key_select;
+extern UINT8 mboard_key_selector;
+
+#endif /* __MBOARD_H__ */
diff --git a/src/mess/machine/mc68328.c b/src/mess/machine/mc68328.c
new file mode 100644
index 00000000000..134f018a532
--- /dev/null
+++ b/src/mess/machine/mc68328.c
@@ -0,0 +1,2833 @@
+/**********************************************************************
+
+ 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 "includes/mc68328.h"
+#include "mc68328.h"
+
+#define VERBOSE_LEVEL (0)
+
+INLINE void 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 );
+ }
+}
+
+static void mc68328_set_interrupt_line(device_t *device, UINT32 line, UINT32 active)
+{
+ mc68328_t* mc68328 = mc68328_get_safe_token( device );
+ device_t *cpu = device->machine().device(mc68328->iface->m68k_cpu_tag);
+
+ if(active)
+ {
+ mc68328->regs.ipr |= line;
+
+ if(!(mc68328->regs.imr & line) && !(mc68328->regs.isr & line))
+ {
+ mc68328->regs.isr |= line;
+
+ if(mc68328->regs.isr & INT_M68K_LINE7)
+ {
+ device_set_input_line_and_vector(cpu, M68K_IRQ_7, ASSERT_LINE, mc68328->regs.ivr | 0x07);
+ }
+ else if(mc68328->regs.isr & INT_M68K_LINE6)
+ {
+ device_set_input_line_and_vector(cpu, M68K_IRQ_6, ASSERT_LINE, mc68328->regs.ivr | 0x06);
+ }
+ else if(mc68328->regs.isr & INT_M68K_LINE5)
+ {
+ device_set_input_line_and_vector(cpu, M68K_IRQ_5, ASSERT_LINE, mc68328->regs.ivr | 0x05);
+ }
+ else if(mc68328->regs.isr & INT_M68K_LINE4)
+ {
+ device_set_input_line_and_vector(cpu, M68K_IRQ_4, ASSERT_LINE, mc68328->regs.ivr | 0x04);
+ }
+ else if(mc68328->regs.isr & INT_M68K_LINE3)
+ {
+ device_set_input_line_and_vector(cpu, M68K_IRQ_3, ASSERT_LINE, mc68328->regs.ivr | 0x03);
+ }
+ else if(mc68328->regs.isr & INT_M68K_LINE2)
+ {
+ device_set_input_line_and_vector(cpu, M68K_IRQ_2, ASSERT_LINE, mc68328->regs.ivr | 0x02);
+ }
+ else if(mc68328->regs.isr & INT_M68K_LINE1)
+ {
+ device_set_input_line_and_vector(cpu, M68K_IRQ_1, ASSERT_LINE, mc68328->regs.ivr | 0x01);
+ }
+ }
+ }
+ else
+ {
+ mc68328->regs.isr &= ~line;
+
+ if((line & INT_M68K_LINE7) && !(mc68328->regs.isr & INT_M68K_LINE7))
+ {
+ device_set_input_line(cpu, M68K_IRQ_7, CLEAR_LINE);
+ }
+ if((line & INT_M68K_LINE6) && !(mc68328->regs.isr & INT_M68K_LINE6))
+ {
+ device_set_input_line(cpu, M68K_IRQ_6, CLEAR_LINE);
+ }
+ if((line & INT_M68K_LINE5) && !(mc68328->regs.isr & INT_M68K_LINE5))
+ {
+ device_set_input_line(cpu, M68K_IRQ_5, CLEAR_LINE);
+ }
+ if((line & INT_M68K_LINE4) && !(mc68328->regs.isr & INT_M68K_LINE4))
+ {
+ device_set_input_line(cpu, M68K_IRQ_4, CLEAR_LINE);
+ }
+ if((line & INT_M68K_LINE3) && !(mc68328->regs.isr & INT_M68K_LINE3))
+ {
+ device_set_input_line(cpu, M68K_IRQ_3, CLEAR_LINE);
+ }
+ if((line & INT_M68K_LINE2) && !(mc68328->regs.isr & INT_M68K_LINE2))
+ {
+ device_set_input_line(cpu, M68K_IRQ_2, CLEAR_LINE);
+ }
+ if((line & INT_M68K_LINE1) && !(mc68328->regs.isr & INT_M68K_LINE1))
+ {
+ device_set_input_line(cpu, M68K_IRQ_1, CLEAR_LINE);
+ }
+ }
+}
+
+static void mc68328_poll_port_d_interrupts(device_t *device)
+{
+ mc68328_t* mc68328 = mc68328_get_safe_token( device );
+ UINT8 line_transitions = mc68328->regs.pddataedge & mc68328->regs.pdirqedge;
+ UINT8 line_holds = mc68328->regs.pddata &~ mc68328->regs.pdirqedge;
+ UINT8 line_interrupts = (line_transitions | line_holds) & mc68328->regs.pdirqen;
+
+ if(line_interrupts)
+ {
+ mc68328_set_interrupt_line(device, line_interrupts << 8, 1);
+ }
+ else
+ {
+ mc68328_set_interrupt_line(device, INT_KBDINTS, 0);
+ }
+}
+
+void mc68328_set_penirq_line(device_t *device, int state)
+{
+ mc68328_t* mc68328 = mc68328_get_safe_token( device );
+
+ if(state)
+ {
+ mc68328_set_interrupt_line(device, INT_PEN, 1);
+ }
+ else
+ {
+ mc68328->regs.ipr &= ~INT_PEN;
+ mc68328_set_interrupt_line(device, INT_PEN, 0);
+ }
+}
+
+void mc68328_set_port_d_lines(device_t *device, UINT8 state, int bit)
+{
+ mc68328_t* mc68328 = mc68328_get_safe_token( device );
+ UINT8 old_button_state = mc68328->regs.pddata;
+
+ if(state & (1 << bit))
+ {
+ mc68328->regs.pddata |= (1 << bit);
+ }
+ else
+ {
+ mc68328->regs.pddata &= ~(1 << bit);
+ }
+
+ mc68328->regs.pddataedge |= ~old_button_state & mc68328->regs.pddata;
+
+ mc68328_poll_port_d_interrupts(device);
+}
+
+static UINT32 mc68328_get_timer_frequency(device_t *device, UINT32 index)
+{
+ mc68328_t* mc68328 = mc68328_get_safe_token( device );
+ UINT32 frequency = 0;
+
+ switch(mc68328->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 /= (mc68328->regs.tprer[index] + 1);
+
+ return frequency;
+}
+
+static void mc68328_maybe_start_timer(device_t *device, UINT32 index, UINT32 new_enable)
+{
+ mc68328_t* mc68328 = mc68328_get_safe_token( device );
+
+ if((mc68328->regs.tctl[index] & TCTL_TEN) == TCTL_TEN_ENABLE && (mc68328->regs.tctl[index] & TCTL_CLKSOURCE) > TCTL_CLKSOURCE_STOP)
+ {
+ if((mc68328->regs.tctl[index] & TCTL_CLKSOURCE) == TCTL_CLKSOURCE_TIN)
+ {
+ mc68328->gptimer[index]->adjust(attotime::never);
+ }
+ else if(mc68328->regs.tcmp[index] == 0)
+ {
+ mc68328->gptimer[index]->adjust(attotime::never);
+ }
+ else
+ {
+ UINT32 frequency = mc68328_get_timer_frequency(device, index);
+ attotime period = (attotime::from_hz(frequency) * mc68328->regs.tcmp[index]);
+
+ if(new_enable)
+ {
+ mc68328->regs.tcn[index] = 0x0000;
+ }
+
+ mc68328->gptimer[index]->adjust(period);
+ }
+ }
+ else
+ {
+ mc68328->gptimer[index]->adjust(attotime::never);
+ }
+}
+
+static void mc68328_timer_compare_event(device_t *device, UINT32 index)
+{
+ mc68328_t* mc68328 = mc68328_get_safe_token( device );
+
+ mc68328->regs.tcn[index] = mc68328->regs.tcmp[index];
+ mc68328->regs.tstat[index] |= TSTAT_COMP;
+
+ if((mc68328->regs.tctl[index] & TCTL_FRR) == TCTL_FRR_RESTART)
+ {
+ UINT32 frequency = mc68328_get_timer_frequency(device, index);
+
+ if(frequency > 0)
+ {
+ attotime period = attotime::from_hz(frequency) * mc68328->regs.tcmp[index];
+
+ mc68328->regs.tcn[index] = 0x0000;
+
+ mc68328->gptimer[index]->adjust(period);
+ }
+ else
+ {
+ mc68328->gptimer[index]->adjust(attotime::never);
+ }
+ }
+ else
+ {
+ UINT32 frequency = mc68328_get_timer_frequency(device, index);
+
+ if(frequency > 0)
+ {
+ attotime period = attotime::from_hz(frequency) * 0x10000;
+
+ mc68328->gptimer[index]->adjust(period);
+ }
+ else
+ {
+ mc68328->gptimer[index]->adjust(attotime::never);
+ }
+ }
+ if((mc68328->regs.tctl[index] & TCTL_IRQEN) == TCTL_IRQEN_ENABLE)
+ {
+ mc68328_set_interrupt_line(device, (index == 0) ? INT_TIMER1 : INT_TIMER2, 1);
+ }
+}
+
+static TIMER_CALLBACK( mc68328_timer1_hit )
+{
+ device_t *device = machine.device(MC68328_TAG);
+
+ mc68328_timer_compare_event(device, 0);
+}
+
+static TIMER_CALLBACK( mc68328_timer2_hit )
+{
+ device_t *device = machine.device(MC68328_TAG);
+
+ mc68328_timer_compare_event(device, 1);
+}
+
+static TIMER_CALLBACK( mc68328_pwm_transition )
+{
+ device_t *device = machine.device(MC68328_TAG);
+ mc68328_t* mc68328 = mc68328_get_safe_token( device );
+
+ if(mc68328->regs.pwmw >= mc68328->regs.pwmp || mc68328->regs.pwmw == 0 || mc68328->regs.pwmp == 0)
+ {
+ mc68328->pwm->adjust(attotime::never);
+ return;
+ }
+
+ if(((mc68328->regs.pwmc & PWMC_POL) == 0 && (mc68328->regs.pwmc & PWMC_PIN) != 0) ||
+ ((mc68328->regs.pwmc & PWMC_POL) != 0 && (mc68328->regs.pwmc & PWMC_PIN) == 0))
+ {
+ UINT32 frequency = 32768 * 506;
+ UINT32 divisor = 4 << (mc68328->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) * (mc68328->regs.pwmp - mc68328->regs.pwmw);
+
+ mc68328->pwm->adjust(period);
+
+ if(mc68328->regs.pwmc & PWMC_IRQEN)
+ {
+ mc68328_set_interrupt_line(device, INT_PWM, 1);
+ }
+ }
+ else
+ {
+ UINT32 frequency = 32768 * 506;
+ UINT32 divisor = 4 << (mc68328->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) * mc68328->regs.pwmw;
+
+ mc68328->pwm->adjust(period);
+ }
+
+ mc68328->regs.pwmc ^= PWMC_PIN;
+
+ if( mc68328->iface->out_pwm_func )
+ {
+ (mc68328->iface->out_pwm_func)( device, 0, (mc68328->regs.pwmc & PWMC_PIN) ? 1 : 0 );
+ }
+}
+
+static TIMER_CALLBACK( mc68328_rtc_tick )
+{
+ device_t *device = machine.device(MC68328_TAG);
+ mc68328_t* mc68328 = mc68328_get_safe_token( device );
+
+ if(mc68328->regs.rtcctl & RTCCTL_ENABLE)
+ {
+ UINT32 set_int = 0;
+
+ mc68328->regs.hmsr++;
+
+ if(mc68328->regs.rtcienr & RTCINT_SECOND)
+ {
+ set_int = 1;
+ mc68328->regs.rtcisr |= RTCINT_SECOND;
+ }
+
+ if((mc68328->regs.hmsr & 0x0000003f) == 0x0000003c)
+ {
+ mc68328->regs.hmsr &= 0xffffffc0;
+ mc68328->regs.hmsr += 0x00010000;
+
+ if(mc68328->regs.rtcienr & RTCINT_MINUTE)
+ {
+ set_int = 1;
+ mc68328->regs.rtcisr |= RTCINT_MINUTE;
+ }
+
+ if((mc68328->regs.hmsr & 0x003f0000) == 0x003c0000)
+ {
+ mc68328->regs.hmsr &= 0xffc0ffff;
+ mc68328->regs.hmsr += 0x0100000;
+
+ if((mc68328->regs.hmsr & 0x1f000000) == 0x18000000)
+ {
+ mc68328->regs.hmsr &= 0xe0ffffff;
+
+ if(mc68328->regs.rtcienr & RTCINT_DAY)
+ {
+ set_int = 1;
+ mc68328->regs.rtcisr |= RTCINT_DAY;
+ }
+ }
+ }
+
+ if(mc68328->regs.stpwtch != 0x003f)
+ {
+ mc68328->regs.stpwtch--;
+ mc68328->regs.stpwtch &= 0x003f;
+
+ if(mc68328->regs.stpwtch == 0x003f)
+ {
+ if(mc68328->regs.rtcienr & RTCINT_STOPWATCH)
+ {
+ set_int = 1;
+ mc68328->regs.rtcisr |= RTCINT_STOPWATCH;
+ }
+ }
+ }
+ }
+
+ if(mc68328->regs.hmsr == mc68328->regs.alarm)
+ {
+ if(mc68328->regs.rtcienr & RTCINT_ALARM)
+ {
+ set_int = 1;
+ mc68328->regs.rtcisr |= RTCINT_STOPWATCH;
+ }
+ }
+
+ if(set_int)
+ {
+ mc68328_set_interrupt_line(device, INT_RTC, 1);
+ }
+ else
+ {
+ mc68328_set_interrupt_line(device, INT_RTC, 0);
+ }
+ }
+}
+
+WRITE16_DEVICE_HANDLER( mc68328_w )
+{
+ mc68328_t* mc68328 = mc68328_get_safe_token( device );
+ UINT32 address = offset << 1;
+ UINT16 temp16[4] = { 0 };
+ UINT32 imr_old = mc68328->regs.imr, imr_diff;
+
+ switch(address)
+ {
+ case 0x000:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: Unknown address (0xfff001) = %02x\n", data & 0x00ff);
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: SCR = %02x\n", (data >> 8) & 0x00ff);
+ }
+ break;
+
+ case 0x100:
+ verboselog(device->machine(), 2, "mc68328_w: GRPBASEA = %04x\n", data);
+ mc68328->regs.grpbasea = data;
+ break;
+
+ case 0x102:
+ verboselog(device->machine(), 2, "mc68328_w: GRPBASEB = %04x\n", data);
+ mc68328->regs.grpbaseb = data;
+ break;
+
+ case 0x104:
+ verboselog(device->machine(), 2, "mc68328_w: GRPBASEC = %04x\n", data);
+ mc68328->regs.grpbasec = data;
+ break;
+
+ case 0x106:
+ verboselog(device->machine(), 2, "mc68328_w: GRPBASED = %04x\n", data);
+ mc68328->regs.grpbased = data;
+ break;
+
+ case 0x108:
+ verboselog(device->machine(), 2, "mc68328_w: GRPMASKA = %04x\n", data);
+ mc68328->regs.grpmaska = data;
+ break;
+
+ case 0x10a:
+ verboselog(device->machine(), 2, "mc68328_w: GRPMASKB = %04x\n", data);
+ mc68328->regs.grpmaskb = data;
+ break;
+
+ case 0x10c:
+ verboselog(device->machine(), 2, "mc68328_w: GRPMASKC = %04x\n", data);
+ mc68328->regs.grpmaskc = data;
+ break;
+
+ case 0x10e:
+ verboselog(device->machine(), 2, "mc68328_w: GRPMASKD = %04x\n", data);
+ mc68328->regs.grpmaskd = data;
+ break;
+
+ case 0x110:
+ verboselog(device->machine(), 5, "mc68328_w: CSA0(0) = %04x\n", data);
+ mc68328->regs.csa0 &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.csa0 |= data & mem_mask;
+ break;
+
+ case 0x112:
+ verboselog(device->machine(), 5, "mc68328_w: CSA0(16) = %04x\n", data);
+ mc68328->regs.csa0 &= ~(mem_mask << 16);
+ mc68328->regs.csa0 |= (data & mem_mask) << 16;
+ break;
+
+ case 0x114:
+ verboselog(device->machine(), 5, "mc68328_w: CSA1(0) = %04x\n", data);
+ mc68328->regs.csa1 &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.csa1 |= data & mem_mask;
+ break;
+
+ case 0x116:
+ verboselog(device->machine(), 5, "mc68328_w: CSA1(16) = %04x\n", data);
+ mc68328->regs.csa1 &= ~(mem_mask << 16);
+ mc68328->regs.csa1 |= (data & mem_mask) << 16;
+ break;
+
+ case 0x118:
+ verboselog(device->machine(), 5, "mc68328_w: CSA2(0) = %04x\n", data);
+ mc68328->regs.csa2 &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.csa2 |= data & mem_mask;
+ break;
+
+ case 0x11a:
+ verboselog(device->machine(), 5, "mc68328_w: CSA2(16) = %04x\n", data);
+ mc68328->regs.csa2 &= ~(mem_mask << 16);
+ mc68328->regs.csa2 |= (data & mem_mask) << 16;
+ break;
+
+ case 0x11c:
+ verboselog(device->machine(), 5, "mc68328_w: CSA3(0) = %04x\n", data);
+ mc68328->regs.csa3 &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.csa3 |= data & mem_mask;
+ break;
+
+ case 0x11e:
+ verboselog(device->machine(), 5, "mc68328_w: CSA3(16) = %04x\n", data);
+ mc68328->regs.csa3 &= ~(mem_mask << 16);
+ mc68328->regs.csa3 |= (data & mem_mask) << 16;
+ break;
+
+ case 0x120:
+ verboselog(device->machine(), 5, "mc68328_w: CSB0(0) = %04x\n", data);
+ mc68328->regs.csb0 &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.csb0 |= data & mem_mask;
+ break;
+
+ case 0x122:
+ verboselog(device->machine(), 5, "mc68328_w: CSB0(16) = %04x\n", data);
+ mc68328->regs.csb0 &= ~(mem_mask << 16);
+ mc68328->regs.csb0 |= (data & mem_mask) << 16;
+ break;
+
+ case 0x124:
+ verboselog(device->machine(), 5, "mc68328_w: CSB1(0) = %04x\n", data);
+ mc68328->regs.csb1 &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.csb1 |= data & mem_mask;
+ break;
+
+ case 0x126:
+ verboselog(device->machine(), 5, "mc68328_w: CSB1(16) = %04x\n", data);
+ mc68328->regs.csb1 &= ~(mem_mask << 16);
+ mc68328->regs.csb1 |= (data & mem_mask) << 16;
+ break;
+
+ case 0x128:
+ verboselog(device->machine(), 5, "mc68328_w: CSB2(0) = %04x\n", data);
+ mc68328->regs.csb2 &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.csb2 |= data & mem_mask;
+ break;
+
+ case 0x12a:
+ verboselog(device->machine(), 5, "mc68328_w: CSB2(16) = %04x\n", data);
+ mc68328->regs.csb2 &= ~(mem_mask << 16);
+ mc68328->regs.csb2 |= (data & mem_mask) << 16;
+ break;
+
+ case 0x12c:
+ verboselog(device->machine(), 5, "mc68328_w: CSB3(0) = %04x\n", data);
+ mc68328->regs.csb3 &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.csb3 |= data & mem_mask;
+ break;
+
+ case 0x12e:
+ verboselog(device->machine(), 5, "mc68328_w: CSB3(16) = %04x\n", data);
+ mc68328->regs.csb3 &= ~(mem_mask << 16);
+ mc68328->regs.csb3 |= (data & mem_mask) << 16;
+ break;
+
+ case 0x130:
+ verboselog(device->machine(), 5, "mc68328_w: CSC0(0) = %04x\n", data);
+ mc68328->regs.csc0 &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.csc0 |= data & mem_mask;
+ break;
+
+ case 0x132:
+ verboselog(device->machine(), 5, "mc68328_w: CSC0(16) = %04x\n", data);
+ mc68328->regs.csc0 &= ~(mem_mask << 16);
+ mc68328->regs.csc0 |= (data & mem_mask) << 16;
+ break;
+
+ case 0x134:
+ verboselog(device->machine(), 5, "mc68328_w: CSC1(0) = %04x\n", data);
+ mc68328->regs.csc1 &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.csc1 |= data & mem_mask;
+ break;
+
+ case 0x136:
+ verboselog(device->machine(), 5, "mc68328_w: CSC1(16) = %04x\n", data);
+ mc68328->regs.csc1 &= ~(mem_mask << 16);
+ mc68328->regs.csc1 |= (data & mem_mask) << 16;
+ break;
+
+ case 0x138:
+ verboselog(device->machine(), 5, "mc68328_w: CSC2(0) = %04x\n", data);
+ mc68328->regs.csc2 &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.csc2 |= data & mem_mask;
+ break;
+
+ case 0x13a:
+ verboselog(device->machine(), 5, "mc68328_w: CSC2(16) = %04x\n", data);
+ mc68328->regs.csc2 &= ~(mem_mask << 16);
+ mc68328->regs.csc2 |= (data & mem_mask) << 16;
+ break;
+
+ case 0x13c:
+ verboselog(device->machine(), 5, "mc68328_w: CSC3(0) = %04x\n", data);
+ mc68328->regs.csc3 &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.csc3 |= data & mem_mask;
+ break;
+
+ case 0x13e:
+ verboselog(device->machine(), 5, "mc68328_w: CSC3(16) = %04x\n", data);
+ mc68328->regs.csc3 &= ~(mem_mask << 16);
+ mc68328->regs.csc3 |= (data & mem_mask) << 16;
+ break;
+
+ case 0x140:
+ verboselog(device->machine(), 5, "mc68328_w: CSD0(0) = %04x\n", data);
+ mc68328->regs.csd0 &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.csd0 |= data & mem_mask;
+ break;
+
+ case 0x142:
+ verboselog(device->machine(), 5, "mc68328_w: CSD0(16) = %04x\n", data);
+ mc68328->regs.csd0 &= ~(mem_mask << 16);
+ mc68328->regs.csd0 |= (data & mem_mask) << 16;
+ break;
+
+ case 0x144:
+ verboselog(device->machine(), 5, "mc68328_w: CSD1(0) = %04x\n", data);
+ mc68328->regs.csd1 &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.csd1 |= data & mem_mask;
+ break;
+
+ case 0x146:
+ verboselog(device->machine(), 5, "mc68328_w: CSD1(16) = %04x\n", data);
+ mc68328->regs.csd1 &= ~(mem_mask << 16);
+ mc68328->regs.csd1 |= (data & mem_mask) << 16;
+ break;
+
+ case 0x148:
+ verboselog(device->machine(), 5, "mc68328_w: CSD2(0) = %04x\n", data);
+ mc68328->regs.csd2 &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.csd2 |= data & mem_mask;
+ break;
+
+ case 0x14a:
+ verboselog(device->machine(), 5, "mc68328_w: CSD2(16) = %04x\n", data);
+ mc68328->regs.csd2 &= ~(mem_mask << 16);
+ mc68328->regs.csd2 |= (data & mem_mask) << 16;
+ break;
+
+ case 0x14c:
+ verboselog(device->machine(), 5, "mc68328_w: CSD3(0) = %04x\n", data);
+ mc68328->regs.csd3 &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.csd3 |= data & mem_mask;
+ break;
+
+ case 0x14e:
+ verboselog(device->machine(), 5, "mc68328_w: CSD3(16) = %04x\n", data);
+ mc68328->regs.csd3 &= ~(mem_mask << 16);
+ mc68328->regs.csd3 |= (data & mem_mask) << 16;
+ break;
+
+ case 0x200:
+ verboselog(device->machine(), 2, "mc68328_w: PLLCR = %04x\n", data);
+ mc68328->regs.pllcr = data;
+ break;
+
+ case 0x202:
+ verboselog(device->machine(), 2, "mc68328_w: PLLFSR = %04x\n", data);
+ mc68328->regs.pllfsr = data;
+ break;
+
+ case 0x206:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PCTLR = %02x\n", data & 0x00ff);
+ mc68328->regs.pctlr = data & 0x00ff;
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: Unknown address (0xfff206) = %02x\n", (data >> 8) & 0x00ff);
+ }
+ break;
+
+ case 0x300:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: Unknown address (0xfff301) = %02x\n", data & 0x00ff);
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: IVR = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.ivr = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x302:
+ verboselog(device->machine(), 2, "mc68328_w: ICR = %04x\n", data);
+ mc68328->regs.icr = data;
+ break;
+
+ case 0x304:
+ verboselog(device->machine(), 2, "mc68328_w: IMR(16) = %04x\n", data);
+ mc68328->regs.imr &= ~(mem_mask << 16);
+ mc68328->regs.imr |= (data & mem_mask) << 16;
+ mc68328->regs.isr &= ~((data & mem_mask) << 16);
+
+ imr_diff = imr_old ^ mc68328->regs.imr;
+ mc68328_set_interrupt_line(device, imr_diff, 0);
+ break;
+
+ case 0x306:
+ verboselog(device->machine(), 2, "mc68328_w: IMR(0) = %04x\n", data);
+ mc68328->regs.imr &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.imr |= data & mem_mask;
+ mc68328->regs.isr &= ~(data & mem_mask);
+
+ imr_diff = imr_old ^ mc68328->regs.imr;
+ mc68328_set_interrupt_line(device, imr_diff, 0);
+ break;
+
+ case 0x308:
+ {
+ verboselog(device->machine(), 2, "mc68328_w: IWR(16) = %04x\n", data);
+ mc68328->regs.iwr &= ~(mem_mask << 16);
+ mc68328->regs.iwr |= (data & mem_mask) << 16;
+ }
+ break;
+
+ case 0x30a:
+ verboselog(device->machine(), 2, "mc68328_w: IWR(0) = %04x\n", data);
+ mc68328->regs.iwr &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.iwr |= data & mem_mask;
+ break;
+
+ case 0x30c:
+ verboselog(device->machine(), 2, "mc68328_w: ISR(16) = %04x\n", data);
+ // Clear edge-triggered IRQ1
+ if((mc68328->regs.icr & ICR_ET1) == ICR_ET1 && (data & INT_IRQ1_SHIFT) == INT_IRQ1_SHIFT)
+ {
+ mc68328->regs.isr &= ~INT_IRQ1;
+ }
+
+ // Clear edge-triggered IRQ2
+ if((mc68328->regs.icr & ICR_ET2) == ICR_ET2 && (data & INT_IRQ2_SHIFT) == INT_IRQ2_SHIFT)
+ {
+ mc68328->regs.isr &= ~INT_IRQ2;
+ }
+
+ // Clear edge-triggered IRQ3
+ if((mc68328->regs.icr & ICR_ET3) == ICR_ET3 && (data & INT_IRQ3_SHIFT) == INT_IRQ3_SHIFT)
+ {
+ mc68328->regs.isr &= ~INT_IRQ3;
+ }
+
+ // Clear edge-triggered IRQ6
+ if((mc68328->regs.icr & ICR_ET6) == ICR_ET6 && (data & INT_IRQ6_SHIFT) == INT_IRQ6_SHIFT)
+ {
+ mc68328->regs.isr &= ~INT_IRQ6;
+ }
+
+ // Clear edge-triggered IRQ7
+ if((data & INT_IRQ7_SHIFT) == INT_IRQ7_SHIFT)
+ {
+ mc68328->regs.isr &= ~INT_IRQ7;
+ }
+ break;
+
+ case 0x30e:
+ verboselog(device->machine(), 2, "mc68328_w: ISR(0) = %04x (Ignored)\n", data);
+ break;
+
+ case 0x310:
+ verboselog(device->machine(), 2, "mc68328_w: IPR(16) = %04x (Ignored)\n");
+ break;
+
+ case 0x312:
+ verboselog(device->machine(), 2, "mc68328_w: IPR(0) = %04x (Ignored)\n");
+ break;
+
+ case 0x400:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PADATA = %02x\n", data & 0x00ff);
+ mc68328->regs.padata = data & 0x00ff;
+ if(mc68328->iface->out_port_a_func)
+ {
+ (mc68328->iface->out_port_a_func)( device, 0, data & 0x00ff );
+ }
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PADIR = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.padir = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x402:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PASEL = %02x\n", data & 0x00ff);
+ mc68328->regs.pasel = data & 0x00ff;
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: Unknown address (0xfff402) = %02x\n", (data >> 8) & 0x00ff);
+ }
+ break;
+
+ case 0x408:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PBDATA = %02x\n", data & 0x00ff);
+ mc68328->regs.pbdata = data & 0x00ff;
+ if(mc68328->iface->out_port_b_func)
+ {
+ (mc68328->iface->out_port_b_func)( device, 0, data & 0x00ff );
+ }
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PBDIR = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.pbdir = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x40a:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PBSEL = %02x\n", data & 0x00ff);
+ mc68328->regs.pbsel = data & 0x00ff;
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: Unknown address (0xfff40a) = %02x\n", (data >> 8) & 0x00ff);
+ }
+ break;
+
+ case 0x410:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PCDATA = %02x\n", data & 0x00ff);
+ mc68328->regs.pcdata = data & 0x00ff;
+ if(mc68328->iface->out_port_c_func)
+ {
+ (mc68328->iface->out_port_c_func)( device, 0, data & 0x00ff );
+ }
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PCDIR = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.pcdir = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x412:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PCSEL = %02x\n", data & 0x00ff);
+ mc68328->regs.pcsel = data & 0x00ff;
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: Unknown address (0xfff412) = %02x\n", (data >> 8) & 0x00ff);
+ }
+ break;
+
+ case 0x418:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PDDATA = %02x\n", data & 0x00ff);
+
+ mc68328->regs.pddataedge &= ~(data & 0x00ff);
+ mc68328_poll_port_d_interrupts(device);
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PDDIR = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.pddir = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x41a:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: Unknown address (0xfff41b) = %02x\n", data & 0x00ff);
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PDPUEN = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.pdpuen = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x41c:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PDIRQEN = %02x\n", data & 0x00ff);
+ mc68328->regs.pdirqen = data & 0x00ff;
+
+ mc68328_poll_port_d_interrupts(device);
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PDPOL = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.pdpol = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x41e:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PDIRQEDGE = %02x\n", data & 0x00ff);
+ mc68328->regs.pdirqedge = data & 0x00ff;
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: Unknown address (0xfff41e) = %02x\n", (data >> 8) & 0x00ff);
+ }
+ break;
+
+ case 0x420:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PEDATA = %02x\n", data & 0x00ff);
+ mc68328->regs.pedata = data & 0x00ff;
+ if(mc68328->iface->out_port_e_func)
+ {
+ (mc68328->iface->out_port_e_func)( device, 0, data & 0x00ff );
+ }
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PEDIR = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.pedir = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x422:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PESEL = %02x\n", data & 0x00ff);
+ mc68328->regs.pesel = data & 0x00ff;
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PEPUEN = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.pepuen = (data >> 8) & 0x00ff;
+ mc68328->regs.pedata |= mc68328->regs.pepuen;
+ }
+ break;
+
+ case 0x428:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PFDATA = %02x\n", data & 0x00ff);
+ mc68328->regs.pfdata = data & 0x00ff;
+ if(mc68328->iface->out_port_f_func)
+ {
+ (mc68328->iface->out_port_f_func)( device, 0, data & 0x00ff );
+ }
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PFDIR = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.pfdir = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x42a:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PFSEL = %02x\n", data & 0x00ff);
+ mc68328->regs.pfsel = data & 0x00ff;
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PFPUEN = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.pfpuen = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x430:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PGDATA = %02x\n", data & 0x00ff);
+ mc68328->regs.pgdata = data & 0x00ff;
+ if(mc68328->iface->out_port_g_func)
+ {
+ (mc68328->iface->out_port_g_func)( device, 0, data & 0x00ff );
+ }
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PGDIR = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.pgdir = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x432:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PGSEL = %02x\n", data & 0x00ff);
+ mc68328->regs.pgsel = data & 0x00ff;
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PGPUEN = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.pgpuen = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x438:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PJDATA = %02x\n", data & 0x00ff);
+ mc68328->regs.pjdata = data & 0x00ff;
+ if(mc68328->iface->out_port_j_func)
+ {
+ (mc68328->iface->out_port_j_func)( device, 0, data & 0x00ff );
+ }
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PJDIR = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.pjdir = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x43a:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PJSEL = %02x\n", data & 0x00ff);
+ mc68328->regs.pjsel = data & 0x00ff;
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: Unknown address (0xfff43a) = %02x\n", (data >> 8) & 0x00ff);
+ }
+ break;
+
+ case 0x440:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PKDATA = %02x\n", data & 0x00ff);
+ mc68328->regs.pkdata = data & 0x00ff;
+ if(mc68328->iface->out_port_k_func)
+ {
+ (mc68328->iface->out_port_k_func)( device, 0, data & 0x00ff );
+ }
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PKDIR = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.pkdir = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x442:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PKSEL = %02x\n", data & 0x00ff);
+ mc68328->regs.pksel = data & 0x00ff;
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PKPUEN = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.pgpuen = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x448:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PMDATA = %02x\n", data & 0x00ff);
+ mc68328->regs.pmdata = data & 0x00ff;
+ if(mc68328->iface->out_port_m_func)
+ {
+ (mc68328->iface->out_port_m_func)( device, 0, data & 0x00ff );
+ }
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PMDIR = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.pmdir = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x44a:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PMSEL = %02x\n", data & 0x00ff);
+ mc68328->regs.pmsel = data & 0x00ff;
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: PMPUEN = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.pmpuen = (data >> 8) & 0x00ff;
+ }
+ break;
+
+ case 0x500:
+ verboselog(device->machine(), 2, "mc68328_w: PWMC = %04x\n", data);
+
+ mc68328->regs.pwmc = data;
+
+ if(mc68328->regs.pwmc & PWMC_PWMIRQ)
+ {
+ mc68328_set_interrupt_line(device, INT_PWM, 1);
+ }
+
+ mc68328->regs.pwmc &= ~PWMC_LOAD;
+
+ if((mc68328->regs.pwmc & PWMC_PWMEN) != 0 && mc68328->regs.pwmw != 0 && mc68328->regs.pwmp != 0)
+ {
+ UINT32 frequency = 32768 * 506;
+ UINT32 divisor = 4 << (mc68328->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) * mc68328->regs.pwmw;
+ mc68328->pwm->adjust(period);
+ if(mc68328->regs.pwmc & PWMC_IRQEN)
+ {
+ mc68328_set_interrupt_line(device, INT_PWM, 1);
+ }
+ mc68328->regs.pwmc ^= PWMC_PIN;
+ }
+ else
+ {
+ mc68328->pwm->adjust(attotime::never);
+ }
+ break;
+
+ case 0x502:
+ verboselog(device->machine(), 2, "mc68328_w: PWMP = %04x\n", data);
+ mc68328->regs.pwmp = data;
+ break;
+
+ case 0x504:
+ verboselog(device->machine(), 2, "mc68328_w: PWMW = %04x\n", data);
+ mc68328->regs.pwmw = data;
+ break;
+
+ case 0x506:
+ verboselog(device->machine(), 2, "mc68328_w: PWMCNT = %04x\n", data);
+ mc68328->regs.pwmcnt = 0;
+ break;
+
+ case 0x600:
+ verboselog(device->machine(), 2, "mc68328_w: TCTL1 = %04x\n", data);
+ temp16[0] = mc68328->regs.tctl[0];
+ mc68328->regs.tctl[0] = data;
+ if((temp16[0] & TCTL_TEN) == (mc68328->regs.tctl[0] & TCTL_TEN))
+ {
+ mc68328_maybe_start_timer(device, 0, 0);
+ }
+ else if((temp16[0] & TCTL_TEN) != TCTL_TEN_ENABLE && (mc68328->regs.tctl[0] & TCTL_TEN) == TCTL_TEN_ENABLE)
+ {
+ mc68328_maybe_start_timer(device, 0, 1);
+ }
+ break;
+
+ case 0x602:
+ verboselog(device->machine(), 2, "mc68328_w: TPRER1 = %04x\n", data);
+ mc68328->regs.tprer[0] = data;
+ mc68328_maybe_start_timer(device, 0, 0);
+ break;
+
+ case 0x604:
+ verboselog(device->machine(), 2, "mc68328_w: TCMP1 = %04x\n", data);
+ mc68328->regs.tcmp[0] = data;
+ mc68328_maybe_start_timer(device, 0, 0);
+ break;
+
+ case 0x606:
+ verboselog(device->machine(), 2, "mc68328_w: TCR1 = %04x (Ignored)\n", data);
+ break;
+
+ case 0x608:
+ verboselog(device->machine(), 2, "mc68328_w: TCN1 = %04x (Ignored)\n", data);
+ break;
+
+ case 0x60a:
+ verboselog(device->machine(), 5, "mc68328_w: TSTAT1 = %04x\n", data);
+ mc68328->regs.tstat[0] &= ~mc68328->regs.tclear[0];
+ if(!(mc68328->regs.tstat[0] & TSTAT_COMP))
+ {
+ mc68328_set_interrupt_line(device, INT_TIMER1, 0);
+ }
+ break;
+
+ case 0x60c:
+ verboselog(device->machine(), 2, "mc68328_w: TCTL2 = %04x\n", data);
+ temp16[0] = mc68328->regs.tctl[1];
+ mc68328->regs.tctl[1] = data;
+ if((temp16[0] & TCTL_TEN) == (mc68328->regs.tctl[1] & TCTL_TEN))
+ {
+ mc68328_maybe_start_timer(device, 1, 0);
+ }
+ else if((temp16[0] & TCTL_TEN) != TCTL_TEN_ENABLE && (mc68328->regs.tctl[1] & TCTL_TEN) == TCTL_TEN_ENABLE)
+ {
+ mc68328_maybe_start_timer(device, 1, 1);
+ }
+ break;
+
+ case 0x60e:
+ verboselog(device->machine(), 2, "mc68328_w: TPRER2 = %04x\n", data);
+ mc68328->regs.tprer[1] = data;
+ mc68328_maybe_start_timer(device, 1, 0);
+ break;
+
+ case 0x610:
+ verboselog(device->machine(), 2, "mc68328_w: TCMP2 = %04x\n", data);
+ mc68328->regs.tcmp[1] = data;
+ mc68328_maybe_start_timer(device, 1, 0);
+ break;
+
+ case 0x612:
+ verboselog(device->machine(), 2, "mc68328_w: TCR2 = %04x (Ignored)\n", data);
+ break;
+
+ case 0x614:
+ verboselog(device->machine(), 2, "mc68328_w: TCN2 = %04x (Ignored)\n", data);
+ break;
+
+ case 0x616:
+ verboselog(device->machine(), 2, "mc68328_w: TSTAT2 = %04x\n", data);
+ mc68328->regs.tstat[1] &= ~mc68328->regs.tclear[1];
+ if(!(mc68328->regs.tstat[1] & TSTAT_COMP))
+ {
+ mc68328_set_interrupt_line(device, INT_TIMER2, 0);
+ }
+ break;
+
+ case 0x618:
+ verboselog(device->machine(), 2, "mc68328_w: WCTLR = %04x\n", data);
+ mc68328->regs.wctlr = data;
+ break;
+
+ case 0x61a:
+ verboselog(device->machine(), 2, "mc68328_w: WCMPR = %04x\n", data);
+ mc68328->regs.wcmpr = data;
+ break;
+
+ case 0x61c:
+ verboselog(device->machine(), 2, "mc68328_w: WCN = %04x (Ignored)\n", data);
+ break;
+
+ case 0x700:
+ verboselog(device->machine(), 2, "mc68328_w: SPISR = %04x\n", data);
+ mc68328->regs.spisr = data;
+ break;
+
+ case 0x800:
+ verboselog(device->machine(), 2, "mc68328_w: SPIMDATA = %04x\n", data);
+ if(mc68328->iface->out_spim_func)
+ {
+ (mc68328->iface->out_spim_func)( device, 0, data, 0xffff );
+ }
+ else
+ {
+ mc68328->regs.spimdata = data;
+ }
+ break;
+
+ case 0x802:
+ verboselog(device->machine(), 2, "mc68328_w: SPIMCONT = %04x\n", data);
+ verboselog(device->machine(), 3, " Count = %d\n", data & SPIM_CLOCK_COUNT);
+ verboselog(device->machine(), 3, " Polarity = %s\n", (data & SPIM_POL) ? "Inverted" : "Active-high");
+ verboselog(device->machine(), 3, " Phase = %s\n", (data & SPIM_PHA) ? "Opposite" : "Normal");
+ verboselog(device->machine(), 3, " IRQ Enable = %s\n", (data & SPIM_IRQEN) ? "Enable" : "Disable");
+ verboselog(device->machine(), 3, " IRQ Pending = %s\n", (data & SPIM_SPIMIRQ) ? "Yes" : "No");
+ verboselog(device->machine(), 3, " Exchange = %s\n", (data & SPIM_XCH) ? "Initiate" : "Idle");
+ verboselog(device->machine(), 3, " SPIM Enable = %s\n", (data & SPIM_SPMEN) ? "Enable" : "Disable");
+ verboselog(device->machine(), 3, " Data Rate = Divide By %d\n", 1 << ((((data & SPIM_RATE) >> 13) & 0x0007) + 2) );
+ mc68328->regs.spimcont = data;
+ // $$HACK$$ We should probably emulate the ADS7843 A/D device properly.
+ if(data & SPIM_XCH)
+ {
+ mc68328->regs.spimcont &= ~SPIM_XCH;
+ if(mc68328->iface->spim_xch_trigger)
+ {
+ (mc68328->iface->spim_xch_trigger)( device );
+ }
+ if(data & SPIM_IRQEN)
+ {
+ mc68328->regs.spimcont |= SPIM_SPIMIRQ;
+ verboselog(device->machine(), 3, "Triggering SPIM Interrupt\n" );
+ mc68328_set_interrupt_line(device, INT_SPIM, 1);
+ }
+ }
+ if(!(data & SPIM_IRQEN))
+ {
+ mc68328_set_interrupt_line(device, INT_SPIM, 0);
+ }
+ break;
+
+ case 0x900:
+ verboselog(device->machine(), 2, "mc68328_w: USTCNT = %04x\n", data);
+ mc68328->regs.ustcnt = data;
+ break;
+
+ case 0x902:
+ verboselog(device->machine(), 2, "mc68328_w: UBAUD = %04x\n", data);
+ mc68328->regs.ubaud = data;
+ break;
+
+ case 0x904:
+ verboselog(device->machine(), 2, "mc68328_w: URX = %04x\n", data);
+ break;
+
+ case 0x906:
+ verboselog(device->machine(), 2, "mc68328_w: UTX = %04x\n", data);
+ break;
+
+ case 0x908:
+ verboselog(device->machine(), 2, "mc68328_w: UMISC = %04x\n", data);
+ mc68328->regs.umisc = data;
+ break;
+
+ case 0xa00:
+ verboselog(device->machine(), 2, "mc68328_w: LSSA(16) = %04x\n", data);
+ mc68328->regs.lssa &= ~(mem_mask << 16);
+ mc68328->regs.lssa |= (data & mem_mask) << 16;
+ verboselog(device->machine(), 3, " Address: %08x\n", mc68328->regs.lssa);
+ break;
+
+ case 0xa02:
+ verboselog(device->machine(), 2, "mc68328_w: LSSA(0) = %04x\n", data);
+ mc68328->regs.lssa &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.lssa |= data & mem_mask;
+ verboselog(device->machine(), 3, " Address: %08x\n", mc68328->regs.lssa);
+ break;
+
+ case 0xa04:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: LVPW = %02x\n", data & 0x00ff);
+ mc68328->regs.lvpw = data & 0x00ff;
+ verboselog(device->machine(), 3, " Page Width: %d or %d\n", (mc68328->regs.lvpw + 1) * ((mc68328->regs.lpicf & 0x01) ? 8 : 16));
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: Unknown address (0xfffa04) = %02x\n", (data >> 8) & 0x00ff);
+ }
+ break;
+
+ case 0xa08:
+ verboselog(device->machine(), 2, "mc68328_w: LXMAX = %04x\n", data);
+ mc68328->regs.lxmax = data;
+ verboselog(device->machine(), 3, " Width: %d\n", (data & 0x03ff) + 1);
+ break;
+
+ case 0xa0a:
+ verboselog(device->machine(), 2, "mc68328_w: LYMAX = %04x\n", data);
+ mc68328->regs.lymax = data;
+ verboselog(device->machine(), 3, " Height: %d\n", (data & 0x03ff) + 1);
+ break;
+
+ case 0xa18:
+ verboselog(device->machine(), 2, "mc68328_w: LCXP = %04x\n", data);
+ mc68328->regs.lcxp = data;
+ verboselog(device->machine(), 3, " X Position: %d\n", data & 0x03ff);
+ switch(mc68328->regs.lcxp >> 14)
+ {
+ case 0:
+ verboselog(device->machine(), 3, " Cursor Control: Transparent\n");
+ break;
+
+ case 1:
+ verboselog(device->machine(), 3, " Cursor Control: Black\n");
+ break;
+
+ case 2:
+ verboselog(device->machine(), 3, " Cursor Control: Reverse\n");
+ break;
+
+ case 3:
+ verboselog(device->machine(), 3, " Cursor Control: Invalid\n");
+ break;
+ }
+ break;
+
+ case 0xa1a:
+ verboselog(device->machine(), 2, "mc68328_w: LCYP = %04x\n", data);
+ mc68328->regs.lcyp = data;
+ verboselog(device->machine(), 3, " Y Position: %d\n", data & 0x01ff);
+ break;
+
+ case 0xa1c:
+ verboselog(device->machine(), 2, "mc68328_w: LCWCH = %04x\n", data);
+ mc68328->regs.lcwch = data;
+ verboselog(device->machine(), 3, " Width: %d\n", (data >> 8) & 0x1f);
+ verboselog(device->machine(), 3, " Height: %d\n", data & 0x1f);
+ break;
+
+ case 0xa1e:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: LBLKC = %02x\n", data & 0x00ff);
+ mc68328->regs.lblkc = data & 0x00ff;
+ verboselog(device->machine(), 3, " Blink Enable: %d\n", mc68328->regs.lblkc >> 7);
+ verboselog(device->machine(), 3, " Blink Divisor: %d\n", mc68328->regs.lblkc & 0x7f);
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: Unknown address (0xfffa1e) = %02x\n", (data >> 8) & 0x00ff);
+ }
+ break;
+
+ case 0xa20:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: LPOLCF = %02x\n", data & 0x00ff);
+ mc68328->regs.lpolcf = data & 0x00ff;
+ verboselog(device->machine(), 3, " LCD Shift Clock Polarity: %s\n", (mc68328->regs.lpicf & 0x08) ? "Active positive edge of LCLK" : "Active negative edge of LCLK");
+ verboselog(device->machine(), 3, " First-line marker polarity: %s\n", (mc68328->regs.lpicf & 0x04) ? "Active Low" : "Active High");
+ verboselog(device->machine(), 3, " Line-pulse polarity: %s\n", (mc68328->regs.lpicf & 0x02) ? "Active Low" : "Active High");
+ verboselog(device->machine(), 3, " Pixel polarity: %s\n", (mc68328->regs.lpicf & 0x01) ? "Active Low" : "Active High");
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: LPICF = %02x\n", (data >> 8) & 0x00ff);
+ mc68328->regs.lpicf = (data >> 8) & 0x00ff;
+ switch((mc68328->regs.lpicf >> 1) & 0x03)
+ {
+ case 0:
+ verboselog(device->machine(), 3, " Bus Size: 1-bit\n");
+ break;
+
+ case 1:
+ verboselog(device->machine(), 3, " Bus Size: 2-bit\n");
+ break;
+
+ case 2:
+ verboselog(device->machine(), 3, " Bus Size: 4-bit\n");
+ break;
+
+ case 3:
+ verboselog(device->machine(), 3, " Bus Size: unused\n");
+ break;
+ }
+ verboselog(device->machine(), 3, " Gray scale enable: %d\n", mc68328->regs.lpicf & 0x01);
+ }
+ break;
+
+ case 0xa22:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: LACDRC = %02x\n", data & 0x00ff);
+ mc68328->regs.lacdrc = data & 0x00ff;
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: Unknown address (0xfffa22) = %02x\n", (data >> 8) & 0x00ff);
+ }
+ break;
+
+ case 0xa24:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: LPXCD = %02x\n", data & 0x00ff);
+ mc68328->regs.lpxcd = data & 0x00ff;
+ verboselog(device->machine(), 3, " Clock Divisor: %d\n", mc68328->regs.lpxcd + 1);
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: Unknown address (0xfffa24) = %02x\n", (data >> 8) & 0x00ff);
+ }
+ break;
+
+ case 0xa26:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: LCKCON = %02x\n", data & 0x00ff);
+ mc68328->regs.lckcon = data & 0x00ff;
+ verboselog(device->machine(), 3, " LCDC Enable: %d\n", (mc68328->regs.lckcon >> 7) & 0x01);
+ verboselog(device->machine(), 3, " DMA Burst Length: %d\n", ((mc68328->regs.lckcon >> 6) & 0x01) ? 16 : 8);
+ verboselog(device->machine(), 3, " DMA Bursting Clock Control: %d\n", ((mc68328->regs.lckcon >> 4) & 0x03) + 1);
+ verboselog(device->machine(), 3, " Bus Width: %d\n", ((mc68328->regs.lckcon >> 1) & 0x01) ? 8 : 16);
+ verboselog(device->machine(), 3, " Pixel Clock Divider Source: %s\n", (mc68328->regs.lckcon & 0x01) ? "PIX" : "SYS");
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: Unknown address (0xfffa26) = %02x\n", (data >> 8) & 0x00ff);
+ }
+ break;
+
+ case 0xa28:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: LLBAR = %02x\n", data & 0x00ff);
+ mc68328->regs.llbar = data & 0x00ff;
+ verboselog(device->machine(), 3, " Address: %d\n", (mc68328->regs.llbar & 0x7f) * ((mc68328->regs.lpicf & 0x01) ? 8 : 16));
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: Unknown address (0xfffa28) = %02x\n", (data >> 8) & 0x00ff);
+ }
+ break;
+
+ case 0xa2a:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: LOTCR = %02x\n", data & 0x00ff);
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: Unknown address (0xfffa2a) = %02x\n", (data >> 8) & 0x00ff);
+ }
+ break;
+
+ case 0xa2c:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: LPOSR = %02x\n", data & 0x00ff);
+ mc68328->regs.lposr = data & 0x00ff;
+ verboselog(device->machine(), 3, " Byte Offset: %d\n", (mc68328->regs.lposr >> 3) & 0x01);
+ verboselog(device->machine(), 3, " Pixel Offset: %d\n", mc68328->regs.lposr & 0x07);
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: Unknown address (0xfffa2c) = %02x\n", (data >> 8) & 0x00ff);
+ }
+ break;
+
+ case 0xa30:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_w: LFRCM = %02x\n", data & 0x00ff);
+ mc68328->regs.lfrcm = data & 0x00ff;
+ verboselog(device->machine(), 3, " X Modulation: %d\n", (mc68328->regs.lfrcm >> 4) & 0x0f);
+ verboselog(device->machine(), 3, " Y Modulation: %d\n", mc68328->regs.lfrcm & 0x0f);
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_w: Unknown address (0xfffa30) = %02x\n", (data >> 8) & 0x00ff);
+ }
+ break;
+
+ case 0xa32:
+ verboselog(device->machine(), 2, "mc68328_w: LGPMR = %04x\n", data);
+ mc68328->regs.lgpmr = data;
+ verboselog(device->machine(), 3, " Palette 0: %d\n", (mc68328->regs.lgpmr >> 8) & 0x07);
+ verboselog(device->machine(), 3, " Palette 1: %d\n", (mc68328->regs.lgpmr >> 12) & 0x07);
+ verboselog(device->machine(), 3, " Palette 2: %d\n", (mc68328->regs.lgpmr >> 0) & 0x07);
+ verboselog(device->machine(), 3, " Palette 3: %d\n", (mc68328->regs.lgpmr >> 4) & 0x07);
+ break;
+
+ case 0xb00:
+ verboselog(device->machine(), 2, "mc68328_w: HMSR(0) = %04x\n", data);
+ mc68328->regs.hmsr &= ~(mem_mask << 16);
+ mc68328->regs.hmsr |= (data & mem_mask) << 16;
+ mc68328->regs.hmsr &= 0x1f3f003f;
+ break;
+
+ case 0xb02:
+ verboselog(device->machine(), 2, "mc68328_w: HMSR(16) = %04x\n", data);
+ mc68328->regs.hmsr &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.hmsr |= data & mem_mask;
+ mc68328->regs.hmsr &= 0x1f3f003f;
+ break;
+
+ case 0xb04:
+ verboselog(device->machine(), 2, "mc68328_w: ALARM(0) = %04x\n", data);
+ mc68328->regs.alarm &= ~(mem_mask << 16);
+ mc68328->regs.alarm |= (data & mem_mask) << 16;
+ mc68328->regs.alarm &= 0x1f3f003f;
+ break;
+
+ case 0xb06:
+ verboselog(device->machine(), 2, "mc68328_w: ALARM(16) = %04x\n", data);
+ mc68328->regs.alarm &= 0xffff0000 | (~mem_mask);
+ mc68328->regs.alarm |= data & mem_mask;
+ mc68328->regs.alarm &= 0x1f3f003f;
+ break;
+
+ case 0xb0c:
+ verboselog(device->machine(), 2, "mc68328_w: RTCCTL = %04x\n", data);
+ mc68328->regs.rtcctl = data & 0x00a0;
+ break;
+
+ case 0xb0e:
+ verboselog(device->machine(), 2, "mc68328_w: RTCISR = %04x\n", data);
+ mc68328->regs.rtcisr &= ~data;
+ if(mc68328->regs.rtcisr == 0)
+ {
+ mc68328_set_interrupt_line(device, INT_RTC, 0);
+ }
+ break;
+
+ case 0xb10:
+ verboselog(device->machine(), 2, "mc68328_w: RTCIENR = %04x\n", data);
+ mc68328->regs.rtcienr = data & 0x001f;
+ break;
+
+ case 0xb12:
+ verboselog(device->machine(), 2, "mc68328_w: STPWTCH = %04x\n", data);
+ mc68328->regs.stpwtch = data & 0x003f;
+ break;
+
+ default:
+ verboselog(device->machine(), 0, "mc68328_w: Unknown address (0x%06x) = %04x (%04x)\n", 0xfff000 + address, data, mem_mask);
+ break;
+ }
+}
+
+READ16_DEVICE_HANDLER( mc68328_r )
+{
+ mc68328_t* mc68328 = mc68328_get_safe_token( device );
+ UINT16 temp16 = 0;
+ UINT32 address = offset << 1;
+
+ switch(address)
+ {
+ case 0x000:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): Unknown address (0xfff001)\n", mem_mask);
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): SCR = %02x\n", mem_mask, mc68328->regs.scr);
+ return mc68328->regs.scr << 8;
+ }
+ break;
+
+ case 0x100:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): GRPBASEA = %04x\n", mem_mask, mc68328->regs.grpbasea);
+ return mc68328->regs.grpbasea;
+
+ case 0x102:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): GRPBASEB = %04x\n", mem_mask, mc68328->regs.grpbaseb);
+ return mc68328->regs.grpbaseb;
+
+ case 0x104:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): GRPBASEC = %04x\n", mem_mask, mc68328->regs.grpbasec);
+ return mc68328->regs.grpbasec;
+
+ case 0x106:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): GRPBASED = %04x\n", mem_mask, mc68328->regs.grpbased);
+ return mc68328->regs.grpbased;
+
+ case 0x108:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): GRPMASKA = %04x\n", mem_mask, mc68328->regs.grpmaska);
+ return mc68328->regs.grpmaska;
+
+ case 0x10a:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): GRPMASKB = %04x\n", mem_mask, mc68328->regs.grpmaskb);
+ return mc68328->regs.grpmaskb;
+
+ case 0x10c:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): GRPMASKC = %04x\n", mem_mask, mc68328->regs.grpmaskc);
+ return mc68328->regs.grpmaskc;
+
+ case 0x10e:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): GRPMASKD = %04x\n", mem_mask, mc68328->regs.grpmaskd);
+ return mc68328->regs.grpmaskd;
+
+ case 0x110:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): CSA0(0) = %04x\n", mem_mask, mc68328->regs.csa0 & 0x0000ffff);
+ return mc68328->regs.csa0 & 0x0000ffff;
+
+ case 0x112:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): CSA0(16) = %04x\n", mem_mask, mc68328->regs.csa0 >> 16);
+ return mc68328->regs.csa0 >> 16;
+
+ case 0x114:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): CSA1(0) = %04x\n", mem_mask, mc68328->regs.csa1 & 0x0000ffff);
+ return mc68328->regs.csa1 & 0x0000ffff;
+
+ case 0x116:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): CSA1(16) = %04x\n", mem_mask, mc68328->regs.csa1 >> 16);
+ return mc68328->regs.csa1 >> 16;
+
+ case 0x118:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): CSA2(0) = %04x\n", mem_mask, mc68328->regs.csa2 & 0x0000ffff);
+ return mc68328->regs.csa2 & 0x0000ffff;
+
+ case 0x11a:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): CSA2(16) = %04x\n", mem_mask, mc68328->regs.csa2 >> 16);
+ return mc68328->regs.csa2 >> 16;
+
+ case 0x11c:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): CSA3(0) = %04x\n", mem_mask, mc68328->regs.csa3 & 0x0000ffff);
+ return mc68328->regs.csa3 & 0x0000ffff;
+
+ case 0x11e:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): CSA3(16) = %04x\n", mem_mask, mc68328->regs.csa3 >> 16);
+ return mc68328->regs.csa3 >> 16;
+
+ case 0x120:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): CSB0(0) = %04x\n", mem_mask, mc68328->regs.csb0 & 0x0000ffff);
+ return mc68328->regs.csb0 & 0x0000ffff;
+
+ case 0x122:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): CSB0(16) = %04x\n", mem_mask, mc68328->regs.csb0 >> 16);
+ return mc68328->regs.csb0 >> 16;
+
+ case 0x124:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): CSB1(0) = %04x\n", mem_mask, mc68328->regs.csb1 & 0x0000ffff);
+ return mc68328->regs.csb1 & 0x0000ffff;
+
+ case 0x126:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): CSB1(16) = %04x\n", mem_mask, mc68328->regs.csb1 >> 16);
+ return mc68328->regs.csb1 >> 16;
+
+ case 0x128:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): CSB2(0) = %04x\n", mem_mask, mc68328->regs.csb2 & 0x0000ffff);
+ return mc68328->regs.csb2 & 0x0000ffff;
+
+ case 0x12a:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): CSB2(16) = %04x\n", mem_mask, mc68328->regs.csb2 >> 16);
+ return mc68328->regs.csb2 >> 16;
+
+ case 0x12c:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): CSB3(0) = %04x\n", mem_mask, mc68328->regs.csb3 & 0x0000ffff);
+ return mc68328->regs.csb3 & 0x0000ffff;
+
+ case 0x12e:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): CSB3(16) = %04x\n", mem_mask, mc68328->regs.csb3 >> 16);
+ return mc68328->regs.csb3 >> 16;
+
+ case 0x130:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): CSC0(0) = %04x\n", mem_mask, mc68328->regs.csc0 & 0x0000ffff);
+ return mc68328->regs.csc0 & 0x0000ffff;
+
+ case 0x132:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): CSC0(16) = %04x\n", mem_mask, mc68328->regs.csc0 >> 16);
+ return mc68328->regs.csc0 >> 16;
+
+ case 0x134:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): CSC1(0) = %04x\n", mem_mask, mc68328->regs.csc1 & 0x0000ffff);
+ return mc68328->regs.csc1 & 0x0000ffff;
+
+ case 0x136:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): CSC1(16) = %04x\n", mem_mask, mc68328->regs.csc1 >> 16);
+ return mc68328->regs.csc1 >> 16;
+
+ case 0x138:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): CSC2(0) = %04x\n", mem_mask, mc68328->regs.csc2 & 0x0000ffff);
+ return mc68328->regs.csc2 & 0x0000ffff;
+
+ case 0x13a:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): CSC2(16) = %04x\n", mem_mask, mc68328->regs.csc2 >> 16);
+ return mc68328->regs.csc2 >> 16;
+
+ case 0x13c:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): CSC3(0) = %04x\n", mem_mask, mc68328->regs.csc3 & 0x0000ffff);
+ return mc68328->regs.csc3 & 0x0000ffff;
+
+ case 0x13e:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): CSC3(16) = %04x\n", mem_mask, mc68328->regs.csc3 >> 16);
+ return mc68328->regs.csc3 >> 16;
+
+ case 0x140:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): CSD0(0) = %04x\n", mem_mask, mc68328->regs.csd0 & 0x0000ffff);
+ return mc68328->regs.csd0 & 0x0000ffff;
+
+ case 0x142:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): CSD0(16) = %04x\n", mem_mask, mc68328->regs.csd0 >> 16);
+ return mc68328->regs.csd0 >> 16;
+
+ case 0x144:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): CSD1(0) = %04x\n", mem_mask, mc68328->regs.csd1 & 0x0000ffff);
+ return mc68328->regs.csd1 & 0x0000ffff;
+
+ case 0x146:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): CSD1(16) = %04x\n", mem_mask, mc68328->regs.csd1 >> 16);
+ return mc68328->regs.csd1 >> 16;
+
+ case 0x148:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): CSD2(0) = %04x\n", mem_mask, mc68328->regs.csd2 & 0x0000ffff);
+ return mc68328->regs.csd2 & 0x0000ffff;
+
+ case 0x14a:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): CSD2(16) = %04x\n", mem_mask, mc68328->regs.csd2 >> 16);
+ return mc68328->regs.csd2 >> 16;
+
+ case 0x14c:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): CSD3(0) = %04x\n", mem_mask, mc68328->regs.csd3 & 0x0000ffff);
+ return mc68328->regs.csd3 & 0x0000ffff;
+
+ case 0x14e:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): CSD3(16) = %04x\n", mem_mask, mc68328->regs.csd3 >> 16);
+ return mc68328->regs.csd3 >> 16;
+
+ case 0x200:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PLLCR = %04x\n", mem_mask, mc68328->regs.pllcr);
+ return mc68328->regs.pllcr;
+
+ case 0x202:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PLLFSR = %04x\n", mem_mask, mc68328->regs.pllfsr);
+ mc68328->regs.pllfsr ^= 0x8000;
+ return mc68328->regs.pllfsr;
+
+ case 0x206:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): Unknown address (0xfff206)\n", mem_mask);
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PCTLR = %02x\n", mem_mask, mc68328->regs.pctlr);
+ return mc68328->regs.pctlr << 8;
+ }
+ break;
+
+ case 0x300:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): Unknown address (0xfff301)\n", mem_mask);
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): IVR = %02x\n", mem_mask, mc68328->regs.ivr);
+ return mc68328->regs.ivr << 8;
+ }
+ break;
+
+ case 0x302:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): ICR = %04x\n", mem_mask, mc68328->regs.icr);
+ return mc68328->regs.icr;
+
+ case 0x304:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): IMR(16) = %04x\n", mem_mask, mc68328->regs.imr >> 16);
+ return mc68328->regs.imr >> 16;
+
+ case 0x306:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): IMR(0) = %04x\n", mem_mask, mc68328->regs.imr & 0x0000ffff);
+ return mc68328->regs.imr & 0x0000ffff;
+
+ case 0x308:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): IWR(16) = %04x\n", mem_mask, mc68328->regs.iwr >> 16);
+ return mc68328->regs.iwr >> 16;
+
+ case 0x30a:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): IWR(0) = %04x\n", mem_mask, mc68328->regs.iwr & 0x0000ffff);
+ return mc68328->regs.iwr & 0x0000ffff;
+
+ case 0x30c:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): ISR(16) = %04x\n", mem_mask, mc68328->regs.isr >> 16);
+ return mc68328->regs.isr >> 16;
+
+ case 0x30e:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): ISR(0) = %04x\n", mem_mask, mc68328->regs.isr & 0x0000ffff);
+ return mc68328->regs.isr & 0x0000ffff;
+
+ case 0x310:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): IPR(16) = %04x\n", mem_mask, mc68328->regs.ipr >> 16);
+ return mc68328->regs.ipr >> 16;
+
+ case 0x312:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): IPR(0) = %04x\n", mem_mask, mc68328->regs.ipr & 0x0000ffff);
+ return mc68328->regs.ipr & 0x0000ffff;
+
+ case 0x400:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PADATA = %02x\n", mem_mask, mc68328->regs.padata);
+ if(mc68328->iface->in_port_a_func)
+ {
+ return (mc68328->iface->in_port_a_func)( device, 0 );
+ }
+ else
+ {
+ return mc68328->regs.padata;
+ }
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PADIR = %02x\n", mem_mask, mc68328->regs.padir);
+ return mc68328->regs.padir << 8;
+ }
+ break;
+
+ case 0x402:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PASEL = %02x\n", mem_mask, mc68328->regs.pasel);
+ return mc68328->regs.pasel;
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): Unknown address (0xfff402)\n", mem_mask);
+ }
+ break;
+
+ case 0x408:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PBDATA = %02x\n", mem_mask, mc68328->regs.pbdata);
+ if(mc68328->iface->in_port_b_func)
+ {
+ return (mc68328->iface->in_port_b_func)( device, 0 );
+ }
+ else
+ {
+ return mc68328->regs.pbdata;
+ }
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PBDIR = %02x\n", mem_mask, mc68328->regs.pbdir);
+ return mc68328->regs.pbdir << 8;
+ }
+ break;
+
+ case 0x40a:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PBSEL = %02x\n", mem_mask, mc68328->regs.pbsel);
+ return mc68328->regs.pbsel;
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): Unknown address (0xfff40a)\n", mem_mask);
+ }
+ break;
+
+ case 0x410:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PCDATA = %02x\n", mem_mask, mc68328->regs.pcdata);
+ if(mc68328->iface->in_port_c_func)
+ {
+ return (mc68328->iface->in_port_c_func)( device, 0 );
+ }
+ else
+ {
+ return mc68328->regs.pcdata;
+ }
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PCDIR = %02x\n", mem_mask, mc68328->regs.pcdir);
+ return mc68328->regs.pcdir << 8;
+ }
+ break;
+
+ case 0x412:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PCSEL = %02x\n", mem_mask, mc68328->regs.pcsel);
+ return mc68328->regs.pcsel;
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): Unknown address (0xfff412)\n", mem_mask);
+ }
+ break;
+
+ case 0x418:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PDDATA = %02x\n", mem_mask, mc68328->regs.pddata);
+ if(mc68328->iface->in_port_d_func)
+ {
+ return (mc68328->iface->in_port_d_func)( device, 0 );
+ }
+ else
+ {
+ return mc68328->regs.pddata;
+ }
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PDDIR = %02x\n", mem_mask, mc68328->regs.pddir);
+ return mc68328->regs.pddir << 8;
+ }
+ break;
+
+ case 0x41a:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): Unknown address (0xfff41b)\n", mem_mask);
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PDPUEN = %02x\n", mem_mask, mc68328->regs.pdpuen);
+ return mc68328->regs.pdpuen << 8;
+ }
+ break;
+
+ case 0x41c:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PDIRQEN = %02x\n", mem_mask, mc68328->regs.pdirqen);
+ return mc68328->regs.pdirqen;
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PDPOL = %02x\n", mem_mask, mc68328->regs.pdpol);
+ return mc68328->regs.pdpol << 8;
+ }
+ break;
+
+ case 0x41e:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PDIRQEDGE = %02x\n", mem_mask, mc68328->regs.pdirqedge);
+ return mc68328->regs.pdirqedge;
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): Unknown address (0xfff41e)\n", mem_mask);
+ }
+ break;
+
+ case 0x420:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PEDATA = %02x\n", mem_mask, mc68328->regs.pedata);
+ if(mc68328->iface->in_port_e_func)
+ {
+ return (mc68328->iface->in_port_e_func)( device, 0 );
+ }
+ else
+ {
+ return mc68328->regs.pedata;
+ }
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PEDIR = %02x\n", mem_mask, mc68328->regs.pedir);
+ return mc68328->regs.pedir << 8;
+ }
+ break;
+
+ case 0x422:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PESEL = %02x\n", mem_mask, mc68328->regs.pesel);
+ return mc68328->regs.pesel;
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PEPUEN = %02x\n", mem_mask, mc68328->regs.pepuen);
+ return mc68328->regs.pepuen << 8;
+ }
+ break;
+
+ case 0x428:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PFDATA = %02x\n", mem_mask, mc68328->regs.pfdata);
+ if(mc68328->iface->in_port_f_func)
+ {
+ return (mc68328->iface->in_port_f_func)( device, 0 );
+ }
+ else
+ {
+ return mc68328->regs.pfdata;
+ }
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PFDIR = %02x\n", mem_mask, mc68328->regs.pfdir);
+ return mc68328->regs.pfdir << 8;
+ }
+ break;
+
+ case 0x42a:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PFSEL = %02x\n", mem_mask, mc68328->regs.pfsel);
+ return mc68328->regs.pfsel;
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PFPUEN = %02x\n", mem_mask, mc68328->regs.pfpuen);
+ return mc68328->regs.pfpuen << 8;
+ }
+ break;
+
+ case 0x430:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PGDATA = %02x\n", mem_mask, mc68328->regs.pgdata);
+ if(mc68328->iface->in_port_g_func)
+ {
+ return (mc68328->iface->in_port_g_func)( device, 0 );
+ }
+ else
+ {
+ return mc68328->regs.pgdata;
+ }
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PGDIR = %02x\n", mem_mask, mc68328->regs.pgdir);
+ return mc68328->regs.pgdir << 8;
+ }
+ break;
+
+ case 0x432:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PGSEL = %02x\n", mem_mask, mc68328->regs.pgsel);
+ return mc68328->regs.pgsel;
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PGPUEN = %02x\n", mem_mask, mc68328->regs.pgpuen);
+ return mc68328->regs.pgpuen << 8;
+ }
+ break;
+
+ case 0x438:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PJDATA = %02x\n", mem_mask, mc68328->regs.pjdata);
+ if(mc68328->iface->in_port_j_func)
+ {
+ return (mc68328->iface->in_port_j_func)( device, 0 );
+ }
+ else
+ {
+ return mc68328->regs.pjdata;
+ }
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PJDIR = %02x\n", mem_mask, mc68328->regs.pjdir);
+ return mc68328->regs.pjdir << 8;
+ }
+ break;
+
+ case 0x43a:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PJSEL = %02x\n", mem_mask, mc68328->regs.pjsel);
+ return mc68328->regs.pjsel;
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): Unknown address (0xfff43a)\n", mem_mask);
+ }
+ break;
+
+ case 0x440:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PKDATA = %02x\n", mem_mask, mc68328->regs.pkdata);
+ if(mc68328->iface->in_port_k_func)
+ {
+ return (mc68328->iface->in_port_k_func)( device, 0 );
+ }
+ else
+ {
+ return mc68328->regs.pkdata;
+ }
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PKDIR = %02x\n", mem_mask, mc68328->regs.pkdir);
+ return mc68328->regs.pkdir << 8;
+ }
+ break;
+
+ case 0x442:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PKSEL = %02x\n", mem_mask, mc68328->regs.pksel);
+ return mc68328->regs.pksel;
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PKPUEN = %02x\n", mem_mask, mc68328->regs.pkpuen);
+ return mc68328->regs.pkpuen << 8;
+ }
+ break;
+
+ case 0x448:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PMDATA = %02x\n", mem_mask, mc68328->regs.pmdata);
+ if(mc68328->iface->in_port_m_func)
+ {
+ return (mc68328->iface->in_port_m_func)( device, 0 );
+ }
+ else
+ {
+ return mc68328->regs.pmdata;
+ }
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PMDIR = %02x\n", mem_mask, mc68328->regs.pmdir);
+ return mc68328->regs.pmdir << 8;
+ }
+ break;
+
+ case 0x44a:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PMSEL = %02x\n", mem_mask, mc68328->regs.pmsel);
+ return mc68328->regs.pmsel;
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PMPUEN = %02x\n", mem_mask, mc68328->regs.pmpuen);
+ return mc68328->regs.pmpuen << 8;
+ }
+ break;
+
+ case 0x500:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PWMC = %04x\n", mem_mask, mc68328->regs.pwmc);
+ temp16 = mc68328->regs.pwmc;
+ if(mc68328->regs.pwmc & PWMC_PWMIRQ)
+ {
+ mc68328->regs.pwmc &= ~PWMC_PWMIRQ;
+ mc68328_set_interrupt_line(device, INT_PWM, 0);
+ }
+ return temp16;
+
+ case 0x502:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PWMP = %04x\n", mem_mask, mc68328->regs.pwmp);
+ return mc68328->regs.pwmp;
+
+ case 0x504:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PWMW = %04x\n", mem_mask, mc68328->regs.pwmw);
+ return mc68328->regs.pwmw;
+
+ case 0x506:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): PWMCNT = %04x\n", mem_mask, mc68328->regs.pwmcnt);
+ return mc68328->regs.pwmcnt;
+
+ case 0x600:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): TCTL1 = %04x\n", mem_mask, mc68328->regs.tctl[0]);
+ return mc68328->regs.tctl[0];
+
+ case 0x602:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): TPRER1 = %04x\n", mem_mask, mc68328->regs.tprer[0]);
+ return mc68328->regs.tprer[0];
+
+ case 0x604:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): TCMP1 = %04x\n", mem_mask, mc68328->regs.tcmp[0]);
+ return mc68328->regs.tcmp[0];
+
+ case 0x606:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): TCR1 = %04x\n", mem_mask, mc68328->regs.tcr[0]);
+ return mc68328->regs.tcr[0];
+
+ case 0x608:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): TCN1 = %04x\n", mem_mask, mc68328->regs.tcn[0]);
+ return mc68328->regs.tcn[0];
+
+ case 0x60a:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): TSTAT1 = %04x\n", mem_mask, mc68328->regs.tstat[0]);
+ mc68328->regs.tclear[0] |= mc68328->regs.tstat[0];
+ return mc68328->regs.tstat[0];
+
+ case 0x60c:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): TCTL2 = %04x\n", mem_mask, mc68328->regs.tctl[1]);
+ return mc68328->regs.tctl[1];
+
+ case 0x60e:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): TPREP2 = %04x\n", mem_mask, mc68328->regs.tprer[1]);
+ return mc68328->regs.tprer[1];
+
+ case 0x610:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): TCMP2 = %04x\n", mem_mask, mc68328->regs.tcmp[1]);
+ return mc68328->regs.tcmp[1];
+
+ case 0x612:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): TCR2 = %04x\n", mem_mask, mc68328->regs.tcr[1]);
+ return mc68328->regs.tcr[1];
+
+ case 0x614:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): TCN2 = %04x\n", mem_mask, mc68328->regs.tcn[1]);
+ return mc68328->regs.tcn[1];
+
+ case 0x616:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): TSTAT2 = %04x\n", mem_mask, mc68328->regs.tstat[1]);
+ mc68328->regs.tclear[1] |= mc68328->regs.tstat[1];
+ return mc68328->regs.tstat[1];
+
+ case 0x618:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): WCTLR = %04x\n", mem_mask, mc68328->regs.wctlr);
+ return mc68328->regs.wctlr;
+
+ case 0x61a:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): WCMPR = %04x\n", mem_mask, mc68328->regs.wcmpr);
+ return mc68328->regs.wcmpr;
+
+ case 0x61c:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): WCN = %04x\n", mem_mask, mc68328->regs.wcn);
+ return mc68328->regs.wcn;
+
+ case 0x700:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): SPISR = %04x\n", mem_mask, mc68328->regs.spisr);
+ return mc68328->regs.spisr;
+
+ case 0x800:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): SPIMDATA = %04x\n", mem_mask, mc68328->regs.spimdata);
+ if(mc68328->iface->in_spim_func)
+ {
+ return (mc68328->iface->in_spim_func)( device, 0, 0xffff );
+ }
+ return mc68328->regs.spimdata;
+
+ case 0x802:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): SPIMCONT = %04x\n", mem_mask, mc68328->regs.spimcont);
+ if(mc68328->regs.spimcont & SPIM_XCH)
+ {
+ mc68328->regs.spimcont &= ~SPIM_XCH;
+ mc68328->regs.spimcont |= SPIM_SPIMIRQ;
+ return ((mc68328->regs.spimcont | SPIM_XCH) &~ SPIM_SPIMIRQ);
+ }
+ return mc68328->regs.spimcont;
+
+ case 0x900:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): USTCNT = %04x\n", mem_mask, mc68328->regs.ustcnt);
+ return mc68328->regs.ustcnt;
+
+ case 0x902:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): UBAUD = %04x\n", mem_mask, mc68328->regs.ubaud);
+ return mc68328->regs.ubaud;
+
+ case 0x904:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): URX = %04x\n", mem_mask, mc68328->regs.urx);
+ return mc68328->regs.urx;
+
+ case 0x906:
+ verboselog(device->machine(), 5, "mc68328_r (%04x): UTX = %04x\n", mem_mask, mc68328->regs.utx);
+ return mc68328->regs.utx | UTX_FIFO_EMPTY | UTX_FIFO_HALF | UTX_TX_AVAIL;
+
+ case 0x908:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): UMISC = %04x\n", mem_mask, mc68328->regs.umisc);
+ return mc68328->regs.umisc;
+
+ case 0xa00:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): LSSA(16) = %04x\n", mem_mask, mc68328->regs.lssa >> 16);
+ return mc68328->regs.lssa >> 16;
+
+ case 0xa02:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): LSSA(0) = %04x\n", mem_mask, mc68328->regs.lssa & 0x0000ffff);
+ return mc68328->regs.lssa & 0x0000ffff;
+
+ case 0xa04:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): LVPW = %02x\n", mem_mask, mc68328->regs.lvpw);
+ return mc68328->regs.lvpw;
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa04)\n", mem_mask);
+ }
+ break;
+
+ case 0xa08:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): LXMAX = %04x\n", mem_mask, mc68328->regs.lxmax);
+ return mc68328->regs.lxmax;
+
+ case 0xa0a:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): LYMAX = %04x\n", mem_mask, mc68328->regs.lymax);
+ return mc68328->regs.lymax;
+
+ case 0xa18:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): LCXP = %04x\n", mem_mask, mc68328->regs.lcxp);
+ return mc68328->regs.lcxp;
+
+ case 0xa1a:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): LCYP = %04x\n", mem_mask, mc68328->regs.lcyp);
+ return mc68328->regs.lcyp;
+
+ case 0xa1c:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): LCWCH = %04x\n", mem_mask, mc68328->regs.lcwch);
+ return mc68328->regs.lcwch;
+
+ case 0xa1e:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): LBLKC = %02x\n", mem_mask, mc68328->regs.lblkc);
+ return mc68328->regs.lblkc;
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa1e)\n", mem_mask);
+ }
+ break;
+
+ case 0xa20:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): LPOLCF = %02x\n", mem_mask, mc68328->regs.lpolcf);
+ return mc68328->regs.lpolcf;
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): LPICF = %02x\n", mem_mask, mc68328->regs.lpicf);
+ return mc68328->regs.lpicf << 8;
+ }
+ break;
+
+ case 0xa22:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): LACDRC = %02x\n", mem_mask, mc68328->regs.lacdrc);
+ return mc68328->regs.lacdrc;
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa22)\n", mem_mask);
+ }
+ break;
+
+ case 0xa24:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): LPXCD = %02x\n", mem_mask, mc68328->regs.lpxcd);
+ return mc68328->regs.lpxcd;
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa24)\n", mem_mask);
+ }
+ break;
+
+ case 0xa26:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): LCKCON = %02x\n", mem_mask, mc68328->regs.lckcon);
+ return mc68328->regs.lckcon;
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa26)\n", mem_mask);
+ }
+ break;
+
+ case 0xa28:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): LLBAR = %02x\n", mem_mask, mc68328->regs.llbar);
+ return mc68328->regs.llbar;
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa28)\n", mem_mask);
+ }
+ break;
+
+ case 0xa2a:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): LOTCR = %02x\n", mem_mask, mc68328->regs.lotcr);
+ return mc68328->regs.lotcr;
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa2a)\n", mem_mask);
+ }
+ break;
+
+ case 0xa2c:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): LPOSR = %02x\n", mem_mask, mc68328->regs.lposr);
+ return mc68328->regs.lposr;
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa2c)\n", mem_mask);
+ }
+ break;
+
+ case 0xa30:
+ if( mem_mask & 0x00ff )
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): LFRCM = %02x\n", mem_mask, mc68328->regs.lfrcm);
+ return mc68328->regs.lfrcm;
+ }
+ else
+ {
+ verboselog(device->machine(), 2, "mc68328_r (%04x): Unknown address (0xfffa30)\n", mem_mask);
+ }
+ break;
+
+ case 0xa32:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): LGPMR = %04x\n", mem_mask, mc68328->regs.lgpmr);
+ return mc68328->regs.lgpmr;
+
+ case 0xb00:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): HMSR(0) = %04x\n", mem_mask, mc68328->regs.hmsr & 0x0000ffff);
+ return mc68328->regs.hmsr & 0x0000ffff;
+
+ case 0xb02:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): HMSR(16) = %04x\n", mem_mask, mc68328->regs.hmsr >> 16);
+ return mc68328->regs.hmsr >> 16;
+
+ case 0xb04:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): ALARM(0) = %04x\n", mem_mask, mc68328->regs.alarm & 0x0000ffff);
+ return mc68328->regs.alarm & 0x0000ffff;
+
+ case 0xb06:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): ALARM(16) = %04x\n", mem_mask, mc68328->regs.alarm >> 16);
+ return mc68328->regs.alarm >> 16;
+
+ case 0xb0c:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): RTCCTL = %04x\n", mem_mask, mc68328->regs.rtcctl);
+ return mc68328->regs.rtcctl;
+
+ case 0xb0e:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): RTCISR = %04x\n", mem_mask, mc68328->regs.rtcisr);
+ return mc68328->regs.rtcisr;
+
+ case 0xb10:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): RTCIENR = %04x\n", mem_mask, mc68328->regs.rtcienr);
+ return mc68328->regs.rtcienr;
+
+ case 0xb12:
+ verboselog(device->machine(), 2, "mc68328_r (%04x): STPWTCH = %04x\n", mem_mask, mc68328->regs.stpwtch);
+ return mc68328->regs.stpwtch;
+
+ default:
+ verboselog(device->machine(), 0, "mc68328_r (%04x): Unknown address (0x%06x)\n", mem_mask, 0xfff000 + address);
+ break;
+ }
+ return 0;
+}
+
+static DEVICE_RESET( mc68328 )
+{
+ mc68328_t* mc68328 = mc68328_get_safe_token( device );
+
+ mc68328->regs.scr = 0x0c;
+ mc68328->regs.grpbasea = 0x0000;
+ mc68328->regs.grpbaseb = 0x0000;
+ mc68328->regs.grpbasec = 0x0000;
+ mc68328->regs.grpbased = 0x0000;
+ mc68328->regs.grpmaska = 0x0000;
+ mc68328->regs.grpmaskb = 0x0000;
+ mc68328->regs.grpmaskc = 0x0000;
+ mc68328->regs.grpmaskd = 0x0000;
+ mc68328->regs.csa0 = 0x00010006;
+ mc68328->regs.csa1 = 0x00010006;
+ mc68328->regs.csa2 = 0x00010006;
+ mc68328->regs.csa3 = 0x00010006;
+ mc68328->regs.csb0 = 0x00010006;
+ mc68328->regs.csb1 = 0x00010006;
+ mc68328->regs.csb2 = 0x00010006;
+ mc68328->regs.csb3 = 0x00010006;
+ mc68328->regs.csc0 = 0x00010006;
+ mc68328->regs.csc1 = 0x00010006;
+ mc68328->regs.csc2 = 0x00010006;
+ mc68328->regs.csc3 = 0x00010006;
+ mc68328->regs.csd0 = 0x00010006;
+ mc68328->regs.csd1 = 0x00010006;
+ mc68328->regs.csd2 = 0x00010006;
+ mc68328->regs.csd3 = 0x00010006;
+
+ mc68328->regs.pllcr = 0x2400;
+ mc68328->regs.pllfsr = 0x0123;
+ mc68328->regs.pctlr = 0x1f;
+
+ mc68328->regs.ivr = 0x00;
+ mc68328->regs.icr = 0x0000;
+ mc68328->regs.imr = 0x00ffffff;
+ mc68328->regs.iwr = 0x00ffffff;
+ mc68328->regs.isr = 0x00000000;
+ mc68328->regs.ipr = 0x00000000;
+
+ mc68328->regs.padir = 0x00;
+ mc68328->regs.padata = 0x00;
+ mc68328->regs.pasel = 0x00;
+ mc68328->regs.pbdir = 0x00;
+ mc68328->regs.pbdata = 0x00;
+ mc68328->regs.pbsel = 0x00;
+ mc68328->regs.pcdir = 0x00;
+ mc68328->regs.pcdata = 0x00;
+ mc68328->regs.pcsel = 0x00;
+ mc68328->regs.pddir = 0x00;
+ mc68328->regs.pddata = 0x00;
+ mc68328->regs.pdpuen = 0xff;
+ mc68328->regs.pdpol = 0x00;
+ mc68328->regs.pdirqen = 0x00;
+ mc68328->regs.pddataedge = 0x00;
+ mc68328->regs.pdirqedge = 0x00;
+ mc68328->regs.pedir = 0x00;
+ mc68328->regs.pedata = 0x00;
+ mc68328->regs.pepuen = 0x80;
+ mc68328->regs.pesel = 0x80;
+ mc68328->regs.pfdir = 0x00;
+ mc68328->regs.pfdata = 0x00;
+ mc68328->regs.pfpuen = 0xff;
+ mc68328->regs.pfsel = 0xff;
+ mc68328->regs.pgdir = 0x00;
+ mc68328->regs.pgdata = 0x00;
+ mc68328->regs.pgpuen = 0xff;
+ mc68328->regs.pgsel = 0xff;
+ mc68328->regs.pjdir = 0x00;
+ mc68328->regs.pjdata = 0x00;
+ mc68328->regs.pjsel = 0x00;
+ mc68328->regs.pkdir = 0x00;
+ mc68328->regs.pkdata = 0x00;
+ mc68328->regs.pkpuen = 0xff;
+ mc68328->regs.pksel = 0xff;
+ mc68328->regs.pmdir = 0x00;
+ mc68328->regs.pmdata = 0x00;
+ mc68328->regs.pmpuen = 0xff;
+ mc68328->regs.pmsel = 0xff;
+
+ mc68328->regs.pwmc = 0x0000;
+ mc68328->regs.pwmp = 0x0000;
+ mc68328->regs.pwmw = 0x0000;
+ mc68328->regs.pwmcnt = 0x0000;
+
+ mc68328->regs.tctl[0] = mc68328->regs.tctl[1] = 0x0000;
+ mc68328->regs.tprer[0] = mc68328->regs.tprer[1] = 0x0000;
+ mc68328->regs.tcmp[0] = mc68328->regs.tcmp[1] = 0xffff;
+ mc68328->regs.tcr[0] = mc68328->regs.tcr[1] = 0x0000;
+ mc68328->regs.tcn[0] = mc68328->regs.tcn[1] = 0x0000;
+ mc68328->regs.tstat[0] = mc68328->regs.tstat[1] = 0x0000;
+ mc68328->regs.wctlr = 0x0000;
+ mc68328->regs.wcmpr = 0xffff;
+ mc68328->regs.wcn = 0x0000;
+
+ mc68328->regs.spisr = 0x0000;
+
+ mc68328->regs.spimdata = 0x0000;
+ mc68328->regs.spimcont = 0x0000;
+
+ mc68328->regs.ustcnt = 0x0000;
+ mc68328->regs.ubaud = 0x003f;
+ mc68328->regs.urx = 0x0000;
+ mc68328->regs.utx = 0x0000;
+ mc68328->regs.umisc = 0x0000;
+
+ mc68328->regs.lssa = 0x00000000;
+ mc68328->regs.lvpw = 0xff;
+ mc68328->regs.lxmax = 0x03ff;
+ mc68328->regs.lymax = 0x01ff;
+ mc68328->regs.lcxp = 0x0000;
+ mc68328->regs.lcyp = 0x0000;
+ mc68328->regs.lcwch = 0x0101;
+ mc68328->regs.lblkc = 0x7f;
+ mc68328->regs.lpicf = 0x00;
+ mc68328->regs.lpolcf = 0x00;
+ mc68328->regs.lacdrc = 0x00;
+ mc68328->regs.lpxcd = 0x00;
+ mc68328->regs.lckcon = 0x40;
+ mc68328->regs.llbar = 0x3e;
+ mc68328->regs.lotcr = 0x3f;
+ mc68328->regs.lposr = 0x00;
+ mc68328->regs.lfrcm = 0xb9;
+ mc68328->regs.lgpmr = 0x1073;
+
+ mc68328->regs.hmsr = 0x00000000;
+ mc68328->regs.alarm = 0x00000000;
+ mc68328->regs.rtcctl = 0x00;
+ mc68328->regs.rtcisr = 0x00;
+ mc68328->regs.rtcienr = 0x00;
+ mc68328->regs.stpwtch = 0x00;
+
+ mc68328->rtc->adjust(attotime::from_hz(1), 0, attotime::from_hz(1));
+}
+
+static void mc68328_register_state_save(device_t *device)
+{
+ mc68328_t* mc68328 = mc68328_get_safe_token( device );
+
+ state_save_register_global(device->machine(), mc68328->regs.scr);
+ state_save_register_global(device->machine(), mc68328->regs.grpbasea);
+ state_save_register_global(device->machine(), mc68328->regs.grpbaseb);
+ state_save_register_global(device->machine(), mc68328->regs.grpbasec);
+ state_save_register_global(device->machine(), mc68328->regs.grpbased);
+ state_save_register_global(device->machine(), mc68328->regs.grpmaska);
+ state_save_register_global(device->machine(), mc68328->regs.grpmaskb);
+ state_save_register_global(device->machine(), mc68328->regs.grpmaskc);
+ state_save_register_global(device->machine(), mc68328->regs.grpmaskd);
+ state_save_register_global(device->machine(), mc68328->regs.csa0);
+ state_save_register_global(device->machine(), mc68328->regs.csa1);
+ state_save_register_global(device->machine(), mc68328->regs.csa2);
+ state_save_register_global(device->machine(), mc68328->regs.csa3);
+ state_save_register_global(device->machine(), mc68328->regs.csb0);
+ state_save_register_global(device->machine(), mc68328->regs.csb1);
+ state_save_register_global(device->machine(), mc68328->regs.csb2);
+ state_save_register_global(device->machine(), mc68328->regs.csb3);
+ state_save_register_global(device->machine(), mc68328->regs.csc0);
+ state_save_register_global(device->machine(), mc68328->regs.csc1);
+ state_save_register_global(device->machine(), mc68328->regs.csc2);
+ state_save_register_global(device->machine(), mc68328->regs.csc3);
+ state_save_register_global(device->machine(), mc68328->regs.csd0);
+ state_save_register_global(device->machine(), mc68328->regs.csd1);
+ state_save_register_global(device->machine(), mc68328->regs.csd2);
+ state_save_register_global(device->machine(), mc68328->regs.csd3);
+
+ state_save_register_global(device->machine(), mc68328->regs.pllcr);
+ state_save_register_global(device->machine(), mc68328->regs.pllfsr);
+ state_save_register_global(device->machine(), mc68328->regs.pctlr);
+
+ state_save_register_global(device->machine(), mc68328->regs.ivr);
+ state_save_register_global(device->machine(), mc68328->regs.icr);
+ state_save_register_global(device->machine(), mc68328->regs.imr);
+ state_save_register_global(device->machine(), mc68328->regs.iwr);
+ state_save_register_global(device->machine(), mc68328->regs.isr);
+ state_save_register_global(device->machine(), mc68328->regs.ipr);
+
+ state_save_register_global(device->machine(), mc68328->regs.padir);
+ state_save_register_global(device->machine(), mc68328->regs.padata);
+ state_save_register_global(device->machine(), mc68328->regs.pasel);
+ state_save_register_global(device->machine(), mc68328->regs.pbdir);
+ state_save_register_global(device->machine(), mc68328->regs.pbdata);
+ state_save_register_global(device->machine(), mc68328->regs.pbsel);
+ state_save_register_global(device->machine(), mc68328->regs.pcdir);
+ state_save_register_global(device->machine(), mc68328->regs.pcdata);
+ state_save_register_global(device->machine(), mc68328->regs.pcsel);
+ state_save_register_global(device->machine(), mc68328->regs.pddir);
+ state_save_register_global(device->machine(), mc68328->regs.pddata);
+ state_save_register_global(device->machine(), mc68328->regs.pdpuen);
+ state_save_register_global(device->machine(), mc68328->regs.pdpol);
+ state_save_register_global(device->machine(), mc68328->regs.pdirqen);
+ state_save_register_global(device->machine(), mc68328->regs.pddataedge);
+ state_save_register_global(device->machine(), mc68328->regs.pdirqedge);
+ state_save_register_global(device->machine(), mc68328->regs.pedir);
+ state_save_register_global(device->machine(), mc68328->regs.pedata);
+ state_save_register_global(device->machine(), mc68328->regs.pepuen);
+ state_save_register_global(device->machine(), mc68328->regs.pesel);
+ state_save_register_global(device->machine(), mc68328->regs.pfdir);
+ state_save_register_global(device->machine(), mc68328->regs.pfdata);
+ state_save_register_global(device->machine(), mc68328->regs.pfpuen);
+ state_save_register_global(device->machine(), mc68328->regs.pfsel);
+ state_save_register_global(device->machine(), mc68328->regs.pgdir);
+ state_save_register_global(device->machine(), mc68328->regs.pgdata);
+ state_save_register_global(device->machine(), mc68328->regs.pgpuen);
+ state_save_register_global(device->machine(), mc68328->regs.pgsel);
+ state_save_register_global(device->machine(), mc68328->regs.pjdir);
+ state_save_register_global(device->machine(), mc68328->regs.pjdata);
+ state_save_register_global(device->machine(), mc68328->regs.pjsel);
+ state_save_register_global(device->machine(), mc68328->regs.pkdir);
+ state_save_register_global(device->machine(), mc68328->regs.pkdata);
+ state_save_register_global(device->machine(), mc68328->regs.pkpuen);
+ state_save_register_global(device->machine(), mc68328->regs.pksel);
+ state_save_register_global(device->machine(), mc68328->regs.pmdir);
+ state_save_register_global(device->machine(), mc68328->regs.pmdata);
+ state_save_register_global(device->machine(), mc68328->regs.pmpuen);
+ state_save_register_global(device->machine(), mc68328->regs.pmsel);
+
+ state_save_register_global(device->machine(), mc68328->regs.pwmc);
+ state_save_register_global(device->machine(), mc68328->regs.pwmp);
+ state_save_register_global(device->machine(), mc68328->regs.pwmw);
+ state_save_register_global(device->machine(), mc68328->regs.pwmcnt);
+
+ state_save_register_global(device->machine(), mc68328->regs.tctl[0]);
+ state_save_register_global(device->machine(), mc68328->regs.tctl[1]);
+ state_save_register_global(device->machine(), mc68328->regs.tprer[0]);
+ state_save_register_global(device->machine(), mc68328->regs.tprer[1]);
+ state_save_register_global(device->machine(), mc68328->regs.tcmp[0]);
+ state_save_register_global(device->machine(), mc68328->regs.tcmp[1]);
+ state_save_register_global(device->machine(), mc68328->regs.tcr[0]);
+ state_save_register_global(device->machine(), mc68328->regs.tcr[1]);
+ state_save_register_global(device->machine(), mc68328->regs.tcn[0]);
+ state_save_register_global(device->machine(), mc68328->regs.tcn[1]);
+ state_save_register_global(device->machine(), mc68328->regs.tstat[0]);
+ state_save_register_global(device->machine(), mc68328->regs.tstat[1]);
+ state_save_register_global(device->machine(), mc68328->regs.wctlr);
+ state_save_register_global(device->machine(), mc68328->regs.wcmpr);
+ state_save_register_global(device->machine(), mc68328->regs.wcn);
+
+ state_save_register_global(device->machine(), mc68328->regs.spisr);
+
+ state_save_register_global(device->machine(), mc68328->regs.spimdata);
+ state_save_register_global(device->machine(), mc68328->regs.spimcont);
+
+ state_save_register_global(device->machine(), mc68328->regs.ustcnt);
+ state_save_register_global(device->machine(), mc68328->regs.ubaud);
+ state_save_register_global(device->machine(), mc68328->regs.urx);
+ state_save_register_global(device->machine(), mc68328->regs.utx);
+ state_save_register_global(device->machine(), mc68328->regs.umisc);
+
+ state_save_register_global(device->machine(), mc68328->regs.lssa);
+ state_save_register_global(device->machine(), mc68328->regs.lvpw);
+ state_save_register_global(device->machine(), mc68328->regs.lxmax);
+ state_save_register_global(device->machine(), mc68328->regs.lymax);
+ state_save_register_global(device->machine(), mc68328->regs.lcxp);
+ state_save_register_global(device->machine(), mc68328->regs.lcyp);
+ state_save_register_global(device->machine(), mc68328->regs.lcwch);
+ state_save_register_global(device->machine(), mc68328->regs.lblkc);
+ state_save_register_global(device->machine(), mc68328->regs.lpicf);
+ state_save_register_global(device->machine(), mc68328->regs.lpolcf);
+ state_save_register_global(device->machine(), mc68328->regs.lacdrc);
+ state_save_register_global(device->machine(), mc68328->regs.lpxcd);
+ state_save_register_global(device->machine(), mc68328->regs.lckcon);
+ state_save_register_global(device->machine(), mc68328->regs.llbar);
+ state_save_register_global(device->machine(), mc68328->regs.lotcr);
+ state_save_register_global(device->machine(), mc68328->regs.lposr);
+ state_save_register_global(device->machine(), mc68328->regs.lfrcm);
+ state_save_register_global(device->machine(), mc68328->regs.lgpmr);
+
+ state_save_register_global(device->machine(), mc68328->regs.hmsr);
+ state_save_register_global(device->machine(), mc68328->regs.alarm);
+ state_save_register_global(device->machine(), mc68328->regs.rtcctl);
+ state_save_register_global(device->machine(), mc68328->regs.rtcisr);
+ state_save_register_global(device->machine(), mc68328->regs.rtcienr);
+ state_save_register_global(device->machine(), mc68328->regs.stpwtch);
+}
+
+static DEVICE_START( mc68328 )
+{
+ mc68328_t* mc68328 = mc68328_get_safe_token( device );
+
+ mc68328->iface = (const mc68328_interface*)device->static_config();
+
+ mc68328->gptimer[0] = device->machine().scheduler().timer_alloc(FUNC(mc68328_timer1_hit));
+ mc68328->gptimer[1] = device->machine().scheduler().timer_alloc(FUNC(mc68328_timer2_hit));
+ mc68328->rtc = device->machine().scheduler().timer_alloc(FUNC(mc68328_rtc_tick));
+ mc68328->pwm = device->machine().scheduler().timer_alloc(FUNC(mc68328_pwm_transition));
+
+ mc68328_register_state_save(device);
+}
+
+DEVICE_GET_INFO( mc68328 )
+{
+ switch ( state )
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(mc68328_t); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(mc68328); break;
+ case DEVINFO_FCT_STOP: /* nothing */ break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(mc68328); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "Motorola MC68328 (DragonBall) Integrated Processor"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "MC68328"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.00"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright the MESS Teams and Ryan Holtz"); break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(MC68328, mc68328);
diff --git a/src/mess/machine/mc68328.h b/src/mess/machine/mc68328.h
new file mode 100644
index 00000000000..8ddee5c8907
--- /dev/null
+++ b/src/mess/machine/mc68328.h
@@ -0,0 +1,541 @@
+/**********************************************************************
+
+ Motorola 68328 ("DragonBall") System-on-a-Chip private data
+
+ By MooglyGuy
+ contact mooglyguy@gmail.com with licensing and usage questions.
+
+**********************************************************************/
+
+#ifndef __MC68328_PRIVATE_H_
+#define __MC68328_PRIVATE_H_
+
+typedef struct
+{
+ // $(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];
+} mc68328_regs_t;
+
+typedef struct
+{
+ const mc68328_interface* iface;
+
+ mc68328_regs_t regs;
+
+ emu_timer *gptimer[2];
+ emu_timer *rtc;
+ emu_timer *pwm;
+} mc68328_t;
+
+#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
+
+INLINE mc68328_t* mc68328_get_safe_token( device_t *device )
+{
+ assert( device != NULL );
+ assert( device->type() == MC68328 );
+ return (mc68328_t*) downcast<legacy_device_base *>(device)->token();
+}
+
+#endif // __MC68328_PRIVATE_H_
diff --git a/src/mess/machine/mc6843.c b/src/mess/machine/mc6843.c
new file mode 100644
index 00000000000..570f8307d47
--- /dev/null
+++ b/src/mess/machine/mc6843.c
@@ -0,0 +1,856 @@
+/**********************************************************************
+
+ 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"
+#include "imagedev/flopdrv.h"
+
+
+/******************* parameters ******************/
+
+#define VERBOSE 0
+
+
+/******************* internal chip data structure ******************/
+
+typedef struct
+{
+
+ /* interface */
+ const mc6843_interface* iface;
+
+ /* registers */
+ UINT8 CTAR; /* current track */
+ UINT8 CMR; /* command */
+ UINT8 ISR; /* interrupt status */
+ UINT8 SUR; /* set-up */
+ UINT8 STRA; /* status */
+ UINT8 STRB; /* status */
+ UINT8 SAR; /* sector address */
+ UINT8 GCR; /* general count */
+ UINT8 CCR; /* CRC control */
+ UINT8 LTAR; /* logical address track (=track destination) */
+
+ /* internal state */
+ UINT8 drive;
+ UINT8 side;
+ UINT8 data[128]; /* sector buffer */
+ UINT32 data_size; /* size of data */
+ UINT32 data_idx; /* current read/write position in data */
+ UINT32 data_id; /* chrd_id for sector write */
+ UINT8 index_pulse;
+
+ /* trigger delayed actions (bottom halves) */
+ emu_timer* timer_cont;
+
+} mc6843_t;
+
+
+
+/* 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)
+
+
+
+INLINE mc6843_t* get_safe_token( device_t *device )
+{
+ assert( device != NULL );
+ assert( device->type() == MC6843 );
+ return (mc6843_t*) downcast<legacy_device_base *>(device)->token();
+}
+
+
+/************************** floppy interface ****************************/
+
+
+
+static device_t* mc6843_floppy_image ( device_t *device )
+{
+ mc6843_t* mc6843 = get_safe_token( device );
+ return floppy_get_device( device->machine(), mc6843->drive );
+}
+
+
+
+void mc6843_set_drive( device_t *device, int drive )
+{
+ mc6843_t* mc6843 = get_safe_token( device );
+ mc6843->drive = drive;
+}
+
+
+
+void mc6843_set_side( device_t *device, int side )
+{
+ mc6843_t* mc6843 = get_safe_token( device );
+ mc6843->side = side;
+}
+
+
+
+/* called after ISR or STRB has changed */
+static void mc6843_status_update( device_t *device )
+{
+ mc6843_t* mc6843 = get_safe_token( device );
+ int irq = 0;
+
+ /* ISR3 */
+ if ( (mc6843->CMR & 0x40) || ! mc6843->STRB )
+ mc6843->ISR &= ~8;
+ else
+ mc6843->ISR |= 8;
+
+ /* interrupts */
+ if ( mc6843->ISR & 4 )
+ irq = 1; /* unmaskable */
+ if ( ! (mc6843->CMR & 0x80) )
+ {
+ /* maskable */
+ if ( mc6843->ISR & ~4 )
+ irq = 1;
+ }
+
+ if ( mc6843->iface->irq_func )
+ {
+ mc6843->iface->irq_func( device, irq );
+ LOG(( "mc6843_status_update: irq=%i (CMR=%02X, ISR=%02X)\n", irq, mc6843->CMR, mc6843->ISR ));
+ }
+}
+
+
+void mc6843_set_index_pulse ( device_t *device, int index_pulse )
+{
+ mc6843_t* mc6843 = get_safe_token( device );
+ mc6843->index_pulse = index_pulse;
+}
+
+
+/* called at end of command */
+static void mc6843_cmd_end( device_t *device )
+{
+ mc6843_t* mc6843 = get_safe_token( device );
+ int cmd = mc6843->CMR & 0x0f;
+ if ( ( cmd == CMD_STZ ) || ( cmd == CMD_SEK ) )
+ {
+ mc6843->ISR |= 0x02; /* set Settling Time Complete */
+ }
+ else
+ {
+ mc6843->ISR |= 0x01; /* set Macro Command Complete */
+ }
+ mc6843->STRA &= ~0x80; /* clear Busy */
+ mc6843->CMR &= 0xf0; /* clear command */
+ mc6843_status_update( device );
+}
+
+
+
+/* Seek Track Zero bottom half */
+static void mc6843_finish_STZ( device_t *device )
+{
+ mc6843_t* mc6843 = get_safe_token( device );
+ device_t* img = mc6843_floppy_image( device );
+ int i;
+
+ /* seek to track zero */
+ for ( i=0; i<83; i++ )
+ {
+ if (floppy_tk00_r(img) == CLEAR_LINE)
+ break;
+ floppy_drive_seek( img, -1 );
+ }
+
+ LOG(( "%f mc6843_finish_STZ: actual=%i\n", device->machine().time().as_double(), floppy_drive_get_current_track( img ) ));
+
+ /* update state */
+ mc6843->CTAR = 0;
+ mc6843->GCR = 0;
+ mc6843->SAR = 0;
+ mc6843->STRB |= floppy_tk00_r(img) << 4;
+
+ mc6843_cmd_end( device );
+}
+
+
+
+/* Seek bottom half */
+static void mc6843_finish_SEK( device_t *device )
+{
+ mc6843_t* mc6843 = get_safe_token( device );
+ device_t* img = mc6843_floppy_image( device );
+
+ /* seek to track */
+ floppy_drive_seek( img, mc6843->GCR - mc6843->CTAR );
+
+ LOG(( "%f mc6843_finish_SEK: from %i to %i (actual=%i)\n", device->machine().time().as_double(), mc6843->CTAR, mc6843->GCR, floppy_drive_get_current_track( img ) ));
+
+ /* update state */
+ mc6843->CTAR = mc6843->GCR;
+ mc6843->SAR = 0;
+ mc6843_cmd_end( device );
+}
+
+
+
+/* preamble to all sector read / write commands, returns 1 if found */
+static int mc6843_address_search( device_t *device, chrn_id* id )
+{
+ mc6843_t* mc6843 = get_safe_token( device );
+ device_t* img = mc6843_floppy_image( device );
+ int r = 0;
+
+ while ( 1 )
+ {
+
+ if ( ( ! floppy_drive_get_next_id( img, mc6843->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", device->machine().time().as_double() ));
+ mc6843->STRB |= 0x0a; /* set CRC error & Sector Address Undetected */
+ mc6843_cmd_end( device );
+ return 0;
+ }
+
+ if ( id->C != mc6843->LTAR )
+ {
+ /* track mismatch */
+ LOG(( "%f mc6843_address_search: track mismatch: logical=%i real=%i\n", device->machine().time().as_double(), mc6843->LTAR, id->C ));
+ mc6843->data[0] = id->C; /* make the track number available to the CPU */
+ mc6843->STRA |= 0x20; /* set Track Not Equal */
+ mc6843_cmd_end( device );
+ return 0;
+ }
+
+ if ( id->R == mc6843->SAR )
+ {
+ /* found! */
+ LOG(( "%f mc6843_address_search: sector %i found on track %i\n", device->machine().time().as_double(), id->R, id->C ));
+ if ( ! (mc6843->CMR & 0x20) )
+ {
+ mc6843->ISR |= 0x04; /* if no DMA, set Status Sense */
+ }
+ return 1;
+ }
+
+ if ( floppy_drive_get_flag_state( img, 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", device->machine().time().as_double(), mc6843->SAR ));
+ mc6843->STRB |= 0x08; /* set Sector Address Undetected */
+ mc6843_cmd_end( device );
+ return 0;
+ }
+ }
+ }
+
+ return 0; /* unreachable */
+}
+
+
+
+/* preamble specific to read commands (adds extra checks) */
+static int mc6843_address_search_read( device_t *device, chrn_id* id )
+{
+ mc6843_t* mc6843 = get_safe_token( device );
+ if ( ! mc6843_address_search( device, id ) )
+ return 0;
+
+ if ( id->flags & ID_FLAG_CRC_ERROR_IN_DATA_FIELD )
+ {
+ LOG(( "%f mc6843_address_search_read: data CRC error\n", device->machine().time().as_double() ));
+ mc6843->STRB |= 0x06; /* set CRC error & Data Mark Undetected */
+ mc6843_cmd_end( device );
+ return 0;
+ }
+
+ if ( id->flags & ID_FLAG_DELETED_DATA )
+ {
+ LOG(( "%f mc6843_address_search_read: deleted data\n", device->machine().time().as_double() ));
+ mc6843->STRA |= 0x02; /* set Delete Data Mark Detected */
+ }
+
+ return 1;
+}
+
+
+
+
+/* Read CRC bottom half */
+static void mc6843_finish_RCR( device_t *device )
+{
+ chrn_id id;
+ if ( ! mc6843_address_search_read( device, &id ) )
+ return;
+ mc6843_cmd_end( device );
+}
+
+
+
+/* Single / Multiple Sector Read bottom half */
+static void mc6843_cont_SR( device_t *device )
+{
+ mc6843_t* mc6843 = get_safe_token( device );
+ chrn_id id;
+ device_t* img = mc6843_floppy_image( device );
+
+ /* sector seek */
+ if ( ! mc6843_address_search_read( device, &id ) )
+ return;
+
+ /* sector read */
+ floppy_drive_read_sector_data( img, mc6843->side, id.data_id, mc6843->data, 128 );
+ mc6843->data_idx = 0;
+ mc6843->data_size = 128;
+ mc6843->STRA |= 0x01; /* set Data Transfer Request */
+ mc6843_status_update( device );
+}
+
+
+
+/* Single / Multiple Sector Write bottom half */
+static void mc6843_cont_SW( device_t *device )
+{
+ mc6843_t* mc6843 = get_safe_token( device );
+ chrn_id id;
+
+ /* sector seek */
+ if ( ! mc6843_address_search( device, &id ) )
+ return;
+
+ /* setup sector write buffer */
+ mc6843->data_idx = 0;
+ mc6843->data_size = 128;
+ mc6843->STRA |= 0x01; /* set Data Transfer Request */
+ mc6843->data_id = id.data_id; /* for subsequent write sector command */
+ mc6843_status_update( device );
+}
+
+
+
+/* bottom halves, called to continue / finish a command after some delay */
+static TIMER_CALLBACK( mc6843_cont )
+{
+ device_t* device = (device_t*) ptr;
+ mc6843_t* mc6843 = get_safe_token( device );
+ int cmd = mc6843->CMR & 0x0f;
+
+ LOG(( "%f mc6843_cont: timer called for cmd=%s(%i)\n", device->machine().time().as_double(), mc6843_cmd[cmd], cmd ));
+
+ mc6843->timer_cont->adjust( attotime::never );
+
+ switch ( cmd )
+ {
+ case CMD_STZ: mc6843_finish_STZ( device ); break;
+ case CMD_SEK: mc6843_finish_SEK( device ); break;
+ case CMD_SSR: mc6843_cont_SR( device ); break;
+ case CMD_SSW: mc6843_cont_SW( device ); break;
+ case CMD_RCR: mc6843_finish_RCR( device ); break;
+ case CMD_SWD: mc6843_cont_SW( device ); break;
+ case CMD_MSW: mc6843_cont_SW( device ); break;
+ case CMD_MSR: mc6843_cont_SR( device ); break;
+ }
+}
+
+
+
+/************************** CPU interface ****************************/
+
+
+
+READ8_DEVICE_HANDLER ( mc6843_r )
+{
+ mc6843_t* mc6843 = get_safe_token( device );
+ UINT8 data = 0;
+
+ switch ( offset ) {
+
+ case 0: /* Data Input Register (DIR) */
+ {
+ int cmd = mc6843->CMR & 0x0f;
+
+ LOG(( "%f $%04x mc6843_r: data input cmd=%s(%i), pos=%i/%i, GCR=%i, ",
+ device->machine().time().as_double(), cpu_get_previouspc( device->machine().firstcpu ),
+ mc6843_cmd[cmd], cmd, mc6843->data_idx,
+ mc6843->data_size, mc6843->GCR ));
+
+ if ( cmd == CMD_SSR || cmd == CMD_MSR )
+ {
+ /* sector read */
+ assert( mc6843->data_size > 0 );
+ assert( mc6843->data_idx < mc6843->data_size );
+ assert( mc6843->data_idx < sizeof(mc6843->data) );
+ data = mc6843->data[ mc6843->data_idx ];
+ mc6843->data_idx++;
+
+ if ( mc6843->data_idx >= mc6843->data_size )
+ {
+ /* end of sector read */
+
+ mc6843->STRA &= ~0x01; /* clear Data Transfer Request */
+
+ if ( cmd == CMD_MSR )
+ {
+ /* schedule next sector in multiple sector read */
+ mc6843->GCR--;
+ mc6843->SAR++;
+ if ( mc6843->GCR == 0xff )
+ {
+ mc6843_cmd_end( device );
+ }
+ else if ( mc6843->SAR > 26 )
+
+ {
+ mc6843->STRB |= 0x08; /* set Sector Address Undetected */
+ mc6843_cmd_end( device );
+ }
+ else
+ {
+ mc6843->timer_cont->adjust( DELAY_ADDR );
+ }
+ }
+ else
+ {
+ mc6843_cmd_end( device );
+ }
+ }
+ }
+ else if ( cmd == 0 )
+ {
+ data = mc6843->data[0];
+ }
+ else
+ {
+ /* XXX TODO: other read modes */
+ data = mc6843->data[0];
+ logerror( "$%04x mc6843 read in unsupported command mode %i\n", cpu_get_previouspc( device->machine().firstcpu ), cmd );
+ }
+
+ LOG(( "data=%02X\n", data ));
+
+ break;
+ }
+
+ case 1: /* Current-Track Address Register (CTAR) */
+ data = mc6843->CTAR;
+ LOG(( "%f $%04x mc6843_r: read CTAR %i (actual=%i)\n",
+ device->machine().time().as_double(), cpu_get_previouspc( device->machine().firstcpu ), data,
+ floppy_drive_get_current_track( mc6843_floppy_image( device ) ) ));
+ break;
+
+ case 2: /* Interrupt Status Register (ISR) */
+ data = mc6843->ISR;
+ LOG(( "%f $%04x mc6843_r: read ISR %02X: cmd=%scomplete settle=%scomplete sense-rq=%i STRB=%i\n",
+ device->machine().time().as_double(), cpu_get_previouspc( device->machine().firstcpu ), data,
+ (data & 1) ? "" : "not-" , (data & 2) ? "" : "not-",
+ (data >> 2) & 1, (data >> 3) & 1 ));
+
+ /* reset */
+ mc6843->ISR &= 8; /* keep STRB */
+ mc6843_status_update( device );
+ break;
+
+ case 3: /* Status Register A (STRA) */
+ {
+ /* update */
+ device_t* img = mc6843_floppy_image( device );
+ int flag = floppy_drive_get_flag_state( img, FLOPPY_DRIVE_READY);
+ mc6843->STRA &= 0xa3;
+ if ( flag & FLOPPY_DRIVE_READY )
+ mc6843->STRA |= 0x04;
+
+ mc6843->STRA |= !floppy_tk00_r(img) << 3;
+ mc6843->STRA |= !floppy_wpt_r(img) << 4;
+
+ if ( mc6843->index_pulse )
+ mc6843->STRA |= 0x40;
+
+ data = mc6843->STRA;
+ LOG(( "%f $%04x 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",
+ device->machine().time().as_double(), cpu_get_previouspc( device->machine().firstcpu ), 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 = mc6843->STRB;
+ LOG(( "%f $%04x 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",
+ device->machine().time().as_double(), cpu_get_previouspc( device->machine().firstcpu ), 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 */
+ mc6843->STRB &= ~0xfb;
+ mc6843_status_update( device );
+ break;
+
+ case 7: /* Logical-Track Address Register (LTAR) */
+ data = mc6843->LTAR;
+ LOG(( "%f $%04x mc6843_r: read LTAR %i (actual=%i)\n",
+ device->machine().time().as_double(), cpu_get_previouspc( device->machine().firstcpu ), data,
+ floppy_drive_get_current_track( mc6843_floppy_image( device ) ) ));
+ break;
+
+ default:
+ logerror( "$%04x mc6843 invalid read offset %i\n", cpu_get_previouspc( device->machine().firstcpu ), offset );
+ }
+
+ return data;
+}
+
+WRITE8_DEVICE_HANDLER ( mc6843_w )
+{
+ mc6843_t* mc6843 = get_safe_token( device );
+ switch ( offset ) {
+
+ case 0: /* Data Output Register (DOR) */
+ {
+ int cmd = mc6843->CMR & 0x0f;
+ int FWF = (mc6843->CMR >> 4) & 1;
+
+ LOG(( "%f $%04x mc6843_w: data output cmd=%s(%i), pos=%i/%i, GCR=%i, data=%02X\n",
+ device->machine().time().as_double(), cpu_get_previouspc( device->machine().firstcpu ),
+ mc6843_cmd[cmd], cmd, mc6843->data_idx,
+ mc6843->data_size, mc6843->GCR, data ));
+
+ if ( cmd == CMD_SSW || cmd == CMD_MSW || cmd == CMD_SWD )
+ {
+ /* sector write */
+ assert( mc6843->data_size > 0 );
+ assert( mc6843->data_idx < mc6843->data_size );
+ assert( mc6843->data_idx < sizeof(mc6843->data) );
+ mc6843->data[ mc6843->data_idx ] = data;
+ mc6843->data_idx++;
+ if ( mc6843->data_idx >= mc6843->data_size )
+ {
+ /* end of sector write */
+ device_t* img = mc6843_floppy_image( device );
+
+ LOG(( "%f $%04x mc6843_w: write sector %i\n", device->machine().time().as_double(), cpu_get_previouspc( device->machine().firstcpu ), mc6843->data_id ));
+
+ floppy_drive_write_sector_data(
+ img, mc6843->side, mc6843->data_id,
+ mc6843->data, mc6843->data_size,
+ (cmd == CMD_SWD) ? ID_FLAG_DELETED_DATA : 0 );
+
+ mc6843->STRA &= ~0x01; /* clear Data Transfer Request */
+
+ if ( cmd == CMD_MSW )
+ {
+ mc6843->GCR--;
+ mc6843->SAR++;
+ if ( mc6843->GCR == 0xff )
+ {
+ mc6843_cmd_end( device );
+ }
+ else if ( mc6843->SAR > 26 )
+
+ {
+ mc6843->STRB |= 0x08; /* set Sector Address Undetected */
+ mc6843_cmd_end( device );
+ }
+ else
+ {
+ mc6843->timer_cont->adjust( DELAY_ADDR );
+ }
+ }
+ else
+ {
+ mc6843_cmd_end( device );
+ }
+ }
+ }
+ 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( mc6843->data_idx < sizeof(mc6843->data) );
+
+ mc6843->data[mc6843->data_idx / 2] =
+ (mc6843->data[mc6843->data_idx / 2] << 4) | nibble;
+
+ if ( (mc6843->data_idx == 0) && (mc6843->data[0] == 0xfe ) )
+ {
+ /* address mark detected */
+ mc6843->data_idx = 2;
+ }
+ else if ( mc6843->data_idx == 9 )
+ {
+ /* address id field complete */
+ if ( (mc6843->data[2] == 0) && (mc6843->data[4] == 0) )
+ {
+ /* valid address id field */
+ device_t* img = mc6843_floppy_image( device );
+ UINT8 track = mc6843->data[1];
+ UINT8 sector = mc6843->data[3];
+ UINT8 filler = 0xe5; /* standard Thomson filler */
+ LOG(( "%f $%04x mc6843_w: address id detected track=%i sector=%i\n", device->machine().time().as_double(), cpu_get_previouspc( device->machine().firstcpu ), track, sector));
+ floppy_drive_format_sector( img, mc6843->side, sector, track, 0, sector, 0, filler );
+ }
+ else
+ {
+ /* abort */
+ mc6843->data_idx = 0;
+ }
+ }
+ else if ( mc6843->data_idx > 0 )
+ {
+ /* accumulate address id field */
+ mc6843->data_idx++;
+ }
+ }
+ else if ( cmd == 0 )
+ {
+ /* nothing */
+ }
+ else
+ {
+ /* XXX TODO: other write modes */
+ logerror( "$%04x mc6843 write %02X in unsupported command mode %i (FWF=%i)\n", cpu_get_previouspc( device->machine().firstcpu ), data, cmd, FWF );
+ }
+ break;
+ }
+
+ case 1: /* Current-Track Address Register (CTAR) */
+ mc6843->CTAR = data & 0x7f;
+ LOG(( "%f $%04x mc6843_w: set CTAR to %i %02X (actual=%i) \n",
+ device->machine().time().as_double(), cpu_get_previouspc( device->machine().firstcpu ), mc6843->CTAR, data,
+ floppy_drive_get_current_track( mc6843_floppy_image( device ) ) ));
+ break;
+
+ case 2: /* Command Register (CMR) */
+ {
+ int cmd = data & 15;
+
+ LOG(( "%f $%04x mc6843_w: set CMR to $%02X: cmd=%s(%i) FWF=%i DMA=%i ISR3-intr=%i fun-intr=%i\n",
+ device->machine().time().as_double(), cpu_get_previouspc( device->machine().firstcpu ),
+ data, mc6843_cmd[cmd], cmd, (data >> 4) & 1, (data >> 5) & 1,
+ (data >> 6) & 1, (data >> 7) & 1 ));
+
+ /* sanitize state */
+ mc6843->STRA &= ~0x81; /* clear Busy & Data Transfer Request */
+ mc6843->data_idx = 0;
+ mc6843->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:
+ mc6843->STRA |= 0x80; /* set Busy */
+ mc6843->STRA &= ~0x22; /* clear Track Not Equal & Delete Data Mark Detected */
+ mc6843->STRB &= ~0x04; /* clear Data Mark Undetected */
+ mc6843->timer_cont->adjust( DELAY_ADDR );
+ break;
+ case CMD_STZ:
+ case CMD_SEK:
+ mc6843->STRA |= 0x80; /* set Busy */
+ mc6843->timer_cont->adjust( DELAY_SEEK );
+ break;
+ case CMD_FFW:
+ case CMD_FFR:
+ mc6843->data_idx = 0;
+ mc6843->STRA |= 0x01; /* set Data Transfer Request */
+ break;
+ }
+
+ mc6843->CMR = data;
+ mc6843_status_update( device );
+ break;
+ }
+
+ case 3: /* Set-Up Register (SUR) */
+ mc6843->SUR = data;
+
+ /* assume CLK freq = 1MHz (IBM 3740 compatibility) */
+ LOG(( "%f $%04x mc6843_w: set SUR to $%02X: head settling time=%fms, track-to-track seek time=%f\n",
+ device->machine().time().as_double(), cpu_get_previouspc( device->machine().firstcpu ),
+ data, 4.096 * (data & 15), 1.024 * ((data >> 4) & 15) ));
+ break;
+
+ case 4: /* Sector Address Register (SAR) */
+ mc6843->SAR = data & 0x1f;
+ LOG(( "%f $%04x mc6843_w: set SAR to %i (%02X)\n", device->machine().time().as_double(), cpu_get_previouspc( device->machine().firstcpu ), mc6843->SAR, data ));
+ break;
+
+ case 5: /* General Count Register (GCR) */
+ mc6843->GCR = data & 0x7f;
+ LOG(( "%f $%04x mc6843_w: set GCR to %i (%02X)\n", device->machine().time().as_double(), cpu_get_previouspc( device->machine().firstcpu ), mc6843->GCR, data ));
+ break;
+
+ case 6: /* CRC Control Register (CCR) */
+ mc6843->CCR = data & 3;
+ LOG(( "%f $%04x mc6843_w: set CCR to %02X: CRC=%s shift=%i\n",
+ device->machine().time().as_double(), cpu_get_previouspc( device->machine().firstcpu ), data,
+ (data & 1) ? "enabled" : "disabled", (data >> 1) & 1 ));
+ break;
+
+ case 7: /* Logical-Track Address Register (LTAR) */
+ mc6843->LTAR = data & 0x7f;
+ LOG(( "%f $%04x mc6843_w: set LTAR to %i %02X (actual=%i)\n",
+ device->machine().time().as_double(), cpu_get_previouspc( device->machine().firstcpu ), mc6843->LTAR, data,
+ floppy_drive_get_current_track( mc6843_floppy_image( device ) ) ));
+ break;
+
+ default:
+ logerror( "$%04x mc6843 invalid write offset %i (data=$%02X)\n", cpu_get_previouspc( device->machine().firstcpu ), offset, data );
+ }
+}
+
+
+
+/************************ reset *****************************/
+
+static DEVICE_RESET( mc6843 )
+{
+ mc6843_t* mc6843 = get_safe_token( device );
+ int i;
+ LOG (( "mc6843 reset\n" ));
+
+ /* setup/reset floppy drive */
+ for ( i = 0; i < 4; i++ )
+ {
+ device_t * img = floppy_get_device( device->machine(), i );
+ floppy_mon_w(img, CLEAR_LINE);
+ floppy_drive_set_ready_state( img, FLOPPY_DRIVE_READY, 0 );
+ floppy_drive_set_rpm( img, 300. );
+ }
+
+ /* reset registers */
+ mc6843->CMR &= 0xf0; /* zero only command */
+ mc6843->ISR = 0;
+ mc6843->STRA &= 0x5c;
+ mc6843->SAR = 0;
+ mc6843->STRB &= 0x20;
+ mc6843_status_update( device );
+
+ mc6843->data_size = 0;
+ mc6843->data_idx = 0;
+ mc6843->timer_cont->adjust( attotime::never );
+}
+
+
+
+/************************ start *****************************/
+
+static DEVICE_START( mc6843 )
+{
+ mc6843_t* mc6843 = get_safe_token( device );
+
+ mc6843->iface = (const mc6843_interface*)device->static_config();
+
+ mc6843->timer_cont = device->machine().scheduler().timer_alloc(FUNC(mc6843_cont), (void*) device) ;
+
+ state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->CTAR );
+ state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->CMR );
+ state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->ISR );
+ state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->SUR );
+ state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->STRA );
+ state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->STRB );
+ state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->SAR );
+ state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->GCR );
+ state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->CCR );
+ state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->LTAR );
+ state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->drive );
+ state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->side );
+ state_save_register_item_array( device->machine(),"mc6843", device->tag(), 0, mc6843->data );
+ state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->data_size );
+ state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->data_idx );
+ state_save_register_item( device->machine(),"mc6843", device->tag(), 0, mc6843->data_id );
+}
+
+
+/************************** configuration ****************************/
+
+DEVICE_GET_INFO( mc6843 ) {
+ switch ( state ) {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(mc6843_t); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(mc6843); break;
+ case DEVINFO_FCT_STOP: /* nothing */ break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(mc6843); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "Motorola MC6843 floppy controller"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "MC6843"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.00"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright the MAME and MESS Teams"); break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(MC6843, mc6843);
+
diff --git a/src/mess/machine/mc6843.h b/src/mess/machine/mc6843.h
new file mode 100644
index 00000000000..876dff50974
--- /dev/null
+++ b/src/mess/machine/mc6843.h
@@ -0,0 +1,41 @@
+/**********************************************************************
+
+ Copyright (C) Antoine Mine' 2007
+
+ Motorola 6843 Floppy Disk Controller emulation.
+
+**********************************************************************/
+
+#ifndef MC6843_H
+#define MC6843_H
+
+DECLARE_LEGACY_DEVICE(MC6843, mc6843);
+
+
+/* ---------- configuration ------------ */
+
+typedef struct _mc6843_interface mc6843_interface;
+struct _mc6843_interface
+{
+ void ( * irq_func ) ( device_t *device, int state );
+};
+
+
+#define MCFG_MC6843_ADD(_tag, _intrf) \
+ MCFG_DEVICE_ADD(_tag, MC6843, 0) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#define MCFG_MC6843_REMOVE(_tag) \
+ MCFG_DEVICE_REMOVE(_tag)
+
+
+/* ---------- functions ------------ */
+
+extern READ8_DEVICE_HANDLER ( mc6843_r );
+extern WRITE8_DEVICE_HANDLER ( mc6843_w );
+
+extern void mc6843_set_drive ( device_t *device, int drive );
+extern void mc6843_set_side ( device_t *device, int side );
+extern void mc6843_set_index_pulse ( device_t *device, int index_pulse );
+
+#endif
diff --git a/src/mess/machine/mc6846.c b/src/mess/machine/mc6846.c
new file mode 100644
index 00000000000..16f5fd12b0e
--- /dev/null
+++ b/src/mess/machine/mc6846.c
@@ -0,0 +1,635 @@
+/**********************************************************************
+
+ 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
+
+
+
+/******************* internal chip data structure ******************/
+
+
+typedef struct
+{
+
+ const mc6846_interface* iface;
+
+ /* registers */
+ UINT8 csr; /* 0,4: combination status register */
+ UINT8 pcr; /* 1: peripheral control register */
+ UINT8 ddr; /* 2: data direction register */
+ UINT8 pdr; /* 3: peripheral data register (last cpu write) */
+ UINT8 tcr; /* 5: timer control register */
+
+ /* lines */
+ UINT8 cp1; /* 1-bit input */
+ UINT8 cp2; /* 1-bit input/output: last external write */
+ UINT8 cp2_cpu; /* last cpu write */
+ UINT8 cto; /* 1-bit timer output (unmasked) */
+
+ /* internal state */
+ UINT8 time_MSB; /* MSB buffer register */
+ UINT8 csr0_to_be_cleared;
+ UINT8 csr1_to_be_cleared;
+ UINT8 csr2_to_be_cleared;
+ UINT16 latch; /* timer latch */
+ UINT16 preset; /* preset value */
+ UINT8 timer_started;
+
+ /* timers */
+ emu_timer *interval; /* interval programmable timer */
+ emu_timer *one_shot; /* 1-us x factor one-shot timer */
+
+ int old_cif;
+ int old_cto;
+} mc6846_t;
+
+
+
+/******************* utility function and macros ********************/
+
+#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
+
+#define PORT \
+ ((mc6846->pdr & mc6846->ddr) | \
+ ((mc6846->iface->in_port_func ? mc6846->iface->in_port_func( device, 0 ) : 0) & \
+ ~mc6846->ddr))
+
+#define CTO \
+ ((MODE == 0x30 || (mc6846->tcr & 0x80)) ? mc6846->cto : 0)
+
+#define MODE (mc6846->tcr & 0x38)
+
+#define FACTOR ((mc6846->tcr & 4) ? 8 : 1)
+
+
+
+INLINE mc6846_t* get_safe_token( device_t *device )
+{
+ assert( device != NULL );
+ assert( device->type() == MC6846 );
+ return (mc6846_t*) downcast<legacy_device_base *>(device)->token();
+}
+
+
+INLINE UINT16 mc6846_counter( device_t *device )
+{
+ mc6846_t* mc6846 = get_safe_token( device );
+ if ( mc6846->timer_started )
+ {
+ attotime delay = mc6846->interval ->remaining( );
+ return delay.as_ticks(1000000) / FACTOR;
+ }
+ else
+ return mc6846->preset;
+}
+
+
+
+INLINE void mc6846_update_irq( device_t *device )
+{
+ mc6846_t* mc6846 = get_safe_token( device );
+ int cif = 0;
+ /* composite interrupt flag */
+ if ( ( (mc6846->csr & 1) && (mc6846->tcr & 0x40) ) ||
+ ( (mc6846->csr & 2) && (mc6846->pcr & 1) ) ||
+ ( (mc6846->csr & 4) && (mc6846->pcr & 8) && ! (mc6846->pcr & 0x20) ) )
+ cif = 1;
+ if ( mc6846->old_cif != cif )
+ {
+ LOG (( "%f: mc6846 interrupt %i (time=%i cp1=%i cp2=%i)\n",
+ device->machine().time().as_double(), cif,
+ mc6846->csr & 1, (mc6846->csr >> 1 ) & 1, (mc6846->csr >> 2 ) & 1 ));
+ mc6846->old_cif = cif;
+ }
+ if ( cif )
+ {
+ mc6846->csr |= 0x80;
+ if ( mc6846->iface->irq_func )
+ mc6846->iface->irq_func( device, 1 );
+ }
+ else
+ {
+ mc6846->csr &= ~0x80;
+ if ( mc6846->iface->irq_func )
+ mc6846->iface->irq_func( device, 0 );
+ }
+}
+
+
+
+INLINE void mc6846_update_cto ( device_t *device )
+{
+ mc6846_t* mc6846 = get_safe_token( device );
+ int cto = CTO;
+ if ( cto != mc6846->old_cto )
+ {
+ LOG (( "%f: mc6846 CTO set to %i\n", device->machine().time().as_double(), cto ));
+ mc6846->old_cto = cto;
+ }
+ if ( mc6846->iface->out_cto_func )
+ mc6846->iface->out_cto_func( device, 0, cto );
+}
+
+
+
+INLINE void mc6846_timer_launch ( device_t *device )
+{
+ mc6846_t* mc6846 = get_safe_token( device );
+ int delay = FACTOR * (mc6846->preset+1);
+ LOG (( "%f: mc6846 timer launch called, mode=%i, preset=%i (x%i)\n", device->machine().time().as_double(), MODE, mc6846->preset, FACTOR ));
+
+ if ( ! (mc6846->tcr & 2) )
+ {
+ logerror( "mc6846 external clock CTC not implemented\n" );
+ }
+
+ switch( MODE )
+ {
+
+ case 0x00:
+ case 0x10: /* continuous */
+ mc6846->cto = 0;
+ break;
+
+ case 0x20: /* single-shot */
+ mc6846->cto = 0;
+ mc6846->one_shot->reset( attotime::from_usec(FACTOR) );
+ break;
+
+ case 0x30: /* cascaded single-shot */
+ break;
+
+ default:
+ logerror( "mc6846 timer mode %i not implemented\n", MODE );
+ mc6846->interval->reset( );
+ mc6846->timer_started = 0;
+ return;
+ }
+
+ mc6846->interval->reset( attotime::from_usec(delay) );
+ mc6846->timer_started = 1;
+
+ mc6846->csr &= ~1;
+ mc6846_update_cto( device );
+ mc6846_update_irq( device );
+}
+
+
+
+/******************* timer callbacks *********************************/
+
+static TIMER_CALLBACK( mc6846_timer_expire )
+{
+ device_t* device = (device_t*) ptr;
+ mc6846_t* mc6846 = get_safe_token( device );
+ int delay = FACTOR * (mc6846->latch+1);
+
+ LOG (( "%f: mc6846 timer expire called, mode=%i, latch=%i (x%i)\n", device->machine().time().as_double(), MODE, mc6846->latch, FACTOR ));
+
+ /* latch => counter */
+ mc6846->preset = mc6846->latch;
+
+ if ( ! (mc6846->tcr & 2) )
+ logerror( "mc6846 external clock CTC not implemented\n" );
+
+ switch ( MODE )
+ {
+ case 0x00:
+ case 0x10: /* continuous */
+ mc6846->cto = 1 ^ mc6846->cto;
+ break;
+
+ case 0x20: /* single-shot */
+ mc6846->cto = 0;
+ break;
+
+ case 0x30: /* cascaded single-shot */
+ mc6846->cto = ( mc6846->tcr & 0x80 ) ? 1 : 0;
+ break;
+
+ default:
+ logerror( "mc6846 timer mode %i not implemented\n", MODE );
+ mc6846->interval->reset( );
+ mc6846->timer_started = 0;
+ return;
+ }
+
+ mc6846->interval->reset( attotime::from_usec(delay) );
+
+ mc6846->csr |= 1;
+ mc6846_update_cto( device );
+ mc6846_update_irq( device );
+}
+
+
+
+static TIMER_CALLBACK( mc6846_timer_one_shot )
+{
+ device_t* device = (device_t*) ptr;
+ mc6846_t* mc6846 = get_safe_token( device );
+ LOG (( "%f: mc6846 timer one shot called\n", device->machine().time().as_double() ));
+
+ /* 1 micro second after one-shot launch, we put cto to high */
+ mc6846->cto = 1;
+ mc6846_update_cto( device );
+}
+
+
+
+/************************** CPU interface ****************************/
+
+
+READ8_DEVICE_HANDLER ( mc6846_r )
+{
+ mc6846_t* mc6846 = get_safe_token( device );
+ switch ( offset )
+ {
+ case 0:
+ case 4:
+ LOG (( "$%04x %f: mc6846 CSR read $%02X intr=%i (timer=%i, cp1=%i, cp2=%i)\n",
+ cpu_get_previouspc( device->machine().firstcpu ), device->machine().time().as_double(),
+ mc6846->csr, (mc6846->csr >> 7) & 1,
+ mc6846->csr & 1, (mc6846->csr >> 1) & 1, (mc6846->csr >> 2) & 1 ));
+ mc6846->csr0_to_be_cleared = mc6846->csr & 1;
+ mc6846->csr1_to_be_cleared = mc6846->csr & 2;
+ mc6846->csr2_to_be_cleared = mc6846->csr & 4;
+ return mc6846->csr;
+
+ case 1:
+ LOG (( "$%04x %f: mc6846 PCR read $%02X\n", cpu_get_previouspc( device->machine().firstcpu ), device->machine().time().as_double(), mc6846->pcr ));
+ return mc6846->pcr;
+
+ case 2:
+ LOG (( "$%04x %f: mc6846 DDR read $%02X\n", cpu_get_previouspc( device->machine().firstcpu ), device->machine().time().as_double(), mc6846->ddr ));
+ return mc6846->ddr;
+
+ case 3:
+ LOG (( "$%04x %f: mc6846 PORT read $%02X\n", cpu_get_previouspc( device->machine().firstcpu ), device->machine().time().as_double(), PORT ));
+ if ( ! (mc6846->pcr & 0x80) )
+ {
+ if ( mc6846->csr1_to_be_cleared )
+ mc6846->csr &= ~2;
+ if ( mc6846->csr2_to_be_cleared )
+ mc6846->csr &= ~4;
+ mc6846_update_irq( device );
+ mc6846->csr1_to_be_cleared = 0;
+ mc6846->csr2_to_be_cleared = 0;
+ }
+ return PORT;
+
+ case 5:
+ LOG (( "$%04x %f: mc6846 TCR read $%02X\n",cpu_get_previouspc( device->machine().firstcpu ), device->machine().time().as_double(), mc6846->tcr ));
+ return mc6846->tcr;
+
+ case 6:
+ LOG (( "$%04x %f: mc6846 COUNTER hi read $%02X\n", cpu_get_previouspc( device->machine().firstcpu ), device->machine().time().as_double(), mc6846_counter( device ) >> 8 ));
+ if ( mc6846->csr0_to_be_cleared )
+ {
+ mc6846->csr &= ~1;
+ mc6846_update_irq( device );
+ }
+ mc6846->csr0_to_be_cleared = 0;
+ return mc6846_counter( device ) >> 8;
+
+ case 7:
+ LOG (( "$%04x %f: mc6846 COUNTER low read $%02X\n", cpu_get_previouspc( device->machine().firstcpu ), device->machine().time().as_double(), mc6846_counter( device ) & 0xff ));
+ if ( mc6846->csr0_to_be_cleared )
+ {
+ mc6846->csr &= ~1;
+ mc6846_update_irq( device );
+ }
+ mc6846->csr0_to_be_cleared = 0;
+ return mc6846_counter( device ) & 0xff;
+
+ default:
+ logerror( "$%04x mc6846 invalid read offset %i\n", cpu_get_previouspc( device->machine().firstcpu ), offset );
+ }
+ return 0;
+}
+
+
+
+WRITE8_DEVICE_HANDLER ( mc6846_w )
+{
+ mc6846_t* mc6846 = get_safe_token( device );
+ 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 (( "$%04x %f: mc6846 PCR write $%02X reset=%i cp2=%s cp1=%s\n",
+ cpu_get_previouspc( device->machine().firstcpu ), device->machine().time().as_double(), data,
+ (data >> 7) & 1, cp2[ (data >> 3) & 7 ], cp1[ data & 7 ] ));
+
+ }
+ mc6846->pcr = data;
+ if ( data & 0x80 )
+ { /* data reset */
+ mc6846->pdr = 0;
+ mc6846->ddr = 0;
+ mc6846->csr &= ~6;
+ mc6846_update_irq( device );
+ }
+ if ( data & 4 )
+ logerror( "$%04x mc6846 CP1 latching not implemented\n", cpu_get_previouspc( device->machine().firstcpu ) );
+ if (data & 0x20)
+ {
+ if (data & 0x10)
+ {
+ mc6846->cp2_cpu = (data >> 3) & 1;
+ if ( mc6846->iface->out_cp2_func )
+ mc6846->iface->out_cp2_func( device, 0, mc6846->cp2_cpu );
+ }
+ else
+ logerror( "$%04x mc6846 acknowledge not implemented\n", cpu_get_previouspc( device->machine().firstcpu ) );
+ }
+ break;
+
+ case 2:
+ LOG (( "$%04x %f: mc6846 DDR write $%02X\n", cpu_get_previouspc( device->machine().firstcpu ), device->machine().time().as_double(), data ));
+ if ( ! (mc6846->pcr & 0x80) )
+ {
+ mc6846->ddr = data;
+ if ( mc6846->iface->out_port_func )
+ mc6846->iface->out_port_func( device, 0, mc6846->pdr & mc6846->ddr );
+ }
+ break;
+
+ case 3:
+ LOG (( "$%04x %f: mc6846 PORT write $%02X (mask=$%02X)\n", cpu_get_previouspc( device->machine().firstcpu ), device->machine().time().as_double(), data,mc6846->ddr ));
+ if ( ! (mc6846->pcr & 0x80) )
+ {
+ mc6846->pdr = data;
+ if ( mc6846->iface->out_port_func )
+ mc6846->iface->out_port_func( device, 0, mc6846->pdr & mc6846->ddr );
+ if ( mc6846->csr1_to_be_cleared && (mc6846->csr & 2) )
+ {
+ mc6846->csr &= ~2;
+ LOG (( "$%04x %f: mc6846 CP1 intr reset\n", cpu_get_previouspc( device->machine().firstcpu ), device->machine().time().as_double() ));
+ }
+ if ( mc6846->csr2_to_be_cleared && (mc6846->csr & 4) )
+ {
+ mc6846->csr &= ~4;
+ LOG (( "$%04x %f: mc6846 CP2 intr reset\n", cpu_get_previouspc( device->machine().firstcpu ), device->machine().time().as_double() ));
+ }
+ mc6846->csr1_to_be_cleared = 0;
+ mc6846->csr2_to_be_cleared = 0;
+ mc6846_update_irq( device );
+ }
+ break;
+
+ case 5:
+ {
+ static const char *const mode[8] =
+ {
+ "continuous", "cascaded", "continuous", "one-shot",
+ "freq-cmp", "freq-cmp", "pulse-cmp", "pulse-cmp"
+ };
+ LOG (( "$%04x %f: mc6846 TCR write $%02X reset=%i clock=%s scale=%i mode=%s out=%s\n",
+ cpu_get_previouspc( device->machine().firstcpu ), device->machine().time().as_double(), data,
+ (data >> 7) & 1, (data & 0x40) ? "extern" : "sys",
+ (data & 0x40) ? 1 : 8, mode[ (data >> 1) & 7 ],
+ (data & 1) ? "enabled" : "0" ));
+
+ mc6846->tcr = data;
+ if ( mc6846->tcr & 1 )
+ {
+ /* timer preset = initialization without launch */
+ mc6846->preset = mc6846->latch;
+ mc6846->csr &= ~1;
+ if ( MODE != 0x30 )
+ mc6846->cto = 0;
+ mc6846_update_cto( device );
+ mc6846->interval->reset( );
+ mc6846->one_shot->reset( );
+ mc6846->timer_started = 0;
+ }
+ else
+ {
+ /* timer launch */
+ if ( ! mc6846->timer_started )
+ mc6846_timer_launch( device );
+ }
+ mc6846_update_irq( device );
+ }
+ break;
+
+ case 6:
+ mc6846->time_MSB = data;
+ break;
+
+ case 7:
+ mc6846->latch = ( ((UINT16) mc6846->time_MSB) << 8 ) + data;
+ LOG (( "$%04x %f: mc6846 COUNT write %i\n", cpu_get_previouspc( device->machine().firstcpu ), device->machine().time().as_double(), mc6846->latch ));
+ if (!(mc6846->tcr & 0x38))
+ {
+ /* timer initialization */
+ mc6846->preset = mc6846->latch;
+ mc6846->csr &= ~1;
+ mc6846_update_irq( device );
+ mc6846->cto = 0;
+ mc6846_update_cto( device );
+ /* launch only if started */
+ if (!(mc6846->tcr & 1))
+ mc6846_timer_launch( device );
+ }
+ break;
+
+ default:
+ logerror( "$%04x mc6846 invalid write offset %i\n", cpu_get_previouspc( device->machine().firstcpu ), offset );
+ }
+}
+
+
+
+/******************** outside world interface ************************/
+
+
+
+void mc6846_set_input_cp1 ( device_t *device, int data )
+{
+ mc6846_t* mc6846 = get_safe_token( device );
+ data = (data != 0 );
+ if ( data == mc6846->cp1 )
+ return;
+ mc6846->cp1 = data;
+ LOG (( "%f: mc6846 input CP1 set to %i\n", device->machine().time().as_double(), data ));
+ if (( data && (mc6846->pcr & 2)) || (!data && !(mc6846->pcr & 2)))
+ {
+ mc6846->csr |= 2;
+ mc6846_update_irq( device );
+ }
+}
+
+void mc6846_set_input_cp2 ( device_t *device, int data )
+{
+ mc6846_t* mc6846 = get_safe_token( device );
+ data = (data != 0 );
+ if ( data == mc6846->cp2 )
+ return;
+ mc6846->cp2 = data;
+ LOG (( "%f: mc6846 input CP2 set to %i\n", device->machine().time().as_double(), data ));
+ if (mc6846->pcr & 0x20)
+ {
+ if (( data && (mc6846->pcr & 0x10)) || (!data && !(mc6846->pcr & 0x10)))
+ {
+ mc6846->csr |= 4;
+ mc6846_update_irq( device );
+ }
+ }
+}
+
+
+
+/************************ accessors **********************************/
+
+
+
+UINT8 mc6846_get_output_port ( device_t *device )
+{
+ mc6846_t* mc6846 = get_safe_token( device );
+ return PORT;
+}
+
+
+
+UINT8 mc6846_get_output_cto ( device_t *device )
+{
+ mc6846_t* mc6846 = get_safe_token( device );
+ return CTO;
+}
+
+
+
+UINT8 mc6846_get_output_cp2 ( device_t *device )
+{
+ mc6846_t* mc6846 = get_safe_token( device );
+ return mc6846->cp2_cpu;
+}
+
+
+
+UINT16 mc6846_get_preset ( device_t *device )
+{
+ mc6846_t* mc6846 = get_safe_token( device );
+ return mc6846->preset;
+}
+
+
+
+/************************ reset *****************************/
+
+
+static DEVICE_RESET( mc6846 )
+{
+ mc6846_t* mc6846 = get_safe_token( device );
+ LOG (( "mc6846_reset\n" ));
+ mc6846->cto = 0;
+ mc6846->csr = 0;
+ mc6846->pcr = 0x80;
+ mc6846->ddr = 0;
+ mc6846->pdr = 0;
+ mc6846->tcr = 1;
+ mc6846->cp1 = 0;
+ mc6846->cp2 = 0;
+ mc6846->cp2_cpu = 0;
+ mc6846->latch = 0xffff;
+ mc6846->preset = 0xffff;
+ mc6846->time_MSB = 0;
+ mc6846->csr0_to_be_cleared = 0;
+ mc6846->csr1_to_be_cleared = 0;
+ mc6846->csr2_to_be_cleared = 0;
+ mc6846->timer_started = 0;
+ mc6846->interval->reset( );
+ mc6846->one_shot->reset( );
+}
+
+
+/************************ start *****************************/
+
+static DEVICE_START( mc6846 )
+{
+ mc6846_t* mc6846 = get_safe_token( device );
+
+ mc6846->iface = (const mc6846_interface*)device->static_config();
+ mc6846->interval = device->machine().scheduler().timer_alloc(FUNC(mc6846_timer_expire), (void*) device );
+ mc6846->one_shot = device->machine().scheduler().timer_alloc(FUNC(mc6846_timer_one_shot), (void*) device );
+
+ state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->csr );
+ state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->pcr );
+ state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->ddr );
+ state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->pdr );
+ state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->tcr );
+ state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->cp1 );
+ state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->cp2 );
+ state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->cp2_cpu );
+ state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->cto );
+ state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->time_MSB );
+ state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->csr0_to_be_cleared );
+ state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->csr1_to_be_cleared );
+ state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->csr2_to_be_cleared );
+ state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->latch );
+ state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->preset );
+ state_save_register_item( device->machine(), "mc6846", device->tag(), 0, mc6846->timer_started );
+}
+
+
+/************************** configuration ****************************/
+
+
+DEVICE_GET_INFO( mc6846 ) {
+ switch ( state ) {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(mc6846_t); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(mc6846); break;
+ case DEVINFO_FCT_STOP: /* nothing */ break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(mc6846); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "Motorola MC6846 programmable timer"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "MC6846"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.00"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright the MAME and MESS Teams"); break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(MC6846, mc6846);
diff --git a/src/mess/machine/mc6846.h b/src/mess/machine/mc6846.h
new file mode 100644
index 00000000000..7373543f1a2
--- /dev/null
+++ b/src/mess/machine/mc6846.h
@@ -0,0 +1,65 @@
+/**********************************************************************
+
+ Copyright (C) Antoine Mine' 2006
+
+ Motorola 6846 timer emulation.
+
+**********************************************************************/
+
+#ifndef MC6846_H
+#define MC6846_H
+
+DECLARE_LEGACY_DEVICE(MC6846, mc6846);
+
+/* ---------- configuration ------------ */
+
+typedef struct _mc6846_interface mc6846_interface;
+struct _mc6846_interface
+{
+ /* CPU write to the outside through chip */
+ write8_device_func out_port_func; /* 8-bit output */
+ write8_device_func out_cp1_func; /* 1-bit output */
+ write8_device_func out_cp2_func; /* 1-bit output */
+
+ /* CPU read from the outside through chip */
+ read8_device_func in_port_func; /* 8-bit input */
+
+ /* asynchronous timer output to outside world */
+ write8_device_func out_cto_func; /* 1-bit output */
+
+ /* timer interrupt */
+ void ( * irq_func ) ( device_t *device, int state );
+};
+
+
+#define MCFG_MC6846_ADD(_tag, _intrf) \
+ MCFG_DEVICE_ADD(_tag, MC6846, 0) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#define MCFG_MC6846_MODIFY(_tag, _intrf) \
+ MCFG_DEVICE_MODIFY(_tag) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#define MCFG_MC6846_REMOVE(_tag) \
+ MCFG_DEVICE_REMOVE(_tag)
+
+
+/* ---------- functions ------------ */
+/* interface to CPU via address/data bus*/
+extern READ8_DEVICE_HANDLER ( mc6846_r );
+extern WRITE8_DEVICE_HANDLER ( mc6846_w );
+
+/* asynchronous write from outside world into interrupt-generating pins */
+extern void mc6846_set_input_cp1 ( device_t *device, int data );
+extern void mc6846_set_input_cp2 ( device_t *device, int data );
+
+/* polling from outside world */
+extern UINT8 mc6846_get_output_port ( device_t *device );
+extern UINT8 mc6846_get_output_cto ( device_t *device );
+extern UINT8 mc6846_get_output_cp2 ( device_t *device );
+
+/* partial access to internal state */
+extern UINT16 mc6846_get_preset ( device_t *device ); /* timer interval - 1 in us */
+
+#endif
+
diff --git a/src/mess/machine/mc6854.c b/src/mess/machine/mc6854.c
new file mode 100644
index 00000000000..6ba7660a81e
--- /dev/null
+++ b/src/mess/machine/mc6854.c
@@ -0,0 +1,1065 @@
+/**********************************************************************
+
+ 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 MAX_FRAME_LENGTH 65536
+/* arbitrary value, you may need to enlarge it if you get truncated frames */
+
+#define FIFO_SIZE 3
+/* hardcoded size of the 6854 FIFO (this is a hardware limit) */
+
+#define FLAG 0x7e
+/* flag value, as defined by HDLC protocol: 01111110 */
+
+#define BIT_LENGTH attotime::from_hz( 500000 )
+
+
+
+/******************* internal chip data structure ******************/
+
+
+typedef struct
+{
+ devcb_resolved_write_line out_irq_func;
+ devcb_resolved_read_line in_rxd_func;
+ devcb_resolved_write_line out_txd_func;
+ devcb_resolved_write_line out_rts_func;
+ devcb_resolved_write_line out_dtr_func;
+
+ /* interface */
+ const mc6854_interface* iface;
+
+ /* registers */
+ UINT8 cr1, cr2, cr3, cr4; /* control registers */
+ UINT8 sr1, sr2; /* status registers */
+
+ UINT8 cts, dcd;
+
+ /* transmit state */
+ UINT8 tstate;
+ UINT16 tfifo[FIFO_SIZE]; /* X x 8-bit FIFO + full & last marker bits */
+ UINT8 tones; /* counter for zero-insertion */
+ emu_timer *ttimer; /* when to ask for more data */
+
+ /* receive state */
+ UINT8 rstate;
+ UINT32 rreg; /* shift register */
+ UINT8 rones; /* count '1 bits */
+ UINT8 rsize; /* bits in the shift register */
+ UINT16 rfifo[FIFO_SIZE]; /* X x 8-bit FIFO + full & addr marker bits */
+
+ /* frame-based interface*/
+ UINT8 frame[MAX_FRAME_LENGTH];
+ UINT32 flen, fpos;
+
+} mc6854_t;
+
+/* 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)
+*/
+
+
+
+/******************* utility function and macros ********************/
+
+
+
+#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+
+/* control register 1 */
+
+#define AC ( mc6854->cr1 & 1 )
+#define FCTDRA ( mc6854->cr2 & 8 )
+/* extra register select bits */
+
+#define RRESET ( mc6854->cr1 & 0x40 )
+#define TRESET ( mc6854->cr1 & 0x80 )
+/* transmit / reset condition */
+
+#define RIE ( mc6854->cr1 & 2 )
+#define TIE ( mc6854->cr1 & 4 )
+/* interrupt enable */
+
+#define DISCONTINUE ( mc6854->cr1 & 0x20 )
+/* discontinue received frame */
+
+
+
+/* control register 2 */
+
+#define PSE ( mc6854->cr2 & 1 )
+/* prioritize status bits (TODO) */
+
+#define TWOBYTES ( mc6854->cr2 & 2 )
+/* two-bytes mode */
+
+#define FMIDLE ( mc6854->cr2 & 4 )
+/* flag time fill (vs. mark idle) */
+
+#define TLAST ( mc6854->cr2 & 0x10 )
+/* transmit last byte of frame */
+
+#define RTS ( mc6854->cr2 & 0x80 )
+/* request-to-send */
+
+
+
+/* control register 3 */
+
+#define LCF ( mc6854->cr3 & 1 )
+/* logical control field select */
+
+#define CEX ( mc6854->cr3 & 2 )
+/* control field is 16 bits instead of 8 */
+
+#define AEX ( mc6854->cr3 & 4 )
+/* extended address mode (vs normal 8-bit address mode) */
+
+#define IDL0 ( mc6854->cr3 & 8 )
+/* idle condition begins with a '0' instead of a '1" */
+
+#define FDSE ( mc6854->cr3 & 0x10 )
+/* enable the flag detect status in SR1 */
+
+#define LOOP ( mc6854->cr3 & 0x20 )
+/* loop mode */
+
+#define TST ( mc6854->cr3 & 0x40 )
+/* test mode (or go active on poll) */
+
+#define DTR ( mc6854->cr3 & 0x80 )
+/* data-transmit-ready (or loop on-line control) */
+
+
+
+/* control register 4 */
+
+#define TWOINTER ( mc6854->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[ ( mc6854->cr4 >> 1 ) & 3 ]
+#define RWL word_length[ ( mc6854->cr4 >> 3 ) & 3 ]
+/* transmit / receive word length */
+
+#define ABT ( mc6854->cr4 & 0x20 )
+/* aborts */
+
+#define ABTEX ( mc6854->cr4 & 0x40 )
+/* abort generates 16 '1' bits instead of 8 */
+
+#define NRZ ( mc6854->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 */
+
+
+
+INLINE mc6854_t* get_safe_token( device_t *device )
+{
+ assert( device != NULL );
+ assert( device->type() == MC6854 );
+ return (mc6854_t*) downcast<legacy_device_base *>(device)->token();
+}
+
+
+/*********************** transmit ***********************/
+
+
+
+/* MC6854 fills bit queue */
+static void mc6854_send_bits( device_t *device, UINT32 data, int len, int zi )
+{
+ mc6854_t* mc6854 = get_safe_token( device );
+ 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;
+ mc6854->tones++;
+ if ( mc6854->tones == 5 )
+ {
+ /* insert a '0' after 5 consecutive '1" */
+ mc6854->tones = 0;
+ l++;
+ }
+ }
+ else
+ mc6854->tones = 0;
+ }
+ data = d;
+ len = l;
+ }
+ else
+ mc6854->tones = 0;
+
+ /* send bits */
+ if ( !mc6854->out_txd_func.isnull() )
+ {
+ for ( i = 0; i < len; i++, data >>= 1 )
+ mc6854->out_txd_func( data & 1 );
+ }
+
+ /* schedule when to ask the MC6854 for more bits */
+ expire = mc6854->ttimer ->remaining( );
+ if ( expire== attotime::never )
+ expire = attotime::zero;
+ mc6854->ttimer->reset( expire + (BIT_LENGTH * len));
+}
+
+
+
+/* CPU push -> tfifo[0] -> ... -> tfifo[FIFO_SIZE-1] -> pop */
+static void mc6854_tfifo_push( device_t *device, UINT8 data )
+{
+ mc6854_t* mc6854 = get_safe_token( device );
+ int i;
+
+ if ( TRESET )
+ return;
+
+ /* push towards the rightmost free entry */
+ for ( i = FIFO_SIZE - 1; i >= 0; i-- )
+ {
+ if ( ! ( mc6854->tfifo[ i ] & 0x100 ) )
+ break;
+ }
+
+ if ( i >= 0 )
+ mc6854->tfifo[ i ] = data | 0x100;
+ else
+ logerror( "%f mc6854_tfifo_push: FIFO overrun\n", device->machine().time().as_double() );
+
+ /* start frame, if needed */
+ if ( ! mc6854->tstate )
+ {
+ LOG(( "%f mc6854_tfifo_push: start frame\n", device->machine().time().as_double() ));
+ mc6854->tstate = 2;
+ mc6854_send_bits( device, FLAG, 8, 0 );
+ }
+}
+
+
+
+/* CPU asks for normal frame termination */
+static void mc6854_tfifo_terminate( device_t *device )
+{
+ mc6854_t* mc6854 = get_safe_token( device );
+
+ /* mark most recently pushed byte as the last one of the frame */
+ int i;
+ for ( i = 0; i < FIFO_SIZE; i++ )
+ {
+ if ( mc6854->tfifo[ i ] & 0x100 )
+ {
+ mc6854->tfifo[ i ] |= 0x200;
+ break;
+ }
+ }
+}
+
+
+
+/* call-back to refill the bit-stream from the FIFO */
+static TIMER_CALLBACK(mc6854_tfifo_cb)
+{
+ device_t* device = (device_t*) ptr;
+ mc6854_t* mc6854 = get_safe_token( device );
+ int i, data = mc6854->tfifo[ FIFO_SIZE - 1 ];
+
+ if ( ! mc6854->tstate )
+ return;
+
+ /* shift FIFO to the right */
+ for ( i = FIFO_SIZE - 1; i > 0; i-- )
+ mc6854->tfifo[ i ] = mc6854->tfifo[ i - 1 ];
+ mc6854->tfifo[ 0 ] = 0;
+
+ if ( data & 0x100 )
+ {
+ /* got data */
+
+ int blen = 8;
+
+ switch ( mc6854->tstate )
+ {
+
+ case 2: /* 8-bit address field */
+ if ( ( data & 1 ) || ( ! AEX ) )
+ mc6854->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 )
+ mc6854->tstate = 4;
+ else if ( LCF )
+ mc6854->tstate = 5;
+ else
+ mc6854->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 )
+ mc6854->tstate = 5;
+ else
+ mc6854->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 ) )
+ mc6854->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(), mc6854->tstate));
+ }
+
+ if ( mc6854->flen < MAX_FRAME_LENGTH )
+ mc6854->frame[ mc6854->flen++ ] = data;
+ else
+ logerror( "mc6854_tfifo_cb: truncated frame, max=%i\n", MAX_FRAME_LENGTH );
+
+ mc6854_send_bits( device, data, blen, 1 );
+ }
+ else
+ {
+ /* data underrun => abort */
+ logerror( "%f mc6854_tfifo_cb: FIFO underrun\n", machine.time().as_double() );
+ mc6854->sr1 |= TU;
+ mc6854->tstate = 0;
+ mc6854_send_bits( device, 0xffff, ABTEX ? 16 : 8, 0 );
+ mc6854->flen = 0;
+ }
+
+ /* close frame, if needed */
+ if ( data & 0x200 )
+ {
+ int len = mc6854->flen;
+
+ LOG(( "%f mc6854_tfifo_cb: end frame\n", machine.time().as_double() ));
+ mc6854_send_bits( device, 0xdeadbeef, 16, 1 ); /* send check-sum: TODO */
+ mc6854_send_bits( device, FLAG, 8, 0 ); /* send closing flag */
+
+ if ( mc6854->tfifo[ FIFO_SIZE - 1 ] & 0x100 )
+ {
+ /* re-open frame asap */
+ LOG(( "%f mc6854_tfifo_cb: start frame\n", machine.time().as_double() ));
+ if ( TWOINTER )
+ mc6854_send_bits( device, FLAG, 8, 0 );
+ }
+ else
+ mc6854->tstate = 0;
+
+ mc6854->flen = 0;
+ if ( mc6854->iface->out_frame )
+ mc6854->iface->out_frame( device, mc6854->frame, len );
+ }
+}
+
+
+
+static void mc6854_tfifo_clear( device_t *device )
+{
+ mc6854_t* mc6854 = get_safe_token( device );
+ memset( mc6854->tfifo, 0, sizeof( mc6854->tfifo ) );
+ mc6854->tstate = 0;
+ mc6854->flen = 0;
+ mc6854->ttimer->reset( );
+}
+
+
+
+/*********************** receive ***********************/
+
+
+
+/* MC6854 pushes a field in the FIFO */
+static void mc6854_rfifo_push( device_t *device, UINT8 d )
+{
+ mc6854_t* mc6854 = get_safe_token( device );
+ int i, blen = 8;
+ unsigned data = d;
+
+ switch ( mc6854->rstate )
+ {
+
+ case 0:
+ case 1:
+ case 2: /* 8-bit address field */
+ if ( ( data & 1 ) || ( ! AEX ) )
+ mc6854->rstate = 3;
+ else
+ mc6854->rstate = 2;
+ LOG(( "%f mc6854_rfifo_push: address field $%02X\n", device->machine().time().as_double(), data ));
+ data |= 0x400; /* address marker */
+ break;
+
+ case 3: /* 8-bit control field */
+ if ( CEX )
+ mc6854->rstate = 4;
+ else if ( LCF )
+ mc6854->rstate = 5;
+ else
+ mc6854->rstate = 6;
+ LOG(( "%f mc6854_rfifo_push: control field $%02X\n", device->machine().time().as_double(), data ));
+ break;
+
+ case 4: /* 8-bit extended control field (optional) */
+ if ( LCF )
+ mc6854->rstate = 5;
+ else
+ mc6854->rstate = 6;
+ LOG(( "%f mc6854_rfifo_push: control field $%02X\n", device->machine().time().as_double(), data ));
+ break;
+
+ case 5: /* 8-bit logical control (optional) */
+ if ( ! ( data & 0x80 ) )
+ mc6854->rstate = 6;
+ LOG(( "%f mc6854_rfifo_push: logical control field $%02X\n", device->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", device->machine().time().as_double(), data, blen ));
+ break;
+ }
+
+ /* no further FIFO fill until FV is cleared! */
+ if ( mc6854->sr2 & FV )
+ {
+ LOG(( "%f mc6854_rfifo_push: field not pushed\n", device->machine().time().as_double() ));
+ return;
+ }
+
+ data |= 0x100; /* entry full marker */
+
+ /* push towards the rightmost free entry */
+ for ( i = FIFO_SIZE - 1; i >= 0; i-- )
+ {
+ if ( ! ( mc6854->rfifo[ i ] & 0x100 ) )
+ break;
+ }
+
+ if ( i >= 0 )
+ mc6854->rfifo[ i ] = data | 0x100;
+ else
+ {
+ /* FIFO full */
+ mc6854->sr2 |= OVRN;
+ mc6854->rfifo[ 0 ] = data;
+ logerror( "%f mc6854_rfifo_push: FIFO overrun\n", device->machine().time().as_double() );
+ }
+
+ mc6854->rsize -= blen;
+}
+
+
+
+static void mc6854_rfifo_terminate( device_t *device )
+{
+ mc6854_t* mc6854 = get_safe_token( device );
+ /* mark most recently pushed byte as the last one of the frame */
+ int i;
+ for ( i = 0; i < FIFO_SIZE; i++ )
+ {
+ if ( mc6854->rfifo[ i ] & 0x100 )
+ {
+ mc6854->tfifo[ i ] |= 0x200;
+ break;
+ }
+
+ }
+
+ mc6854->flen = 0;
+ mc6854->rstate = 1;
+}
+
+
+
+/* CPU pops the FIFO */
+static UINT8 mc6854_rfifo_pop( device_t *device )
+{
+ mc6854_t* mc6854 = get_safe_token( device );
+ int i, data = mc6854->rfifo[ FIFO_SIZE - 1 ];
+
+ /* shift FIFO to the right */
+ for ( i = FIFO_SIZE - 1; i > 0; i -- )
+ mc6854->rfifo[ i ] = mc6854->rfifo[ i - 1 ];
+ mc6854->rfifo[ 0 ] = 0;
+
+ if ( mc6854->rfifo[ FIFO_SIZE - 1 ] & 0x200 )
+ {
+ /* last byte in frame */
+ mc6854->sr2 |= FV; /* TODO: check CRC & set ERR instead of FV if error*/
+ }
+
+ /* auto-refill in frame mode */
+ if ( mc6854->flen > 0 )
+ {
+ mc6854_rfifo_push( device, mc6854->frame[ mc6854->fpos++ ] );
+ if ( mc6854->fpos == mc6854->flen )
+ mc6854_rfifo_terminate( device );
+ }
+
+ return data;
+}
+
+
+/* MC6854 makes fields from bits */
+WRITE_LINE_DEVICE_HANDLER( mc6854_set_rx )
+{
+ mc6854_t* mc6854 = get_safe_token( device );
+ int fieldlen = ( mc6854->rstate < 6 ) ? 8 : RWL;
+
+ if ( RRESET || (mc6854->sr2 & DCD) )
+ return;
+
+ if ( state )
+ {
+ mc6854->rones++;
+ mc6854->rreg = (mc6854->rreg >> 1) | 0x80000000;
+ if ( mc6854->rones >= 8 )
+ {
+ /* abort */
+ mc6854->rstate = 0;
+ mc6854->rsize = 0;
+ if ( mc6854->rstate > 1 )
+ {
+ /* only in-frame abort */
+ mc6854->sr2 |= RABT;
+ LOG(( "%f mc6854_receive_bit: abort\n", device->machine().time().as_double() ));
+ }
+ }
+ else
+ {
+ mc6854->rsize++;
+ if ( mc6854->rstate && mc6854->rsize >= fieldlen + 24 )
+ mc6854_rfifo_push( device, mc6854->rreg );
+ }
+ }
+ else if ( mc6854->rones == 5 )
+ {
+ /* discards '0' inserted after 5 '1' */
+ mc6854->rones = 0;
+ return;
+ }
+ else if ( mc6854->rones == 6 )
+ {
+ /* flag */
+ if ( FDSE )
+ mc6854->sr1 |= FD;
+
+ if ( mc6854->rstate > 1 )
+ {
+ /* end of frame */
+ mc6854->rreg >>= 1;
+ mc6854->rsize++;
+ if ( mc6854->rsize >= fieldlen + 24 ) /* last field */
+ mc6854_rfifo_push( device, mc6854->rreg );
+ mc6854_rfifo_terminate( device );
+ LOG(( "%f mc6854_receive_bit: end of frame\n", device->machine().time().as_double() ));
+ }
+ mc6854->rones = 0;
+ mc6854->rstate = 1;
+ mc6854->rsize = 0;
+ } else
+ {
+ mc6854->rones = 0;
+ mc6854->rreg >>= 1;
+ mc6854->rsize++;
+ if ( mc6854->rstate && mc6854->rsize >= fieldlen + 24 )
+ mc6854_rfifo_push( device, mc6854->rreg );
+ }
+}
+
+
+
+static void mc6854_rfifo_clear( device_t *device )
+{
+ mc6854_t* mc6854 = get_safe_token( device );
+ memset( mc6854->rfifo, 0, sizeof( mc6854->rfifo ) );
+ mc6854->rstate = 0;
+ mc6854->rreg = 0;
+ mc6854->rsize = 0;
+ mc6854->rones = 0;
+ mc6854->flen = 0;
+}
+
+
+
+int mc6854_send_frame( device_t *device, UINT8* data, int len )
+{
+ mc6854_t* mc6854 = get_safe_token( device );
+ if ( mc6854->rstate > 1 || mc6854->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( mc6854->frame, data, len );
+ if ( FDSE )
+ mc6854->sr1 |= FD;
+ mc6854->flen = len;
+ mc6854->fpos = 0;
+ mc6854_rfifo_push( device, mc6854->frame[ mc6854->fpos++ ] );
+ mc6854_rfifo_push( device, mc6854->frame[ mc6854->fpos++ ] );
+ if ( mc6854->fpos == mc6854->flen )
+ mc6854_rfifo_terminate( device );
+ return 0;
+}
+
+
+
+/************************** CPU interface ****************************/
+
+
+
+WRITE_LINE_DEVICE_HANDLER( mc6854_set_cts )
+{
+ mc6854_t* mc6854 = get_safe_token( device );
+ if ( ! mc6854->cts && state )
+ mc6854->sr1 |= CTS;
+ mc6854->cts = state;
+
+ if ( mc6854->cts )
+ mc6854->sr1 |= CTS;
+ else
+ mc6854->sr1 &= ~CTS;
+}
+
+
+
+WRITE_LINE_DEVICE_HANDLER( mc6854_set_dcd )
+{
+ mc6854_t* mc6854 = get_safe_token( device );
+ if ( ! mc6854->dcd && state )
+ {
+ mc6854->sr2 |= DCD;
+ /* partial reset */
+ mc6854->rstate = 0;
+ mc6854->rreg = 0;
+ mc6854->rsize = 0;
+ mc6854->rones = 0;
+ }
+ mc6854->dcd = state;
+}
+
+
+
+static void mc6854_update_sr2( mc6854_t* mc6854 )
+{
+ /* update RDA */
+ mc6854->sr2 |= RDA2;
+ if ( ! (mc6854->rfifo[ FIFO_SIZE - 1 ] & 0x100) )
+ mc6854->sr2 &= ~RDA2;
+ else if ( TWOBYTES && ! (mc6854->tfifo[ FIFO_SIZE - 2 ] & 0x100) )
+ mc6854->sr2 &= ~RDA2;
+
+ /* update AP */
+ if ( mc6854->rfifo[ FIFO_SIZE - 1 ] & 0x400 )
+ mc6854->sr2 |= AP;
+ else
+ mc6854->sr2 &= ~AP;
+}
+
+
+
+static void mc6854_update_sr1( mc6854_t* mc6854 )
+{
+ mc6854_update_sr2( mc6854 );
+
+ /* update S2RQ */
+ if ( mc6854->sr2 & 0x7f )
+ mc6854->sr1 |= S2RQ;
+ else
+ mc6854->sr1 &= ~S2RQ;
+
+ /* update TRDA (always prioritized by CTS) */
+ if ( TRESET || ( mc6854->sr1 & CTS ) )
+ mc6854->sr1 &= ~TDRA;
+ else
+ {
+ mc6854->sr1 |= TDRA;
+ if ( mc6854->tfifo[ 0 ] & 0x100 )
+ mc6854->sr1 &= ~TDRA;
+ else if ( TWOBYTES && (mc6854->tfifo[ 1 ] & 0x100) )
+ mc6854->sr1 &= ~TDRA;
+ }
+
+ /* update RDA */
+ if ( mc6854->sr2 & RDA2 )
+ mc6854->sr1 |= RDA;
+ else
+ mc6854->sr1 &= ~RDA;
+
+ /* update IRQ */
+ mc6854->sr1 &= ~IRQ;
+ if ( RIE && (mc6854->sr1 & (TU | TDRA) ) )
+ mc6854->sr1 |= IRQ;
+ if ( TIE )
+ {
+ if ( mc6854->sr1 & (S2RQ | RDA | CTS) )
+ mc6854->sr1 |= IRQ;
+ if ( mc6854->sr2 & (ERR | FV | DCD | OVRN | RABT | RIDLE | AP) )
+ mc6854->sr1 |= IRQ;
+ }
+
+ mc6854->out_irq_func((mc6854->sr1 & IRQ) ? ASSERT_LINE : CLEAR_LINE);
+}
+
+
+
+READ8_DEVICE_HANDLER ( mc6854_r )
+{
+ mc6854_t* mc6854 = get_safe_token( device );
+ switch ( offset )
+ {
+
+ case 0: /* status register 1 */
+ mc6854_update_sr1( mc6854 );
+ LOG(( "%f $%04x mc6854_r: get SR1=$%02X (rda=%i,s2rq=%i,fd=%i,cts=%i,tu=%i,tdra=%i,irq=%i)\n",
+ device->machine().time().as_double(), cpu_get_previouspc( device->machine().firstcpu ), mc6854->sr1,
+ ( mc6854->sr1 & RDA) ? 1 : 0, ( mc6854->sr1 & S2RQ) ? 1 : 0,
+ ( mc6854->sr1 & FD ) ? 1 : 0, ( mc6854->sr1 & CTS ) ? 1 : 0,
+ ( mc6854->sr1 & TU ) ? 1 : 0, ( mc6854->sr1 & TDRA) ? 1 : 0,
+ ( mc6854->sr1 & IRQ) ? 1 : 0 ));
+ return mc6854->sr1;
+
+ case 1: /* status register 2 */
+ mc6854_update_sr2( mc6854 );
+ LOG(( "%f $%04x mc6854_r: get SR2=$%02X (ap=%i,fv=%i,ridle=%i,rabt=%i,err=%i,dcd=%i,ovrn=%i,rda2=%i)\n",
+ device->machine().time().as_double(), cpu_get_previouspc( device->machine().firstcpu ), mc6854->sr2,
+ ( mc6854->sr2 & AP ) ? 1 : 0, ( mc6854->sr2 & FV ) ? 1 : 0,
+ ( mc6854->sr2 & RIDLE) ? 1 : 0, ( mc6854->sr2 & RABT) ? 1 : 0,
+ ( mc6854->sr2 & ERR ) ? 1 : 0, ( mc6854->sr2 & DCD ) ? 1 : 0,
+ ( mc6854->sr2 & OVRN ) ? 1 : 0, ( mc6854->sr2 & RDA2) ? 1 : 0 ));
+ return mc6854->sr2;
+
+ case 2: /* receiver data register */
+ case 3:
+ {
+ UINT8 data = mc6854_rfifo_pop( device );
+ LOG(( "%f $%04x mc6854_r: get data $%02X\n",
+ device->machine().time().as_double(), cpu_get_previouspc( device->machine().firstcpu ), data ));
+ return data;
+ }
+
+ default:
+ logerror( "$%04x mc6854 invalid read offset %i\n", cpu_get_previouspc( device->machine().firstcpu ), offset );
+ }
+ return 0;
+}
+
+
+
+WRITE8_DEVICE_HANDLER ( mc6854_w )
+{
+ mc6854_t* mc6854 = get_safe_token( device );
+ switch ( offset )
+ {
+
+ case 0: /* control register 1 */
+ mc6854->cr1 = data;
+ LOG(( "%f $%04x mc6854_w: set CR1=$%02X (ac=%i,irq=%c%c,%sreset=%c%c)\n",
+ device->machine().time().as_double(), cpu_get_previouspc( device->machine().firstcpu ), mc6854->cr1,
+ AC ? 1 : 0,
+ RIE ? 'r' : '-', TIE ? 't' : '-',
+ DISCONTINUE ? "discontinue," : "",
+ RRESET ? 'r' : '-', TRESET ? 't' : '-'
+ ));
+ if ( mc6854->cr1 & 0xc )
+ logerror( "$%04x mc6854 DMA not handled (CR1=$%02X)\n",
+ cpu_get_previouspc( device->machine().firstcpu ), mc6854->cr1 );
+ if ( DISCONTINUE )
+ {
+ /* abort receive FIFO but keeps shift register & synchro */
+ mc6854->rstate = 0;
+ memset( mc6854->rfifo, 0, sizeof( mc6854->rfifo ) );
+ }
+ if ( RRESET )
+ {
+ /* abort FIFO & synchro */
+ mc6854_rfifo_clear( device );
+ mc6854->sr1 &= ~FD;
+ mc6854->sr2 &= ~(AP | FV | RIDLE | RABT | ERR | OVRN | DCD);
+ if ( mc6854->dcd ) mc6854->sr2 |= DCD;
+ }
+ if ( TRESET )
+ {
+ mc6854_tfifo_clear( device );
+ mc6854->sr1 &= ~(TU | TDRA | CTS);
+ if ( mc6854->cts ) mc6854->sr1 |= CTS;
+ }
+ break;
+
+ case 1:
+ if ( AC )
+ {
+ /* control register 3 */
+ mc6854->cr3 = data;
+ LOG(( "%f $%04x mc6854_w: set CR3=$%02X (lcf=%i,aex=%i,idl=%i,fdse=%i,loop=%i,tst=%i,dtr=%i)\n",
+ device->machine().time().as_double(), cpu_get_previouspc( device->machine().firstcpu ), mc6854->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( "$%04x mc6854 loop mode not handled (CR3=$%02X)\n", cpu_get_previouspc( device->machine().firstcpu ), mc6854->cr3 );
+ if ( TST )
+ logerror( "$%04x mc6854 test mode not handled (CR3=$%02X)\n", cpu_get_previouspc( device->machine().firstcpu ), mc6854->cr3 );
+
+ mc6854->out_dtr_func( DTR ? 1 : 0 );
+
+ }
+ else
+ {
+ /* control register 2 */
+ mc6854->cr2 = data;
+ LOG(( "%f $%04x mc6854_w: set CR2=$%02X (pse=%i,bytes=%i,fmidle=%i,%s,tlast=%i,clr=%c%c,rts=%i)\n",
+ device->machine().time().as_double(), cpu_get_previouspc( device->machine().firstcpu ), mc6854->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( "$%04x mc6854 status prioritization not handled (CR2=$%02X)\n", cpu_get_previouspc( device->machine().firstcpu ), mc6854->cr2 );
+ if ( TLAST )
+ mc6854_tfifo_terminate( device );
+ if ( data & 0x20 )
+ {
+ /* clear receiver status */
+ mc6854->sr1 &= ~FD;
+ mc6854->sr2 &= ~(AP | FV | RIDLE | RABT | ERR | OVRN | DCD);
+ if ( mc6854->dcd )
+ mc6854->sr2 |= DCD;
+ }
+ if ( data & 0x40 )
+ {
+ /* clear transmitter status */
+ mc6854->sr1 &= ~(TU | TDRA | CTS);
+ if ( mc6854->cts )
+ mc6854->sr1 |= CTS;
+ }
+
+ mc6854->out_rts_func( RTS ? 1 : 0 );
+ }
+ break;
+
+ case 2: /* transmitter data: continue data */
+ LOG(( "%f $%04xmc6854_w: push data=$%02X\n", device->machine().time().as_double(), cpu_get_previouspc( device->machine().firstcpu ), data ));
+ mc6854_tfifo_push( device, data );
+ break;
+
+ case 3:
+ if ( AC )
+ {
+ /* control register 4 */
+ mc6854->cr4 = data;
+ LOG(( "%f $%04x mc6854_w: set CR4=$%02X (interframe=%i,tlen=%i,rlen=%i,%s%s)\n", device->machine().time().as_double(), cpu_get_previouspc( device->machine().firstcpu ), mc6854->cr4,
+ TWOINTER ? 2 : 1,
+ TWL, RWL,
+ ABT ? ( ABTEX ? "abort-ext," : "abort,") : "",
+ NRZ ? "nrz" : "nrzi" ));
+ if ( ABT )
+ {
+ mc6854->tstate = 0;
+ mc6854_send_bits( device, 0xffff, ABTEX ? 16 : 8, 0 );
+ mc6854->flen = 0;
+ }
+ }
+ else
+ {
+ /* transmitter data: last data */
+ LOG(( "%f $%04x mc6854_w: push last-data=$%02X\n", device->machine().time().as_double(), cpu_get_previouspc( device->machine().firstcpu ), data ));
+ mc6854_tfifo_push( device, data );
+ mc6854_tfifo_terminate( device );
+ }
+ break;
+
+ default:
+ logerror( "$%04x mc6854 invalid write offset %i (data=$%02X)\n", cpu_get_previouspc( device->machine().firstcpu ), offset, data );
+ }
+}
+
+WRITE_LINE_DEVICE_HANDLER( mc6854_rxc_w )
+{
+ // TODO
+}
+
+WRITE_LINE_DEVICE_HANDLER( mc6854_txc_w )
+{
+ // TODO
+}
+
+/************************ reset *****************************/
+
+static DEVICE_RESET( mc6854 )
+{
+ mc6854_t* mc6854 = get_safe_token( device );
+ LOG (( "mc6854 reset\n" ));
+ mc6854->cr1 = 0xc0; /* reset condition */
+ mc6854->cr2 = 0;
+ mc6854->cr3 = 0;
+ mc6854->cr4 = 0;
+ mc6854->sr1 = 0;
+ mc6854->sr2 = 0;
+ mc6854->cts = 0;
+ mc6854->dcd = 0;
+ mc6854_tfifo_clear( device );
+ mc6854_rfifo_clear( device );
+}
+
+
+
+/************************ start *****************************/
+
+static DEVICE_START( mc6854 )
+{
+ mc6854_t* mc6854 = get_safe_token( device );
+
+ mc6854->iface = (const mc6854_interface*)device->static_config();
+ mc6854->out_irq_func.resolve(mc6854->iface->out_irq_func, *device);
+ mc6854->in_rxd_func.resolve(mc6854->iface->in_rxd_func, *device);
+ mc6854->out_txd_func.resolve(mc6854->iface->out_txd_func, *device);
+ mc6854->out_rts_func.resolve(mc6854->iface->out_rts_func, *device);
+ mc6854->out_dtr_func.resolve(mc6854->iface->out_dtr_func, *device);
+
+ mc6854->ttimer = device->machine().scheduler().timer_alloc(FUNC(mc6854_tfifo_cb), (void*) device );
+
+ state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->cr1 );
+ state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->cr2 );
+ state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->cr3 );
+ state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->cr4 );
+ state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->sr1 );
+ state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->sr2 );
+ state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->cts );
+ state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->dcd );
+ state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->tstate );
+ state_save_register_item_array( device->machine(), "mc6854", device->tag(), 0, mc6854->tfifo );
+ state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->tones );
+ state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->rstate );
+ state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->rreg );
+ state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->rones );
+ state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->rsize );
+ state_save_register_item_array( device->machine(), "mc6854", device->tag(), 0, mc6854->rfifo );
+ state_save_register_item_array( device->machine(), "mc6854", device->tag(), 0, mc6854->frame );
+ state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->flen );
+ state_save_register_item( device->machine(), "mc6854", device->tag(), 0, mc6854->fpos );
+}
+
+
+
+/************************** configuration ****************************/
+
+
+DEVICE_GET_INFO( mc6854 ) {
+ switch ( state ) {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(mc6854_t); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(mc6854); break;
+ case DEVINFO_FCT_STOP: /* nothing */ break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(mc6854); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "Motorola MC6854 ADLC"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "MC6854"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.00"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright the MAME and MESS Teams"); break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(MC6854, mc6854);
diff --git a/src/mess/machine/mc6854.h b/src/mess/machine/mc6854.h
new file mode 100644
index 00000000000..e0b13373625
--- /dev/null
+++ b/src/mess/machine/mc6854.h
@@ -0,0 +1,82 @@
+/**********************************************************************
+
+ Copyright (C) Antoine Mine' 2006
+
+ Motorola 6854 emulation (network interface).
+
+**********************************************************************/
+
+#ifndef MC6854_H
+#define MC6854_H
+
+DECLARE_LEGACY_DEVICE(MC6854, 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.
+*/
+
+
+/* ---------- configuration ------------ */
+
+typedef struct _mc6854_interface mc6854_interface;
+struct _mc6854_interface
+{
+ devcb_write_line out_irq_func; /* interrupt request */
+
+ /* low-level, bit-based interface */
+ devcb_read_line in_rxd_func; /* receive bit */
+ devcb_write_line out_txd_func; /* transmit bit */
+
+ /* high-level, frame-based interface */
+ void ( * out_frame ) ( device_t *device, UINT8* data, int length );
+
+ /* control lines */
+ devcb_write_line out_rts_func; /* 1 = transmitting, 0 = idle */
+ devcb_write_line out_dtr_func; /* 1 = data transmit ready, 0 = busy */
+};
+
+
+#define MCFG_MC6854_ADD(_tag, _intrf) \
+ MCFG_DEVICE_ADD(_tag, MC6854, 0) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#define MCFG_MC6854_REMOVE(_tag) \
+ MCFG_DEVICE_REMOVE(_tag)
+
+
+/* ---------- functions ------------ */
+/* interface to CPU via address/data bus*/
+extern READ8_DEVICE_HANDLER ( mc6854_r );
+extern WRITE8_DEVICE_HANDLER ( mc6854_w );
+
+/* low-level, bit-based interface */
+WRITE_LINE_DEVICE_HANDLER( mc6854_set_rx );
+
+/* high-level, frame-based interface */
+extern int mc6854_send_frame( device_t *device, UINT8* data, int length ); /* ret -1 if busy */
+
+/* control lines */
+WRITE_LINE_DEVICE_HANDLER( mc6854_set_cts ); /* 1 = clear-to-send, 0 = busy */
+WRITE_LINE_DEVICE_HANDLER( mc6854_set_dcd ); /* 1 = carrier, 0 = no carrier */
+
+/* clock */
+WRITE_LINE_DEVICE_HANDLER( mc6854_rxc_w );
+WRITE_LINE_DEVICE_HANDLER( mc6854_txc_w );
+
+#endif
diff --git a/src/mess/machine/mc80.c b/src/mess/machine/mc80.c
new file mode 100644
index 00000000000..fc5bb06633d
--- /dev/null
+++ b/src/mess/machine/mc80.c
@@ -0,0 +1,203 @@
+/***************************************************************************
+
+ MC-80.xx by Miodrag Milanovic
+
+ 15/05/2009 Initial implementation
+ 12/05/2009 Skeleton driver.
+
+****************************************************************************/
+
+#include "includes/mc80.h"
+
+/*****************************************************************************/
+/* Implementation for MC80.2x */
+/*****************************************************************************/
+
+static IRQ_CALLBACK( mc8020_irq_callback )
+{
+ return 0x00;
+}
+
+MACHINE_RESET( mc8020 )
+{
+ device_set_irq_callback(machine.device("maincpu"), mc8020_irq_callback);
+}
+
+WRITE_LINE_MEMBER( mc80_state::ctc_z0_w )
+{
+}
+
+WRITE_LINE_MEMBER( mc80_state::ctc_z1_w )
+{
+}
+
+static WRITE_LINE_DEVICE_HANDLER( ctc_z2_w )
+{
+ downcast<z80ctc_device *>(device)->trg0(state);
+ downcast<z80ctc_device *>(device)->trg1(state);
+}
+
+Z80CTC_INTERFACE( mc8020_ctc_intf )
+{
+ DEVCB_CPU_INPUT_LINE("maincpu", INPUT_LINE_IRQ0),
+ DEVCB_DRIVER_LINE_MEMBER(mc80_state, ctc_z0_w),
+ DEVCB_DRIVER_LINE_MEMBER(mc80_state, ctc_z1_w),
+ DEVCB_LINE(ctc_z2_w)
+};
+
+
+READ8_MEMBER( mc80_state::mc80_port_b_r )
+{
+ return 0;
+}
+
+READ8_MEMBER( mc80_state::mc80_port_a_r )
+{
+ return 0;
+}
+
+WRITE8_MEMBER( mc80_state::mc80_port_a_w )
+{
+}
+
+WRITE8_MEMBER( mc80_state::mc80_port_b_w )
+{
+}
+
+Z80PIO_INTERFACE( mc8020_z80pio_intf )
+{
+ DEVCB_NULL, /* callback when change interrupt status */
+ DEVCB_DRIVER_MEMBER(mc80_state, mc80_port_a_r),
+ DEVCB_DRIVER_MEMBER(mc80_state, mc80_port_a_w),
+ DEVCB_NULL,
+ DEVCB_DRIVER_MEMBER(mc80_state, mc80_port_b_r),
+ DEVCB_DRIVER_MEMBER(mc80_state, mc80_port_b_w),
+ DEVCB_NULL
+};
+
+/*****************************************************************************/
+/* Implementation for MC80.3x */
+/*****************************************************************************/
+
+WRITE8_MEMBER( mc80_state::mc8030_zve_write_protect_w )
+{
+}
+
+WRITE8_MEMBER( mc80_state::mc8030_vis_w )
+{
+ // reg C
+ // 7 6 5 4 -- module
+ // 3 - 0 left half, 1 right half
+ // 2 1 0
+ // =====
+ // 0 0 0 - dark
+ // 0 0 1 - light
+ // 0 1 0 - in reg pixel
+ // 0 1 1 - negate in reg pixel
+ // 1 0 x - operation code in B reg
+ // reg B
+ //
+ UINT16 addr = ((offset & 0xff00) >> 2) | ((offset & 0x08) << 2) | (data >> 3);
+ static const UINT8 val[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
+ int c = offset & 1;
+ m_p_videoram[addr] = m_p_videoram[addr] | (val[data & 7]*c);
+}
+
+WRITE8_MEMBER( mc80_state::mc8030_eprom_prog_w )
+{
+}
+
+static IRQ_CALLBACK( mc8030_irq_callback )
+{
+ return 0x20;
+}
+
+MACHINE_RESET( mc8030 )
+{
+ device_set_irq_callback(machine.device("maincpu"), mc8030_irq_callback);
+}
+
+READ8_MEMBER( mc80_state::zve_port_a_r )
+{
+ return 0xff;
+}
+
+READ8_MEMBER( mc80_state::zve_port_b_r )
+{
+ return 0xff;
+}
+
+WRITE8_MEMBER( mc80_state::zve_port_a_w )
+{
+}
+
+WRITE8_MEMBER( mc80_state::zve_port_b_w )
+{
+}
+
+Z80PIO_INTERFACE( mc8030_zve_z80pio_intf )
+{
+ DEVCB_NULL, /* callback when change interrupt status */
+ DEVCB_DRIVER_MEMBER(mc80_state, zve_port_a_r),
+ DEVCB_DRIVER_MEMBER(mc80_state, zve_port_a_w),
+ DEVCB_NULL,
+ DEVCB_DRIVER_MEMBER(mc80_state, zve_port_b_r),
+ DEVCB_DRIVER_MEMBER(mc80_state, zve_port_b_w),
+ DEVCB_NULL
+};
+
+READ8_MEMBER( mc80_state::asp_port_a_r )
+{
+ return 0xff;
+}
+
+READ8_MEMBER( mc80_state::asp_port_b_r )
+{
+ return 0xff;
+}
+
+WRITE8_MEMBER( mc80_state::asp_port_a_w )
+{
+}
+
+WRITE8_MEMBER( mc80_state::asp_port_b_w )
+{
+}
+
+Z80PIO_INTERFACE( mc8030_asp_z80pio_intf )
+{
+ DEVCB_NULL, /* callback when change interrupt status */
+ DEVCB_DRIVER_MEMBER(mc80_state, asp_port_a_r),
+ DEVCB_DRIVER_MEMBER(mc80_state, asp_port_a_w),
+ DEVCB_NULL,
+ DEVCB_DRIVER_MEMBER(mc80_state, asp_port_b_r),
+ DEVCB_DRIVER_MEMBER(mc80_state, asp_port_b_w),
+ DEVCB_NULL
+};
+
+Z80CTC_INTERFACE( mc8030_zve_z80ctc_intf )
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+Z80CTC_INTERFACE( mc8030_asp_z80ctc_intf )
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+const z80sio_interface mc8030_asp_z80sio_intf =
+{
+ 0, /* interrupt handler */
+ 0, /* DTR changed handler */
+ 0, /* RTS changed handler */
+ 0, /* BREAK changed handler */
+ 0, /* transmit handler - which channel is this for? */
+ 0 /* receive handler - which channel is this for? */
+};
+
diff --git a/src/mess/machine/mface2.c b/src/mess/machine/mface2.c
new file mode 100644
index 00000000000..b8269761968
--- /dev/null
+++ b/src/mess/machine/mface2.c
@@ -0,0 +1,348 @@
+/*
+ * mface2.c -- Romantic Robot Multiface II expansion device for the Amstrad CPC/CPC+
+ *
+ * Created on: 31/07/2011
+ */
+
+#include "emu.h"
+#include "machine/mface2.h"
+#include "includes/amstrad.h"
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type CPC_MFACE2 = &device_creator<cpc_multiface2_device>;
+
+CPC_EXPANSION_INTERFACE(sub_exp_intf)
+{
+ DEVCB_LINE(cpc_irq_w),
+ DEVCB_LINE(cpc_nmi_w),//LINE_MEMBER(cpc_expansion_slot_device,nmi_w),
+ DEVCB_NULL, // RESET
+ DEVCB_LINE(cpc_romdis), // ROMDIS
+ DEVCB_LINE(cpc_romen) // /ROMEN
+};
+
+// device machine config
+static MACHINE_CONFIG_FRAGMENT( cpc_mface2 )
+ // pass-through
+ MCFG_CPC_EXPANSION_SLOT_ADD("exp",sub_exp_intf,cpc_exp_cards,NULL,NULL)
+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 = cpu_get_pc(machine().device("maincpu"));
+ /* 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;
+ m_slot->romen_w(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;
+ m_slot->romen_w(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),
+ device_cpc_expansion_card_interface(mconfig, *this)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void cpc_multiface2_device::device_start()
+{
+ m_slot = dynamic_cast<cpc_expansion_slot_device *>(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/mess/machine/mface2.h b/src/mess/machine/mface2.h
new file mode 100644
index 00000000000..6b613774a9c
--- /dev/null
+++ b/src/mess/machine/mface2.h
@@ -0,0 +1,70 @@
+/*
+ * 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 "machine/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();
+ virtual void device_config_complete() { m_shortname = "cpc_mf2"; }
+
+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/mess/machine/micropolis.c b/src/mess/machine/micropolis.c
new file mode 100644
index 00000000000..f4b04512624
--- /dev/null
+++ b/src/mess/machine/micropolis.c
@@ -0,0 +1,395 @@
+/***************************************************************************
+
+ micropolis.c
+
+ by Robbbert, August 2011.
+
+This is a rough implementation of the Micropolis floppy-disk controller
+as used for the Exidy Sorcerer. Since there is no documentation, coding
+was done by looking at the Z80 code, and supplying the expected values.
+
+Currently, only reading of disks is supported.
+
+ToDo:
+- Rewrite to be a standard device able to be used in a general way
+- Fix bug where if you run a program on drive B,C,D then exit, you
+ get a disk error.
+- Enable the ability to write to disk when above bug gets fixed.
+- When the controller is reset via command 5, what exactly gets reset?
+
+
+Ports:
+BE00 and BE01 can be used as command registers (they are identical),
+ and they are also used as status registers (different).
+
+BE02 and BE03 - read data, write data
+
+***************************************************************************/
+
+
+#include "emu.h"
+#include "imagedev/flopdrv.h"
+#include "machine/micropolis.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+
+#define STAT_RFC 0x20
+#define STAT_TRACK0 0x08
+#define STAT_READY 0x80
+
+#define VERBOSE 0 /* General logging */
+#define VERBOSE_DATA 0 /* Logging of each byte during read and write */
+
+/* structure describing a single density track */
+#define TRKSIZE_SD 16*270
+#if 0
+static const UINT8 track_SD[][2] = {
+ { 1, 0xff}, /* 1 * FF (marker) */
+ { 1, 0x00}, /* 1 byte, track number (00-4C) */
+ { 1, 0x01}, /* 1 byte, sector number (00-0F) */
+ {10, 0x00}, /* 10 bytes of zeroes */
+ {256, 0xe5}, /* 256 bytes of sector data */
+ { 1, 0xb7}, /* 1 byte, CRC */
+};
+#endif
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _micropolis_state micropolis_state;
+struct _micropolis_state
+{
+ /* register */
+ UINT8 data;
+ UINT8 drive_num;
+ UINT8 track;
+ UINT8 sector;
+ UINT8 command;
+ UINT8 status;
+
+ UINT8 write_cmd; /* last write command issued */
+
+ UINT8 buffer[6144]; /* I/O buffer (holds up to a whole track) */
+ UINT32 data_offset; /* offset into I/O buffer */
+ INT32 data_count; /* transfer count from/into I/O buffer */
+
+ UINT32 sector_length; /* sector length (byte) */
+
+ /* this is the drive currently selected */
+ device_t *drive;
+
+ /* Pointer to interface */
+ const micropolis_interface *intf;
+};
+
+
+/***************************************************************************
+ DEFAULT INTERFACES
+***************************************************************************/
+
+const micropolis_interface default_micropolis_interface =
+{
+ DEVCB_NULL, DEVCB_NULL, DEVCB_NULL, { FLOPPY_0, FLOPPY_1, FLOPPY_2, FLOPPY_3}
+};
+
+const micropolis_interface default_micropolis_interface_2_drives =
+{
+ DEVCB_NULL, DEVCB_NULL, DEVCB_NULL, { FLOPPY_0, FLOPPY_1, NULL, NULL}
+};
+
+
+/*****************************************************************************
+ INLINE FUNCTIONS
+*****************************************************************************/
+
+INLINE micropolis_state *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == MICROPOLIS);
+
+ return (micropolis_state *)downcast<legacy_device_base *>(device)->token();
+}
+
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+
+/* read a sector */
+static void micropolis_read_sector(device_t *device)
+{
+ micropolis_state *w = get_safe_token(device);
+ w->data_offset = 0;
+ w->data_count = w->sector_length;
+
+ /* read data */
+ floppy_drive_read_sector_data(w->drive, 0, w->sector, (char *)w->buffer, w->sector_length);
+}
+
+
+static void micropolis_write_sector(device_t *device)
+{
+#if 0
+ micropolis_state *w = get_safe_token(device);
+ /* at this point, the disc is write enabled, and data
+ * has been transfered into our buffer - now write it to
+ * the disc image or to the real disc
+ */
+
+ /* find sector */
+ w->data_count = w->sector_length;
+
+ /* write data */
+ floppy_drive_write_sector_data(w->drive, 0, w->sector, (char *)w->buffer, w->sector_length, w->write_cmd & 0x01);
+#endif
+}
+
+
+
+
+/***************************************************************************
+ INTERFACE
+***************************************************************************/
+
+/* select a drive */
+void micropolis_set_drive(device_t *device, UINT8 drive)
+{
+ micropolis_state *w = get_safe_token(device);
+
+ if (VERBOSE)
+ logerror("micropolis_set_drive: $%02x\n", drive);
+
+ if (w->intf->floppy_drive_tags[drive])
+ w->drive = device->siblingdevice(w->intf->floppy_drive_tags[drive]);
+}
+
+
+/***************************************************************************
+ DEVICE HANDLERS
+***************************************************************************/
+
+
+/* read the FDC status register. */
+READ8_DEVICE_HANDLER( micropolis_status_r )
+{
+ micropolis_state *w = get_safe_token(device);
+ static int inv = 0;
+
+ if (offset)
+ return w->status | w->drive_num;
+ else
+ {
+ // FIXME - find out what controls current sector
+ w->sector = (w->sector + 3 + inv) & 15;
+ micropolis_read_sector(device);
+ inv ^= 1;
+ return (w->status & STAT_READY) | w->sector;
+ }
+}
+
+
+/* read the FDC data register */
+READ8_DEVICE_HANDLER( micropolis_data_r )
+{
+ micropolis_state *w = get_safe_token(device);
+
+ if (w->data_offset >= w->sector_length)
+ w->data_offset = 0;
+
+ return w->buffer[w->data_offset++];
+}
+
+/* write the FDC command register */
+WRITE8_DEVICE_HANDLER( micropolis_command_w )
+{
+/* List of commands:
+Command (bits 5,6,7) Options (bits 0,1,2,3,4)
+0 Not used
+1 Drive/head select bits 0,1 select drive 0-3; bit 4 chooses a side
+2 INT sector control bit 0 LO = disable; HI = enable
+3 Step bit 0 LO step out; HI = step in (increment track number)
+4 Set Write
+5 Reset controller
+6 Not used
+7 Not used */
+
+ micropolis_state *w = get_safe_token(device);
+ int direction = 0;
+
+ switch (data >> 5)
+ {
+ case 1:
+ w->drive_num = data & 3;
+ floppy_mon_w(w->drive, 1); // turn off the old drive
+ micropolis_set_drive(device, w->drive_num); // select new drive
+ floppy_mon_w(w->drive, 0); // turn it on
+ break;
+ case 2: // not emulated, not used in sorcerer
+ break;
+ case 3:
+ if (BIT(data, 0))
+ {
+ if (w->track < 77)
+ {
+ w->track++;
+ direction = 1;
+ }
+ }
+ else
+ {
+ if (w->track)
+ {
+ w->track--;
+ direction = -1;
+ }
+ }
+ break;
+ case 4: // not emulated, to be done
+ break;
+ case 5: // not emulated, to be done
+ break;
+ }
+
+
+ w->status = STAT_RFC;
+
+ if (BIT(data, 5))
+ w->status |= STAT_READY;
+
+ floppy_drive_set_ready_state(w->drive, 1,0);
+
+
+ if (!w->track)
+ w->status |= STAT_TRACK0;
+
+ floppy_drive_seek(w->drive, direction);
+}
+
+
+/* write the FDC data register */
+WRITE8_DEVICE_HANDLER( micropolis_data_w )
+{
+ micropolis_state *w = get_safe_token(device);
+
+ if (w->data_count > 0)
+ {
+ /* put byte into buffer */
+ if (VERBOSE_DATA)
+ logerror("micropolis_info buffered data: $%02X at offset %d.\n", data, w->data_offset);
+
+ w->buffer[w->data_offset++] = data;
+
+ if (--w->data_count < 1)
+ {
+ micropolis_write_sector(device);
+
+ w->data_offset = 0;
+ }
+ }
+ else
+ {
+ if (VERBOSE)
+ logerror("%s: micropolis_data_w $%02X\n", device->machine().describe_context(), data);
+ }
+ w->data = data;
+}
+
+READ8_DEVICE_HANDLER( micropolis_r )
+{
+ UINT8 data = 0;
+
+ switch (offset & 0x03)
+ {
+ case 0: data = micropolis_status_r(device, 0); break;
+ case 1: data = micropolis_status_r(device, 1); break;
+ case 2:
+ case 3: data = micropolis_data_r(device, 0); break;
+ }
+
+ return data;
+}
+
+WRITE8_DEVICE_HANDLER( micropolis_w )
+{
+ switch (offset & 0x03)
+ {
+ case 0:
+ case 1: micropolis_command_w(device, 0, data); break;
+ case 2:
+ case 3: micropolis_data_w(device, 0, data); break;
+ }
+}
+
+
+/***************************************************************************
+ MAME DEVICE INTERFACE
+***************************************************************************/
+
+static DEVICE_START( micropolis )
+{
+ micropolis_state *w = get_safe_token(device);
+
+ assert(device->static_config() != NULL);
+
+ w->intf = (const micropolis_interface*)device->static_config();
+}
+
+static DEVICE_RESET( micropolis )
+{
+ micropolis_state *w = get_safe_token(device);
+ int i;
+
+ for (i = 0; i < 4; i++)
+ {
+ if(w->intf->floppy_drive_tags[i])
+ {
+ device_t *img = NULL;
+
+ img = device->siblingdevice(w->intf->floppy_drive_tags[i]);
+
+ if (img)
+ {
+ floppy_drive_set_controller(img,device);
+ //floppy_drive_set_index_pulse_callback(img, wd17xx_index_pulse_callback);
+ floppy_drive_set_rpm( img, 300.);
+ }
+ }
+ }
+
+ micropolis_set_drive(device, 0);
+
+ w->drive_num = 0;
+ w->sector = 0;
+ w->track = 0;
+ w->sector_length = 270;
+ w->status = STAT_TRACK0;
+}
+
+void micropolis_reset(device_t *device)
+{
+ DEVICE_RESET_CALL( micropolis );
+}
+
+
+/***************************************************************************
+ DEVICE GETINFO
+***************************************************************************/
+
+static const char DEVTEMPLATE_SOURCE[] = __FILE__;
+
+#define DEVTEMPLATE_ID(p,s) p##micropolis##s
+#define DEVTEMPLATE_FEATURES DT_HAS_START | DT_HAS_RESET
+#define DEVTEMPLATE_NAME "MICROPOLIS"
+#define DEVTEMPLATE_FAMILY "MICROPOLIS"
+#define DEVTEMPLATE_VERSION "0.1"
+#define DEVTEMPLATE_CREDITS "Copyright MESS Team"
+#include "devtempl.h"
+
+DEFINE_LEGACY_DEVICE(MICROPOLIS, micropolis);
diff --git a/src/mess/machine/micropolis.h b/src/mess/machine/micropolis.h
new file mode 100644
index 00000000000..d9b7c4bc1cd
--- /dev/null
+++ b/src/mess/machine/micropolis.h
@@ -0,0 +1,66 @@
+/*********************************************************************
+
+ micropolis.h
+
+ Implementations of the Micropolis
+ floppy disk controller for the Sorcerer
+
+*********************************************************************/
+
+#ifndef __MICROPOLIS_H__
+#define __MICROPOLIS_H__
+
+#include "devcb.h"
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+DECLARE_LEGACY_DEVICE(MICROPOLIS, micropolis);
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* Interface */
+typedef struct _micropolis_interface micropolis_interface;
+struct _micropolis_interface
+{
+ devcb_read_line in_dden_func;
+ devcb_write_line out_intrq_func;
+ devcb_write_line out_drq_func;
+ const char *floppy_drive_tags[4];
+};
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+void micropolis_reset(device_t *device);
+
+void micropolis_set_drive(device_t *device, UINT8); // set current drive (0-3)
+
+READ8_DEVICE_HANDLER( micropolis_status_r );
+READ8_DEVICE_HANDLER( micropolis_data_r );
+
+WRITE8_DEVICE_HANDLER( micropolis_command_w );
+WRITE8_DEVICE_HANDLER( micropolis_data_w );
+
+READ8_DEVICE_HANDLER( micropolis_r );
+WRITE8_DEVICE_HANDLER( micropolis_w );
+
+extern const micropolis_interface default_micropolis_interface;
+
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+#define MCFG_MICROPOLIS_ADD(_tag, _intrf) \
+ MCFG_DEVICE_ADD(_tag, MICROPOLIS, 0) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#endif /* __MICROPOLIS_H__ */
diff --git a/src/mess/machine/microtan.c b/src/mess/machine/microtan.c
new file mode 100644
index 00000000000..2f3bc921bbf
--- /dev/null
+++ b/src/mess/machine/microtan.c
@@ -0,0 +1,584 @@
+/******************************************************************************
+ * Microtan 65
+ *
+ * machine driver
+ *
+ * Juergen Buchmueller <pullmoll@t-online.de>, Jul 2000
+ *
+ * Thanks go to Geoff Macdonald <mail@geoff.org.uk>
+ * for his site http:://www.geo255.redhotant.com
+ * and to Fabrice Frances <frances@ensica.fr>
+ * for his site http://www.ifrance.com/oric/microtan.html
+ *
+ *****************************************************************************/
+
+/* Core includes */
+#include "emu.h"
+#include "includes/microtan.h"
+
+/* Components */
+#include "cpu/m6502/m6502.h"
+#include "machine/6522via.h"
+#include "machine/6551acia.h"
+#include "sound/ay8910.h"
+
+/* Devices */
+#include "imagedev/cassette.h"
+//#include "imagedev/snapquik.h"
+
+
+#ifndef VERBOSE
+#define VERBOSE 0
+#endif
+
+#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+
+
+static const char keyboard[8][9][8] = {
+ { /* normal */
+ { 27,'1','2','3','4','5','6','7'},
+ {'8','9','0','-','=','`',127, 9},
+ {'q','w','e','r','t','y','u','i'},
+ {'o','p','[',']', 13,127, 0, 0},
+ {'a','s','d','f','g','h','j','k'},
+ {'l',';', 39, 92, 0,'z','x','c'},
+ {'v','b','n','m',',','.','/', 0},
+ { 10,' ','-',',', 13,'.','0','1'},
+ {'2','3','4','5','6','7','8','9'},
+ },
+ { /* Shift */
+ { 27,'!','@','#','$','%','^','&'},
+ {'*','(',')','_','+','~',127, 9},
+ {'Q','W','E','R','T','Y','U','I'},
+ {'O','P','{','}', 13,127, 0, 0},
+ {'A','S','D','F','G','H','J','K'},
+ {'L',':','"','|', 0,'Z','X','C'},
+ {'V','B','N','M','<','>','?', 0},
+ { 10,' ','-',',', 13,'.','0','1'},
+ {'2','3','4','5','6','7','8','9'},
+ },
+ { /* Control */
+ { 27,'1','2','3','4','5','6','7'},
+ {'8','9','0','-','=','`',127, 9},
+ { 17, 23, 5, 18, 20, 25, 21, 9},
+ { 15, 16, 27, 29, 13,127, 0, 0},
+ { 1, 19, 4, 6, 7, 8, 10, 11},
+ { 12,';', 39, 28, 0, 26, 24, 3},
+ { 22, 2, 14, 13,',','.','/', 0},
+ { 10,' ','-',',', 13,'.','0','1'},
+ {'2','3','4','5','6','7','8','9'},
+ },
+ { /* Shift+Control */
+ { 27,'!', 0,'#','$','%', 30,'&'},
+ {'*','(',')', 31,'+','~',127, 9},
+ { 17, 23, 5, 18, 20, 25, 21, 9},
+ { 15, 16, 27, 29, 13,127, 0, 0},
+ { 1, 19, 4, 6, 7, 8, 10, 11},
+ { 12,':','"', 28, 0, 26, 24, 3},
+ { 22, 2, 14, 13,',','.','/', 0},
+ { 10,' ','-',',', 13,'.','0','1'},
+ {'2','3','4','5','6','7','8','9'},
+ },
+ { /* CapsLock */
+ { 27,'1','2','3','4','5','6','7'},
+ {'8','9','0','-','=','`',127, 9},
+ {'Q','W','E','R','T','Y','U','I'},
+ {'O','P','[',']', 13,127, 0, 0},
+ {'A','S','D','F','G','H','J','K'},
+ {'L',';', 39, 92, 0,'Z','X','C'},
+ {'V','B','N','M',',','.','/', 0},
+ { 10,' ','-',',', 13,'.','0','1'},
+ {'2','3','4','5','6','7','8','9'},
+ },
+ { /* Shift+CapsLock */
+ { 27,'!','@','#','$','%','^','&'},
+ {'*','(',')','_','+','~',127, 9},
+ {'Q','W','E','R','T','Y','U','I'},
+ {'O','P','{','}', 13,127, 0, 0},
+ {'A','S','D','F','G','H','J','K'},
+ {'L',':','"','|', 0,'Z','X','C'},
+ {'V','B','N','M','<','>','?', 0},
+ { 10,' ','-',',', 13,'.','0','1'},
+ {'2','3','4','5','6','7','8','9'},
+ },
+ { /* Control+CapsLock */
+ { 27,'1','2','3','4','5','6','7'},
+ {'8','9','0','-','=','`',127, 9},
+ { 17, 23, 5, 18, 20, 25, 21, 9},
+ { 15, 16, 27, 29, 13,127, 0, 0},
+ { 1, 19, 4, 6, 7, 8, 10, 11},
+ { 12,';', 39, 28, 0, 26, 24, 3},
+ { 22, 2, 14, 13,',','.','/', 0},
+ { 10,' ','-',',', 13,'.','0','1'},
+ {'2','3','4','5','6','7','8','9'},
+ },
+ { /* Shift+Control+CapsLock */
+ { 27,'!', 0,'#','$','%', 30,'&'},
+ {'*','(',')', 31,'+','~',127, 9},
+ { 17, 23, 5, 18, 20, 25, 21, 9},
+ { 15, 16, 27, 29, 13,127, 0, 0},
+ { 1, 19, 4, 6, 7, 8, 10, 11},
+ { 12,':','"', 28, 0, 26, 24, 3},
+ { 22, 2, 14, 13,',','.','/', 0},
+ { 10,' ','-',',', 13,'.','0','1'},
+ {'2','3','4','5','6','7','8','9'},
+ },
+};
+
+static UINT8 read_dsw(running_machine &machine)
+{
+ UINT8 result;
+ switch(machine.phase())
+ {
+ case MACHINE_PHASE_RESET:
+ case MACHINE_PHASE_RUNNING:
+ result = machine.root_device().ioport("DSW")->read();
+ break;
+
+ default:
+ result = 0x00;
+ break;
+ }
+ return result;
+}
+
+static void microtan_set_irq_line(running_machine &machine)
+{
+ microtan_state *state = machine.driver_data<microtan_state>();
+ /* The 6502 IRQ line is active low and probably driven
+ by open collector outputs (guess). Since MAME/MESS use
+ a non-0 value for ASSERT_LINE we OR the signals here */
+ cputag_set_input_line(machine, "maincpu", 0, state->m_via_0_irq_line | state->m_via_1_irq_line | state->m_kbd_irq_line);
+}
+
+static cassette_image_device *cassette_device_image(running_machine &machine)
+{
+ return machine.device<cassette_image_device>(CASSETTE_TAG);
+}
+
+/**************************************************************
+ * VIA callback functions for VIA #0
+ **************************************************************/
+static READ8_DEVICE_HANDLER (via_0_in_a )
+{
+ int data = device->machine().root_device().ioport("JOY")->read();
+ LOG(("microtan_via_0_in_a %02X\n", data));
+ return data;
+}
+
+static READ8_DEVICE_HANDLER ( via_0_in_b )
+{
+ int data = 0xff;
+ LOG(("microtan_via_0_in_b %02X\n", data));
+ return data;
+}
+
+static READ8_DEVICE_HANDLER ( via_0_in_ca1 )
+{
+ int data = 1;
+ LOG(("microtan_via_0_in_ca1 %d\n", data));
+ return data;
+}
+
+static READ8_DEVICE_HANDLER ( via_0_in_cb1 )
+{
+ int data = 1;
+ LOG(("microtan_via_0_in_cb1 %d\n", data));
+ return data;
+}
+
+static READ8_DEVICE_HANDLER ( via_0_in_ca2 )
+{
+ int data = 1;
+ LOG(("microtan_via_0_in_ca2 %d\n", data));
+ return data;
+}
+
+static READ8_DEVICE_HANDLER ( via_0_in_cb2 )
+{
+ int data = 1;
+ LOG(("microtan_via_0_in_cb2 %d\n", data));
+ return data;
+}
+
+static WRITE8_DEVICE_HANDLER ( via_0_out_a )
+{
+ LOG(("microtan_via_0_out_a %02X\n", data));
+}
+
+static WRITE8_DEVICE_HANDLER (via_0_out_b )
+{
+ LOG(("microtan_via_0_out_b %02X\n", data));
+ /* bit #7 is the cassette output signal */
+ cassette_device_image(device->machine())->output(data & 0x80 ? +1.0 : -1.0);
+}
+
+static WRITE8_DEVICE_HANDLER ( via_0_out_ca2 )
+{
+ LOG(("microtan_via_0_out_ca2 %d\n", data));
+}
+
+static WRITE8_DEVICE_HANDLER (via_0_out_cb2 )
+{
+ LOG(("microtan_via_0_out_cb2 %d\n", data));
+}
+
+static void via_0_irq(device_t *device, int state)
+{
+ microtan_state *drvstate = device->machine().driver_data<microtan_state>();
+ LOG(("microtan_via_0_irq %d\n", state));
+ drvstate->m_via_0_irq_line = state;
+ microtan_set_irq_line(device->machine());
+}
+
+/**************************************************************
+ * VIA callback functions for VIA #1
+ **************************************************************/
+static READ8_DEVICE_HANDLER ( via_1_in_a )
+{
+ int data = 0xff;
+ LOG(("microtan_via_1_in_a %02X\n", data));
+ return data;
+}
+
+static READ8_DEVICE_HANDLER ( via_1_in_b )
+{
+ int data = 0xff;
+ LOG(("microtan_via_1_in_b %02X\n", data));
+ return data;
+}
+
+static READ8_DEVICE_HANDLER ( via_1_in_ca1 )
+{
+ int data = 1;
+ LOG(("microtan_via_1_in_ca1 %d\n", data));
+ return data;
+}
+
+static READ8_DEVICE_HANDLER ( via_1_in_cb1 )
+{
+ int data = 1;
+ LOG(("microtan_via_1_in_cb1 %d\n", data));
+ return data;
+}
+
+static READ8_DEVICE_HANDLER ( via_1_in_ca2 )
+{
+ int data = 1;
+ LOG(("microtan_via_1_in_ca2 %d\n", data));
+ return data;
+}
+
+static READ8_DEVICE_HANDLER ( via_1_in_cb2 )
+{
+ int data = 1;
+ LOG(("microtan_via_1_in_cb2 %d\n", data));
+ return data;
+}
+
+static WRITE8_DEVICE_HANDLER ( via_1_out_a )
+{
+ LOG(("microtan_via_1_out_a %02X\n", data));
+}
+
+static WRITE8_DEVICE_HANDLER ( via_1_out_b )
+{
+ LOG(("microtan_via_1_out_b %02X\n", data));
+}
+
+static WRITE8_DEVICE_HANDLER (via_1_out_ca2 )
+{
+ LOG(("microtan_via_1_out_ca2 %d\n", data));
+}
+
+static WRITE8_DEVICE_HANDLER ( via_1_out_cb2 )
+{
+ LOG(("microtan_via_1_out_cb2 %d\n", data));
+}
+
+static void via_1_irq(device_t *device, int state)
+{
+ microtan_state *drvstate = device->machine().driver_data<microtan_state>();
+ LOG(("microtan_via_1_irq %d\n", state));
+ drvstate->m_via_1_irq_line = state;
+ microtan_set_irq_line(device->machine());
+}
+
+/**************************************************************
+ * VIA interface structure
+ **************************************************************/
+const via6522_interface microtan_via6522_0 =
+{
+ /* VIA#1 at bfc0-bfcf*/
+ DEVCB_HANDLER(via_0_in_a), DEVCB_HANDLER(via_0_in_b),
+ DEVCB_HANDLER(via_0_in_ca1), DEVCB_HANDLER(via_0_in_cb1),
+ DEVCB_HANDLER(via_0_in_ca2), DEVCB_HANDLER(via_0_in_cb2),
+ DEVCB_HANDLER(via_0_out_a), DEVCB_HANDLER(via_0_out_b),
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_HANDLER(via_0_out_ca2),DEVCB_HANDLER(via_0_out_cb2),
+ DEVCB_LINE(via_0_irq)
+};
+
+const via6522_interface microtan_via6522_1 =
+{
+ /* VIA#1 at bfe0-bfef*/
+ DEVCB_HANDLER(via_1_in_a), DEVCB_HANDLER(via_1_in_b),
+ DEVCB_HANDLER(via_1_in_ca1), DEVCB_HANDLER(via_1_in_cb1),
+ DEVCB_HANDLER(via_1_in_ca2), DEVCB_HANDLER(via_1_in_cb2),
+ DEVCB_HANDLER(via_1_out_a), DEVCB_HANDLER(via_1_out_b),
+ DEVCB_NULL, DEVCB_NULL,
+ DEVCB_HANDLER(via_1_out_ca2),DEVCB_HANDLER(via_1_out_cb2),
+ DEVCB_LINE(via_1_irq)
+};
+
+static TIMER_CALLBACK(microtan_read_cassette)
+{
+ double level = (cassette_device_image(machine))->input();
+ via6522_device *via_0 = machine.device<via6522_device>("via6522_0");
+
+ LOG(("microtan_read_cassette: %g\n", level));
+ if (level < -0.07)
+ via_0->write_cb2(0);
+ else if (level > +0.07)
+ via_0->write_cb2(1);
+}
+
+READ8_MEMBER(microtan_state::microtan_sound_r)
+{
+ int data = 0xff;
+ LOG(("microtan_sound_r: -> %02x\n", data));
+ return data;
+}
+
+WRITE8_MEMBER(microtan_state::microtan_sound_w)
+{
+ LOG(("microtan_sound_w: <- %02x\n", data));
+}
+
+
+READ8_MEMBER(microtan_state::microtan_bffx_r)
+{
+ int data = 0xff;
+ switch( offset & 3 )
+ {
+ case 0: /* BFF0: read enables chunky graphics */
+ m_chunky_graphics = 1;
+ LOG(("microtan_bff0_r: -> %02x (chunky graphics on)\n", data));
+ break;
+ case 1: /* BFF1: read undefined (?) */
+ LOG(("microtan_bff1_r: -> %02x\n", data));
+ break;
+ case 2: /* BFF2: read undefined (?) */
+ LOG(("microtan_bff2_r: -> %02x\n", data));
+ break;
+ default: /* BFF3: read keyboard ASCII value */
+ data = m_keyboard_ascii;
+ LOG(("microtan_bff3_r: -> %02x (keyboard ASCII)\n", data));
+ }
+ return data;
+}
+
+
+/* This callback is called one clock cycle after BFF2 is written (delayed nmi) */
+static TIMER_CALLBACK(microtan_pulse_nmi)
+{
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_NMI, PULSE_LINE);
+}
+
+WRITE8_MEMBER(microtan_state::microtan_bffx_w)
+{
+ switch( offset & 3 )
+ {
+ case 0: /* BFF0: write reset keyboard interrupt flag */
+ /* This removes bit 7 from the ASCII value of the last key pressed. */
+ LOG(("microtan_bff0_w: %d <- %02x (keyboard IRQ clear )\n", offset, data));
+ m_keyboard_ascii &= ~0x80;
+ m_kbd_irq_line = CLEAR_LINE;
+ microtan_set_irq_line(machine());
+ break;
+ case 1: /* BFF1: write delayed NMI */
+ LOG(("microtan_bff1_w: %d <- %02x (delayed NMI)\n", offset, data));
+ machine().scheduler().timer_set(machine().device<cpu_device>("maincpu")->cycles_to_attotime(8), FUNC(microtan_pulse_nmi));
+ break;
+ case 2: /* BFF2: write keypad column write (what is this meant for?) */
+ LOG(("microtan_bff2_w: %d <- %02x (keypad column)\n", offset, data));
+ m_keypad_column = data;
+ break;
+ default: /* BFF3: write disable chunky graphics */
+ LOG(("microtan_bff3_w: %d <- %02x (chunky graphics off)\n", offset, data));
+ m_chunky_graphics = 0;
+ }
+}
+
+static void store_key(running_machine &machine, int key)
+{
+ microtan_state *state = machine.driver_data<microtan_state>();
+ LOG(("microtan: store key '%c'\n", key));
+ state->m_keyboard_ascii = key | 0x80;
+ state->m_kbd_irq_line = ASSERT_LINE;
+ microtan_set_irq_line(machine);
+}
+
+INTERRUPT_GEN( microtan_interrupt )
+{
+ microtan_state *state = device->machine().driver_data<microtan_state>();
+ int mod, row, col, chg, newvar;
+ static const char *const keynames[] = { "ROW0", "ROW1", "ROW2", "ROW3", "ROW4", "ROW5", "ROW6", "ROW7", "ROW8" };
+
+ if( state->m_repeat )
+ {
+ if( !--state->m_repeat )
+ state->m_repeater = 4;
+ }
+ else if( state->m_repeater )
+ {
+ state->m_repeat = state->m_repeater;
+ }
+
+
+ row = 9;
+ newvar = device->machine().root_device().ioport("ROW8")->read();
+ chg = state->m_keyrows[--row] ^ newvar;
+
+ while ( !chg && row > 0)
+ {
+ newvar = device->machine().root_device().ioport(keynames[row - 1])->read();
+ chg = state->m_keyrows[--row] ^ newvar;
+ }
+ if (!chg)
+ --row;
+
+ if (row >= 0)
+ {
+ state->m_repeater = 0x00;
+ state->m_mask = 0x00;
+ state->m_key = 0x00;
+ state->m_lastrow = row;
+ /* CapsLock LED */
+ if( row == 3 && chg == 0x80 )
+ set_led_status(device->machine(), 1, (state->m_keyrows[3] & 0x80) ? 0 : 1);
+
+ if (newvar & chg) /* key(s) pressed ? */
+ {
+ mod = 0;
+
+ /* Shift modifier */
+ if ( (state->m_keyrows[5] & 0x10) || (state->m_keyrows[6] & 0x80) )
+ mod |= 1;
+
+ /* Control modifier */
+ if (state->m_keyrows[3] & 0x40)
+ mod |= 2;
+
+ /* CapsLock modifier */
+ if (state->m_keyrows[3] & 0x80)
+ mod |= 4;
+
+ /* find newvar key */
+ state->m_mask = 0x01;
+ for (col = 0; col < 8; col ++)
+ {
+ if (chg & state->m_mask)
+ {
+ newvar &= state->m_mask;
+ state->m_key = keyboard[mod][row][col];
+ break;
+ }
+ state->m_mask <<= 1;
+ }
+ if( state->m_key ) /* normal key */
+ {
+ state->m_repeater = 30;
+ store_key(device->machine(), state->m_key);
+ }
+ else
+ if( (row == 0) && (chg == 0x04) ) /* Ctrl-@ (NUL) */
+ store_key(device->machine(), 0);
+ state->m_keyrows[row] |= newvar;
+ }
+ else
+ {
+ state->m_keyrows[row] = newvar;
+ }
+ state->m_repeat = state->m_repeater;
+ }
+ else
+ if ( state->m_key && (state->m_keyrows[state->m_lastrow] & state->m_mask) && state->m_repeat == 0 )
+ {
+ store_key(device->machine(), state->m_key);
+ }
+}
+
+DRIVER_INIT_MEMBER(microtan_state,microtan)
+{
+ UINT8 *dst = memregion("gfx2")->base();
+ int i;
+ address_space *space = machine().device("maincpu")->memory().space(AS_PROGRAM);
+
+ for (i = 0; i < 256; i++)
+ {
+ switch (i & 3)
+ {
+ case 0: dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = 0x00; break;
+ case 1: dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = 0xf0; break;
+ case 2: dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = 0x0f; break;
+ case 3: dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = 0xff; break;
+ }
+ dst += 4;
+ switch ((i >> 2) & 3)
+ {
+ case 0: dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = 0x00; break;
+ case 1: dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = 0xf0; break;
+ case 2: dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = 0x0f; break;
+ case 3: dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = 0xff; break;
+ }
+ dst += 4;
+ switch ((i >> 4) & 3)
+ {
+ case 0: dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = 0x00; break;
+ case 1: dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = 0xf0; break;
+ case 2: dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = 0x0f; break;
+ case 3: dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = 0xff; break;
+ }
+ dst += 4;
+ switch ((i >> 6) & 3)
+ {
+ case 0: dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = 0x00; break;
+ case 1: dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = 0xf0; break;
+ case 2: dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = 0x0f; break;
+ case 3: dst[ 0] = dst[ 1] = dst[ 2] = dst[ 3] = 0xff; break;
+ }
+ dst += 4;
+ }
+
+ switch (read_dsw(machine()) & 3)
+ {
+ case 0: // 1K only :)
+ space->nop_readwrite(0x0400, 0xbbff);
+ break;
+ case 1: // +7K TANEX
+ space->install_ram(0x0400, 0x1fff,NULL);
+ space->nop_readwrite(0x2000, 0xbbff);
+ break;
+ default: // +7K TANEX + 40K TANRAM
+ space->install_ram(0x0400, 0xbbff, NULL);
+ break;
+ }
+
+ m_timer = machine().scheduler().timer_alloc(FUNC(microtan_read_cassette));
+}
+
+MACHINE_RESET( microtan )
+{
+ microtan_state *state = machine.driver_data<microtan_state>();
+ int i;
+ static const char *const keynames[] = { "ROW0", "ROW1", "ROW2", "ROW3", "ROW4", "ROW5", "ROW6", "ROW7", "ROW8" };
+
+ for (i = 1; i < 10; i++)
+ {
+ state->m_keyrows[i] = machine.root_device().ioport(keynames[i-1])->read();
+ }
+ set_led_status(machine, 1, (state->m_keyrows[3] & 0x80) ? 0 : 1);
+}
diff --git a/src/mess/machine/mikro80.c b/src/mess/machine/mikro80.c
new file mode 100644
index 00000000000..b2deb3cce0d
--- /dev/null
+++ b/src/mess/machine/mikro80.c
@@ -0,0 +1,113 @@
+/***************************************************************************
+
+ Mikro-80 machine driver by Miodrag Milanovic
+
+ 10/03/2008 Preliminary driver.
+
+****************************************************************************/
+
+
+#include "emu.h"
+#include "cpu/i8085/i8085.h"
+#include "imagedev/cassette.h"
+#include "machine/i8255.h"
+#include "includes/mikro80.h"
+
+/* Driver initialization */
+DRIVER_INIT_MEMBER(mikro80_state,mikro80)
+{
+ /* set initialy ROM to be visible on first bank */
+ UINT8 *RAM = memregion("maincpu")->base();
+ memset(RAM,0x0000,0x0800); // make frist page empty by default
+ membank("bank1")->configure_entries(1, 2, RAM, 0x0000);
+ membank("bank1")->configure_entries(0, 2, RAM, 0xf800);
+ m_key_mask = 0x7f;
+}
+
+DRIVER_INIT_MEMBER(mikro80_state,radio99)
+{
+ DRIVER_INIT_CALL(mikro80);
+ m_key_mask = 0xff;
+}
+
+READ8_MEMBER(mikro80_state::mikro80_8255_portb_r)
+{
+ UINT8 key = 0xff;
+ if ((m_keyboard_mask & 0x01)!=0) { key &= ioport("LINE0")->read(); }
+ if ((m_keyboard_mask & 0x02)!=0) { key &= ioport("LINE1")->read(); }
+ if ((m_keyboard_mask & 0x04)!=0) { key &= ioport("LINE2")->read(); }
+ if ((m_keyboard_mask & 0x08)!=0) { key &= ioport("LINE3")->read(); }
+ if ((m_keyboard_mask & 0x10)!=0) { key &= ioport("LINE4")->read(); }
+ if ((m_keyboard_mask & 0x20)!=0) { key &= ioport("LINE5")->read(); }
+ if ((m_keyboard_mask & 0x40)!=0) { key &= ioport("LINE6")->read(); }
+ if ((m_keyboard_mask & 0x80)!=0) { key &= ioport("LINE7")->read(); }
+ return key & m_key_mask;
+}
+
+READ8_MEMBER(mikro80_state::mikro80_8255_portc_r)
+{
+ return ioport("LINE8")->read();
+}
+
+WRITE8_MEMBER(mikro80_state::mikro80_8255_porta_w)
+{
+ m_keyboard_mask = data ^ 0xff;
+}
+
+WRITE8_MEMBER(mikro80_state::mikro80_8255_portc_w)
+{
+}
+
+I8255_INTERFACE( mikro80_ppi8255_interface )
+{
+ DEVCB_NULL,
+ DEVCB_DRIVER_MEMBER(mikro80_state, mikro80_8255_porta_w),
+ DEVCB_DRIVER_MEMBER(mikro80_state, mikro80_8255_portb_r),
+ DEVCB_NULL,
+ DEVCB_DRIVER_MEMBER(mikro80_state, mikro80_8255_portc_r),
+ DEVCB_NULL,
+};
+
+
+static TIMER_CALLBACK( mikro80_reset )
+{
+ mikro80_state *state = machine.driver_data<mikro80_state>();
+ state->membank("bank1")->set_entry(0);
+}
+
+MACHINE_RESET( mikro80 )
+{
+ mikro80_state *state = machine.driver_data<mikro80_state>();
+ machine.scheduler().timer_set(attotime::from_usec(10), FUNC(mikro80_reset));
+ state->membank("bank1")->set_entry(1);
+ state->m_keyboard_mask = 0;
+}
+
+
+READ8_MEMBER(mikro80_state::mikro80_keyboard_r)
+{
+ i8255_device *ppi = machine().device<i8255_device>("ppi8255");
+ return ppi->read(space, offset^0x03);
+}
+
+WRITE8_MEMBER(mikro80_state::mikro80_keyboard_w)
+{
+ i8255_device *ppi = machine().device<i8255_device>("ppi8255");
+ ppi->write(space, offset^0x03, data);
+}
+
+
+WRITE8_MEMBER(mikro80_state::mikro80_tape_w)
+{
+ machine().device<cassette_image_device>(CASSETTE_TAG)->output(data & 0x01 ? 1 : -1);
+}
+
+
+READ8_MEMBER(mikro80_state::mikro80_tape_r)
+{
+ double level = machine().device<cassette_image_device>(CASSETTE_TAG)->input();
+ if (level < 0) {
+ return 0x00;
+ }
+ return 0xff;
+}
diff --git a/src/mess/machine/mm58274c.c b/src/mess/machine/mm58274c.c
new file mode 100644
index 00000000000..aa12c95fdbf
--- /dev/null
+++ b/src/mess/machine/mm58274c.c
@@ -0,0 +1,542 @@
+/***************************************************************************
+
+ mm58274c.c
+
+ mm58274c emulation
+
+ Reference:
+ * National Semiconductor MM58274C Microprocessor Compatible Real Time Clock
+ <http://www.national.com/ds/MM/MM58274C.pdf>
+
+ 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 "mm58274c.h"
+
+typedef struct _mm58274c_t mm58274c_t;
+
+struct _mm58274c_t
+{
+ const mm58274c_interface *intf;
+
+ int status; /* status register (*read* from address 0 = control register) */
+ int control; /* control register (*write* to address 0) */
+
+ int clk_set; /* clock setting register */
+ int int_ctl; /* interrupt control register */
+
+
+ int wday; /* day of the week (1-7 (1=day1 as set in init)) */
+ int years1; /* years (BCD: 0-99) */
+ int years2;
+ int months1; /* months (BCD: 1-12) */
+ int months2;
+ int days1; /* days (BCD: 1-31) */
+ int days2;
+ int hours1; /* hours (BCD : 0-23) */
+ int hours2;
+ int minutes1; /* minutes (BCD : 0-59) */
+ int minutes2;
+ int seconds1; /* seconds (BCD : 0-59) */
+ int seconds2;
+ int tenths; /* tenths of second (BCD : 0-9) */
+
+ emu_timer *increment_rtc;
+ emu_timer *interrupt_timer;
+};
+
+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 */
+};
+
+
+INLINE mm58274c_t *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == MM58274C);
+
+ return (mm58274c_t *)downcast<legacy_device_base *>(device)->token();
+}
+
+static attotime 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");
+ }
+};
+
+READ8_DEVICE_HANDLER( mm58274c_r )
+{
+ mm58274c_t *mm58274c = get_safe_token(device);
+ int reply;
+
+ offset &= 0xf;
+
+ switch (offset)
+ {
+ case 0x0: /* Control Register */
+ reply = mm58274c->status;
+ mm58274c->status = 0;
+ break;
+
+ case 0x1: /* Tenths of Seconds */
+ reply = mm58274c->tenths;
+ break;
+
+ case 0x2: /* Units Seconds */
+ reply = mm58274c->seconds2;
+ break;
+
+ case 0x3: /* Tens Seconds */
+ reply = mm58274c->seconds1;
+ break;
+
+ case 0x04: /* Units Minutes */
+ reply = mm58274c->minutes2;
+ break;
+
+ case 0x5: /* Tens Minutes */
+ reply = mm58274c->minutes1;
+ break;
+
+ case 0x6: /* Units Hours */
+ reply = mm58274c->hours2;
+ break;
+
+ case 0x7: /* Tens Hours */
+ reply = mm58274c->hours1;
+ break;
+
+ case 0x8: /* Units Days */
+ reply = mm58274c->days2;
+ break;
+
+ case 0x9: /* Tens Days */
+ reply = mm58274c->days1;
+ break;
+
+ case 0xA: /* Units Months */
+ reply = mm58274c->months2;
+ break;
+
+ case 0xB: /* Tens Months */
+ reply = mm58274c->months1;
+ break;
+
+ case 0xC: /* Units Years */
+ reply = mm58274c->years2;
+ break;
+
+ case 0xD: /* Tens Years */
+ reply = mm58274c->years1;
+ break;
+
+ case 0xE: /* Day of Week */
+ reply = mm58274c->wday;
+ break;
+
+ case 0xF: /* Clock Setting & Interrupt Registers */
+ if (mm58274c->control & ctl_intsel)
+ /* interrupt register */
+ reply = mm58274c->int_ctl;
+ else
+ { /* clock setting register */
+ if (mm58274c->clk_set & clk_set_24)
+ /* 24-hour mode */
+ reply = mm58274c->clk_set & ~clk_set_pm;
+ else
+ /* 12-hour mode */
+ reply = mm58274c->clk_set;
+ }
+ break;
+
+ default:
+ reply = 0;
+ break;
+ }
+
+ return reply;
+}
+
+
+WRITE8_DEVICE_HANDLER (mm58274c_w)
+{
+ mm58274c_t *mm58274c = get_safe_token(device);
+
+ offset &= 0xf;
+ data &= 0xf;
+
+ switch (offset)
+ {
+ case 0x0: /* Control Register (test mode and interrupt not emulated) */
+ if ((! (mm58274c->control & ctl_intstop)) && (data & ctl_intstop))
+ /* interrupt stop */
+ mm58274c->interrupt_timer->enable(0);
+ else if ((mm58274c->control & ctl_intstop) && (! (data & ctl_intstop)))
+ {
+ /* interrupt run */
+ attotime period = interrupt_period_table(mm58274c->int_ctl & int_ctl_dly);
+
+ mm58274c->interrupt_timer->adjust(period, 0, mm58274c->int_ctl & int_ctl_rpt ? period : attotime::zero);
+ }
+ if (data & ctl_clkstop)
+ /* stopping the clock clears the tenth counter */
+ mm58274c->tenths = 0;
+ mm58274c->control = data;
+ break;
+
+ case 0x1: /* Tenths of Seconds: cannot be written */
+ break;
+
+ case 0x2: /* Units Seconds */
+ mm58274c->seconds2 = data;
+ break;
+
+ case 0x3: /* Tens Seconds */
+ mm58274c->seconds1 = data;
+ break;
+
+ case 0x4: /* Units Minutes */
+ mm58274c->minutes2 = data;
+ break;
+
+ case 0x5: /* Tens Minutes */
+ mm58274c->minutes1 = data;
+ break;
+
+ case 0x6: /* Units Hours */
+ mm58274c->hours2 = data;
+ break;
+
+ case 0x7: /* Tens Hours */
+ mm58274c->hours1 = data;
+ break;
+
+ case 0x8: /* Units Days */
+ mm58274c->days2 = data;
+ break;
+
+ case 0x9: /* Tens Days */
+ mm58274c->days1 = data;
+ break;
+
+ case 0xA: /* Units Months */
+ mm58274c->months2 = data;
+ break;
+
+ case 0xB: /* Tens Months */
+ mm58274c->months1 = data;
+ break;
+
+ case 0xC: /* Units Years */
+ mm58274c->years2 = data;
+ break;
+
+ case 0xD: /* Tens Years */
+ mm58274c->years1 = data;
+ break;
+
+ case 0xE: /* Day of Week */
+ mm58274c->wday = data;
+ break;
+
+ case 0xF: /* Clock Setting & Interrupt Registers */
+ if (mm58274c->control & ctl_intsel)
+ {
+ /* interrupt register (not emulated) */
+ mm58274c->int_ctl = data;
+ if (! (mm58274c->control & ctl_intstop))
+ {
+ /* interrupt run */
+ attotime period = interrupt_period_table(mm58274c->int_ctl & int_ctl_dly);
+
+ mm58274c->interrupt_timer->adjust(period, 0, mm58274c->int_ctl & int_ctl_rpt ? period : attotime::zero);
+ }
+ }
+ else
+ {
+ /* clock setting register */
+ mm58274c->clk_set = data;
+ #if 0
+ if (mm58274c->clk_set & clk_set_24)
+ /* 24-hour mode */
+ mm58274c->clk_set &= ~clk_set_pm;
+ #endif
+ }
+ break;
+ }
+}
+
+
+/*
+ Set RTC interrupt flag
+*/
+static TIMER_CALLBACK(rtc_interrupt_callback)
+{
+ device_t *device = (device_t *)ptr;
+ mm58274c_t *mm58274c = get_safe_token(device);
+ mm58274c->status |= st_if;
+}
+
+
+/*
+ Increment RTC clock (timed interrupt every 1/10s)
+*/
+
+static TIMER_CALLBACK(increment_rtc)
+{
+ device_t *device = (device_t *)ptr;
+ mm58274c_t *mm58274c = get_safe_token(device);
+ if (! (mm58274c->control & ctl_clkstop))
+ {
+ mm58274c->status |= st_dcf;
+
+ if ((++mm58274c->tenths) == 10)
+ {
+ mm58274c->tenths = 0;
+
+ if ((++mm58274c->seconds2) == 10)
+ {
+ mm58274c->seconds2 = 0;
+
+ if ((++mm58274c->seconds1) == 6)
+ {
+ mm58274c->seconds1 = 0;
+
+ if ((++mm58274c->minutes2) == 10)
+ {
+ mm58274c->minutes2 = 0;
+
+ if ((++mm58274c->minutes1) == 6)
+ {
+ mm58274c->minutes1 = 0;
+
+ if ((++mm58274c->hours2) == 10)
+ {
+ mm58274c->hours2 = 0;
+
+ mm58274c->hours1++;
+ }
+
+ /* handle wrap-around */
+ if ((! (mm58274c->clk_set & clk_set_24))
+ && ((mm58274c->hours1*10 + mm58274c->hours2) == 12))
+ {
+ mm58274c->clk_set ^= clk_set_pm;
+ }
+ if ((! (mm58274c->clk_set & clk_set_24))
+ && ((mm58274c->hours1*10 + mm58274c->hours2) == 13))
+ {
+ mm58274c->hours1 = 0;
+ mm58274c->hours2 = 1;
+ }
+
+ if ((mm58274c->clk_set & clk_set_24)
+ && ((mm58274c->hours1*10 + mm58274c->hours2) == 24))
+ {
+ mm58274c->hours1 = mm58274c->hours2 = 0;
+ }
+
+ /* increment day if needed */
+ if ((mm58274c->clk_set & clk_set_24)
+ ? ((mm58274c->hours1*10 + mm58274c->hours2) == 0)
+ : (((mm58274c->hours1*10 + mm58274c->hours2) == 12)
+ && (! (mm58274c->clk_set & clk_set_pm))))
+ {
+ int days_in_month;
+
+ if ((++mm58274c->days2) == 10)
+ {
+ mm58274c->days2 = 0;
+
+ mm58274c->days1++;
+ }
+
+ if ((++mm58274c->wday) == 8)
+ mm58274c->wday = 1;
+
+ {
+ static const int days_in_month_array[] =
+ {
+ 31,28,31, 30,31,30,
+ 31,31,30, 31,30,31
+ };
+
+ if (((mm58274c->months1*10 + mm58274c->months2) != 2) || (mm58274c->clk_set & clk_set_leap))
+ days_in_month = days_in_month_array[mm58274c->months1*10 + mm58274c->months2 - 1];
+ else
+ days_in_month = 29;
+ }
+
+
+ if ((mm58274c->days1*10 + mm58274c->days2) == days_in_month+1)
+ {
+ mm58274c->days1 = 0;
+ mm58274c->days2 = 1;
+
+ if ((++mm58274c->months2) == 10)
+ {
+ mm58274c->months2 = 0;
+
+ mm58274c->months1++;
+ }
+
+ if ((mm58274c->months1*10 + mm58274c->months2) == 13)
+ {
+ mm58274c->months1 = 0;
+ mm58274c->months2 = 1;
+
+ mm58274c->clk_set = (mm58274c->clk_set & ~clk_set_leap)
+ | ((mm58274c->clk_set + clk_set_leap_inc) & clk_set_leap);
+
+ if ((++mm58274c->years2) == 10)
+ {
+ mm58274c->years2 = 0;
+
+ if ((++mm58274c->years1) == 10)
+ mm58274c->years1 = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/* Device Interface */
+
+static DEVICE_START( mm58274c )
+{
+ mm58274c_t *mm58274c = get_safe_token(device);
+
+ // validate arguments
+ assert(device != NULL);
+ assert(device->tag() != NULL);
+ assert(device->static_config() != NULL);
+
+ mm58274c->intf = (const mm58274c_interface*)device->static_config();
+ // register for state saving
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->status);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->control);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->clk_set);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->int_ctl);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->wday);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->years1);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->years2);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->months1);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->months2);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->days1);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->days2);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->hours1);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->hours2);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->minutes1);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->minutes2);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->seconds1);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->seconds2);
+ state_save_register_item(device->machine(), "mm58274c", device->tag(), 0, mm58274c->tenths);
+
+ mm58274c->increment_rtc = device->machine().scheduler().timer_alloc(FUNC(increment_rtc), ((void*)device));
+ mm58274c->increment_rtc->adjust(attotime::zero, 0, attotime::from_msec(100));
+ mm58274c->interrupt_timer = device->machine().scheduler().timer_alloc(FUNC(rtc_interrupt_callback), ((void*)device));
+}
+
+
+static DEVICE_RESET( mm58274c )
+{
+ mm58274c_t *mm58274c = get_safe_token(device);
+ system_time systime;
+
+ /* get the current date/time from the core */
+ device->machine().current_datetime(systime);
+
+ mm58274c->clk_set = systime.local_time.year & 3 << 2;
+ if (mm58274c->intf->mode24)
+ mm58274c->clk_set |= clk_set_24;
+
+ /* The clock count starts on 1st January 1900 */
+ mm58274c->wday = 1 + ((systime.local_time.weekday - mm58274c->intf->day1)%7);
+ mm58274c->years1 = (systime.local_time.year / 10) % 10;
+ mm58274c->years2 = systime.local_time.year % 10;
+ mm58274c->months1 = (systime.local_time.month + 1) / 10;
+ mm58274c->months2 = (systime.local_time.month + 1) % 10;
+ mm58274c->days1 = systime.local_time.mday / 10;
+ mm58274c->days2 = systime.local_time.mday % 10;
+ if (!mm58274c->intf->mode24)
+ {
+ /* 12-hour mode */
+ if (systime.local_time.hour > 12)
+ {
+ systime.local_time.hour -= 12;
+ mm58274c->clk_set |= clk_set_pm;
+ }
+ if (systime.local_time.hour == 0)
+ systime.local_time.hour = 12;
+ }
+ mm58274c->hours1 = systime.local_time.hour / 10;
+ mm58274c->hours2 = systime.local_time.hour % 10;
+ mm58274c->minutes1 = systime.local_time.minute / 10;
+ mm58274c->minutes2 = systime.local_time.minute % 10;
+ mm58274c->seconds1 = systime.local_time.second / 10;
+ mm58274c->seconds2 = systime.local_time.second % 10;
+ mm58274c->tenths = 0;
+}
+
+DEVICE_GET_INFO( mm58274c )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(mm58274c_t); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(mm58274c); break;
+ case DEVINFO_FCT_STOP: /* Nothing */ break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(mm58274c); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "National Semiconductor MM58274C");break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "National Semiconductor MM58274C");break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright MESS Team"); break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(MM58274C, mm58274c);
diff --git a/src/mess/machine/mm58274c.h b/src/mess/machine/mm58274c.h
new file mode 100644
index 00000000000..c17e1eb1332
--- /dev/null
+++ b/src/mess/machine/mm58274c.h
@@ -0,0 +1,38 @@
+#ifndef MM58274C_H
+#define MM58274C_H
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+DECLARE_LEGACY_DEVICE(MM58274C, mm58274c);
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+/* interface */
+/*
+ Initializes the clock chip.
+ 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.
+*/
+typedef struct _mm58274c_interface mm58274c_interface;
+struct _mm58274c_interface
+{
+ int mode24; /* 24/12 mode */
+ int day1; /* first day of week */
+};
+
+READ8_DEVICE_HANDLER ( mm58274c_r );
+WRITE8_DEVICE_HANDLER( mm58274c_w );
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+#define MCFG_MM58274C_ADD(_tag, _intrf) \
+ MCFG_DEVICE_ADD(_tag, MM58274C, 0) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#endif /* MM58274C_H */
diff --git a/src/mess/machine/mos6530.c b/src/mess/machine/mos6530.c
new file mode 100644
index 00000000000..e8554a1d339
--- /dev/null
+++ b/src/mess/machine/mos6530.c
@@ -0,0 +1,459 @@
+/***************************************************************************
+
+ 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
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _mos6530_port mos6530_port;
+struct _mos6530_port
+{
+ devcb_resolved_read8 in_port_func;
+ devcb_resolved_write8 out_port_func;
+
+ UINT8 in;
+ UINT8 out;
+ UINT8 ddr;
+};
+
+
+typedef struct _mos6530_state mos6530_state;
+struct _mos6530_state
+{
+ devcb_resolved_write_line out_irq_func;
+
+ mos6530_port port[2];
+
+ UINT8 irqstate;
+ UINT8 irqenable;
+
+ UINT8 timershift;
+ UINT8 timerstate;
+ emu_timer * timer;
+
+ UINT32 clock;
+};
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ get_safe_token - convert a device's token
+ into a mos6530_state
+-------------------------------------------------*/
+
+INLINE mos6530_state *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == MOS6530);
+ return (mos6530_state *)downcast<legacy_device_base *>(device)->token();
+}
+
+
+/*-------------------------------------------------
+ update_irqstate - update the IRQ state
+ based on interrupt enables
+-------------------------------------------------*/
+
+INLINE void update_irqstate(device_t *device)
+{
+ mos6530_state *miot = get_safe_token(device);
+ UINT8 out = miot->port[1].out;
+
+ if ( miot->irqenable )
+ out = ( ( miot->irqstate & TIMER_FLAG ) ? 0x00 : 0x80 ) | ( out & 0x7F );
+
+ if (!miot->port[1].out_port_func.isnull())
+ miot->port[1].out_port_func(0, out);
+ else
+ logerror("6530MIOT chip %s: Port B is being written to but has no handler.\n", device->tag());
+}
+
+
+/*-------------------------------------------------
+ get_timer - return the current timer value
+-------------------------------------------------*/
+
+INLINE UINT8 get_timer(mos6530_state *miot)
+{
+ /* if idle, return 0 */
+ if (miot->timerstate == TIMER_IDLE)
+ return 0;
+
+ /* if counting, return the number of ticks remaining */
+ else if (miot->timerstate == TIMER_COUNTING)
+ return miot->timer->remaining().as_ticks(miot->clock) >> miot->timershift;
+
+ /* if finishing, return the number of ticks without the shift */
+ else
+ return miot->timer->remaining().as_ticks(miot->clock);
+}
+
+
+/***************************************************************************
+ INTERNAL FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ timer_end_callback - callback to process the
+ timer
+-------------------------------------------------*/
+
+static TIMER_CALLBACK( timer_end_callback )
+{
+ device_t *device = (device_t *)ptr;
+ mos6530_state *miot = get_safe_token(device);
+
+ assert(miot->timerstate != TIMER_IDLE);
+
+ /* if we finished counting, switch to the finishing state */
+ if (miot->timerstate == TIMER_COUNTING)
+ {
+ miot->timerstate = TIMER_FINISHING;
+ miot->timer->adjust(attotime::from_ticks(256, miot->clock));
+
+ /* signal timer IRQ as well */
+ miot->irqstate |= TIMER_FLAG;
+ update_irqstate(device);
+ }
+
+ /* if we finished finishing, switch to the idle state */
+ else if (miot->timerstate == TIMER_FINISHING)
+ {
+ miot->timerstate = TIMER_IDLE;
+ miot->timer->adjust(attotime::never);
+ }
+}
+
+
+
+/***************************************************************************
+ I/O ACCESS
+***************************************************************************/
+
+/*-------------------------------------------------
+ mos6530_w - master I/O write access
+-------------------------------------------------*/
+
+WRITE8_DEVICE_HANDLER( mos6530_w )
+{
+ mos6530_state *miot = get_safe_token(device);
+
+ /* if A2 == 1, we are writing to the timer */
+ if (offset & 0x04)
+ {
+ static const UINT8 timershift[4] = { 0, 3, 6, 10 };
+ attotime curtime = device->machine().time();
+ INT64 target;
+
+ /* A0-A1 contain the timer divisor */
+ miot->timershift = timershift[offset & 3];
+
+ /* A3 contains the timer IRQ enable */
+ if (offset & 8)
+ miot->irqenable |= TIMER_FLAG;
+ else
+ miot->irqenable &= ~TIMER_FLAG;
+
+ /* writes here clear the timer flag */
+ if (miot->timerstate != TIMER_FINISHING || get_timer(miot) != 0xff)
+ miot->irqstate &= ~TIMER_FLAG;
+ update_irqstate(device);
+
+ /* update the timer */
+ miot->timerstate = TIMER_COUNTING;
+ target = curtime.as_ticks(miot->clock) + 1 + (data << miot->timershift);
+ miot->timer->adjust(attotime::from_ticks(target, miot->clock) - curtime);
+ }
+
+ /* if A2 == 0, we are writing to the I/O section */
+ else
+ {
+ /* A1 selects the port */
+ mos6530_port *port = &miot->port[(offset >> 1) & 1];
+
+ /* if A0 == 1, we are writing to the port's DDR */
+ if (offset & 1)
+ port->ddr = data;
+
+ /* if A0 == 0, we are writing to the port's output */
+ else
+ {
+ UINT8 olddata = port->out;
+ port->out = data;
+
+ if ( ( offset & 2 ) && miot->irqenable )
+ {
+ olddata = ( ( miot->irqstate & TIMER_FLAG ) ? 0x00 : 0x80 ) | ( olddata & 0x7F );
+ data = ( ( miot->irqstate & TIMER_FLAG ) ? 0x00 : 0x80 ) | ( data & 0x7F );
+ }
+
+ if (!port->out_port_func.isnull())
+ port->out_port_func(0, data);
+ else
+ logerror("6530MIOT chip %s: Port %c is being written to but has no handler. PC: %08X - %02X\n", device->tag(), 'A' + (offset & 1), cpu_get_pc(device->machine().firstcpu), data);
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ mos6530_r - master I/O read access
+-------------------------------------------------*/
+
+READ8_DEVICE_HANDLER( mos6530_r )
+{
+ mos6530_state *miot = get_safe_token(device);
+ UINT8 val = 0;
+
+ /* if A2 == 1 and A0 == 1, we are reading interrupt flags */
+ if ((offset & 0x05) == 0x05)
+ {
+ val = miot->irqstate;
+ }
+
+ /* if A2 == 1 and A0 == 0, we are reading the timer */
+ else if ((offset & 0x05) == 0x04)
+ {
+ val = get_timer(miot);
+
+ /* A3 contains the timer IRQ enable */
+ if (offset & 8)
+ miot->irqenable |= TIMER_FLAG;
+ else
+ miot->irqenable &= ~TIMER_FLAG;
+
+ /* implicitly clears the timer flag */
+ if (miot->timerstate != TIMER_FINISHING || val != 0xff)
+ miot->irqstate &= ~TIMER_FLAG;
+ update_irqstate(device);
+ }
+
+ /* if A2 == 0 and A0 == anything, we are reading from ports */
+ else
+ {
+ /* A1 selects the port */
+ mos6530_port *port = &miot->port[(offset >> 1) & 1];
+
+ /* if A0 == 1, we are reading the port's DDR */
+ if (offset & 1)
+ val = port->ddr;
+
+ /* if A0 == 0, we are reading the port as an input */
+ else
+ {
+ UINT8 out = port->out;
+
+ if ( ( offset & 2 ) && miot->irqenable )
+ out = ( ( miot->irqstate & TIMER_FLAG ) ? 0x00 : 0x80 ) | ( out & 0x7F );
+
+ /* call the input callback if it exists */
+ if (!port->in_port_func.isnull())
+ {
+ port->in = port->in_port_func(0);
+ }
+ else
+ logerror("6530MIOT chip %s: Port %c is being read but has no handler. PC: %08X\n", device->tag(), 'A' + (offset & 1), cpu_get_pc(device->machine().firstcpu));
+
+ /* apply the DDR to the result */
+ val = (out & port->ddr) | (port->in & ~port->ddr);
+ }
+ }
+ return val;
+}
+
+
+/*-------------------------------------------------
+ mos6530_porta_in_set - set port A input
+ value
+-------------------------------------------------*/
+
+void mos6530_porta_in_set(device_t *device, UINT8 data, UINT8 mask)
+{
+ mos6530_state *miot = get_safe_token(device);
+ miot->port[0].in = (miot->port[0].in & ~mask) | (data & mask);
+}
+
+
+/*-------------------------------------------------
+ mos6530_portb_in_set - set port B input
+ value
+-------------------------------------------------*/
+
+void mos6530_portb_in_set(device_t *device, UINT8 data, UINT8 mask)
+{
+ mos6530_state *miot = get_safe_token(device);
+ miot->port[1].in = (miot->port[1].in & ~mask) | (data & mask);
+}
+
+
+/*-------------------------------------------------
+ mos6530_porta_in_get - return port A input
+ value
+-------------------------------------------------*/
+
+UINT8 mos6530_porta_in_get(device_t *device)
+{
+ mos6530_state *miot = get_safe_token(device);
+ return miot->port[0].in;
+}
+
+
+/*-------------------------------------------------
+ mos6530_portb_in_get - return port B input
+ value
+-------------------------------------------------*/
+
+UINT8 mos6530_portb_in_get(device_t *device)
+{
+ mos6530_state *miot = get_safe_token(device);
+ return miot->port[1].in;
+}
+
+
+/*-------------------------------------------------
+ mos6530_porta_in_get - return port A output
+ value
+-------------------------------------------------*/
+
+UINT8 mos6530_porta_out_get(device_t *device)
+{
+ mos6530_state *miot = get_safe_token(device);
+ return miot->port[0].out;
+}
+
+
+/*-------------------------------------------------
+ mos6530_portb_in_get - return port B output
+ value
+-------------------------------------------------*/
+
+UINT8 mos6530_portb_out_get(device_t *device)
+{
+ mos6530_state *miot = get_safe_token(device);
+ return miot->port[1].out;
+}
+
+
+/***************************************************************************
+ DEVICE INTERFACE
+***************************************************************************/
+
+static DEVICE_START( mos6530 )
+{
+ mos6530_state *miot = get_safe_token(device);
+ const mos6530_interface *intf = (const mos6530_interface*)device->static_config();
+
+ /* validate arguments */
+ assert(device != NULL);
+ assert(device->tag() != NULL);
+
+ /* set static values */
+ miot->clock = device->clock();
+
+ /* resolve callbacks */
+ miot->port[0].in_port_func.resolve(intf->in_pa_func, *device);
+ miot->port[1].in_port_func.resolve(intf->in_pb_func, *device);
+ miot->port[0].out_port_func.resolve(intf->out_pa_func, *device);
+ miot->port[1].out_port_func.resolve(intf->out_pb_func, *device);
+
+ /* allocate timers */
+ miot->timer = device->machine().scheduler().timer_alloc(FUNC(timer_end_callback), (void *)device);
+
+ /* register for save states */
+ device->save_item(NAME(miot->port[0].in));
+ device->save_item(NAME(miot->port[0].out));
+ device->save_item(NAME(miot->port[0].ddr));
+ device->save_item(NAME(miot->port[1].in));
+ device->save_item(NAME(miot->port[1].out));
+ device->save_item(NAME(miot->port[1].ddr));
+
+ device->save_item(NAME(miot->irqstate));
+ device->save_item(NAME(miot->irqenable));
+
+ device->save_item(NAME(miot->timershift));
+ device->save_item(NAME(miot->timerstate));
+}
+
+
+static DEVICE_RESET( mos6530 )
+{
+ mos6530_state *miot = get_safe_token(device);
+
+ /* reset I/O states */
+ miot->port[0].out = 0;
+ miot->port[0].ddr = 0;
+ miot->port[1].out = 0;
+ miot->port[1].ddr = 0;
+
+ /* reset IRQ states */
+ miot->irqenable = 0;
+ miot->irqstate = TIMER_FLAG;
+ update_irqstate(device);
+
+ /* reset timer states */
+ miot->timershift = 0;
+ miot->timerstate = TIMER_IDLE;
+ miot->timer->adjust(attotime::never);
+}
+
+
+DEVICE_GET_INFO( mos6530 )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(mos6530_state); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(mos6530); break;
+ case DEVINFO_FCT_STOP: /* Nothing */ break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(mos6530); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "MOS6530"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "MOS6500"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright MESS Team"); break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(MOS6530, mos6530);
diff --git a/src/mess/machine/mos6530.h b/src/mess/machine/mos6530.h
new file mode 100644
index 00000000000..3c34917d950
--- /dev/null
+++ b/src/mess/machine/mos6530.h
@@ -0,0 +1,79 @@
+/**********************************************************************
+
+ MOS Technology 6530 Memory, I/O, Timer Array emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+ _____ _____
+ 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__
+
+/***************************************************************************
+ MACROS / CONSTANTS
+***************************************************************************/
+
+DECLARE_LEGACY_DEVICE(MOS6530, mos6530);
+
+#define MCFG_MOS6530_ADD(_tag, _clock, _config) \
+ MCFG_DEVICE_ADD((_tag), MOS6530, _clock) \
+ MCFG_DEVICE_CONFIG(_config)
+
+#define MOS6530_INTERFACE(name) \
+ const mos6530_interface (name) =
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _mos6530_interface mos6530_interface;
+struct _mos6530_interface
+{
+ devcb_read8 in_pa_func;
+ devcb_write8 out_pa_func;
+
+ devcb_read8 in_pb_func;
+ devcb_write8 out_pb_func;
+};
+
+/***************************************************************************
+ PROTOTYPES
+***************************************************************************/
+
+READ8_DEVICE_HANDLER( mos6530_r );
+WRITE8_DEVICE_HANDLER( mos6530_w );
+
+void mos6530_porta_in_set(device_t *device, UINT8 data, UINT8 mask);
+void mos6530_portb_in_set(device_t *device, UINT8 data, UINT8 mask);
+
+UINT8 mos6530_porta_in_get(device_t *device);
+UINT8 mos6530_portb_in_get(device_t *device);
+
+UINT8 mos6530_porta_out_get(device_t *device);
+UINT8 mos6530_portb_out_get(device_t *device);
+
+#endif
diff --git a/src/mess/machine/mpc105.c b/src/mess/machine/mpc105.c
new file mode 100644
index 00000000000..4a7dcfeb5cd
--- /dev/null
+++ b/src/mess/machine/mpc105.c
@@ -0,0 +1,256 @@
+/***************************************************************************
+
+ machine/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<mpc105_device>;
+
+
+//**************************************************************************
+// 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),
+ pci_device_interface( mconfig, *this ),
+ m_maincpu(NULL)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void mpc105_device::device_start()
+{
+ m_maincpu = machine().device(m_cputag);
+}
+
+//-------------------------------------------------
+// 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));
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void mpc105_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const mpc105_interface *intf = reinterpret_cast<const mpc105_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<mpc105_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_cputag, 0, sizeof(m_cputag));
+ m_bank_base_default = 0;
+
+ }
+ m_shortname = "mpc105";
+}
+
+//-------------------------------------------------
+// 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->memory().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_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_device>(RAM_TAG)->pointer(), machine().device<ram_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_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");
+ break;
+ }
+ 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", offset, data);
+ break;
+ }
+}
diff --git a/src/mess/machine/mpc105.h b/src/mess/machine/mpc105.h
new file mode 100644
index 00000000000..5a1370ba1f2
--- /dev/null
+++ b/src/mess/machine/mpc105.h
@@ -0,0 +1,57 @@
+/***************************************************************************
+
+ machine/mpc105.h
+
+ Motorola MPC105 PCI bridge
+
+***************************************************************************/
+
+#ifndef MPC105_H
+#define MPC105_H
+
+#include "machine/pci.h"
+
+#define MPC105_MEMORYBANK_COUNT 8
+
+// ======================> mpc105_interface
+
+struct mpc105_interface
+{
+ const char *m_cputag;
+ int m_bank_base_default;
+};
+
+// ======================> mpc105_device
+
+class mpc105_device : public device_t,
+ public pci_device_interface,
+ public mpc105_interface
+{
+public:
+ // construction/destruction
+ mpc105_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();
+ virtual void device_config_complete();
+
+ void update_memory();
+
+private:
+ int m_bank_base;
+ UINT8 m_bank_enable;
+ UINT32 m_bank_registers[8];
+
+ device_t* m_maincpu;
+};
+
+
+// device type definition
+extern const device_type MPC105;
+
+#endif /* MPC105_H */
diff --git a/src/mess/machine/msx.c b/src/mess/machine/msx.c
new file mode 100644
index 00000000000..3b9a0ed6eea
--- /dev/null
+++ b/src/mess/machine/msx.c
@@ -0,0 +1,1184 @@
+/*
+ * msx.c: MSX emulation
+ *
+ * Copyright (C) 2004 Sean Young
+ *
+ * Todo:
+ *
+ * - fix mouse support
+ * - cassette support doesn't work
+ * - Ensure changing cartridge after boot works
+ * - wd2793, nms8255
+ */
+
+#include "includes/msx.h"
+
+#define VERBOSE 0
+
+static void msx_memory_init (running_machine &machine);
+static void msx_memory_set_carts (running_machine &machine);
+
+
+static int msx_probe_type (UINT8* pmem, int size)
+{
+ int kon4, kon5, asc8, asc16, i;
+
+ if (size <= 0x10000) return 0;
+
+ if ( (pmem[0x10] == 'Y') && (pmem[0x11] == 'Z') && (size > 0x18000) )
+ return 6;
+
+ kon4 = kon5 = asc8 = asc16 = 0;
+
+ for (i=0;i<size-3;i++)
+ {
+ if (pmem[i] == 0x32 && pmem[i+1] == 0)
+ {
+ switch (pmem[i+2])
+ {
+ case 0x60:
+ case 0x70:
+ asc16++;
+ asc8++;
+ break;
+ case 0x68:
+ case 0x78:
+ asc8++;
+ asc16--;
+ }
+
+ switch (pmem[i+2])
+ {
+ case 0x60:
+ case 0x80:
+ case 0xa0:
+ kon4++;
+ break;
+ case 0x50:
+ case 0x70:
+ case 0x90:
+ case 0xb0:
+ kon5++;
+ }
+ }
+ }
+
+ if (MAX (kon4, kon5) > MAX (asc8, asc16) )
+ return (kon5 > kon4) ? 2 : 3;
+ else
+ return (asc8 > asc16) ? 4 : 5;
+}
+
+DEVICE_IMAGE_LOAD (msx_cart)
+{
+ msx_state *state = image.device().machine().driver_data<msx_state>();
+ int size;
+ int size_aligned;
+ UINT8 *mem;
+ int type = -1;
+ const char *extra = NULL;
+ char *sramfile;
+ slot_state *st;
+ int id = -1;
+
+ if (strcmp(image.device().tag(),":cart1")==0)
+ id = 0;
+
+ if (strcmp(image.device().tag(),":cart2")==0)
+ id = 1;
+
+ if( id == -1 )
+ {
+ //logerror ("error: invalid cart tag '%s'\n", image->tag);
+ return IMAGE_INIT_FAIL;
+ }
+
+ if ( image.software_entry() != NULL )
+ {
+ /* Load software from software list */
+ /* TODO: Add proper SRAM (size) handling */
+
+ const char *mapper = software_part_get_feature( (software_part*)image.part_entry(), "mapper" );
+ const char *sram = software_part_get_feature( (software_part*)image.part_entry(), "sram" );
+
+ if ( mapper != NULL )
+ {
+ /* TODO: Split out the SRAM recognition code and 8KB/16KB bank configuration */
+ static const struct { const char *mapper_name; bool sram_present; int mapper_type; } mapper_types[] =
+ {
+ { "M60002-0125SP", false, SLOT_ASCII8 },
+ { "M60002-0125SP", true, SLOT_ASCII8_SRAM },
+ { "LZ93A13", false, SLOT_ASCII8 },
+ { "LZ93A13", true, SLOT_ASCII8_SRAM },
+ { "LZ93A13-16", false, SLOT_ASCII16 },
+ { "LZ93A13-16", true, SLOT_ASCII16_SRAM },
+ { "M60002-0125SP-16", false, SLOT_ASCII16 },
+ { "M60002-0125SP-16", true, SLOT_ASCII16_SRAM },
+ { "IREM TAM-S1", false, SLOT_RTYPE },
+ { "MR6401", false, SLOT_ASCII16 },
+ { "NEOS MR6401", false, SLOT_ASCII8 },
+ { "BS6202", false, SLOT_ASCII8 },
+ { "BS6101", false, SLOT_ASCII8 },
+ { "BS6101-16", false, SLOT_ASCII16 },
+ };
+
+ for ( int i = 0; i < ARRAY_LENGTH(mapper_types) && type < 0; i++ )
+ {
+ if ( !mame_stricmp( mapper, mapper_types[i].mapper_name ) )
+ {
+ if ( sram == NULL && ! mapper_types[i].sram_present )
+ type = mapper_types[i].mapper_type;
+
+
+ if ( sram != NULL && mapper_types[i].sram_present )
+ type = mapper_types[i].mapper_type;
+ }
+ }
+
+ if ( -1 == type )
+ logerror( "Mapper '%s' not recognized!\n", mapper );
+ }
+
+ UINT8 *rom_region = image.get_software_region( "rom" );
+ size = size_aligned = image.get_software_region_length( "rom" );
+
+ mem = auto_alloc_array( image.device().machine(), UINT8, size_aligned );
+ memcpy( mem, rom_region, size_aligned );
+ }
+ else
+ {
+ /* Old style image loading */
+
+ size = image.length ();
+ if (size < 0x2000)
+ {
+ logerror ("cart #%d: error: file is smaller than 2kb, too small to be true!\n", id);
+ return IMAGE_INIT_FAIL;
+ }
+
+ /* allocate memory and load */
+ size_aligned = 0x2000;
+ while (size_aligned < size)
+ size_aligned *= 2;
+
+ mem = auto_alloc_array(image.device().machine(),UINT8,size_aligned);
+ if (!mem)
+ {
+ logerror ("cart #%d: error: failed to allocate memory for cartridge\n", id);
+ return IMAGE_INIT_FAIL;
+ }
+
+ if (size < size_aligned)
+ memset (mem, 0xff, size_aligned);
+
+ if (image.fread(mem, size) != size)
+ {
+ logerror ("cart #%d: %s: can't read full %d bytes\n", id, image.filename (), size);
+ return IMAGE_INIT_FAIL;
+ }
+
+ /* see if msx.crc will tell us more */
+ extra = hashfile_extrainfo(image);
+
+ if (!extra)
+ {
+ logerror("cart #%d: warning: no information in crc file\n", id);
+ type = -1;
+ }
+ else
+ if ((1 != sscanf(extra, "%d", &type) ) || type < 0 || type > SLOT_LAST_CARTRIDGE_TYPE)
+ {
+ logerror("cart #%d: warning: information in crc file not valid\n", id);
+ type = -1;
+ }
+ else
+ logerror ("cart #%d: info: cart extra info: '%s' = %s\n", id, extra, msx_slot_list[type].name);
+
+ /* if not, attempt autodetection */
+ if (type < 0)
+ {
+ type = msx_probe_type (mem, size);
+
+ if (mem[0] != 'A' || mem[1] != 'B')
+ logerror("cart #%d: %s: May not be a valid ROM file\n", id, image.filename ());
+
+ logerror("cart #%d: Probed cartridge mapper %d/%s\n", id, type, msx_slot_list[type].name);
+ }
+ }
+
+ /* mapper type 0 always needs 64kB */
+ if (!type && size_aligned != 0x10000)
+ {
+ UINT8 *old_mem = mem;
+ int old_size_aligned = size_aligned;
+
+ size_aligned = 0x10000;
+ mem = auto_alloc_array(image.device().machine(),UINT8, 0x10000);
+ if (!mem)
+ {
+ auto_free(image.device().machine(),old_mem);
+ logerror ("cart #%d: error: cannot allocate memory\n", id);
+ return IMAGE_INIT_FAIL;
+ }
+
+ if (size < 0x10000)
+ memset (mem + size, 0xff, 0x10000 - size);
+
+ if (size > 0x10000)
+ {
+ logerror ("cart #%d: warning: rom truncated to 64kb due to mapperless type (possibly detected)\n", id);
+
+ size = 0x10000;
+ }
+
+ /* Copy old contents to newly claimed memory */
+ memcpy(mem,old_mem,old_size_aligned);
+ auto_free(image.device().machine(),old_mem);
+ }
+
+ /* mapper type 0 (ROM) might need moving around a bit */
+ if (!type)
+ {
+ int i, page = 1;
+
+ /* find the correct page */
+ if (mem[0] == 'A' && mem[1] == 'B')
+ {
+ for (i=2; i<=8; i += 2)
+ {
+ if (mem[i] || mem[i+1])
+ {
+ page = mem[i+1] / 0x40;
+ break;
+ }
+ }
+ }
+
+ if (size <= 0x4000)
+ {
+ if (page == 1 || page == 2)
+ {
+ /* copy to the respective page */
+ memcpy (mem + (page * 0x4000), mem, 0x4000);
+ memset (mem, 0xff, 0x4000);
+ }
+ else
+ {
+ /* memory is repeated 4 times */
+ page = -1;
+ memcpy (mem + 0x4000, mem, 0x4000);
+ memcpy (mem + 0x8000, mem, 0x4000);
+ memcpy (mem + 0xc000, mem, 0x4000);
+ }
+ }
+ else /*if (size <= 0xc000) */
+ {
+ if (page)
+ {
+ /* shift up 16kB; custom memcpy so overlapping memory isn't corrupted. ROM starts in page 1 (0x4000) */
+ UINT8 *m;
+
+ page = 1;
+ i = 0xc000; m = mem + 0xffff;
+ while (i--)
+ {
+ *m = *(m - 0x4000);
+ m--;
+ }
+ memset (mem, 0xff, 0x4000);
+ }
+ }
+
+ if (page)
+ logerror ("cart #%d: info: rom in page %d\n", id, page);
+ else
+ logerror ("cart #%d: info: rom duplicted in all pages\n", id);
+ }
+
+ /* kludge */
+ if (type == 0)
+ type = SLOT_ROM;
+
+ /* allocate and set slot_state for this cartridge */
+ st = auto_alloc(image.device().machine(),slot_state);
+ if (!st)
+ {
+ logerror ("cart #%d: error: cannot allocate memory for cartridge state\n", id);
+ return IMAGE_INIT_FAIL;
+ }
+ memset (st, 0, sizeof (slot_state));
+
+ st->m_type = type;
+ sramfile = auto_alloc_array(image.device().machine(), char, strlen (image.filename () + 1));
+
+ if (sramfile)
+ {
+ char *ext;
+
+ strcpy (sramfile, image.basename ());
+ ext = strrchr (sramfile, '.');
+ if (ext)
+ *ext = 0;
+
+ st->m_sramfile = sramfile;
+ }
+
+ if (msx_slot_list[type].init (image.device().machine(), st, 0, mem, size_aligned))
+ return IMAGE_INIT_FAIL;
+
+ if (msx_slot_list[type].loadsram)
+ msx_slot_list[type].loadsram (image.device().machine(), st);
+
+ state->m_cart_state[id] = st;
+ msx_memory_set_carts (image.device().machine());
+
+ return IMAGE_INIT_PASS;
+}
+
+DEVICE_IMAGE_UNLOAD (msx_cart)
+{
+ msx_state *state = image.device().machine().driver_data<msx_state>();
+ int id = -1;
+
+ if (strcmp(image.device().tag(),":cart1")==0)
+ id = 0;
+
+ if (strcmp(image.device().tag(),":cart2")==0)
+ id = 1;
+
+ if( id == -1 )
+ {
+ //logerror ("error: invalid cart tag '%s'\n", image->tag);
+ return;
+ }
+
+ if (msx_slot_list[state->m_cart_state[id]->m_type].savesram)
+ msx_slot_list[state->m_cart_state[id]->m_type].savesram (image.device().machine(), state->m_cart_state[id]);
+}
+
+void msx_vdp_interrupt(device_t *, v99x8_device &device, int i)
+{
+ cputag_set_input_line (device.machine(), "maincpu", 0, (i ? HOLD_LINE : CLEAR_LINE));
+}
+
+void msx_state::msx_ch_reset_core ()
+{
+ msx_memory_reset ();
+ msx_memory_map_all ();
+}
+
+MACHINE_START( msx )
+{
+ MACHINE_START_CALL( msx2 );
+}
+
+MACHINE_START( msx2 )
+{
+ msx_state *state = machine.driver_data<msx_state>();
+ state->m_port_c_old = 0xff;
+ state->m_dsk_stat = 0x7f;
+}
+
+MACHINE_RESET( msx )
+{
+ msx_state *state = machine.driver_data<msx_state>();
+ state->msx_ch_reset_core ();
+}
+
+MACHINE_RESET( msx2 )
+{
+ msx_state *state = machine.driver_data<msx_state>();
+ state->msx_ch_reset_core ();
+}
+
+I8255_INTERFACE( msx_ppi8255_interface )
+{
+ DEVCB_NULL,
+ DEVCB_DRIVER_MEMBER(msx_state, msx_ppi_port_a_w),
+ DEVCB_DRIVER_MEMBER(msx_state, msx_ppi_port_b_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DRIVER_MEMBER(msx_state, msx_ppi_port_c_w)
+};
+
+
+static const UINT8 cc_op[0x100] = {
+ 4+1,10+1, 7+1, 6+1, 4+1, 4+1, 7+1, 4+1, 4+1,11+1, 7+1, 6+1, 4+1, 4+1, 7+1, 4+1,
+ 8+1,10+1, 7+1, 6+1, 4+1, 4+1, 7+1, 4+1,12+1,11+1, 7+1, 6+1, 4+1, 4+1, 7+1, 4+1,
+ 7+1,10+1,16+1, 6+1, 4+1, 4+1, 7+1, 4+1, 7+1,11+1,16+1, 6+1, 4+1, 4+1, 7+1, 4+1,
+ 7+1,10+1,13+1, 6+1,11+1,11+1,10+1, 4+1, 7+1,11+1,13+1, 6+1, 4+1, 4+1, 7+1, 4+1,
+ 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1,
+ 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1,
+ 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1,
+ 7+1, 7+1, 7+1, 7+1, 7+1, 7+1, 4+1, 7+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1,
+ 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1,
+ 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1,
+ 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1,
+ 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1,
+ 5+1,10+1,10+1,10+1,10+1,11+1, 7+1,11+1, 5+1,10+1,10+1, 0+0,10+1,17+1, 7+1,11+1,
+ 5+1,10+1,10+1,11+1,10+1,11+1, 7+1,11+1, 5+1, 4+1,10+1,11+1,10+1, 0+0, 7+1,11+1,
+ 5+1,10+1,10+1,19+1,10+1,11+1, 7+1,11+1, 5+1, 4+1,10+1, 4+1,10+1, 0+0, 7+1,11+1,
+ 5+1,10+1,10+1, 4+1,10+1,11+1, 7+1,11+1, 5+1, 6+1,10+1, 4+1,10+1, 0+0, 7+1,11+1
+};
+
+static const UINT8 cc_cb[0x100] = {
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,12+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,12+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,12+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,12+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,12+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,12+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,12+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,12+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2
+};
+
+static const UINT8 cc_ed[0x100] = {
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
+12+2,12+2,15+2,20+2, 8+2,14+2, 8+2, 9+2,12+2,12+2,15+2,20+2, 8+2,14+2, 8+2, 9+2,
+12+2,12+2,15+2,20+2, 8+2,14+2, 8+2, 9+2,12+2,12+2,15+2,20+2, 8+2,14+2, 8+2, 9+2,
+12+2,12+2,15+2,20+2, 8+2,14+2, 8+2,18+2,12+2,12+2,15+2,20+2, 8+2,14+2, 8+2,18+2,
+12+2,12+2,15+2,20+2, 8+2,14+2, 8+2, 8+2,12+2,12+2,15+2,20+2, 8+2,14+2, 8+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
+16+2,16+2,16+2,16+2, 8+2, 8+2, 8+2, 8+2,16+2,16+2,16+2,16+2, 8+2, 8+2, 8+2, 8+2,
+16+2,16+2,16+2,16+2, 8+2, 8+2, 8+2, 8+2,16+2,16+2,16+2,16+2, 8+2, 8+2, 8+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2
+};
+
+static const UINT8 cc_xy[0x100] = {
+ 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2,15+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2,
+ 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2,15+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2,
+ 4+2,14+2,20+2,10+2, 9+2, 9+2,11+2, 4+2, 4+2,15+2,20+2,10+2, 9+2, 9+2,11+2, 4+2,
+ 4+2, 4+2, 4+2, 4+2,23+2,23+2,19+2, 4+2, 4+2,15+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2,
+ 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2, 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2,
+ 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2, 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2,
+ 9+2, 9+2, 9+2, 9+2, 9+2, 9+2,19+2, 9+2, 9+2, 9+2, 9+2, 9+2, 9+2, 9+2,19+2, 9+2,
+19+2,19+2,19+2,19+2,19+2,19+2, 4+2,19+2, 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2,
+ 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2, 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2,
+ 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2, 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2,
+ 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2, 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2,
+ 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2, 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2,
+ 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 0+0, 4+2, 4+2, 4+2, 4+2,
+ 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2,
+ 4+2,14+2, 4+2,23+2, 4+2,15+2, 4+2, 4+2, 4+2, 8+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2,
+ 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2,10+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2
+};
+
+static const UINT8 cc_xycb[0x100] = {
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
+20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,
+20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,
+20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,
+20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2
+};
+
+/* 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+1
+};
+
+
+DRIVER_INIT_MEMBER(msx_state,msx)
+{
+ device_set_input_line_vector (machine().device("maincpu"), 0, 0xff);
+
+ msx_memory_init (machine());
+
+ z80_set_cycle_tables( machine().device("maincpu"), cc_op, cc_cb, cc_ed, cc_xy, cc_xycb, cc_ex );
+}
+
+TIMER_DEVICE_CALLBACK( msx2_interrupt )
+{
+ msx_state *state = timer.machine().driver_data<msx_state>();
+ state->m_v9938->set_sprite_limit(timer.machine().root_device().ioport("DSW")->read() & 0x20);
+ state->m_v9938->set_resolution(timer.machine().root_device().ioport("DSW")->read() & 0x03);
+ state->m_v9938->interrupt();
+}
+
+INTERRUPT_GEN( msx_interrupt )
+{
+ msx_state *state = device->machine().driver_data<msx_state>();
+ int i;
+
+ for (i=0; i<2; i++)
+ {
+ state->m_mouse[i] = state->ioport(i ? "MOUSE1" : "MOUSE0")->read();
+ state->m_mouse_stat[i] = -1;
+ }
+}
+
+/*
+** The I/O functions
+*/
+
+
+READ8_MEMBER(msx_state::msx_psg_port_a_r)
+{
+ UINT8 data;
+
+ data = (m_cass->input() > 0.0038 ? 0x80 : 0);
+
+ if ( (m_psg_b ^ ioport("DSW")->read() ) & 0x40)
+ {
+ /* game port 2 */
+ UINT8 inp = ioport("JOY1")->read();
+ if ( !(inp & 0x80) )
+ {
+ /* joystick */
+ data |= ( inp & 0x7f );
+ }
+ else
+ {
+ /* mouse */
+ data |= ( inp & 0x70 );
+ if (m_mouse_stat[1] < 0)
+ data |= 0xf;
+ else
+ data |= ~(m_mouse[1] >> (4*m_mouse_stat[1]) ) & 15;
+ }
+ }
+ else
+ {
+ /* game port 1 */
+ UINT8 inp = ioport("JOY0")->read();
+ if ( !(inp & 0x80) )
+ {
+ /* joystick */
+ data |= ( inp & 0x7f );
+ }
+ else
+ {
+ /* mouse */
+ data |= ( inp & 0x70 );
+ if (m_mouse_stat[0] < 0)
+ data |= 0xf;
+ else
+ data |= ~(m_mouse[0] >> (4*m_mouse_stat[0]) ) & 15;
+ }
+ }
+
+ return data;
+}
+
+READ8_MEMBER(msx_state::msx_psg_port_b_r)
+{
+ return m_psg_b;
+}
+
+WRITE8_MEMBER(msx_state::msx_psg_port_a_w)
+{
+}
+
+WRITE8_MEMBER(msx_state::msx_psg_port_b_w)
+{
+ /* Arabic or kana mode led */
+ if ( (data ^ m_psg_b) & 0x80)
+ set_led_status (machine(), 2, !(data & 0x80) );
+
+ if ( (m_psg_b ^ data) & 0x10)
+ {
+ if (++m_mouse_stat[0] > 3) m_mouse_stat[0] = -1;
+ }
+ if ( (m_psg_b ^ data) & 0x20)
+ {
+ if (++m_mouse_stat[1] > 3) m_mouse_stat[1] = -1;
+ }
+
+ m_psg_b = data;
+}
+
+WRITE8_DEVICE_HANDLER( msx_printer_strobe_w )
+{
+ device->machine().device<centronics_device>("centronics")->strobe_w(BIT(data, 1));
+}
+
+WRITE8_DEVICE_HANDLER( msx_printer_data_w )
+{
+ if (device->machine().root_device().ioport("DSW")->read() & 0x80)
+ /* SIMPL emulation */
+ device->machine().device<dac_device>("dac")->write_signed8(data);
+ else
+ device->machine().device<centronics_device>("centronics")->write(*device->machine().memory().first_space(), 0, data);
+}
+
+READ8_DEVICE_HANDLER( msx_printer_status_r )
+{
+ UINT8 result = 0xfd;
+
+ if (device->machine().root_device().ioport("DSW")->read() & 0x80)
+ return 0xff;
+
+ result |= device->machine().device<centronics_device>("centronics")->busy_r() << 1;
+
+ return result;
+}
+
+WRITE8_MEMBER( msx_state::msx_fmpac_w )
+{
+ if (m_opll_active)
+ {
+ if (offset == 1)
+ ym2413_w (m_ym, 1, data);
+ else
+ ym2413_w (m_ym, 0, data);
+ }
+}
+
+/*
+** RTC functions
+*/
+
+WRITE8_MEMBER( msx_state::msx_rtc_latch_w )
+{
+ m_rtc_latch = data & 15;
+}
+
+WRITE8_MEMBER( msx_state::msx_rtc_reg_w )
+{
+ m_rtc->write(space, m_rtc_latch, data);
+}
+
+READ8_MEMBER( msx_state::msx_rtc_reg_r )
+{
+ return m_rtc->read(space, m_rtc_latch);
+}
+
+/*
+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)
+
+*/
+
+WRITE_LINE_MEMBER( msx_state::msx_wd179x_intrq_w )
+{
+ if (state)
+ m_dsk_stat &= ~0x40;
+ else
+ m_dsk_stat |= 0x40;
+}
+
+WRITE_LINE_MEMBER( msx_state::msx_wd179x_drq_w )
+{
+ if (state)
+ m_dsk_stat &= ~0x80;
+ else
+ m_dsk_stat |= 0x80;
+}
+
+const wd17xx_interface msx_wd17xx_interface =
+{
+ DEVCB_LINE_VCC,
+ DEVCB_DRIVER_LINE_MEMBER(msx_state, msx_wd179x_intrq_w),
+ DEVCB_DRIVER_LINE_MEMBER(msx_state, msx_wd179x_drq_w),
+ {FLOPPY_0, FLOPPY_1, NULL, NULL}
+};
+
+LEGACY_FLOPPY_OPTIONS_START(msx)
+ LEGACY_FLOPPY_OPTION(msx, "dsk", "MSX SS", basicdsk_identify_default, basicdsk_construct_default, NULL,
+ HEADS([1])
+ TRACKS([80])
+ SECTORS([9])
+ SECTOR_LENGTH([512])
+ FIRST_SECTOR_ID([1]))
+ LEGACY_FLOPPY_OPTION(msx, "dsk", "MSX DS", basicdsk_identify_default, basicdsk_construct_default, NULL,
+ HEADS([2])
+ TRACKS([80])
+ SECTORS([9])
+ SECTOR_LENGTH([512])
+ FIRST_SECTOR_ID([1]))
+LEGACY_FLOPPY_OPTIONS_END
+
+/*
+** The PPI functions
+*/
+
+WRITE8_MEMBER( msx_state::msx_ppi_port_a_w )
+{
+ m_primary_slot = data;
+
+ if (VERBOSE)
+ logerror ("write to primary slot select: %02x\n", m_primary_slot);
+ msx_memory_map_all ();
+}
+
+WRITE8_MEMBER( msx_state::msx_ppi_port_c_w )
+{
+ keylatch = data & 0x0f;
+
+ /* caps lock */
+ if ( BIT(m_port_c_old ^ data, 6) )
+ set_led_status (machine(), 1, !BIT(data, 6) );
+
+ /* key click */
+ if ( BIT(m_port_c_old ^ data, 7) )
+ m_dac->write_signed8(BIT(data, 7) ? 0x7f : 0);
+
+ /* cassette motor on/off */
+ if ( BIT(m_port_c_old ^ data, 4) )
+ m_cass->change_state(BIT(data, 4) ? CASSETTE_MOTOR_DISABLED : CASSETTE_MOTOR_ENABLED, CASSETTE_MASK_MOTOR);
+
+ /* cassette signal write */
+ if ( BIT(m_port_c_old ^ data, 5) )
+ m_cass->output(BIT(data, 5) ? -1.0 : 1.0);
+
+ m_port_c_old = data;
+}
+
+READ8_MEMBER( msx_state::msx_ppi_port_b_r )
+{
+ UINT8 result = 0xff;
+ int row, data;
+ static const char *const keynames[] = { "KEY0", "KEY1", "KEY2", "KEY3", "KEY4", "KEY5" };
+
+ row = keylatch;
+ if (row <= 10)
+ {
+ data = ioport(keynames[row / 2])->read();
+
+ if (BIT(row, 0))
+ data >>= 8;
+ result = data & 0xff;
+ }
+ return result;
+}
+
+/************************************************************************
+ *
+ * New memory emulation !!
+ *
+ ***********************************************************************/
+
+static void msx_memory_init (running_machine &machine)
+{
+ msx_state *state = machine.driver_data<msx_state>();
+ int prim, sec, page, extent, option;
+ int size = 0;
+ const msx_slot_layout *layout= (msx_slot_layout*)NULL;
+ const msx_slot *slot;
+ const msx_driver_struct *driver;
+ slot_state *st;
+ UINT8 *mem = NULL;
+
+ state->m_empty = auto_alloc_array(machine, UINT8, 0x4000);
+ memset (state->m_empty, 0xff, 0x4000);
+
+ for (prim=0; prim<4; prim++) {
+ for (sec=0; sec<4; sec++) {
+ for (page=0; page<4; page++) {
+ state->m_all_state[prim][sec][page]= (slot_state*)NULL;
+ }
+ }
+ }
+
+ for (driver = msx_driver_list; driver->name[0]; driver++) {
+ if (!strcmp (driver->name, machine.system().name)) {
+ layout = driver->layout;
+ }
+ }
+
+ if (!layout) {
+ logerror ("msx_memory_init: error: missing layout definition in "
+ "msx_driver_list\n");
+ return;
+ }
+
+ state->layout = layout;
+
+ for (; layout->entry != MSX_LAYOUT_LAST; layout++) {
+
+ switch (layout->entry) {
+ case MSX_LAYOUT_SLOT_ENTRY:
+ prim = layout->slot_primary;
+ sec = layout->slot_secondary;
+ page = layout->slot_page;
+ extent = layout->page_extent;
+
+ if (layout->slot_secondary) {
+ state->m_slot_expanded[layout->slot_primary]= TRUE;
+ }
+
+ slot = &msx_slot_list[layout->type];
+ if (slot->slot_type != layout->type) {
+ logerror ("internal error: msx_slot_list[%d].type != %d\n",
+ slot->slot_type, slot->slot_type);
+ }
+
+ size = layout->size;
+ option = layout->option;
+
+ if (VERBOSE)
+ {
+ logerror ("slot %d/%d/%d-%d: type %s, size 0x%x\n",
+ prim, sec, page, page + extent - 1, slot->name, size);
+ }
+
+ st = (slot_state*)NULL;
+ if (layout->type == SLOT_CARTRIDGE1) {
+ st = state->m_cart_state[0];
+ if (!st) {
+ slot = &msx_slot_list[SLOT_SOUNDCARTRIDGE];
+ size = 0x20000;
+ }
+ }
+ if (layout->type == SLOT_CARTRIDGE2) {
+ st = state->m_cart_state[1];
+ if (!st) {
+ /* Check whether the optional FM-PAC rom is present */
+ option = 0x10000;
+ size = 0x10000;
+ mem = machine.root_device().memregion("maincpu")->base() + option;
+ if (machine.root_device().memregion("maincpu")->bytes() >= size + option && mem[0] == 'A' && mem[1] == 'B') {
+ slot = &msx_slot_list[SLOT_FMPAC];
+ }
+ else {
+ slot = &msx_slot_list[SLOT_EMPTY];
+ }
+ }
+ }
+
+ if (!st) {
+ switch (slot->mem_type) {
+
+ case MSX_MEM_HANDLER:
+ case MSX_MEM_ROM:
+ mem = machine.root_device().memregion("maincpu")->base() + option;
+ break;
+ case MSX_MEM_RAM:
+ mem = NULL;
+ break;
+ }
+ st = auto_alloc_clear (machine, slot_state);
+ memset (st, 0, sizeof (slot_state));
+
+ if (slot->init (machine, st, layout->slot_page, mem, size)) {
+ continue;
+ }
+ }
+
+ while (extent--) {
+ if (page > 3) {
+ logerror ("internal error: msx_slot_layout wrong, "
+ "page + extent > 3\n");
+ break;
+ }
+ state->m_all_state[prim][sec][page] = st;
+ page++;
+ }
+ break;
+ case MSX_LAYOUT_KANJI_ENTRY:
+ state->m_kanji_mem = machine.root_device().memregion("maincpu")->base() + layout->option;
+ break;
+ case MSX_LAYOUT_RAMIO_SET_BITS_ENTRY:
+ state->m_ramio_set_bits = (UINT8)layout->option;
+ break;
+ }
+ }
+}
+
+void msx_state::msx_memory_reset ()
+{
+ slot_state *st, *last_st = (slot_state*)NULL;
+ int prim, sec, page;
+
+ m_primary_slot = 0;
+
+ for (prim=0; prim<4; prim++)
+ {
+ m_secondary_slot[prim] = 0;
+ for (sec=0; sec<4; sec++)
+ {
+ for (page=0; page<4; page++)
+ {
+ st = m_all_state[prim][sec][page];
+ if (st && st != last_st)
+ msx_slot_list[st->m_type].reset (machine(), st);
+ last_st = st;
+ }
+ }
+ }
+}
+
+static void msx_memory_set_carts (running_machine &machine)
+{
+ msx_state *state = machine.driver_data<msx_state>();
+ const msx_slot_layout *layout;
+ int page;
+
+ if (!state->layout)
+ return;
+
+ for (layout = state->layout; layout->entry != MSX_LAYOUT_LAST; layout++)
+ {
+ if (layout->entry == MSX_LAYOUT_SLOT_ENTRY)
+ {
+ switch (layout->type)
+ {
+ case SLOT_CARTRIDGE1:
+ for (page=0; page<4; page++)
+ state->m_all_state[layout->slot_primary][layout->slot_secondary][page]
+ = state->m_cart_state[0];
+ break;
+ case SLOT_CARTRIDGE2:
+ for (page=0; page<4; page++)
+ state->m_all_state[layout->slot_primary][layout->slot_secondary][page]
+ = state->m_cart_state[1];
+ break;
+ }
+ }
+ }
+}
+
+void msx_state::msx_memory_map_page (UINT8 page)
+{
+ int slot_primary;
+ int slot_secondary;
+ slot_state *st;
+ const msx_slot *slot;
+
+ slot_primary = (m_primary_slot >> (page * 2)) & 3;
+ slot_secondary = (m_secondary_slot[slot_primary] >> (page * 2)) & 3;
+
+ st = m_all_state[slot_primary][slot_secondary][page];
+ slot = st ? &msx_slot_list[st->m_type] : &msx_slot_list[SLOT_EMPTY];
+ m_state[page] = st;
+ m_slot[page] = slot;
+
+ if (VERBOSE)
+ logerror ("mapping %s in %d/%d/%d\n", slot->name, slot_primary, slot_secondary, page);
+
+ slot->map (machine(), st, page);
+}
+
+void msx_state::msx_memory_map_all ()
+{
+ for (UINT8 i=0; i<4; i++)
+ msx_memory_map_page (i);
+}
+
+WRITE8_MEMBER( msx_state::msx_page0_w )
+{
+ if ( offset == 0 )
+ {
+ m_superloadrunner_bank = data;
+ if (m_slot[2]->slot_type == SLOT_SUPERLOADRUNNER)
+ m_slot[2]->map (machine(), m_state[2], 2);
+ }
+
+ switch (m_slot[0]->mem_type)
+ {
+ case MSX_MEM_RAM:
+ m_ram_pages[0][offset] = data;
+ break;
+ case MSX_MEM_HANDLER:
+ m_slot[0]->write (machine(), m_state[0], offset, data);
+ }
+}
+
+WRITE8_MEMBER( msx_state::msx_page0_1_w )
+{
+ msx_page0_w( space, 0x2000 + offset, data );
+}
+
+WRITE8_MEMBER( msx_state::msx_page1_w )
+{
+ switch (m_slot[1]->mem_type)
+ {
+ case MSX_MEM_RAM:
+ m_ram_pages[1][offset] = data;
+ break;
+ case MSX_MEM_HANDLER:
+ m_slot[1]->write (machine(), m_state[1], 0x4000 + offset, data);
+ }
+}
+
+WRITE8_MEMBER( msx_state::msx_page1_1_w )
+{
+ msx_page1_w( space, 0x2000 + offset, data );
+}
+
+WRITE8_MEMBER( msx_state::msx_page1_2_w )
+{
+ msx_page1_w( space, 0x3ff8 + offset, data );
+}
+
+WRITE8_MEMBER( msx_state::msx_page2_w )
+{
+ switch (m_slot[2]->mem_type)
+ {
+ case MSX_MEM_RAM:
+ m_ram_pages[2][offset] = data;
+ break;
+ case MSX_MEM_HANDLER:
+ m_slot[2]->write (machine(), m_state[2], 0x8000 + offset, data);
+ }
+}
+
+WRITE8_MEMBER( msx_state::msx_page2_1_w )
+{
+ msx_page2_w( space, 0x1800 + offset, data );
+}
+
+WRITE8_MEMBER( msx_state::msx_page2_2_w )
+{
+ msx_page2_w( space, 0x2000 + offset, data );
+}
+
+WRITE8_MEMBER( msx_state::msx_page2_3_w )
+{
+ msx_page2_w( space, 0x3800 + offset, data );
+}
+
+WRITE8_MEMBER( msx_state::msx_page3_w )
+{
+ switch (m_slot[3]->mem_type)
+ {
+ case MSX_MEM_RAM:
+ m_ram_pages[3][offset] = data;
+ break;
+ case MSX_MEM_HANDLER:
+ m_slot[3]->write (machine(), m_state[3], 0xc000 + offset, data);
+ }
+}
+
+WRITE8_MEMBER( msx_state::msx_page3_1_w )
+{
+ msx_page3_w( space, 0x2000 + offset, data );
+}
+
+WRITE8_MEMBER( msx_state::msx_sec_slot_w )
+{
+ int slot = m_primary_slot >> 6;
+ if (m_slot_expanded[slot])
+ {
+ if (VERBOSE)
+ logerror ("write to secondary slot %d select: %02x\n", slot, data);
+
+ m_secondary_slot[slot] = data;
+ msx_memory_map_all ();
+ }
+ else
+ msx_page3_w(space, 0x3fff, data);
+}
+
+READ8_MEMBER( msx_state::msx_sec_slot_r )
+{
+ UINT8 result;
+ int slot = m_primary_slot >> 6;
+
+ if (m_slot_expanded[slot])
+ result = ~m_secondary_slot[slot];
+ else
+ result = m_top_page[0x1fff];
+
+ return result;
+}
+
+WRITE8_MEMBER( msx_state::msx_ram_mapper_w )
+{
+ m_ram_mapper[offset] = data;
+ if (m_slot[offset]->slot_type == SLOT_RAM_MM)
+ m_slot[offset]->map (machine(), m_state[offset], offset);
+}
+
+READ8_MEMBER( msx_state::msx_ram_mapper_r )
+{
+ return m_ram_mapper[offset] | m_ramio_set_bits;
+}
+
+WRITE8_MEMBER( msx_state::msx_90in1_w )
+{
+ m_korean90in1_bank = data;
+ if (m_slot[1]->slot_type == SLOT_KOREAN_90IN1)
+ m_slot[1]->map (machine(), m_state[1], 1);
+
+ if (m_slot[2]->slot_type == SLOT_KOREAN_90IN1)
+ m_slot[2]->map (machine(), m_state[2], 2);
+}
+
+READ8_MEMBER( msx_state::msx_kanji_r )
+{
+ UINT8 result = 0xff;
+
+ if (offset && m_kanji_mem)
+ {
+ int latch = m_kanji_latch;
+ result = m_kanji_mem[latch++];
+
+ m_kanji_latch &= ~0x1f;
+ m_kanji_latch |= latch & 0x1f;
+ }
+ return result;
+}
+
+WRITE8_MEMBER( msx_state::msx_kanji_w )
+{
+ if (offset)
+ m_kanji_latch = (m_kanji_latch & 0x007E0) | ((data & 0x3f) << 11);
+ else
+ m_kanji_latch = (m_kanji_latch & 0x1f800) | ((data & 0x3f) << 5);
+}
diff --git a/src/mess/machine/msx_slot.c b/src/mess/machine/msx_slot.c
new file mode 100644
index 00000000000..ca3f74ad2d9
--- /dev/null
+++ b/src/mess/machine/msx_slot.c
@@ -0,0 +1,2487 @@
+/*
+ * msx_slot.c : definitions of the different slots
+ *
+ * Copyright (C) 2004 Sean Young
+ *
+ * Missing:
+ * - Holy Qu'ran
+ * like ascii8, with switch address 5000h/5400h/5800h/5c00h, not working.
+ * - Harry Fox
+ * 16kb banks, 6000h and 7000h switch address; isn't it really an ascii16?
+ * - Halnote
+ * writes to page 0?
+ * - Playball
+ * Unemulated D7756C, same as src/drivers/homerun.c
+ * - Some ascii8 w/ sram need 32kb sram?
+ * - MegaRAM
+ * - fmsx painter.rom
+ */
+
+#include "emu.h"
+#include "emuopts.h"
+#include "machine/i8255.h"
+#include "includes/msx_slot.h"
+#include "includes/msx.h"
+#include "machine/wd17xx.h"
+#include "sound/k051649.h"
+#include "sound/2413intf.h"
+#include "sound/dac.h"
+#include "sound/ay8910.h"
+
+static void msx_cpu_setbank (running_machine &machine, int page, UINT8 *mem)
+{
+ msx_state *state = machine.driver_data<msx_state>();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ switch (page)
+ {
+ case 1:
+ state->membank ("bank1")->set_base (mem);
+ break;
+ case 2:
+ state->membank ("bank2")->set_base (mem);
+ break;
+ case 3:
+ state->membank ("bank3")->set_base (mem);
+ break;
+ case 4:
+ state->membank ("bank4")->set_base (mem);
+ state->membank ("bank5")->set_base (mem + 0x1ff8);
+ space->install_read_bank(0x7ff8, 0x7fff, "bank5");
+ break;
+ case 5:
+ state->membank ("bank6")->set_base (mem);
+ state->membank ("bank7")->set_base (mem + 0x1800);
+ space->install_read_bank(0x9800, 0x9fff, "bank7");
+ break;
+ case 6:
+ state->membank ("bank8")->set_base (mem);
+ state->membank ("bank9")->set_base (mem + 0x1800);
+ space->install_read_bank(0xb800, 0xbfff, "bank9");
+ break;
+ case 7:
+ state->membank ("bank10")->set_base (mem);
+ break;
+ case 8:
+ state->membank ("bank11")->set_base (mem);
+ state->m_top_page = mem;
+ break;
+ }
+}
+
+MSX_SLOT_INIT(empty)
+{
+ state->m_type = SLOT_EMPTY;
+
+ return 0;
+}
+
+MSX_SLOT_RESET(empty)
+{
+ /* reset void */
+}
+
+MSX_SLOT_MAP(empty)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ msx_cpu_setbank (machine, page * 2 + 1, drvstate->m_empty);
+ msx_cpu_setbank (machine, page * 2 + 2, drvstate->m_empty);
+}
+
+MSX_SLOT_INIT(rom)
+{
+ state->m_type = SLOT_ROM;
+ state->m_mem = mem;
+ state->m_size = size;
+ state->m_start_page = page;
+
+ return 0;
+}
+
+MSX_SLOT_RESET(rom)
+{
+ /* state-less */
+}
+
+MSX_SLOT_MAP(rom)
+{
+ UINT8 *mem = state->m_mem + (page - state->m_start_page) * 0x4000;
+
+ msx_cpu_setbank (machine, page * 2 + 1, mem);
+ msx_cpu_setbank (machine, page * 2 + 2, mem + 0x2000);
+}
+
+MSX_SLOT_INIT(ram)
+{
+ state->m_mem = auto_alloc_array(machine, UINT8, size);
+ memset (state->m_mem, 0, size);
+ state->m_type = SLOT_RAM;
+ state->m_start_page = page;
+ state->m_size = size;
+
+ return 0;
+}
+
+MSX_SLOT_MAP(ram)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ UINT8 *mem = state->m_mem + (page - state->m_start_page) * 0x4000;
+
+ drvstate->m_ram_pages[page] = mem;
+ msx_cpu_setbank (machine, page * 2 + 1, mem);
+ msx_cpu_setbank (machine, page * 2 + 2, mem + 0x2000);
+}
+
+MSX_SLOT_RESET(ram)
+{
+}
+
+MSX_SLOT_INIT(rammm)
+{
+ int i, mask, nsize;
+
+ nsize = 0x10000; /* 64 kb */
+ mask = 3;
+ for (i=0; i<6; i++)
+ {
+ if (size == nsize)
+ {
+ break;
+ }
+ mask = (mask << 1) | 1;
+ nsize <<= 1;
+ }
+ if (i == 6)
+ {
+ logerror ("ram mapper: error: must be 64kb, 128kb, 256kb, 512kb, "
+ "1mb, 2mb or 4mb\n");
+ return 1;
+ }
+ state->m_mem = auto_alloc_array(machine, UINT8, size);
+ memset (state->m_mem, 0, size);
+
+ state->m_type = SLOT_RAM_MM;
+ state->m_start_page = page;
+ state->m_size = size;
+ state->m_bank_mask = mask;
+
+ return 0;
+}
+
+MSX_SLOT_RESET(rammm)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ int i;
+
+ for (i=0; i<4; i++)
+ {
+ drvstate->m_ram_mapper[i] = 3 - i;
+ }
+}
+
+MSX_SLOT_MAP(rammm)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ UINT8 *mem = state->m_mem +
+ 0x4000 * (drvstate->m_ram_mapper[page] & state->m_bank_mask);
+
+ drvstate->m_ram_pages[page] = mem;
+ msx_cpu_setbank (machine, page * 2 + 1, mem);
+ msx_cpu_setbank (machine, page * 2 + 2, mem + 0x2000);
+}
+
+MSX_SLOT_INIT(msxdos2)
+{
+ if (size != 0x10000)
+ {
+ logerror ("msxdos2: error: rom file must be 64kb\n");
+ return 1;
+ }
+ state->m_type = SLOT_MSXDOS2;
+ state->m_mem = mem;
+ state->m_size = size;
+
+ return 0;
+}
+
+MSX_SLOT_RESET(msxdos2)
+{
+ state->m_banks[0] = 0;
+}
+
+MSX_SLOT_MAP(msxdos2)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ if (page != 1)
+ {
+ msx_cpu_setbank (machine, page * 2 + 1, drvstate->m_empty);
+ msx_cpu_setbank (machine, page * 2 + 2, drvstate->m_empty);
+ }
+ else
+ {
+ msx_cpu_setbank (machine, 3, state->m_mem + state->m_banks[0] * 0x4000);
+ msx_cpu_setbank (machine, 4, state->m_mem + state->m_banks[0] * 0x4000 + 0x2000);
+ }
+}
+
+MSX_SLOT_WRITE(msxdos2)
+{
+ if (addr == 0x6000)
+ {
+ state->m_banks[0] = val & 3;
+ slot_msxdos2_map (machine, state, 1);
+ }
+}
+
+MSX_SLOT_INIT(konami)
+{
+ int banks;
+
+ if (size > 0x200000)
+ {
+ logerror ("konami: warning: truncating to 2mb\n");
+ size = 0x200000;
+ }
+ banks = size / 0x2000;
+ if (size != banks * 0x2000 || (~(banks - 1) % banks))
+ {
+ logerror ("konami: error: must be a 2 power of 8kb\n");
+ return 1;
+ }
+ state->m_type = SLOT_KONAMI;
+ state->m_mem = mem;
+ state->m_size = size;
+ state->m_bank_mask = banks - 1;
+
+ return 0;
+}
+
+MSX_SLOT_RESET(konami)
+{
+ int i;
+
+ for (i=0; i<4; i++) state->m_banks[i] = i;
+}
+
+MSX_SLOT_MAP(konami)
+{
+ switch (page)
+ {
+ case 0:
+ msx_cpu_setbank (machine, 1, state->m_mem);
+ msx_cpu_setbank (machine, 2, state->m_mem + state->m_banks[1] * 0x2000);
+ break;
+ case 1:
+ msx_cpu_setbank (machine, 3, state->m_mem);
+ msx_cpu_setbank (machine, 4, state->m_mem + state->m_banks[1] * 0x2000);
+ break;
+ case 2:
+ msx_cpu_setbank (machine, 5, state->m_mem + state->m_banks[2] * 0x2000);
+ msx_cpu_setbank (machine, 6, state->m_mem + state->m_banks[3] * 0x2000);
+ break;
+ case 3:
+ msx_cpu_setbank (machine, 7, state->m_mem + state->m_banks[2] * 0x2000);
+ msx_cpu_setbank (machine, 8, state->m_mem + state->m_banks[3] * 0x2000);
+ }
+}
+
+MSX_SLOT_WRITE(konami)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ switch (addr)
+ {
+ case 0x6000:
+ state->m_banks[1] = val & state->m_bank_mask;
+ slot_konami_map (machine, state, 1);
+ if (drvstate->m_state[0] == state)
+ {
+ slot_konami_map (machine, state, 0);
+ }
+ break;
+ case 0x8000:
+ state->m_banks[2] = val & state->m_bank_mask;
+ slot_konami_map (machine, state, 2);
+ if (drvstate->m_state[3] == state)
+ {
+ slot_konami_map (machine, state, 3);
+ }
+ break;
+ case 0xa000:
+ state->m_banks[3] = val & state->m_bank_mask;
+ slot_konami_map (machine, state, 2);
+ if (drvstate->m_state[3] == state)
+ {
+ slot_konami_map (machine, state, 3);
+ }
+ }
+}
+
+MSX_SLOT_INIT(konami_scc)
+{
+ int banks;
+
+ if (size > 0x200000)
+ {
+ logerror ("konami_scc: warning: truncating to 2mb\n");
+ size = 0x200000;
+ }
+ banks = size / 0x2000;
+ if (size != banks * 0x2000 || (~(banks - 1) % banks))
+ {
+ logerror ("konami_scc: error: must be a 2 power of 8kb\n");
+ return 1;
+ }
+
+ state->m_type = SLOT_KONAMI_SCC;
+ state->m_mem = mem;
+ state->m_size = size;
+ state->m_bank_mask = banks - 1;
+
+ return 0;
+}
+
+MSX_SLOT_RESET(konami_scc)
+{
+ int i;
+
+ for (i=0; i<4; i++) state->m_banks[i] = i;
+ state->m_cart.scc.active = 0;
+}
+
+static READ8_HANDLER (konami_scc_bank5)
+{
+ if (offset & 0x80)
+ {
+ if ((offset & 0xff) >= 0xe0)
+ {
+ return k051649_test_r (space->machine().device("k051649"), offset & 0xff);
+ }
+ return 0xff;
+ }
+ else
+ {
+ return k051649_waveform_r (space->machine().device("k051649"), offset & 0x7f);
+ }
+}
+
+MSX_SLOT_MAP(konami_scc)
+{
+ switch (page)
+ {
+ case 0:
+ msx_cpu_setbank (machine, 1, state->m_mem + state->m_banks[2] * 0x2000);
+ msx_cpu_setbank (machine, 2, state->m_mem + state->m_banks[3] * 0x2000);
+ break;
+ case 1:
+ msx_cpu_setbank (machine, 3, state->m_mem + state->m_banks[0] * 0x2000);
+ msx_cpu_setbank (machine, 4, state->m_mem + state->m_banks[1] * 0x2000);
+ break;
+ case 2:
+ msx_cpu_setbank (machine, 5, state->m_mem + state->m_banks[2] * 0x2000);
+ msx_cpu_setbank (machine, 6, state->m_mem + state->m_banks[3] * 0x2000);
+ if (state->m_cart.scc.active ) {
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x9800, 0x9fff, FUNC(konami_scc_bank5));
+ } else {
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(0x9800, 0x9fff,"bank7");
+ }
+ break;
+ case 3:
+ msx_cpu_setbank (machine, 7, state->m_mem + state->m_banks[0] * 0x2000);
+ msx_cpu_setbank (machine, 8, state->m_mem + state->m_banks[1] * 0x2000);
+ }
+}
+
+MSX_SLOT_WRITE(konami_scc)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ if (addr >= 0x5000 && addr < 0x5800)
+ {
+ state->m_banks[0] = val & state->m_bank_mask;
+ slot_konami_scc_map (machine, state, 1);
+ if (drvstate->m_state[3] == state)
+ {
+ slot_konami_scc_map (machine, state, 3);
+ }
+ }
+ else if (addr >= 0x7000 && addr < 0x7800)
+ {
+ state->m_banks[1] = val & state->m_bank_mask;
+ slot_konami_scc_map (machine, state, 1);
+ if (drvstate->m_state[3] == state)
+ {
+ slot_konami_scc_map (machine, state, 3);
+ }
+ }
+ else if (addr >= 0x9000 && addr < 0x9800)
+ {
+ state->m_banks[2] = val & state->m_bank_mask;
+ state->m_cart.scc.active = ((val & 0x3f) == 0x3f);
+ slot_konami_scc_map (machine, state, 2);
+ if (drvstate->m_state[0] == state)
+ {
+ slot_konami_scc_map (machine, state, 0);
+ }
+ }
+ else if (state->m_cart.scc.active && addr >= 0x9800 && addr < 0xa000)
+ {
+ device_t *k051649 = space->machine().device("k051649");
+ int offset = addr & 0xff;
+
+ if (offset < 0x80)
+ {
+ k051649_waveform_w (k051649, offset, val);
+ }
+ else if (offset < 0xa0)
+ {
+ offset &= 0xf;
+ if (offset < 0xa)
+ {
+ k051649_frequency_w (k051649, offset, val);
+ }
+ else if (offset < 0xf)
+ {
+ k051649_volume_w (k051649, offset - 0xa, val);
+ }
+ else
+ {
+ k051649_keyonoff_w (k051649, 0, val);
+ }
+ }
+ else if (offset >= 0xe0)
+ {
+ k051649_test_w (k051649, offset, val);
+ }
+ }
+ else if (addr >= 0xb000 && addr < 0xb800)
+ {
+ state->m_banks[3] = val & state->m_bank_mask;
+ slot_konami_scc_map (machine, state, 2);
+ if (drvstate->m_state[0] == state)
+ {
+ slot_konami_scc_map (machine, state, 0);
+ }
+ }
+}
+
+MSX_SLOT_INIT(ascii8)
+{
+ int banks;
+
+ if (size > 0x200000)
+ {
+ logerror ("ascii8: warning: truncating to 2mb\n");
+ size = 0x200000;
+ }
+ banks = size / 0x2000;
+ if (size != banks * 0x2000 || (~(banks - 1) % banks))
+ {
+ logerror ("ascii8: error: must be a 2 power of 8kb\n");
+ return 1;
+ }
+ state->m_type = SLOT_ASCII8;
+ state->m_mem = mem;
+ state->m_size = size;
+ state->m_bank_mask = banks - 1;
+
+ return 0;
+}
+
+MSX_SLOT_RESET(ascii8)
+{
+ int i;
+
+ for (i=0; i<4; i++) state->m_banks[i] = i;
+}
+
+MSX_SLOT_MAP(ascii8)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ switch (page)
+ {
+ case 0:
+ msx_cpu_setbank (machine, 1, drvstate->m_empty);
+ msx_cpu_setbank (machine, 2, drvstate->m_empty);
+ break;
+ case 1:
+ msx_cpu_setbank (machine, 3, state->m_mem + state->m_banks[0] * 0x2000);
+ msx_cpu_setbank (machine, 4, state->m_mem + state->m_banks[1] * 0x2000);
+ break;
+ case 2:
+ msx_cpu_setbank (machine, 5, state->m_mem + state->m_banks[2] * 0x2000);
+ msx_cpu_setbank (machine, 6, state->m_mem + state->m_banks[3] * 0x2000);
+ break;
+ case 3:
+ msx_cpu_setbank (machine, 7, drvstate->m_empty);
+ msx_cpu_setbank (machine, 8, drvstate->m_empty);
+ }
+}
+
+MSX_SLOT_WRITE(ascii8)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ int bank;
+
+ if (addr >= 0x6000 && addr < 0x8000)
+ {
+ bank = (addr / 0x800) & 3;
+
+ state->m_banks[bank] = val & state->m_bank_mask;
+ if (bank <= 1)
+ {
+ slot_ascii8_map (machine, state, 1);
+ }
+ else if (drvstate->m_state[2] == state)
+ {
+ slot_ascii8_map (machine, state, 2);
+ }
+ }
+}
+
+MSX_SLOT_INIT(ascii16)
+{
+ int banks;
+
+ if (size > 0x400000)
+ {
+ logerror ("ascii16: warning: truncating to 4mb\n");
+ size = 0x400000;
+ }
+ banks = size / 0x4000;
+ if (size != banks * 0x4000 || (~(banks - 1) % banks))
+ {
+ logerror ("ascii16: error: must be a 2 power of 16kb\n");
+ return 1;
+ }
+
+ state->m_type = SLOT_ASCII16;
+ state->m_mem = mem;
+ state->m_size = size;
+ state->m_bank_mask = banks - 1;
+
+ return 0;
+}
+
+MSX_SLOT_RESET(ascii16)
+{
+ int i;
+
+ for (i=0; i<2; i++) state->m_banks[i] = 0;
+}
+
+MSX_SLOT_MAP(ascii16)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ UINT8 *mem;
+
+ switch (page)
+ {
+ case 0:
+ msx_cpu_setbank (machine, 1, drvstate->m_empty);
+ msx_cpu_setbank (machine, 2, drvstate->m_empty);
+ break;
+ case 1:
+ mem = state->m_mem + state->m_banks[0] * 0x4000;
+ msx_cpu_setbank (machine, 3, mem);
+ msx_cpu_setbank (machine, 4, mem + 0x2000);
+ break;
+ case 2:
+ mem = state->m_mem + state->m_banks[1] * 0x4000;
+ msx_cpu_setbank (machine, 5, mem);
+ msx_cpu_setbank (machine, 6, mem + 0x2000);
+ break;
+ case 3:
+ msx_cpu_setbank (machine, 7, drvstate->m_empty);
+ msx_cpu_setbank (machine, 8, drvstate->m_empty);
+ }
+}
+
+MSX_SLOT_WRITE(ascii16)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ if (addr >= 0x6000 && addr < 0x6800)
+ {
+ state->m_banks[0] = val & state->m_bank_mask;
+ slot_ascii16_map (machine, state, 1);
+ }
+ else if (addr >= 0x7000 && addr < 0x7800)
+ {
+ state->m_banks[1] = val & state->m_bank_mask;
+ if (drvstate->m_state[2] == state)
+ {
+ slot_ascii16_map (machine, state, 2);
+ }
+ }
+}
+
+MSX_SLOT_INIT(ascii8_sram)
+{
+ static const char sramfile[] = "ascii8";
+ int banks;
+
+ state->m_cart.sram.mem = auto_alloc_array(machine, UINT8, 0x2000);
+ if (size > 0x100000)
+ {
+ logerror ("ascii8_sram: warning: truncating to 1mb\n");
+ size = 0x100000;
+ }
+ banks = size / 0x2000;
+ if (size != banks * 0x2000 || (~(banks - 1) % banks))
+ {
+ logerror ("ascii8_sram: error: must be a 2 power of 8kb\n");
+ return 1;
+ }
+ memset (state->m_cart.sram.mem, 0, 0x2000);
+ state->m_type = SLOT_ASCII8_SRAM;
+ state->m_mem = mem;
+ state->m_size = size;
+ state->m_bank_mask = banks - 1;
+ state->m_cart.sram.sram_mask = banks;
+ state->m_cart.sram.empty_mask = ~(banks | (banks - 1));
+ if (!state->m_sramfile)
+ {
+ state->m_sramfile = sramfile;
+ }
+
+ return 0;
+}
+
+MSX_SLOT_RESET(ascii8_sram)
+{
+ int i;
+
+ for (i=0; i<4; i++) state->m_banks[i] = i;
+}
+
+static UINT8 *ascii8_sram_bank_select (msx_state *drvstate, slot_state *state, int bankno)
+{
+ int bank = state->m_banks[bankno];
+
+ if (bank & state->m_cart.sram.empty_mask)
+ {
+ return drvstate->m_empty;
+ }
+ else if (bank & state->m_cart.sram.sram_mask)
+ {
+ return state->m_cart.sram.mem;
+ }
+ else
+ {
+ return state->m_mem + (bank & state->m_bank_mask) * 0x2000;
+ }
+}
+
+MSX_SLOT_MAP(ascii8_sram)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ switch (page)
+ {
+ case 0:
+ msx_cpu_setbank (machine, 1, drvstate->m_empty);
+ msx_cpu_setbank (machine, 2, drvstate->m_empty);
+ break;
+ case 1:
+ msx_cpu_setbank (machine, 3, ascii8_sram_bank_select (drvstate, state, 0));
+ msx_cpu_setbank (machine, 4, ascii8_sram_bank_select (drvstate, state, 1));
+ break;
+ case 2:
+ msx_cpu_setbank (machine, 5, ascii8_sram_bank_select (drvstate, state, 2));
+ msx_cpu_setbank (machine, 6, ascii8_sram_bank_select (drvstate, state, 3));
+ break;
+ case 3:
+ msx_cpu_setbank (machine, 7, drvstate->m_empty);
+ msx_cpu_setbank (machine, 8, drvstate->m_empty);
+ }
+}
+
+MSX_SLOT_WRITE(ascii8_sram)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ int bank;
+
+ if (addr >= 0x6000 && addr < 0x8000)
+ {
+ bank = (addr / 0x800) & 3;
+
+ state->m_banks[bank] = val;
+ if (bank <= 1)
+ {
+ slot_ascii8_sram_map (machine, state, 1);
+ }
+ else if (drvstate->m_state[2] == state)
+ {
+ slot_ascii8_sram_map (machine, state, 2);
+ }
+ }
+ if (addr >= 0x8000 && addr < 0xc000)
+ {
+ bank = addr < 0xa000 ? 2 : 3;
+ if (!(state->m_banks[bank] & state->m_cart.sram.empty_mask) &&
+ (state->m_banks[bank] & state->m_cart.sram.sram_mask))
+ {
+ state->m_cart.sram.mem[addr & 0x1fff] = val;
+ }
+ }
+}
+
+MSX_SLOT_LOADSRAM(ascii8_sram)
+{
+ if (!state->m_sramfile)
+ {
+ logerror ("ascii8_sram: error: no sram filename provided\n");
+ return 1;
+ }
+ emu_file f(machine.options().memcard_directory(), OPEN_FLAG_READ);
+ file_error filerr = f.open(state->m_sramfile);
+ if (filerr == FILERR_NONE)
+ {
+ if (f.read(state->m_cart.sram.mem, 0x2000) == 0x2000)
+ {
+ logerror ("ascii8_sram: info: sram loaded\n");
+ return 0;
+ }
+ memset (state->m_cart.sram.mem, 0, 0x2000);
+ logerror ("ascii8_sram: warning: could not read sram file\n");
+ return 1;
+ }
+
+ logerror ("ascii8_sram: warning: could not open sram file for reading\n");
+
+ return 1;
+}
+
+MSX_SLOT_SAVESRAM(ascii8_sram)
+{
+ if (!state->m_sramfile)
+ {
+ return 0;
+ }
+
+ emu_file f(machine.options().memcard_directory(), OPEN_FLAG_WRITE);
+ file_error filerr = f.open(state->m_sramfile);
+ if (filerr == FILERR_NONE)
+ {
+ f.write(state->m_cart.sram.mem, 0x2000);
+ logerror ("ascii8_sram: info: sram saved\n");
+
+ return 0;
+ }
+
+ logerror ("ascii8_sram: warning: could not open sram file for saving\n");
+
+ return 1;
+}
+
+MSX_SLOT_INIT(ascii16_sram)
+{
+ static const char sramfile[] = "ascii16";
+ int banks;
+
+ state->m_cart.sram.mem = auto_alloc_array(machine, UINT8, 0x4000);
+
+ if (size > 0x200000)
+ {
+ logerror ("ascii16_sram: warning: truncating to 2mb\n");
+ size = 0x200000;
+ }
+ banks = size / 0x4000;
+ if (size != banks * 0x4000 || (~(banks - 1) % banks))
+ {
+ logerror ("ascii16_sram: error: must be a 2 power of 16kb\n");
+ return 1;
+ }
+
+ memset (state->m_cart.sram.mem, 0, 0x4000);
+ state->m_type = SLOT_ASCII16_SRAM;
+ state->m_mem = mem;
+ state->m_size = size;
+ state->m_bank_mask = banks - 1;
+ state->m_cart.sram.sram_mask = banks;
+ state->m_cart.sram.empty_mask = ~(banks | (banks - 1));
+ if (!state->m_sramfile)
+ {
+ state->m_sramfile = sramfile;
+ }
+
+ return 0;
+}
+
+MSX_SLOT_RESET(ascii16_sram)
+{
+ int i;
+
+ for (i=0; i<2; i++) state->m_banks[i] = i;
+}
+
+static UINT8 *ascii16_sram_bank_select (msx_state *drvstate, slot_state *state, int bankno)
+{
+ int bank = state->m_banks[bankno];
+
+ if (bank & state->m_cart.sram.empty_mask)
+ {
+ return drvstate->m_empty;
+ }
+ else if (bank & state->m_cart.sram.sram_mask)
+ {
+ return state->m_cart.sram.mem;
+ }
+ else
+ {
+ return state->m_mem + (bank & state->m_bank_mask) * 0x4000;
+ }
+}
+
+MSX_SLOT_MAP(ascii16_sram)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ UINT8 *mem;
+
+ switch (page)
+ {
+ case 0:
+ msx_cpu_setbank (machine, 1, drvstate->m_empty);
+ msx_cpu_setbank (machine, 2, drvstate->m_empty);
+ break;
+ case 1:
+ mem = ascii16_sram_bank_select (drvstate, state, 0);
+ msx_cpu_setbank (machine, 3, mem);
+ msx_cpu_setbank (machine, 4, mem + 0x2000);
+ break;
+ case 2:
+ mem = ascii16_sram_bank_select (drvstate, state, 1);
+ msx_cpu_setbank (machine, 5, mem);
+ msx_cpu_setbank (machine, 6, mem + 0x2000);
+ break;
+ case 3:
+ msx_cpu_setbank (machine, 7, drvstate->m_empty);
+ msx_cpu_setbank (machine, 8, drvstate->m_empty);
+ }
+}
+
+MSX_SLOT_WRITE(ascii16_sram)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ if (addr >= 0x6000 && addr < 0x6800)
+ {
+ state->m_banks[0] = val;
+ slot_ascii16_sram_map (machine, state, 1);
+ }
+ else if (addr >= 0x7000 && addr < 0x7800)
+ {
+ state->m_banks[1] = val;
+ if (drvstate->m_state[2] == state)
+ {
+ slot_ascii16_sram_map (machine, state, 2);
+ }
+ }
+ else if (addr >= 0x8000 && addr < 0xc000)
+ {
+ if (!(state->m_banks[1] & state->m_cart.sram.empty_mask) &&
+ (state->m_banks[1] & state->m_cart.sram.sram_mask))
+ {
+ int offset, i;
+
+ offset = addr & 0x07ff;
+ for (i=0; i<8; i++)
+ {
+ state->m_cart.sram.mem[offset] = val;
+ offset += 0x0800;
+ }
+ }
+ }
+}
+
+MSX_SLOT_LOADSRAM(ascii16_sram)
+{
+ UINT8 *p;
+
+ if (!state->m_sramfile)
+ {
+ logerror ("ascii16_sram: error: no sram filename provided\n");
+ return 1;
+ }
+
+ emu_file f(machine.options().memcard_directory(), OPEN_FLAG_READ);
+ file_error filerr = f.open(state->m_sramfile);
+ if (filerr == FILERR_NONE)
+ {
+ p = state->m_cart.sram.mem;
+
+ if (f.read(state->m_cart.sram.mem, 0x200) == 0x200)
+ {
+ int /*offset,*/ i;
+ //offset = 0;
+ for (i=0; i<7; i++)
+ {
+ memcpy (p + 0x800, p, 0x800);
+ p += 0x800;
+ }
+
+ logerror ("ascii16_sram: info: sram loaded\n");
+ return 0;
+ }
+ memset (state->m_cart.sram.mem, 0, 0x4000);
+ logerror ("ascii16_sram: warning: could not read sram file\n");
+ return 1;
+ }
+
+ logerror ("ascii16_sram: warning: could not open sram file for reading\n");
+
+ return 1;
+}
+
+MSX_SLOT_SAVESRAM(ascii16_sram)
+{
+ if (!state->m_sramfile)
+ {
+ return 0;
+ }
+ emu_file f(machine.options().memcard_directory(), OPEN_FLAG_WRITE);
+ file_error filerr = f.open(state->m_sramfile);
+ if (filerr == FILERR_NONE)
+ {
+ f.write(state->m_cart.sram.mem, 0x200);
+ logerror ("ascii16_sram: info: sram saved\n");
+
+ return 0;
+ }
+
+ logerror ("ascii16_sram: warning: could not open sram file for saving\n");
+
+ return 1;
+}
+
+MSX_SLOT_INIT(rtype)
+{
+ if (!(size == 0x60000 || size == 0x80000))
+ {
+ logerror ("rtype: error: rom file should be exactly 384kb\n");
+ return 1;
+ }
+
+ state->m_type = SLOT_RTYPE;
+ state->m_mem = mem;
+ state->m_size = size;
+
+ return 0;
+}
+
+MSX_SLOT_RESET(rtype)
+{
+ state->m_banks[0] = 15;
+}
+
+MSX_SLOT_MAP(rtype)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ UINT8 *mem;
+
+ switch (page)
+ {
+ case 0:
+ msx_cpu_setbank (machine, 1, drvstate->m_empty);
+ msx_cpu_setbank (machine, 2, drvstate->m_empty);
+ break;
+ case 1:
+ mem = state->m_mem + 15 * 0x4000;
+ msx_cpu_setbank (machine, 3, mem);
+ msx_cpu_setbank (machine, 4, mem + 0x2000);
+ break;
+ case 2:
+ mem = state->m_mem + state->m_banks[0] * 0x4000;
+ msx_cpu_setbank (machine, 5, mem);
+ msx_cpu_setbank (machine, 6, mem + 0x2000);
+ break;
+ case 3:
+ msx_cpu_setbank (machine, 7, drvstate->m_empty);
+ msx_cpu_setbank (machine, 8, drvstate->m_empty);
+ }
+}
+
+MSX_SLOT_WRITE(rtype)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ if (addr >= 0x7000 && addr < 0x8000)
+ {
+ int data ;
+
+ if (val & 0x10)
+ {
+ data = 0x10 | (val & 7);
+ }
+ else
+ {
+ data = val & 0x0f;
+ }
+ state->m_banks[0] = data;
+ if (drvstate->m_state[2] == state)
+ {
+ slot_rtype_map (machine, state, 2);
+ }
+ }
+}
+
+MSX_SLOT_INIT(gmaster2)
+{
+ UINT8 *p;
+ static const char sramfile[] = "GameMaster2";
+
+ if (size != 0x20000)
+ {
+ logerror ("gmaster2: error: rom file should be 128kb\n");
+ return 1;
+ }
+ state->m_type = SLOT_GAMEMASTER2;
+ state->m_size = size;
+ state->m_mem = mem;
+
+ p = auto_alloc_array(machine, UINT8, 0x4000);
+ memset (p, 0, 0x4000);
+ state->m_cart.sram.mem = p;
+ if (!state->m_sramfile)
+ {
+ state->m_sramfile = sramfile;
+ }
+
+ return 0;
+}
+
+MSX_SLOT_RESET(gmaster2)
+{
+ int i;
+
+ for (i=0; i<4; i++)
+ {
+ state->m_banks[i] = i;
+ }
+}
+
+MSX_SLOT_MAP(gmaster2)
+{
+ switch (page)
+ {
+ case 0:
+ case 1:
+ msx_cpu_setbank (machine, 1 + page * 2, state->m_mem); /* bank 0 is hardwired */
+ if (state->m_banks[1] > 15)
+ {
+ msx_cpu_setbank (machine, 2 + page * 2, state->m_cart.sram.mem +
+ (state->m_banks[1] - 16) * 0x2000);
+ }
+ else
+ {
+ msx_cpu_setbank (machine, 2 + page * 2, state->m_mem + state->m_banks[1] * 0x2000);
+ }
+ break;
+ case 2:
+ case 3:
+ if (state->m_banks[2] > 15)
+ {
+ msx_cpu_setbank (machine, 5 + page * 2, state->m_cart.sram.mem +
+ (state->m_banks[2] - 16) * 0x2000);
+ }
+ else
+ {
+ msx_cpu_setbank (machine, 5 + page * 2, state->m_mem + state->m_banks[2] * 0x2000);
+ }
+ if (state->m_banks[3] > 15)
+ {
+ msx_cpu_setbank (machine, 6 + page * 2, state->m_cart.sram.mem +
+ (state->m_banks[3] - 16) * 0x2000);
+ }
+ else
+ {
+ msx_cpu_setbank (machine, 6 + page * 2, state->m_mem + state->m_banks[3] * 0x2000);
+ }
+ break;
+ }
+}
+
+MSX_SLOT_WRITE(gmaster2)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ if (addr >= 0x6000 && addr < 0x7000)
+ {
+ if (val & 0x10)
+ {
+ val = val & 0x20 ? 17 : 16;
+ }
+ else
+ {
+ val = val & 15;
+ }
+ state->m_banks[1] = val;
+ slot_gmaster2_map (machine, state, 1);
+ if (drvstate->m_state[0] == state)
+ {
+ slot_gmaster2_map (machine, state, 0);
+ }
+ }
+ else if (addr >= 0x8000 && addr < 0x9000)
+ {
+ if (val & 0x10)
+ {
+ val = val & 0x20 ? 17 : 16;
+ }
+ else
+ {
+ val = val & 15;
+ }
+ state->m_banks[2] = val;
+ slot_gmaster2_map (machine, state, 2);
+ if (drvstate->m_state[3] == state)
+ {
+ slot_gmaster2_map (machine, state, 3);
+ }
+ }
+ else if (addr >= 0xa000 && addr < 0xb000)
+ {
+ if (val & 0x10)
+ {
+ val = val & 0x20 ? 17 : 16;
+ }
+ else
+ {
+ val = val & 15;
+ }
+ state->m_banks[3] = val;
+ slot_gmaster2_map (machine, state, 2);
+ if (drvstate->m_state[3] == state)
+ {
+ slot_gmaster2_map (machine, state, 3);
+ }
+ }
+ else if (addr >= 0xb000 && addr < 0xc000)
+ {
+ addr &= 0x0fff;
+ switch (state->m_banks[3])
+ {
+ case 16:
+ state->m_cart.sram.mem[addr] = val;
+ state->m_cart.sram.mem[addr + 0x1000] = val;
+ break;
+ case 17:
+ state->m_cart.sram.mem[addr + 0x2000] = val;
+ state->m_cart.sram.mem[addr + 0x3000] = val;
+ break;
+ }
+ }
+}
+
+MSX_SLOT_LOADSRAM(gmaster2)
+{
+ UINT8 *p;
+
+ p = state->m_cart.sram.mem;
+
+ emu_file f(machine.options().memcard_directory(), OPEN_FLAG_READ);
+ file_error filerr = f.open(state->m_sramfile);
+ if (filerr == FILERR_NONE)
+ {
+ if (f.read(p + 0x1000, 0x2000) == 0x2000)
+ {
+ memcpy (p, p + 0x1000, 0x1000);
+ memcpy (p + 0x3000, p + 0x2000, 0x1000);
+ logerror ("gmaster2: info: sram loaded\n");
+ return 0;
+ }
+ memset (p, 0, 0x4000);
+ logerror ("gmaster2: warning: could not read sram file\n");
+ return 1;
+ }
+
+ logerror ("gmaster2: warning: could not open sram file for reading\n");
+
+ return 1;
+}
+
+MSX_SLOT_SAVESRAM(gmaster2)
+{
+ emu_file f(machine.options().memcard_directory(), OPEN_FLAG_WRITE);
+ file_error filerr = f.open(state->m_sramfile);
+ if (filerr == FILERR_NONE)
+ {
+ f.write(state->m_cart.sram.mem + 0x1000, 0x2000);
+ logerror ("gmaster2: info: sram saved\n");
+
+ return 0;
+ }
+
+ logerror ("gmaster2: warning: could not open sram file for saving\n");
+
+ return 1;
+}
+
+MSX_SLOT_INIT(diskrom)
+{
+ if (size != 0x4000)
+ {
+ logerror ("diskrom: error: the diskrom should be 16kb\n");
+ return 1;
+ }
+
+ state->m_type = SLOT_DISK_ROM;
+ state->m_mem = mem;
+ state->m_size = size;
+
+ return 0;
+}
+
+MSX_SLOT_RESET(diskrom)
+{
+ device_t *fdc = machine.device("wd179x");
+ wd17xx_reset(fdc);
+}
+
+static READ8_HANDLER (msx_diskrom_page1_r)
+{
+ msx_state *state = space->machine().driver_data<msx_state>();
+ device_t *fdc = space->machine().device("wd179x");
+ switch (offset)
+ {
+ case 0: return wd17xx_status_r (fdc, 0);
+ case 1: return wd17xx_track_r (fdc, 0);
+ case 2: return wd17xx_sector_r (fdc, 0);
+ case 3: return wd17xx_data_r (fdc, 0);
+ case 7: return state->m_dsk_stat;
+ default:
+ return state->m_state[1]->m_mem[offset + 0x3ff8];
+ }
+}
+
+static READ8_HANDLER (msx_diskrom_page2_r)
+{
+ msx_state *state = space->machine().driver_data<msx_state>();
+ device_t *fdc = space->machine().device("wd179x");
+ if (offset >= 0x7f8)
+ {
+ switch (offset)
+ {
+ case 0x7f8:
+ return wd17xx_status_r (fdc, 0);
+ case 0x7f9:
+ return wd17xx_track_r (fdc, 0);
+ case 0x7fa:
+ return wd17xx_sector_r (fdc, 0);
+ case 0x7fb:
+ return wd17xx_data_r (fdc, 0);
+ case 0x7ff:
+ return state->m_dsk_stat;
+ default:
+ return state->m_state[2]->m_mem[offset + 0x3800];
+ }
+ }
+ else
+ {
+ return 0xff;
+ }
+}
+
+MSX_SLOT_MAP(diskrom)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ switch (page)
+ {
+ case 0:
+ msx_cpu_setbank (machine, 1, drvstate->m_empty);
+ msx_cpu_setbank (machine, 2, drvstate->m_empty);
+ break;
+ case 1:
+ msx_cpu_setbank (machine, 3, state->m_mem);
+ msx_cpu_setbank (machine, 4, state->m_mem + 0x2000);
+ space->install_legacy_read_handler(0x7ff8, 0x7fff, FUNC(msx_diskrom_page1_r));
+ break;
+ case 2:
+ msx_cpu_setbank (machine, 5, drvstate->m_empty);
+ msx_cpu_setbank (machine, 6, drvstate->m_empty);
+ space->install_legacy_read_handler(0xb800, 0xbfff, FUNC(msx_diskrom_page2_r));
+ break;
+ case 3:
+ msx_cpu_setbank (machine, 7, drvstate->m_empty);
+ msx_cpu_setbank (machine, 8, drvstate->m_empty);
+ break;
+ }
+}
+
+MSX_SLOT_WRITE(diskrom)
+{
+ device_t *fdc = machine.device("wd179x");
+ if (addr >= 0xa000 && addr < 0xc000)
+ {
+ addr -= 0x4000;
+ }
+ switch (addr)
+ {
+ case 0x7ff8:
+ wd17xx_command_w (fdc, 0, val);
+ break;
+ case 0x7ff9:
+ wd17xx_track_w (fdc, 0, val);
+ break;
+ case 0x7ffa:
+ wd17xx_sector_w (fdc, 0, val);
+ break;
+ case 0x7ffb:
+ wd17xx_data_w (fdc, 0, val);
+ break;
+ case 0x7ffc:
+ wd17xx_set_side (fdc,val & 1);
+ state->m_mem[0x3ffc] = val | 0xfe;
+ break;
+ case 0x7ffd:
+ wd17xx_set_drive (fdc,val & 1);
+ if ((state->m_mem[0x3ffd] ^ val) & 0x40)
+ {
+ set_led_status (machine, 0, !(val & 0x40));
+ }
+ state->m_mem[0x3ffd] = (val | 0x7c) & ~0x04;
+ break;
+ }
+}
+
+MSX_SLOT_INIT(diskrom2)
+{
+ if (size != 0x4000)
+ {
+ logerror ("diskrom2: error: the diskrom2 should be 16kb\n");
+ return 1;
+ }
+
+ state->m_type = SLOT_DISK_ROM2;
+ state->m_mem = mem;
+ state->m_size = size;
+
+ return 0;
+}
+
+MSX_SLOT_RESET(diskrom2)
+{
+ device_t *fdc = machine.device("wd179x");
+ wd17xx_reset (fdc);
+}
+
+static READ8_HANDLER (msx_diskrom2_page1_r)
+{
+ msx_state *state = space->machine().driver_data<msx_state>();
+ device_t *fdc = space->machine().device("wd179x");
+ switch (offset)
+ {
+ case 0: return wd17xx_status_r(fdc, 0);
+ case 1: return wd17xx_track_r(fdc, 0);
+ case 2: return wd17xx_sector_r(fdc, 0);
+ case 3: return wd17xx_data_r(fdc, 0);
+ case 4: return state->m_dsk_stat;
+ default:
+ return state->m_state[1]->m_mem[offset + 0x3ff8];
+ }
+}
+
+static READ8_HANDLER (msx_diskrom2_page2_r)
+{
+ msx_state *state = space->machine().driver_data<msx_state>();
+ device_t *fdc = space->machine().device("wd179x");
+ if (offset >= 0x7b8)
+ {
+ switch (offset)
+ {
+ case 0x7b8:
+ return wd17xx_status_r (fdc, 0);
+ case 0x7b9:
+ return wd17xx_track_r (fdc, 0);
+ case 0x7ba:
+ return wd17xx_sector_r (fdc, 0);
+ case 0x7bb:
+ return wd17xx_data_r (fdc, 0);
+ case 0x7bc:
+ return state->m_dsk_stat;
+ default:
+ return state->m_state[2]->m_mem[offset + 0x3800];
+ }
+ }
+ else
+ {
+ return 0xff;
+ }
+}
+
+MSX_SLOT_MAP(diskrom2)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ switch (page)
+ {
+ case 0:
+ msx_cpu_setbank (machine, 1, drvstate->m_empty);
+ msx_cpu_setbank (machine, 2, drvstate->m_empty);
+ break;
+ case 1:
+ msx_cpu_setbank (machine, 3, state->m_mem);
+ msx_cpu_setbank (machine, 4, state->m_mem + 0x2000);
+ space->install_legacy_read_handler(0x7fb8, 0x7fbc, FUNC(msx_diskrom2_page1_r));
+ break;
+ case 2:
+ msx_cpu_setbank (machine, 5, drvstate->m_empty);
+ msx_cpu_setbank (machine, 6, drvstate->m_empty);
+ space->install_legacy_read_handler(0xb800, 0xbfbc, FUNC(msx_diskrom2_page2_r));
+ break;
+ case 3:
+ msx_cpu_setbank (machine, 7, drvstate->m_empty);
+ msx_cpu_setbank (machine, 8, drvstate->m_empty);
+ }
+}
+
+MSX_SLOT_WRITE(diskrom2)
+{
+ device_t *fdc = machine.device("wd179x");
+ if (addr >= 0xa000 && addr < 0xc000)
+ {
+ addr -= 0x4000;
+ }
+ switch (addr)
+ {
+ case 0x7fb8:
+ wd17xx_command_w (fdc, 0, val);
+ break;
+ case 0x7fb9:
+ wd17xx_track_w (fdc, 0, val);
+ break;
+ case 0x7fba:
+ wd17xx_sector_w (fdc, 0, val);
+ break;
+ case 0x7fbb:
+ wd17xx_data_w (fdc, 0, val);
+ break;
+ case 0x7fbc:
+ wd17xx_set_side (fdc,val & 1);
+ state->m_mem[0x3fbc] = val | 0xfe;
+ wd17xx_set_drive (fdc,val & 1);
+ if ((state->m_mem[0x3fbc] ^ val) & 0x40)
+ {
+ set_led_status (machine, 0, !(val & 0x40));
+ }
+ state->m_mem[0x3fbc] = (val | 0x7c) & ~0x04;
+ break;
+ }
+}
+
+MSX_SLOT_INIT(synthesizer)
+{
+ if (size != 0x8000)
+ {
+ logerror ("synthesizer: error: rom file must be 32kb\n");
+ return 1;
+ }
+ state->m_type = SLOT_SYNTHESIZER;
+ state->m_mem = mem;
+ state->m_size = size;
+
+ return 0;
+}
+
+MSX_SLOT_RESET(synthesizer)
+{
+ /* empty */
+}
+
+MSX_SLOT_MAP(synthesizer)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ switch (page)
+ {
+ case 0:
+ msx_cpu_setbank (machine, 1, drvstate->m_empty);
+ msx_cpu_setbank (machine, 2, drvstate->m_empty);
+ break;
+ case 1:
+ msx_cpu_setbank (machine, 3, state->m_mem);
+ msx_cpu_setbank (machine, 4, state->m_mem + 0x2000);
+ break;
+ case 2:
+ msx_cpu_setbank (machine, 5, state->m_mem + 0x4000);
+ msx_cpu_setbank (machine, 6, state->m_mem + 0x6000);
+ break;
+ case 3:
+ msx_cpu_setbank (machine, 7, drvstate->m_empty);
+ msx_cpu_setbank (machine, 8, drvstate->m_empty);
+ }
+}
+
+MSX_SLOT_WRITE(synthesizer)
+{
+ if (addr >= 0x4000 && addr < 0x8000 && !(addr & 0x0010))
+ {
+ machine.device<dac_device>("dac")->write_unsigned8(val);
+ }
+}
+
+MSX_SLOT_INIT(majutsushi)
+{
+ if (size != 0x20000)
+ {
+ logerror ("majutsushi: error: rom file must be 128kb\n");
+ return 1;
+ }
+ state->m_type = SLOT_MAJUTSUSHI;
+ state->m_mem = mem;
+ state->m_size = size;
+ state->m_bank_mask = 0x0f;
+
+ return 0;
+}
+
+MSX_SLOT_RESET(majutsushi)
+{
+ int i;
+
+ for (i=0; i<4; i++)
+ {
+ state->m_banks[i] = i;
+ }
+}
+
+MSX_SLOT_MAP(majutsushi)
+{
+ switch (page)
+ {
+ case 0:
+ msx_cpu_setbank (machine, 1, state->m_mem + state->m_banks[0] * 0x2000);
+ msx_cpu_setbank (machine, 2, state->m_mem + state->m_banks[1] * 0x2000);
+ break;
+ case 1:
+ msx_cpu_setbank (machine, 3, state->m_mem + state->m_banks[0] * 0x2000);
+ msx_cpu_setbank (machine, 4, state->m_mem + state->m_banks[1] * 0x2000);
+ break;
+ case 2:
+ msx_cpu_setbank (machine, 5, state->m_mem + state->m_banks[2] * 0x2000);
+ msx_cpu_setbank (machine, 6, state->m_mem + state->m_banks[3] * 0x2000);
+ break;
+ case 3:
+ msx_cpu_setbank (machine, 7, state->m_mem + state->m_banks[2] * 0x2000);
+ msx_cpu_setbank (machine, 8, state->m_mem + state->m_banks[3] * 0x2000);
+ break;
+ }
+}
+
+MSX_SLOT_WRITE(majutsushi)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ if (addr >= 0x5000 && addr < 0x6000)
+ {
+ machine.device<dac_device>("dac")->write_unsigned8(val);
+ }
+ else if (addr >= 0x6000 && addr < 0x8000)
+ {
+ state->m_banks[1] = val & 0x0f;
+ slot_majutsushi_map (machine, state, 1);
+ if (drvstate->m_state[0] == state)
+ {
+ slot_konami_map (machine, state, 0);
+ }
+ }
+ else if (addr >= 0x8000 && addr < 0xc000)
+ {
+ state->m_banks[addr < 0xa000 ? 2 : 3] = val & 0x0f;
+ slot_majutsushi_map (machine, state, 2);
+ if (drvstate->m_state[3] == state)
+ {
+ slot_konami_map (machine, state, 3);
+ }
+ }
+}
+
+MSX_SLOT_INIT(fmpac)
+{
+ static const char sramfile[] = "fmpac.rom";
+ UINT8 *p;
+ int banks;
+
+ if (size > 0x400000)
+ {
+ logerror ("fmpac: warning: truncating rom to 4mb\n");
+ size = 0x400000;
+ }
+ banks = size / 0x4000;
+ if (size != banks * 0x4000 || (~(banks - 1) % banks))
+ {
+ logerror ("fmpac: error: must be a 2 power of 16kb\n");
+ return 1;
+ }
+
+ if (!strncmp ((char*)mem + 0x18, "PAC2", 4))
+ {
+ state->m_cart.fmpac.sram_support = 1;
+ p = auto_alloc_array(machine, UINT8, 0x4000);
+ memset (p, 0, 0x2000);
+ memset (p + 0x2000, 0xff, 0x2000);
+ state->m_cart.fmpac.mem = p;
+ }
+ else
+ {
+ state->m_cart.fmpac.sram_support = 0;
+ state->m_cart.fmpac.mem = NULL;
+ }
+
+ state->m_type = SLOT_FMPAC;
+ state->m_size = size;
+ state->m_mem = mem;
+ state->m_bank_mask = banks - 1;
+ if (!state->m_sramfile)
+ {
+ state->m_sramfile = sramfile;
+ }
+
+ return 0;
+}
+
+MSX_SLOT_RESET(fmpac)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ int i;
+
+ state->m_banks[0] = 0;
+ state->m_cart.fmpac.sram_active = 0;
+ state->m_cart.fmpac.opll_active = 0;
+ drvstate->m_opll_active = 0;
+ for (i=0; i<=state->m_bank_mask; i++)
+ {
+ state->m_mem[0x3ff6 + i * 0x4000] = 0;
+ }
+
+ /* NPW 21-Feb-2004 - Adding check for null */
+ if (state->m_cart.fmpac.mem)
+ {
+ state->m_cart.fmpac.mem[0x3ff6] = 0;
+ state->m_cart.fmpac.mem[0x3ff7] = 0;
+ }
+
+ /* IMPROVE: reset sound chip */
+}
+
+MSX_SLOT_MAP(fmpac)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ if (page == 1)
+ {
+ if (state->m_cart.fmpac.sram_active)
+ {
+ msx_cpu_setbank (machine, 3, state->m_cart.fmpac.mem);
+ msx_cpu_setbank (machine, 4, state->m_cart.fmpac.mem + 0x2000);
+ }
+ else
+ {
+ msx_cpu_setbank (machine, 3, state->m_mem + state->m_banks[0] * 0x4000);
+ msx_cpu_setbank (machine, 4, state->m_mem + state->m_banks[0] * 0x4000 + 0x2000);
+ }
+ }
+ else
+ {
+ msx_cpu_setbank (machine, page * 2 + 1, drvstate->m_empty);
+ msx_cpu_setbank (machine, page * 2 + 2, drvstate->m_empty);
+ }
+}
+
+MSX_SLOT_WRITE(fmpac)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ int i, data;
+
+ if (addr >= 0x4000 && addr < 0x6000 && state->m_cart.fmpac.sram_support)
+ {
+ if (state->m_cart.fmpac.sram_active || addr >= 0x5ffe)
+ {
+ state->m_cart.fmpac.mem[addr & 0x1fff] = val;
+ }
+
+ state->m_cart.fmpac.sram_active =
+ (state->m_cart.fmpac.mem[0x1ffe] == 0x4d &&
+ state->m_cart.fmpac.mem[0x1fff] == 0x69);
+ }
+
+ switch (addr)
+ {
+ case 0x7ff4:
+ if (state->m_cart.fmpac.opll_active)
+ {
+ ym2413_w (space->machine().device("ay8910"), 0, val);
+ }
+ break;
+ case 0x7ff5:
+ if (state->m_cart.fmpac.opll_active)
+ {
+ ym2413_w (space->machine().device("ay8910"), 1, val);
+ }
+ break;
+ case 0x7ff6:
+ data = val & 0x11;
+ for (i=0; i<=state->m_bank_mask; i++)
+ {
+ state->m_mem[0x3ff6 + i * 0x4000] = data;
+ }
+ state->m_cart.fmpac.mem[0x3ff6] = data;
+ state->m_cart.fmpac.opll_active = val & 1;
+ if ((drvstate->m_opll_active ^ val) & 1)
+ {
+ logerror ("FM-PAC: OPLL %sactivated\n", val & 1 ? "" : "de");
+ }
+ drvstate->m_opll_active = val & 1;
+ break;
+ case 0x7ff7:
+ state->m_banks[0] = val & state->m_bank_mask;
+ state->m_cart.fmpac.mem[0x3ff7] = val & state->m_bank_mask;
+ slot_fmpac_map (machine, state, 1);
+ break;
+ }
+}
+
+static const char PAC_HEADER[] = "PAC2 BACKUP DATA";
+#define PAC_HEADER_LEN (16)
+
+MSX_SLOT_LOADSRAM(fmpac)
+{
+ char buf[PAC_HEADER_LEN];
+
+ if (!state->m_cart.fmpac.sram_support)
+ {
+ logerror ("Your fmpac.rom does not support sram\n");
+ return 1;
+ }
+
+ if (!state->m_sramfile)
+ {
+ logerror ("No sram filename provided\n");
+ return 1;
+ }
+ emu_file f(machine.options().memcard_directory(), OPEN_FLAG_READ);
+ file_error filerr = f.open(state->m_sramfile);
+ if (filerr == FILERR_NONE)
+ {
+ if ((f.read(buf, PAC_HEADER_LEN) == PAC_HEADER_LEN) &&
+ !strncmp (buf, PAC_HEADER, PAC_HEADER_LEN) &&
+ f.read(state->m_cart.fmpac.mem, 0x1ffe))
+ {
+ logerror ("fmpac: info: sram loaded\n");
+ return 0;
+ }
+ else
+ {
+ logerror ("fmpac: warning: failed to load sram\n");
+ return 1;
+ }
+ }
+
+ logerror ("fmpac: warning: could not open sram file\n");
+ return 1;
+}
+
+MSX_SLOT_SAVESRAM(fmpac)
+{
+ if (!state->m_cart.fmpac.sram_support || !state->m_sramfile)
+ {
+ return 0;
+ }
+
+ emu_file f(machine.options().memcard_directory(), OPEN_FLAG_WRITE);
+ file_error filerr = f.open(state->m_sramfile);
+ if (filerr == FILERR_NONE)
+ {
+ if ((f.write(PAC_HEADER, PAC_HEADER_LEN) == PAC_HEADER_LEN) &&
+ (f.write(state->m_cart.fmpac.mem, 0x1ffe) == 0x1ffe))
+ {
+ logerror ("fmpac: info: sram saved\n");
+ return 0;
+ }
+ else
+ {
+ logerror ("fmpac: warning: sram save to file failed\n");
+ return 1;
+ }
+ }
+
+ logerror ("fmpac: warning: could not open sram file for writing\n");
+
+ return 1;
+}
+
+MSX_SLOT_INIT(superloadrunner)
+{
+ if (size != 0x20000)
+ {
+ logerror ("superloadrunner: error: rom file should be exactly "
+ "128kb\n");
+ return 1;
+ }
+ state->m_type = SLOT_SUPERLOADRUNNER;
+ state->m_mem = mem;
+ state->m_size = size;
+ state->m_start_page = page;
+ state->m_bank_mask = 7;
+
+ return 0;
+}
+
+MSX_SLOT_RESET(superloadrunner)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ drvstate->m_superloadrunner_bank = 0;
+}
+
+MSX_SLOT_MAP(superloadrunner)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ if (page == 2)
+ {
+ UINT8 *mem = state->m_mem +
+ (drvstate->m_superloadrunner_bank & state->m_bank_mask) * 0x4000;
+
+ msx_cpu_setbank (machine, 5, mem);
+ msx_cpu_setbank (machine, 6, mem + 0x2000);
+ }
+ else
+ {
+ msx_cpu_setbank (machine, page * 2 + 1, drvstate->m_empty);
+ msx_cpu_setbank (machine, page * 2 + 2, drvstate->m_empty);
+ }
+}
+
+MSX_SLOT_INIT(crossblaim)
+{
+ if (size != 0x10000)
+ {
+ logerror ("crossblaim: error: rom file should be exactly 64kb\n");
+ return 1;
+ }
+ state->m_type = SLOT_CROSS_BLAIM;
+ state->m_mem = mem;
+ state->m_size = size;
+
+ return 0;
+}
+
+MSX_SLOT_RESET(crossblaim)
+{
+ state->m_banks[0] = 1;
+}
+
+MSX_SLOT_MAP(crossblaim)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ UINT8 *mem;
+
+ /* This might look odd, but it's what happens on the real cartridge */
+
+ switch (page)
+ {
+ case 0:
+ if (state->m_banks[0] < 2){
+ mem = state->m_mem + state->m_banks[0] * 0x4000;
+ msx_cpu_setbank (machine, 1, mem);
+ msx_cpu_setbank (machine, 2, mem + 0x2000);
+ }
+ else
+ {
+ msx_cpu_setbank (machine, 1, drvstate->m_empty);
+ msx_cpu_setbank (machine, 2, drvstate->m_empty);
+ }
+ break;
+ case 1:
+ msx_cpu_setbank (machine, 3, state->m_mem);
+ msx_cpu_setbank (machine, 4, state->m_mem + 0x2000);
+ break;
+ case 2:
+ mem = state->m_mem + state->m_banks[0] * 0x4000;
+ msx_cpu_setbank (machine, 5, mem);
+ msx_cpu_setbank (machine, 6, mem + 0x2000);
+ break;
+ case 3:
+ if (state->m_banks[0] < 2){
+ mem = state->m_mem + state->m_banks[0] * 0x4000;
+ msx_cpu_setbank (machine, 7, mem);
+ msx_cpu_setbank (machine, 8, mem + 0x2000);
+ }
+ else
+ {
+ msx_cpu_setbank (machine, 7, drvstate->m_empty);
+ msx_cpu_setbank (machine, 8, drvstate->m_empty);
+ }
+ }
+}
+
+MSX_SLOT_WRITE(crossblaim)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ UINT8 block = val & 3;
+
+ if (!block) block = 1;
+ state->m_banks[0] = block;
+
+ if (drvstate->m_state[0] == state)
+ {
+ slot_crossblaim_map (machine, state, 0);
+ }
+ if (drvstate->m_state[2] == state)
+ {
+ slot_crossblaim_map (machine, state, 2);
+ }
+ if (drvstate->m_state[3] == state)
+ {
+ slot_crossblaim_map (machine, state, 3);
+ }
+}
+
+MSX_SLOT_INIT(korean80in1)
+{
+ int banks;
+
+ if (size > 0x200000)
+ {
+ logerror ("korean-80in1: warning: truncating to 2mb\n");
+ size = 0x200000;
+ }
+ banks = size / 0x2000;
+ if (size != banks * 0x2000 || (~(banks - 1) % banks))
+ {
+ logerror ("korean-80in1: error: must be a 2 power of 8kb\n");
+ return 1;
+ }
+ state->m_type = SLOT_KOREAN_80IN1;
+ state->m_mem = mem;
+ state->m_size = size;
+ state->m_bank_mask = banks - 1;
+
+ return 0;
+}
+
+MSX_SLOT_RESET(korean80in1)
+{
+ int i;
+
+ for (i=0; i<4; i++)
+ {
+ state->m_banks[i] = i;
+ }
+}
+
+MSX_SLOT_MAP(korean80in1)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ switch (page)
+ {
+ case 0:
+ msx_cpu_setbank (machine, 1, drvstate->m_empty);
+ msx_cpu_setbank (machine, 2, drvstate->m_empty);
+ break;
+ case 1:
+ msx_cpu_setbank (machine, 3, state->m_mem + state->m_banks[0] * 0x2000);
+ msx_cpu_setbank (machine, 4, state->m_mem + state->m_banks[1] * 0x2000);
+ break;
+ case 2:
+ msx_cpu_setbank (machine, 5, state->m_mem + state->m_banks[2] * 0x2000);
+ msx_cpu_setbank (machine, 6, state->m_mem + state->m_banks[3] * 0x2000);
+ break;
+ case 3:
+ msx_cpu_setbank (machine, 7, drvstate->m_empty);
+ msx_cpu_setbank (machine, 8, drvstate->m_empty);
+ }
+}
+
+MSX_SLOT_WRITE(korean80in1)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ int bank;
+
+ if (addr >= 0x4000 && addr < 0x4004)
+ {
+ bank = addr & 3;
+
+ state->m_banks[bank] = val & state->m_bank_mask;
+ if (bank <= 1)
+ {
+ slot_korean80in1_map (machine, state, 1);
+ }
+ else if (drvstate->m_state[2] == state)
+ {
+ slot_korean80in1_map (machine, state, 2);
+ }
+ }
+}
+
+MSX_SLOT_INIT(korean90in1)
+{
+ int banks;
+
+ if (size > 0x100000)
+ {
+ logerror ("korean-90in1: warning: truncating to 1mb\n");
+ size = 0x100000;
+ }
+ banks = size / 0x4000;
+ if (size != banks * 0x4000 || (~(banks - 1) % banks))
+ {
+ logerror ("korean-90in1: error: must be a 2 power of 16kb\n");
+ return 1;
+ }
+ state->m_type = SLOT_KOREAN_90IN1;
+ state->m_mem = mem;
+ state->m_size = size;
+ state->m_bank_mask = banks - 1;
+
+ return 0;
+}
+
+MSX_SLOT_RESET(korean90in1)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ drvstate->m_korean90in1_bank = 0;
+}
+
+MSX_SLOT_MAP(korean90in1)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ UINT8 *mem;
+ UINT8 mask = (drvstate->m_korean90in1_bank & 0xc0) == 0x80 ? 0x3e : 0x3f;
+ mem = state->m_mem +
+ ((drvstate->m_korean90in1_bank & mask) & state->m_bank_mask) * 0x4000;
+
+ switch (page)
+ {
+ case 0:
+ msx_cpu_setbank (machine, 1, drvstate->m_empty);
+ msx_cpu_setbank (machine, 2, drvstate->m_empty);
+ break;
+ case 1:
+ msx_cpu_setbank (machine, 3, mem);
+ msx_cpu_setbank (machine, 4, mem + 0x2000);
+ break;
+ case 2:
+ switch (drvstate->m_korean90in1_bank & 0xc0)
+ {
+ case 0x80: /* 32 kb mode */
+ mem += 0x4000;
+ default: /* ie. 0x00 and 0x40: same memory as page 1 */
+ msx_cpu_setbank (machine, 5, mem);
+ msx_cpu_setbank (machine, 6, mem + 0x2000);
+ break;
+ case 0xc0: /* same memory as page 1, but swap lower/upper 8kb */
+ msx_cpu_setbank (machine, 5, mem + 0x2000);
+ msx_cpu_setbank (machine, 6, mem);
+ break;
+ }
+ break;
+ case 3:
+ msx_cpu_setbank (machine, 7, drvstate->m_empty);
+ msx_cpu_setbank (machine, 8, drvstate->m_empty);
+ }
+}
+
+MSX_SLOT_INIT(korean126in1)
+{
+ int banks;
+
+ if (size > 0x400000)
+ {
+ logerror ("korean-126in1: warning: truncating to 4mb\n");
+ size = 0x400000;
+ }
+ banks = size / 0x4000;
+ if (size != banks * 0x4000 || (~(banks - 1) % banks))
+ {
+ logerror ("korean-126in1: error: must be a 2 power of 16kb\n");
+ return 1;
+ }
+
+ state->m_type = SLOT_KOREAN_126IN1;
+ state->m_mem = mem;
+ state->m_size = size;
+ state->m_bank_mask = banks - 1;
+
+ return 0;
+}
+
+MSX_SLOT_RESET(korean126in1)
+{
+ int i;
+
+ for (i=0; i<2; i++) state->m_banks[i] = i;
+}
+
+MSX_SLOT_MAP(korean126in1)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ UINT8 *mem;
+
+ switch (page)
+ {
+ case 0:
+ msx_cpu_setbank (machine, 1, drvstate->m_empty);
+ msx_cpu_setbank (machine, 2, drvstate->m_empty);
+ break;
+ case 1:
+ mem = state->m_mem + state->m_banks[0] * 0x4000;
+ msx_cpu_setbank (machine, 3, mem);
+ msx_cpu_setbank (machine, 4, mem + 0x2000);
+ break;
+ case 2:
+ mem = state->m_mem + state->m_banks[1] * 0x4000;
+ msx_cpu_setbank (machine, 5, mem);
+ msx_cpu_setbank (machine, 6, mem + 0x2000);
+ break;
+ case 3:
+ msx_cpu_setbank (machine, 7, drvstate->m_empty);
+ msx_cpu_setbank (machine, 8, drvstate->m_empty);
+ }
+}
+
+MSX_SLOT_WRITE(korean126in1)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ if (addr >= 0x4000 && addr < 0x4002)
+ {
+ int bank = addr & 1;
+ state->m_banks[bank] = val & state->m_bank_mask;
+ if (bank == 0)
+ {
+ slot_korean126in1_map (machine, state, 1);
+ }
+ else if (drvstate->m_state[2] == state)
+ {
+ slot_korean126in1_map (machine, state, 2);
+ }
+ }
+}
+
+MSX_SLOT_INIT(soundcartridge)
+{
+ UINT8 *p;
+
+ p = auto_alloc_array(machine, UINT8, 0x20000);
+ memset (p, 0, 0x20000);
+
+ state->m_mem = p;
+ state->m_size = 0x20000;
+ state->m_bank_mask = 15;
+ state->m_type = SLOT_SOUNDCARTRIDGE;
+
+ return 0;
+}
+
+MSX_SLOT_RESET(soundcartridge)
+{
+ int i;
+
+ for (i=0; i<4; i++)
+ {
+ state->m_banks[i] = i;
+ state->m_cart.sccp.ram_mode[i] = 0;
+ state->m_cart.sccp.banks_saved[i] = i;
+ }
+ state->m_cart.sccp.mode = 0;
+ state->m_cart.sccp.scc_active = 0;
+ state->m_cart.sccp.sccp_active = 0;
+}
+
+static READ8_HANDLER (soundcartridge_scc)
+{
+ msx_state *state = space->machine().driver_data<msx_state>();
+ int reg;
+
+
+ if (offset >= 0x7e0)
+ {
+ return state->m_state[2]->m_mem[
+ state->m_state[2]->m_banks[2] * 0x2000 + 0x1800 + offset];
+ }
+
+ reg = offset & 0xff;
+
+ if (reg < 0x80)
+ {
+ return k051649_waveform_r (space->machine().device("k051649"), reg);
+ }
+ else if (reg < 0xa0)
+ {
+ /* nothing */
+ }
+ else if (reg < 0xc0)
+ {
+ /* read wave 5 */
+ return k051649_waveform_r (space->machine().device("k051649"), 0x80 + (reg & 0x1f));
+ }
+ else if (reg < 0xe0)
+ {
+ return k051649_test_r (space->machine().device("k051649"), reg);
+ }
+
+ return 0xff;
+}
+
+static READ8_HANDLER (soundcartridge_sccp)
+{
+ msx_state *state = space->machine().driver_data<msx_state>();
+ int reg;
+
+ if (offset >= 0x7e0)
+ {
+ return state->m_state[2]->m_mem[
+ state->m_state[2]->m_banks[3] * 0x2000 + 0x1800 + offset];
+ }
+
+ reg = offset & 0xff;
+
+ if (reg < 0xa0)
+ {
+ return k052539_waveform_r (space->machine().device("k051649"), reg);
+ }
+ else if (reg >= 0xc0 && reg < 0xe0)
+ {
+ return k051649_test_r (space->machine().device("k051649"), reg);
+ }
+
+ return 0xff;
+}
+
+MSX_SLOT_MAP(soundcartridge)
+{
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ switch (page)
+ {
+ case 0:
+ msx_cpu_setbank (machine, 1, state->m_mem + state->m_banks[2] * 0x2000);
+ msx_cpu_setbank (machine, 2, state->m_mem + state->m_banks[3] * 0x2000);
+ break;
+ case 1:
+ msx_cpu_setbank (machine, 3, state->m_mem + state->m_banks[0] * 0x2000);
+ msx_cpu_setbank (machine, 4, state->m_mem + state->m_banks[1] * 0x2000);
+ break;
+ case 2:
+ msx_cpu_setbank (machine, 5, state->m_mem + state->m_banks[2] * 0x2000);
+ msx_cpu_setbank (machine, 6, state->m_mem + state->m_banks[3] * 0x2000);
+ if (state->m_cart.sccp.scc_active) {
+ space->install_legacy_read_handler(0x9800, 0x9fff, FUNC(soundcartridge_scc));
+ } else {
+ space->install_read_bank(0x9800, 0x9fff, "bank7");
+ }
+ if (state->m_cart.sccp.scc_active) {
+ space->install_legacy_read_handler(0xb800, 0xbfff, FUNC(soundcartridge_sccp));
+ } else {
+ space->install_read_bank(0xb800, 0xbfff, "bank9");
+ }
+ break;
+ case 3:
+ msx_cpu_setbank (machine, 7, state->m_mem + state->m_banks[0] * 0x2000);
+ msx_cpu_setbank (machine, 8, state->m_mem + state->m_banks[1] * 0x2000);
+ break;
+ }
+}
+
+MSX_SLOT_WRITE(soundcartridge)
+{
+ msx_state *drvstate = machine.driver_data<msx_state>();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ int i;
+
+ if (addr < 0x4000)
+ {
+ return;
+ }
+ else if (addr < 0x6000)
+ {
+ if (state->m_cart.sccp.ram_mode[0])
+ {
+ state->m_mem[state->m_banks[0] * 0x2000 + (addr & 0x1fff)] = val;
+ }
+ else if (addr >= 0x5000 && addr < 0x5800)
+ {
+ state->m_banks[0] = val & state->m_bank_mask;
+ state->m_cart.sccp.banks_saved[0] = val;
+ slot_soundcartridge_map (machine, state, 1);
+ if (drvstate->m_state[3] == state)
+ {
+ slot_soundcartridge_map (machine, state, 3);
+ }
+ }
+ }
+ else if (addr < 0x8000)
+ {
+ if (state->m_cart.sccp.ram_mode[1])
+ {
+ state->m_mem[state->m_banks[1] * 0x2000 + (addr & 0x1fff)] = val;
+ }
+ else if (addr >= 0x7000 && addr < 0x7800)
+ {
+ state->m_banks[1] = val & state->m_bank_mask;
+ state->m_cart.sccp.banks_saved[1] = val;
+ if (drvstate->m_state[3] == state)
+ {
+ slot_soundcartridge_map (machine, state, 3);
+ }
+ slot_soundcartridge_map (machine, state, 1);
+ }
+ }
+ else if (addr < 0xa000)
+ {
+ if (state->m_cart.sccp.ram_mode[2])
+ {
+ state->m_mem[state->m_banks[2] * 0x2000 + (addr & 0x1fff)] = val;
+ }
+ else if (addr >= 0x9000 && addr < 0x9800)
+ {
+ state->m_banks[2] = val & state->m_bank_mask;
+ state->m_cart.sccp.banks_saved[2] = val;
+ state->m_cart.sccp.scc_active =
+ (((val & 0x3f) == 0x3f) && !(state->m_cart.sccp.mode & 0x20));
+
+ slot_soundcartridge_map (machine, state, 2);
+ if (drvstate->m_state[0] == state)
+ {
+ slot_soundcartridge_map (machine, state, 0);
+ }
+ }
+ else if (addr >= 0x9800 && state->m_cart.sccp.scc_active)
+ {
+ device_t *k051649 = space->machine().device("k051649");
+ int offset = addr & 0xff;
+
+ if (offset < 0x80)
+ {
+ k051649_waveform_w (k051649, offset, val);
+ }
+ else if (offset < 0xa0)
+ {
+ offset &= 0xf;
+
+ if (offset < 0xa)
+ {
+ k051649_frequency_w (k051649, offset, val);
+ }
+ else if (offset < 0x0f)
+ {
+ k051649_volume_w (k051649, offset - 0xa, val);
+ }
+ else if (offset == 0x0f)
+ {
+ k051649_keyonoff_w (k051649, 0, val);
+ }
+ }
+ else if (offset < 0xe0)
+ {
+ k051649_test_w (k051649, offset, val);
+ }
+ }
+ }
+ else if (addr < 0xbffe)
+ {
+ if (state->m_cart.sccp.ram_mode[3])
+ {
+ state->m_mem[state->m_banks[3] * 0x2000 + (addr & 0x1fff)] = val;
+ }
+ else if (addr >= 0xb000 && addr < 0xb800)
+ {
+ state->m_cart.sccp.banks_saved[3] = val;
+ state->m_banks[3] = val & state->m_bank_mask;
+ state->m_cart.sccp.sccp_active =
+ (val & 0x80) && (state->m_cart.sccp.mode & 0x20);
+ slot_soundcartridge_map (machine, state, 2);
+ if (drvstate->m_state[0] == state)
+ {
+ slot_soundcartridge_map (machine, state, 0);
+ }
+ }
+ else if (addr >= 0xb800 && state->m_cart.sccp.sccp_active)
+ {
+ device_t *k051649 = space->machine().device("k051649");
+ int offset = addr & 0xff;
+
+ if (offset < 0xa0)
+ {
+ k052539_waveform_w (k051649, offset, val);
+ }
+ else if (offset < 0xc0)
+ {
+ offset &= 0x0f;
+
+ if (offset < 0x0a)
+ {
+ k051649_frequency_w (k051649, offset, val);
+ }
+ else if (offset < 0x0f)
+ {
+ k051649_volume_w (k051649, offset - 0x0a, val);
+ }
+ else if (offset == 0x0f)
+ {
+ k051649_keyonoff_w (k051649, 0, val);
+ }
+ }
+ else if (offset < 0xe0)
+ {
+ k051649_test_w (k051649, offset, val);
+ }
+ }
+ }
+ else if (addr < 0xc000)
+ {
+ /* write to mode register */
+ if ((state->m_cart.sccp.mode ^ val) & 0x20)
+ {
+ logerror ("soundcartrige: changed to %s mode\n",
+ val & 0x20 ? "scc+" : "scc");
+ }
+ state->m_cart.sccp.mode = val;
+ if (val & 0x10)
+ {
+ /* all ram mode */
+ for (i=0; i<4; i++)
+ {
+ state->m_cart.sccp.ram_mode[i] = 1;
+ }
+ }
+ else
+ {
+ state->m_cart.sccp.ram_mode[0] = val & 1;
+ state->m_cart.sccp.ram_mode[1] = val & 2;
+ state->m_cart.sccp.ram_mode[2] = (val & 4) && (val & 0x20);
+ state->m_cart.sccp.ram_mode[3] = 0;
+
+ }
+
+ state->m_cart.sccp.scc_active =
+ (((state->m_cart.sccp.banks_saved[2] & 0x3f) == 0x3f) &&
+ !(val & 0x20));
+
+ state->m_cart.sccp.sccp_active =
+ ((state->m_cart.sccp.banks_saved[3] & 0x80) && (val & 0x20));
+
+ slot_soundcartridge_map (machine, state, 2);
+ }
+}
+
+MSX_SLOT_START
+ MSX_SLOT_ROM (SLOT_EMPTY, empty)
+ MSX_SLOT (SLOT_MSXDOS2, msxdos2)
+ MSX_SLOT (SLOT_KONAMI_SCC, konami_scc)
+ MSX_SLOT (SLOT_KONAMI, konami)
+ MSX_SLOT (SLOT_ASCII8, ascii8)
+ MSX_SLOT (SLOT_ASCII16, ascii16)
+ MSX_SLOT_SRAM (SLOT_GAMEMASTER2, gmaster2)
+ MSX_SLOT_SRAM (SLOT_ASCII8_SRAM, ascii8_sram)
+ MSX_SLOT_SRAM (SLOT_ASCII16_SRAM, ascii16_sram)
+ MSX_SLOT (SLOT_RTYPE, rtype)
+ MSX_SLOT (SLOT_MAJUTSUSHI, majutsushi)
+ MSX_SLOT_SRAM (SLOT_FMPAC, fmpac)
+ MSX_SLOT_ROM (SLOT_SUPERLOADRUNNER, superloadrunner)
+ MSX_SLOT (SLOT_SYNTHESIZER, synthesizer)
+ MSX_SLOT (SLOT_CROSS_BLAIM, crossblaim)
+ MSX_SLOT (SLOT_DISK_ROM, diskrom)
+ MSX_SLOT (SLOT_KOREAN_80IN1, korean80in1)
+ MSX_SLOT (SLOT_KOREAN_126IN1, korean126in1)
+ MSX_SLOT_ROM (SLOT_KOREAN_90IN1, korean90in1)
+ MSX_SLOT (SLOT_SOUNDCARTRIDGE, soundcartridge)
+ MSX_SLOT_ROM (SLOT_ROM, rom)
+ MSX_SLOT_RAM (SLOT_RAM, ram)
+ MSX_SLOT_RAM (SLOT_RAM_MM, rammm)
+ MSX_SLOT_NULL (SLOT_CARTRIDGE1)
+ MSX_SLOT_NULL (SLOT_CARTRIDGE2)
+ MSX_SLOT (SLOT_DISK_ROM2, diskrom2)
+MSX_SLOT_END
+
diff --git a/src/mess/machine/mtx.c b/src/mess/machine/mtx.c
new file mode 100644
index 00000000000..aeb787fc7d6
--- /dev/null
+++ b/src/mess/machine/mtx.c
@@ -0,0 +1,400 @@
+/*************************************************************************
+
+ machine/mtx.c
+
+ Memotech MTX 500, MTX 512 and RS 128
+
+**************************************************************************/
+
+#include "emu.h"
+#include "formats/imageutl.h"
+#include "includes/mtx.h"
+#include "cpu/z80/z80.h"
+#include "imagedev/cassette.h"
+#include "machine/ram.h"
+#include "imagedev/snapquik.h"
+#include "machine/ctronics.h"
+#include "machine/z80ctc.h"
+#include "machine/z80dart.h"
+#include "video/tms9928a.h"
+#include "sound/sn76496.h"
+
+/***************************************************************************
+ READ/WRITE HANDLERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ mtx_strobe_r - centronics strobe
+-------------------------------------------------*/
+
+READ8_DEVICE_HANDLER( mtx_strobe_r )
+{
+ centronics_device *centronics = device->machine().device<centronics_device>(CENTRONICS_TAG);
+ /* set STROBE low */
+ centronics->strobe_w(FALSE);
+
+ return 0xff;
+}
+
+/*-------------------------------------------------
+ mtx_bankswitch_w - bankswitch
+-------------------------------------------------*/
+
+/*
+ There are two memory models on the MTX, the standard one and a
+ CBM mode. In standard mode, the memory map is defined as:
+
+ 0x0000 - 0x1fff OSROM
+ 0x2000 - 0x3fff Paged ROM
+ 0x4000 - 0x7fff Paged RAM
+ 0x8000 - 0xbfff Paged RAM
+ 0xc000 - 0xffff RAM
+
+ Banks are selected by output port 0. Bits 0-3 define the RAM page
+ and bits 4-6 the ROM page.
+
+ CBM mode is selected by bit 7 of output port 0. ROM is replaced
+ by RAM in this mode.
+*/
+
+static void bankswitch(running_machine &machine, UINT8 data)
+{
+ /*
+
+ bit description
+
+ 0 P0
+ 1 P1
+ 2 P2
+ 3 P3
+ 4 R0
+ 5 R1
+ 6 R2
+ 7 RELCPMH
+
+ */
+ mtx_state *state = machine.driver_data<mtx_state>();
+ address_space *program = machine.device(Z80_TAG)->memory().space(AS_PROGRAM);
+ ram_device *messram = machine.device<ram_device>(RAM_TAG);
+
+// UINT8 cbm_mode = data >> 7 & 0x01;
+ UINT8 rom_page = data >> 4 & 0x07;
+ UINT8 ram_page = data >> 0 & 0x0f;
+
+ /* set rom bank (switches between basic and assembler rom or cartridges) */
+ state->membank("bank2")->set_entry(rom_page);
+
+ /* set ram bank, for invalid pages a nop-handler will be installed */
+ if (ram_page >= messram->size()/0x8000)
+ {
+ program->nop_readwrite(0x4000, 0x7fff);
+ program->nop_readwrite(0x8000, 0xbfff);
+ }
+ else if (ram_page + 1 == messram->size()/0x8000)
+ {
+ program->nop_readwrite(0x4000, 0x7fff);
+ program->install_readwrite_bank(0x8000, 0xbfff, "bank4");
+ state->membank("bank4")->set_entry(ram_page);
+ }
+ else
+ {
+ program->install_readwrite_bank(0x4000, 0x7fff, "bank3");
+ program->install_readwrite_bank(0x8000, 0xbfff, "bank4");
+ state->membank("bank3")->set_entry(ram_page);
+ state->membank("bank4")->set_entry(ram_page);
+ }
+}
+
+WRITE8_MEMBER(mtx_state::mtx_bankswitch_w)
+{
+ bankswitch(machine(), data);
+}
+
+/*-------------------------------------------------
+ mtx_sound_strobe_r - sound strobe
+-------------------------------------------------*/
+
+READ8_DEVICE_HANDLER( mtx_sound_strobe_r )
+{
+ mtx_state *state = device->machine().driver_data<mtx_state>();
+
+ sn76496_w(device, 0, state->m_sound_latch);
+
+ return 0xff;
+}
+
+/*-------------------------------------------------
+ mtx_sound_latch_w - sound latch write
+-------------------------------------------------*/
+
+WRITE8_MEMBER(mtx_state::mtx_sound_latch_w)
+{
+
+ m_sound_latch = data;
+}
+
+/*-------------------------------------------------
+ mtx_cst_w - cassette write
+-------------------------------------------------*/
+
+WRITE8_DEVICE_HANDLER( mtx_cst_w )
+{
+ dynamic_cast<cassette_image_device *>(device)->output( BIT(data, 0) ? -1 : 1);
+}
+
+/*-------------------------------------------------
+ mtx_prt_r - centronics status
+-------------------------------------------------*/
+
+READ8_DEVICE_HANDLER( mtx_prt_r )
+{
+ centronics_device *centronics = device->machine().device<centronics_device>(CENTRONICS_TAG);
+
+ /*
+
+ bit description
+
+ 0 BUSY
+ 1 ERROR
+ 2 PE
+ 3 SLCT
+ 4
+ 5
+ 6
+ 7
+
+ */
+
+ UINT8 data = 0;
+
+ /* reset STROBE to high */
+ centronics->strobe_w( TRUE);
+
+ /* busy */
+ data |= centronics->busy_r() << 0;
+
+ /* fault */
+ data |= centronics->fault_r() << 1;
+
+ /* paper empty */
+ data |= !centronics->pe_r() << 2;
+
+ /* select */
+ data |= centronics->vcc_r() << 3;
+
+ return data;
+}
+
+/*-------------------------------------------------
+ mtx_sense_w - keyboard sense write
+-------------------------------------------------*/
+
+WRITE8_MEMBER(mtx_state::mtx_sense_w)
+{
+
+ m_key_sense = data;
+}
+
+/*-------------------------------------------------
+ mtx_key_lo_r - keyboard low read
+-------------------------------------------------*/
+
+READ8_MEMBER(mtx_state::mtx_key_lo_r)
+{
+
+ UINT8 data = 0xff;
+
+ if (!(m_key_sense & 0x01)) data &= ioport("ROW0")->read();
+ if (!(m_key_sense & 0x02)) data &= ioport("ROW1")->read();
+ if (!(m_key_sense & 0x04)) data &= ioport("ROW2")->read();
+ if (!(m_key_sense & 0x08)) data &= ioport("ROW3")->read();
+ if (!(m_key_sense & 0x10)) data &= ioport("ROW4")->read();
+ if (!(m_key_sense & 0x20)) data &= ioport("ROW5")->read();
+ if (!(m_key_sense & 0x40)) data &= ioport("ROW6")->read();
+ if (!(m_key_sense & 0x80)) data &= ioport("ROW7")->read();
+
+ return data;
+}
+
+/*-------------------------------------------------
+ mtx_key_lo_r - keyboard high read
+-------------------------------------------------*/
+
+READ8_MEMBER(mtx_state::mtx_key_hi_r)
+{
+
+ UINT8 data = ioport("country_code")->read();
+
+ if (!(m_key_sense & 0x01)) data &= ioport("ROW0")->read() >> 8;
+ if (!(m_key_sense & 0x02)) data &= ioport("ROW1")->read() >> 8;
+ if (!(m_key_sense & 0x04)) data &= ioport("ROW2")->read() >> 8;
+ if (!(m_key_sense & 0x08)) data &= ioport("ROW3")->read() >> 8;
+ if (!(m_key_sense & 0x10)) data &= ioport("ROW4")->read() >> 8;
+ if (!(m_key_sense & 0x20)) data &= ioport("ROW5")->read() >> 8;
+ if (!(m_key_sense & 0x40)) data &= ioport("ROW6")->read() >> 8;
+ if (!(m_key_sense & 0x80)) data &= ioport("ROW7")->read() >> 8;
+
+ return data;
+}
+
+/*-------------------------------------------------
+ hrx_address_w - HRX video RAM address
+-------------------------------------------------*/
+
+WRITE8_MEMBER(mtx_state::hrx_address_w)
+{
+ if (offset)
+ {
+ /*
+
+ bit description
+
+ 0 A8
+ 1 A9
+ 2 A10
+ 3
+ 4
+ 5 attribute memory write enable
+ 6 ASCII memory write enable
+ 7 cycle (0=read/1=write)
+
+ */
+ }
+ else
+ {
+ /*
+
+ bit description
+
+ 0 A0
+ 1 A1
+ 2 A2
+ 3 A3
+ 4 A4
+ 5 A5
+ 6 A6
+ 7 A7
+
+ */
+ }
+}
+
+/*-------------------------------------------------
+ hrx_data_r - HRX data read
+-------------------------------------------------*/
+
+READ8_MEMBER(mtx_state::hrx_data_r)
+{
+ return 0;
+}
+
+/*-------------------------------------------------
+ hrx_data_w - HRX data write
+-------------------------------------------------*/
+
+WRITE8_MEMBER(mtx_state::hrx_data_w)
+{
+}
+
+/*-------------------------------------------------
+ hrx_attr_r - HRX attribute read
+-------------------------------------------------*/
+
+READ8_MEMBER(mtx_state::hrx_attr_r)
+{
+ return 0;
+}
+
+/*-------------------------------------------------
+ hrx_attr_r - HRX attribute write
+-------------------------------------------------*/
+
+WRITE8_MEMBER(mtx_state::hrx_attr_w)
+{
+ /*
+
+ bit description
+
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+
+ */
+}
+
+/***************************************************************************
+ SNAPSHOT
+***************************************************************************/
+
+SNAPSHOT_LOAD( mtx )
+{
+ address_space *program = image.device().machine().device(Z80_TAG)->memory().space(AS_PROGRAM);
+
+ UINT8 header[18];
+ UINT16 addr;
+
+ /* get the header */
+ image.fread( &header, sizeof(header));
+
+ if (header[0] == 0xff)
+ {
+ /* long header */
+ addr = pick_integer_le(header, 16, 2);
+ void *ptr = program->get_write_ptr(addr);
+ image.fread( ptr, 599);
+ ptr = program->get_write_ptr(0xc000);
+ image.fread( ptr, snapshot_size - 599 - 18);
+ }
+ else
+ {
+ /* short header */
+ addr = pick_integer_le(header, 0, 2);
+ image.fseek(4, SEEK_SET);
+ void *ptr = program->get_write_ptr(addr);
+ image.fread( ptr, 599);
+ ptr = program->get_write_ptr(0xc000);
+ image.fread( ptr, snapshot_size - 599 - 4);
+ }
+
+ return IMAGE_INIT_PASS;
+}
+
+/***************************************************************************
+ MACHINE INITIALIZATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ MACHINE_START( mtx512 )
+-------------------------------------------------*/
+
+MACHINE_START( mtx512 )
+{
+ mtx_state *state = machine.driver_data<mtx_state>();
+ ram_device *messram = machine.device<ram_device>(RAM_TAG);
+
+ /* find devices */
+ state->m_z80ctc = machine.device<z80ctc_device>(Z80CTC_TAG);
+ state->m_z80dart = machine.device(Z80DART_TAG);
+ state->m_cassette = machine.device<cassette_image_device>(CASSETTE_TAG);
+
+ /* configure memory */
+ state->membank("bank1")->set_base(machine.root_device().memregion("user1")->base());
+ state->membank("bank2")->configure_entries(0, 8, state->memregion("user2")->base(), 0x2000);
+ state->membank("bank3")->configure_entries(0, messram->size()/0x4000/2, messram->pointer(), 0x4000);
+ state->membank("bank4")->configure_entries(0, messram->size()/0x4000/2, messram->pointer() + messram->size()/2, 0x4000);
+}
+
+/*-------------------------------------------------
+ MACHINE_RESET( mtx512 )
+-------------------------------------------------*/
+
+MACHINE_RESET( mtx512 )
+{
+ /* bank switching */
+ bankswitch(machine, 0);
+}
diff --git a/src/mess/machine/mz700.c b/src/mess/machine/mz700.c
new file mode 100644
index 00000000000..1594c12ae82
--- /dev/null
+++ b/src/mess/machine/mz700.c
@@ -0,0 +1,679 @@
+/******************************************************************************
+ * Sharp MZ700
+ *
+ * machine driver
+ *
+ * Juergen Buchmueller <pullmoll@t-online.de>, Jul 2000
+ *
+ * Reference: http://sharpmz.computingmuseum.com
+ *
+ *****************************************************************************/
+
+#include "emu.h"
+#include "includes/mz700.h"
+#include "cpu/z80/z80.h"
+#include "machine/pit8253.h"
+#include "machine/i8255.h"
+#include "machine/z80pio.h"
+#include "machine/74145.h"
+#include "machine/ctronics.h"
+#include "sound/speaker.h"
+#include "imagedev/cassette.h"
+#include "machine/ram.h"
+
+#ifndef VERBOSE
+#define VERBOSE 1
+#endif
+
+#define LOG(N,M,A,mac) \
+ do { \
+ if(VERBOSE>=N) \
+ { \
+ if( M ) \
+ logerror("%11.6f: %-24s",mac.time().as_double(), (const char*)M ); \
+ logerror A; \
+ } \
+ } while (0)
+
+
+static READ8_DEVICE_HANDLER ( pio_port_b_r );
+static READ8_DEVICE_HANDLER ( pio_port_c_r );
+static WRITE8_DEVICE_HANDLER ( pio_port_a_w );
+static WRITE8_DEVICE_HANDLER ( pio_port_c_w );
+
+I8255_INTERFACE( mz700_ppi8255_interface )
+{
+ DEVCB_NULL,
+ DEVCB_DEVICE_HANDLER("ls145", pio_port_a_w),
+ DEVCB_DEVICE_HANDLER("ls145", pio_port_b_r),
+ DEVCB_NULL,
+ DEVCB_DEVICE_HANDLER("ppi8255", pio_port_c_r),
+ DEVCB_DEVICE_HANDLER("ppi8255", pio_port_c_w)
+};
+
+
+static WRITE_LINE_DEVICE_HANDLER( pit_out0_changed );
+static WRITE_LINE_DEVICE_HANDLER( pit_irq_2 );
+
+const struct pit8253_config mz700_pit8253_config =
+{
+ {
+ /* clockin gate callback */
+ { XTAL_17_73447MHz/20, DEVCB_NULL, DEVCB_DEVICE_LINE("pit8253", pit_out0_changed) },
+ { 15611.0, DEVCB_LINE_VCC, DEVCB_DEVICE_LINE("pit8253", pit8253_clk2_w) },
+ { 0, DEVCB_LINE_VCC, DEVCB_DEVICE_LINE("pit8253", pit_irq_2) },
+ }
+};
+
+const struct pit8253_config mz800_pit8253_config =
+{
+ {
+ /* clockin gate callback */
+ { XTAL_17_73447MHz/16, DEVCB_NULL, DEVCB_DEVICE_LINE("pit8253", pit_out0_changed) },
+ { 15611.0, DEVCB_LINE_VCC, DEVCB_DEVICE_LINE("pit8253", pit8253_clk2_w) },
+ { 0, DEVCB_LINE_VCC, DEVCB_DEVICE_LINE("pit8253", pit_irq_2) },
+ }
+};
+
+
+/***************************************************************************
+ INITIALIZATIoN
+***************************************************************************/
+
+DRIVER_INIT_MEMBER(mz_state,mz700)
+{
+ m_mz700 = TRUE;
+ m_mz700_mode = TRUE;
+
+ m_videoram = auto_alloc_array(machine(), UINT8, 0x800);
+ m_colorram = auto_alloc_array(machine(), UINT8, 0x800);
+}
+
+DRIVER_INIT_MEMBER(mz_state,mz800)
+{
+ m_mz700 = FALSE;
+ m_mz700_mode = FALSE;
+
+ /* video ram */
+ m_videoram = auto_alloc_array(machine(), UINT8, 0x4000);
+ m_colorram = m_videoram + 0x800;
+
+ /* character generator ram */
+ m_cgram = auto_alloc_array(machine(), UINT8, 0x1000);
+}
+
+MACHINE_START( mz700 )
+{
+ mz_state *mz = machine.driver_data<mz_state>();
+
+ mz->m_pit = machine.device("pit8253");
+ mz->m_ppi = machine.device<i8255_device>("ppi8255");
+
+ /* reset memory map to defaults */
+ mz->mz700_bank_4_w(*machine.device("maincpu")->memory().space(AS_PROGRAM), 0, 0);
+}
+
+
+/***************************************************************************
+ MMIO
+***************************************************************************/
+
+READ8_MEMBER(mz_state::mz700_e008_r)
+{
+ UINT8 data = 0;
+
+ data |= m_other_timer;
+ data |= ioport("JOY")->read();
+ data |= machine().primary_screen->hblank() << 7;
+
+ LOG(1, "mz700_e008_r", ("%02X\n", data), machine());
+
+ return data;
+}
+
+WRITE8_MEMBER(mz_state::mz700_e008_w)
+{
+ pit8253_gate0_w(m_pit, BIT(data, 0));
+}
+
+
+/***************************************************************************
+ BANK SWITCHING
+***************************************************************************/
+
+READ8_MEMBER(mz_state::mz800_bank_0_r)
+{
+ UINT8 *videoram = m_videoram;
+ address_space *spc = machine().device("maincpu")->memory().space(AS_PROGRAM);
+
+ /* switch in cgrom */
+ spc->install_read_bank(0x1000, 0x1fff, "bank2");
+ spc->nop_write(0x1000, 0x1fff);
+ membank("bank2")->set_base(machine().root_device().memregion("monitor")->base() + 0x1000);
+
+ if (m_mz700_mode)
+ {
+ /* cgram from 0xc000 to 0xcfff */
+ spc->install_read_bank(0xc000, 0xcfff, "bank6");
+ spc->install_write_handler(0xc000, 0xcfff, write8_delegate(FUNC(mz_state::mz800_cgram_w),this));
+ membank("bank6")->set_base(m_cgram);
+ }
+ else
+ {
+ if (m_hires_mode)
+ {
+ /* vram from 0x8000 to 0xbfff */
+ spc->install_readwrite_bank(0x8000, 0xbfff, "bank4");
+ membank("bank4")->set_base(videoram);
+ }
+ else
+ {
+ /* vram from 0x8000 to 0x9fff */
+ spc->install_readwrite_bank(0x8000, 0x9fff, "bank4");
+ membank("bank4")->set_base(videoram);
+
+ /* ram from 0xa000 to 0xbfff */
+ spc->install_readwrite_bank(0xa000, 0xbfff, "bank5");
+ membank("bank5")->set_base(machine().device<ram_device>(RAM_TAG)->pointer() + 0xa000);
+ }
+ }
+
+ return 0xff;
+}
+
+WRITE8_MEMBER(mz_state::mz700_bank_0_w)
+{
+ address_space *spc = machine().device("maincpu")->memory().space(AS_PROGRAM);
+
+ spc->install_readwrite_bank(0x0000, 0x0fff, "bank1");
+ membank("bank1")->set_base(machine().device<ram_device>(RAM_TAG)->pointer());
+}
+
+WRITE8_MEMBER(mz_state::mz800_bank_0_w)
+{
+ address_space *spc = machine().device("maincpu")->memory().space(AS_PROGRAM);
+
+ spc->install_readwrite_bank(0x0000, 0x7fff, "bank1");
+ membank("bank1")->set_base(machine().device<ram_device>(RAM_TAG)->pointer());
+}
+
+READ8_MEMBER(mz_state::mz800_bank_1_r)
+{
+ address_space *spc = machine().device("maincpu")->memory().space(AS_PROGRAM);
+
+ /* switch in ram from 0x1000 to 0x1fff */
+ spc->install_readwrite_bank(0x1000, 0x1fff, "bank2");
+ membank("bank2")->set_base(machine().device<ram_device>(RAM_TAG)->pointer() + 0x1000);
+
+ if (m_mz700_mode)
+ {
+ /* ram from 0xc000 to 0xcfff */
+ spc->install_readwrite_bank(0xc000, 0xcfff, "bank6");
+ membank("bank6")->set_base(machine().device<ram_device>(RAM_TAG)->pointer() + 0xc000);
+ }
+ else
+ {
+ /* ram from 0x8000 to 0xbfff */
+ spc->install_readwrite_bank(0x8000, 0xbfff, "bank4");
+ membank("bank4")->set_base(machine().device<ram_device>(RAM_TAG)->pointer() + 0x8000);
+ }
+
+ return 0xff;
+}
+
+WRITE8_MEMBER(mz_state::mz700_bank_1_w)
+{
+ address_space *spc = machine().device("maincpu")->memory().space(AS_PROGRAM);
+
+ if (m_mz700_mode)
+ {
+ /* switch in ram when not locked */
+ if (!m_mz700_ram_lock)
+ {
+ spc->install_readwrite_bank(0xd000, 0xffff, "bank7");
+ membank("bank7")->set_base(machine().device<ram_device>(RAM_TAG)->pointer() + 0xd000);
+ m_mz700_ram_vram = FALSE;
+ }
+ }
+ else
+ {
+ /* switch in ram when not locked */
+ if (!m_mz800_ram_lock)
+ {
+ spc->install_readwrite_bank(0xe000, 0xffff, "bank8");
+ membank("bank8")->set_base(machine().device<ram_device>(RAM_TAG)->pointer() + 0xe000);
+ m_mz800_ram_monitor = FALSE;
+ }
+ }
+}
+
+WRITE8_MEMBER(mz_state::mz700_bank_2_w)
+{
+ address_space *spc = machine().device("maincpu")->memory().space(AS_PROGRAM);
+
+ spc->install_read_bank(0x0000, 0x0fff, "bank1");
+ spc->nop_write(0x0000, 0x0fff);
+ membank("bank1")->set_base(machine().root_device().memregion("monitor")->base());
+}
+
+WRITE8_MEMBER(mz_state::mz700_bank_3_w)
+{
+ UINT8 *videoram = m_videoram;
+ address_space *spc = machine().device("maincpu")->memory().space(AS_PROGRAM);
+
+ if (m_mz700_mode)
+ {
+ if (!m_mz700_ram_lock)
+ {
+ /* switch in videoram */
+ spc->install_readwrite_bank(0xd000, 0xd7ff, "bank7");
+ membank("bank7")->set_base(videoram);
+
+ /* switch in colorram */
+ spc->install_readwrite_bank(0xd800, 0xdfff, "bank9");
+ membank("bank9")->set_base(m_colorram);
+
+ m_mz700_ram_vram = TRUE;
+
+ /* switch in memory mapped i/o devices */
+ if (m_mz700)
+ {
+ spc->install_readwrite_handler(0xe000, 0xfff3, 0, 0x1ff0, read8_delegate(FUNC(i8255_device::read), (i8255_device*)m_ppi), write8_delegate(FUNC(i8255_device::write), (i8255_device*)m_ppi));
+ spc->install_legacy_readwrite_handler(*m_pit, 0xe004, 0xfff7, 0, 0x1ff0, FUNC(pit8253_r), FUNC(pit8253_w));
+ spc->install_readwrite_handler(0xe008, 0xfff8, 0, 0x1ff0, read8_delegate(FUNC(mz_state::mz700_e008_r),this), write8_delegate(FUNC(mz_state::mz700_e008_w),this));
+ }
+ else
+ {
+ spc->install_readwrite_handler(0xe000, 0xe003, read8_delegate(FUNC(i8255_device::read), (i8255_device*)m_ppi), write8_delegate(FUNC(i8255_device::write), (i8255_device*)m_ppi));
+ spc->install_legacy_readwrite_handler(*m_pit, 0xe004, 0xe007, FUNC(pit8253_r), FUNC(pit8253_w));
+ spc->install_readwrite_handler(0xe008, 0xe008, read8_delegate(FUNC(mz_state::mz700_e008_r),this), write8_delegate(FUNC(mz_state::mz700_e008_w),this));
+ }
+ }
+ }
+ else
+ {
+ if (!m_mz800_ram_lock)
+ {
+ /* switch in mz800 monitor rom if not locked */
+ spc->install_read_bank(0xe000, 0xffff, "bank8");
+ spc->nop_write(0xe000, 0xffff);
+ membank("bank8")->set_base(machine().root_device().memregion("monitor")->base() + 0x2000);
+ m_mz800_ram_monitor = TRUE;
+ }
+ }
+}
+
+WRITE8_MEMBER(mz_state::mz700_bank_4_w)
+{
+ UINT8 *videoram = m_videoram;
+ address_space *spc = machine().device("maincpu")->memory().space(AS_PROGRAM);
+
+ if (m_mz700_mode)
+ {
+ m_mz700_ram_lock = FALSE; /* reset lock */
+ mz700_bank_2_w(space, 0, 0); /* switch in monitor rom */
+ mz700_bank_3_w(space, 0, 0); /* switch in videoram, colorram, and mmio */
+
+ /* rest is ram is always ram in mz700 mode */
+ spc->install_readwrite_bank(0x1000, 0xcfff, "bank2");
+ membank("bank2")->set_base(machine().device<ram_device>(RAM_TAG)->pointer() + 0x1000);
+ }
+ else
+ {
+ /* monitor rom and cgrom */
+ spc->install_read_bank(0x0000, 0x1fff, "bank1");
+ spc->nop_write(0x0000, 0x1fff);
+ membank("bank1")->set_base(machine().root_device().memregion("monitor")->base());
+
+ /* ram from 0x2000 to 0x7fff */
+ spc->install_readwrite_bank(0x2000, 0x7fff, "bank3");
+ membank("bank3")->set_base(machine().device<ram_device>(RAM_TAG)->pointer());
+
+ if (m_hires_mode)
+ {
+ /* vram from 0x8000 to 0xbfff */
+ spc->install_readwrite_bank(0x8000, 0xbfff, "bank4");
+ membank("bank4")->set_base(videoram);
+ }
+ else
+ {
+ /* vram from 0x8000 to 0x9fff */
+ spc->install_readwrite_bank(0x8000, 0x9fff, "bank4");
+ membank("bank4")->set_base(videoram);
+
+ /* ram from 0xa000 to 0xbfff */
+ spc->install_readwrite_bank(0xa000, 0xbfff, "bank5");
+ membank("bank5")->set_base(machine().device<ram_device>(RAM_TAG)->pointer() + 0xa000);
+ }
+
+ /* ram from 0xc000 to 0xdfff */
+ spc->install_readwrite_bank(0xc000, 0xdfff, "bank6");
+ membank("bank6")->set_base(machine().device<ram_device>(RAM_TAG)->pointer() + 0xc000);
+
+ /* mz800 monitor rom from 0xe000 to 0xffff */
+ spc->install_read_bank(0xe000, 0xffff, "bank8");
+ spc->nop_write(0xe000, 0xffff);
+ membank("bank8")->set_base(machine().root_device().memregion("monitor")->base() + 0x2000);
+ m_mz800_ram_monitor = TRUE;
+
+ m_mz800_ram_lock = FALSE; /* reset lock? */
+ }
+}
+
+WRITE8_MEMBER(mz_state::mz700_bank_5_w)
+{
+ address_space *spc = machine().device("maincpu")->memory().space(AS_PROGRAM);
+
+ if (m_mz700_mode)
+ {
+ /* prevent access from 0xd000 to 0xffff */
+ m_mz700_ram_lock = TRUE;
+ spc->nop_readwrite(0xd000, 0xffff);
+ }
+ else
+ {
+ /* prevent access from 0xe000 to 0xffff */
+ m_mz800_ram_lock = TRUE;
+ spc->nop_readwrite(0xe000, 0xffff);
+ }
+}
+
+WRITE8_MEMBER(mz_state::mz700_bank_6_w)
+{
+
+ if (m_mz700_mode)
+ {
+ m_mz700_ram_lock = FALSE;
+
+ /* restore access */
+ if (m_mz700_ram_vram)
+ mz700_bank_3_w(space, 0, 0);
+ else
+ mz700_bank_1_w(space, 0, 0);
+ }
+ else
+ {
+ m_mz800_ram_lock = FALSE;
+
+ /* restore access from 0xe000 to 0xffff */
+ if (m_mz800_ram_monitor)
+ mz700_bank_3_w(space, 0, 0);
+ else
+ mz700_bank_1_w(space, 0, 0);
+ }
+}
+
+
+/************************ PIT ************************************************/
+
+/* Timer 0 is the clock for the speaker output */
+
+static WRITE_LINE_DEVICE_HANDLER( pit_out0_changed )
+{
+ mz_state *drvstate = device->machine().driver_data<mz_state>();
+ device_t *speaker = device->machine().device(SPEAKER_TAG);
+ if((drvstate->m_prev_state==0) && (state==1)) {
+ drvstate->m_speaker_level ^= 1;
+ }
+ drvstate->m_prev_state = state;
+ speaker_level_w( speaker, drvstate->m_speaker_level);
+}
+
+/* timer 2 is the AM/PM (12 hour) interrupt */
+static WRITE_LINE_DEVICE_HANDLER( pit_irq_2 )
+{
+ mz_state *mz = device->machine().driver_data<mz_state>();
+
+ if (!mz->m_intmsk)
+ cputag_set_input_line(device->machine(), "maincpu", 0, state);
+}
+
+
+/***************************************************************************
+ 8255 PPI
+***************************************************************************/
+
+static READ8_DEVICE_HANDLER( pio_port_b_r )
+{
+ int key_line = dynamic_cast<ttl74145_device *>(device)->read();
+
+ switch (key_line)
+ {
+ case 1 << 0: return device->machine().root_device().ioport("ROW0")->read();
+ case 1 << 1: return device->machine().root_device().ioport("ROW1")->read();
+ case 1 << 2: return device->machine().root_device().ioport("ROW2")->read();
+ case 1 << 3: return device->machine().root_device().ioport("ROW3")->read();
+ case 1 << 4: return device->machine().root_device().ioport("ROW4")->read();
+ case 1 << 5: return device->machine().root_device().ioport("ROW5")->read();
+ case 1 << 6: return device->machine().root_device().ioport("ROW6")->read();
+ case 1 << 7: return device->machine().root_device().ioport("ROW7")->read();
+ case 1 << 8: return device->machine().root_device().ioport("ROW8")->read();
+ case 1 << 9: return device->machine().root_device().ioport("ROW9")->read();
+ }
+
+ /* should never reach this */
+ return 0xff;
+}
+
+/*
+ * bit 7 in vertical blank
+ * bit 6 in NE556 output
+ * bit 5 in tape data (RDATA)
+ * bit 4 in motor (1 = on)
+ */
+static READ8_DEVICE_HANDLER( pio_port_c_r )
+{
+ cassette_image_device *cas = device->machine().device<cassette_image_device>(CASSETTE_TAG);
+ mz_state *mz = device->machine().driver_data<mz_state>();
+ UINT8 data = 0;
+
+ /* note: this is actually connected to Q output of the motor-control flip-flop (see below) */
+ if ((cas->get_state() & CASSETTE_MASK_UISTATE) != CASSETTE_STOPPED)
+ data |= 0x10;
+
+ if ((cas)->input() > 0.0038)
+ data |= 0x20; /* set the RDATA status */
+
+ data |= mz->m_cursor_timer << 6;
+ data |= device->machine().primary_screen->vblank() << 7;
+
+ LOG(2,"mz700_pio_port_c_r",("%02X\n", data),device->machine());
+
+ return data;
+}
+
+
+static WRITE8_DEVICE_HANDLER( pio_port_a_w )
+{
+ timer_device *timer = device->machine().device<timer_device>("cursor");
+
+ LOG(2,"mz700_pio_port_a_w",("%02X\n", data),device->machine());
+
+ /* the ls145 is connected to PA0-PA3 */
+ dynamic_cast<ttl74145_device *>(device)->write(data & 0x07);
+
+ /* ne556 reset is connected to PA7 */
+ timer->enable(BIT(data, 7));
+}
+
+
+static WRITE8_DEVICE_HANDLER( pio_port_c_w )
+{
+ /*
+ * bit 3 out motor control (0 = on)
+ * bit 2 out INTMSK
+ * bit 1 out tape data (WDATA)
+ * bit 0 out unused
+ */
+
+// UINT8 state = cassette_get_state(device->machine().device<cassette_image_device>(CASSETTE_TAG));
+// UINT8 action = ((~pio_port_c_output & 8) & (data & 8)); /* detect low-to-high transition */
+
+ /* The motor control circuit consists of a resistor, capacitor, invertor, nand-gate, and D flip-flop.
+ The sense input from the cassette player goes low whenever play, rewind or fast-forward is pressed.
+ This connects to most of the above components.
+ The Q output enables the motor, and also connects to Bit 4 (input).
+ Bit 3 outputs a string of pulses to the Clock pin, and therefore cannot be used to control
+ the motor directly.
+ For the moment, the user can use the UI to select play, stop, etc.
+ If you load from the command-line or the software-picker, type in L <enter> immediately. */
+#if 0
+
+ device->machine().device<cassette_image_device>(CASSETTE_TAG)->change_state(
+ ((data & 0x08) && mz700_motor_on) ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED,
+ CASSETTE_MOTOR_DISABLED);
+
+#endif
+
+ LOG(2,"mz700_pio_port_c_w",("%02X\n", data),device->machine());
+
+ device->machine().device<cassette_image_device>(CASSETTE_TAG)->output((data & 0x02) ? +1.0 : -1.0);
+}
+
+
+/******************************************************************************
+ * Sharp MZ800
+ *
+ *
+ ******************************************************************************/
+
+//static UINT8 mz800_display_mode = 0;
+//static UINT8 mz800_port_e8 = 0;
+
+
+/***************************************************************************
+ Z80 PIO
+***************************************************************************/
+
+static void mz800_z80pio_irq(device_t *device, int which)
+{
+ cputag_set_input_line(device->machine(), "maincpu", 0, which);
+}
+
+static READ8_DEVICE_HANDLER( mz800_z80pio_port_a_r )
+{
+ centronics_device *centronics = device->machine().device<centronics_device>("centronics");
+ UINT8 result = 0;
+
+ result |= centronics->busy_r();
+ result |= centronics->pe_r() << 1;
+ result |= device->machine().primary_screen->hblank() << 5;
+
+ return result;
+}
+
+static WRITE8_DEVICE_HANDLER( mz800_z80pio_port_a_w )
+{
+ centronics_device *centronics = device->machine().device<centronics_device>("centronics");
+
+ centronics->init_prime_w(BIT(data, 6));
+ centronics->strobe_w(BIT(data, 7));
+}
+
+const z80pio_interface mz800_z80pio_config =
+{
+ DEVCB_DEVICE_LINE("z80pio", mz800_z80pio_irq),
+ DEVCB_DEVICE_HANDLER("z80pio", mz800_z80pio_port_a_r),
+ DEVCB_DEVICE_HANDLER("z80pio", mz800_z80pio_port_a_w),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER("centronics", centronics_device, write),
+ DEVCB_NULL,
+};
+
+
+
+
+/* port CE */
+READ8_MEMBER(mz_state::mz800_crtc_r)
+{
+ UINT8 data = 0x00;
+ LOG(1,"mz800_crtc_r",("%02X\n",data),machine());
+ return data;
+}
+
+
+/* port EA */
+READ8_MEMBER(mz_state::mz800_ramdisk_r)
+{
+ UINT8 *mem = space.machine().root_device().memregion("user1")->base();
+ UINT8 data = mem[m_mz800_ramaddr];
+ LOG(2,"mz800_ramdisk_r",("[%04X] -> %02X\n", m_mz800_ramaddr, data),machine());
+ if (m_mz800_ramaddr++ == 0)
+ LOG(1,"mz800_ramdisk_r",("address wrap 0000\n"),machine());
+ return data;
+}
+
+/* port CC */
+WRITE8_MEMBER(mz_state::mz800_write_format_w)
+{
+ LOG(1,"mz800_write_format_w",("%02X\n", data),machine());
+}
+
+/* port CD */
+WRITE8_MEMBER(mz_state::mz800_read_format_w)
+{
+ LOG(1,"mz800_read_format_w",("%02X\n", data),machine());
+}
+
+/* port CE
+ * bit 3 1: MZ700 mode 0: MZ800 mode
+ * bit 2 1: 640 horizontal 0: 320 horizontal
+ * bit 1 1: 4bpp/2bpp 0: 2bpp/1bpp
+ * bit 0 ???
+ */
+WRITE8_MEMBER(mz_state::mz800_display_mode_w)
+{
+
+ m_mz700_mode = BIT(data, 3);
+ m_hires_mode = BIT(data, 2);
+ m_screen = data & 0x03;
+
+ /* change memory maps if we switched mode */
+// if (BIT(data, 3) != m_mz700_mode)
+// {
+// logerror("mz800_display_mode_w: switching mode to %s\n", (BIT(data, 3) ? "mz700" : "mz800"));
+// m_mz700_mode = BIT(data, 3);
+// mz700_bank_4_w(machine().device("maincpu")->memory().&space(AS_PROGRAM), 0, 0);
+// }
+}
+
+/* port CF */
+WRITE8_MEMBER(mz_state::mz800_scroll_border_w)
+{
+ LOG(1,"mz800_scroll_border_w",("%02X\n", data),machine());
+}
+
+/* port EA */
+WRITE8_MEMBER(mz_state::mz800_ramdisk_w)
+{
+ UINT8 *mem = memregion("user1")->base();
+ LOG(2,"mz800_ramdisk_w",("[%04X] <- %02X\n", m_mz800_ramaddr, data),machine());
+ mem[m_mz800_ramaddr] = data;
+ if (m_mz800_ramaddr++ == 0)
+ LOG(1,"mz800_ramdisk_w",("address wrap 0000\n"),machine());
+}
+
+/* port EB */
+WRITE8_MEMBER(mz_state::mz800_ramaddr_w)
+{
+ m_mz800_ramaddr = (cpu_get_reg(machine().device("maincpu"), Z80_BC) & 0xff00) | (data & 0xff);
+ LOG(1,"mz800_ramaddr_w",("%04X\n", m_mz800_ramaddr),machine());
+}
+
+/* port F0 */
+WRITE8_MEMBER(mz_state::mz800_palette_w)
+{
+ if (data & 0x40)
+ {
+ m_mz800_palette_bank = data & 3;
+ LOG(1,"mz800_palette_w",("bank: %d\n", m_mz800_palette_bank),machine());
+ }
+ else
+ {
+ int idx = (data >> 4) & 3;
+ int val = data & 15;
+ LOG(1,"mz800_palette_w",("palette[%d] <- %d\n", idx, val),machine());
+ m_mz800_palette[idx] = val;
+ }
+}
diff --git a/src/mess/machine/mz80.c b/src/mess/machine/mz80.c
new file mode 100644
index 00000000000..fe5bdd25f70
--- /dev/null
+++ b/src/mess/machine/mz80.c
@@ -0,0 +1,103 @@
+/***************************************************************************
+
+ MZ80 driver by Miodrag Milanovic
+
+ 22/11/2008 Preliminary driver.
+
+****************************************************************************/
+
+#include "includes/mz80.h"
+
+
+/* Driver initialization */
+DRIVER_INIT_MEMBER(mz80_state,mz80k)
+{
+}
+
+MACHINE_RESET( mz80k )
+{
+ mz80_state *state = machine.driver_data<mz80_state>();
+ state->m_mz80k_tempo_strobe = 0;
+ state->m_mz80k_vertical = 0;
+ state->m_mz80k_cursor_cnt = 0;
+ state->m_mz80k_keyboard_line = 0;
+}
+
+
+READ8_MEMBER( mz80_state::mz80k_8255_portb_r )
+{
+ char kbdrow[8];
+ sprintf(kbdrow,"LINE%d", m_mz80k_keyboard_line);
+ if (m_mz80k_keyboard_line > 9)
+ return 0xff;
+ else
+ return ioport(kbdrow)->read();
+}
+
+READ8_MEMBER( mz80_state::mz80k_8255_portc_r )
+{
+ UINT8 val = 0;
+ val |= m_mz80k_vertical ? 0x80 : 0x00;
+ val |= ((m_mz80k_cursor_cnt & 0x3f) > 31) ? 0x40 : 0x00;
+ val |= (m_cass->get_state() & CASSETTE_MASK_UISTATE)== CASSETTE_PLAY ? 0x10 : 0x00;
+
+ if (m_cass->input() > 0.00)
+ val |= 0x20;
+
+ return val;
+}
+
+WRITE8_MEMBER( mz80_state::mz80k_8255_porta_w )
+{
+ m_mz80k_keyboard_line = data & 0x0f;
+}
+
+WRITE8_MEMBER( mz80_state::mz80k_8255_portc_w )
+{
+// logerror("mz80k_8255_portc_w %02x\n",data);
+}
+
+
+WRITE_LINE_MEMBER( mz80_state::pit_out0_changed )
+{
+ if(!m_prev_state && state)
+ m_speaker_level++;
+
+ m_prev_state = state;
+ speaker_level_w(m_speaker, BIT(m_speaker_level, 1));
+}
+
+WRITE_LINE_MEMBER( mz80_state::pit_out2_changed )
+{
+ cputag_set_input_line(machine(), "maincpu", 0, HOLD_LINE);
+}
+
+I8255_INTERFACE( mz80k_8255_int )
+{
+ DEVCB_NULL,
+ DEVCB_DRIVER_MEMBER(mz80_state, mz80k_8255_porta_w),
+ DEVCB_DRIVER_MEMBER(mz80_state, mz80k_8255_portb_r),
+ DEVCB_NULL,
+ DEVCB_DRIVER_MEMBER(mz80_state, mz80k_8255_portc_r),
+ DEVCB_DRIVER_MEMBER(mz80_state, mz80k_8255_portc_w),
+};
+
+const struct pit8253_config mz80k_pit8253_config =
+{
+ {
+ /* clockin gate callback */
+ { XTAL_8MHz/ 4, DEVCB_NULL, DEVCB_DRIVER_LINE_MEMBER(mz80_state, pit_out0_changed) },
+ { XTAL_8MHz/256, DEVCB_NULL, DEVCB_DEVICE_LINE("pit8253", pit8253_clk2_w) },
+ { 0, DEVCB_NULL, DEVCB_DRIVER_LINE_MEMBER(mz80_state, pit_out2_changed) },
+ }
+};
+
+READ8_MEMBER( mz80_state::mz80k_strobe_r )
+{
+ return 0x7e | (UINT8)m_mz80k_tempo_strobe;
+}
+
+WRITE8_MEMBER( mz80_state::mz80k_strobe_w )
+{
+ pit8253_gate0_w(m_pit, BIT(data, 0));
+}
diff --git a/src/mess/machine/n82077aa.c b/src/mess/machine/n82077aa.c
new file mode 100644
index 00000000000..5f7f96599f1
--- /dev/null
+++ b/src/mess/machine/n82077aa.c
@@ -0,0 +1,1212 @@
+
+#include "n82077aa.h"
+
+const device_type N82077AA = &device_creator<n82077aa_device>;
+
+DEVICE_ADDRESS_MAP_START(amap, 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
+
+int n82077aa_device::rates[4] = { 500000, 300000, 250000, 1000000 };
+
+n82077aa_device::n82077aa_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : device_t(mconfig, N82077AA, "N82077AA", tag, owner, clock)
+{
+}
+
+void n82077aa_device::set_mode(int _mode)
+{
+ mode = _mode;
+}
+
+void n82077aa_device::setup_intrq_cb(line_cb cb)
+{
+ intrq_cb = cb;
+}
+
+void n82077aa_device::setup_drq_cb(line_cb cb)
+{
+ drq_cb = cb;
+}
+
+void n82077aa_device::device_start()
+{
+ static const char *names[] = { "fd0", "fd1", "fd2", "fd3" };
+ for(int i=0; i != 4; i++) {
+ flopi[i].tm = timer_alloc(i);
+ flopi[i].id = i;
+ floppy_connector *con = machine().device<floppy_connector>(names[i]);
+ if(con) {
+ flopi[i].dev = con->get_device();
+ flopi[i].dev->setup_index_pulse_cb(floppy_image_device::index_pulse_cb(FUNC(n82077aa_device::index_callback), this));
+ } else
+ flopi[i].dev = 0;
+ }
+}
+
+void n82077aa_device::device_reset()
+{
+ main_phase = PHASE_CMD;
+ for(int i=0; i<4; i++) {
+ flopi[i].main_state = IDLE;
+ flopi[i].sub_state = IDLE;
+ flopi[i].irq = false;
+ flopi[i].live = false;
+ }
+ data_irq = false;
+ dor = 0x00;
+ fifo_pos = 0;
+ command_pos = 0;
+ result_pos = 0;
+ fifocfg = 0x10;
+ cur_live.fi = 0;
+ cur_irq = false;
+ drq = false;
+ live_abort();
+}
+
+READ8_MEMBER(n82077aa_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((dsr & 3) == 0 || (dsr & 3) == 3)
+ 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(n82077aa_device::srb_r)
+{
+ return 0;
+}
+
+READ8_MEMBER(n82077aa_device::dor_r)
+{
+ return dor;
+}
+
+WRITE8_MEMBER(n82077aa_device::dor_w)
+{
+ UINT8 diff = dor ^ data;
+ dor = data;
+ if((diff & 4) && !(data & 4))
+ device_reset();
+ else
+ for(int i=0; i<4; i++) {
+ floppy_info &fi = flopi[i];
+ if(fi.dev && (diff & (0x10 << i)))
+ fi.dev->mon_w(!(dor & (0x10 << i)));
+ }
+
+}
+
+READ8_MEMBER(n82077aa_device::tdr_r)
+{
+ return 0;
+}
+
+WRITE8_MEMBER(n82077aa_device::tdr_w)
+{
+}
+
+READ8_MEMBER(n82077aa_device::msr_r)
+{
+ UINT32 msr = 0;
+ switch(main_phase) {
+ case PHASE_CMD:
+ msr |= 0x80;
+ if(command_pos)
+ msr |= 0x10;
+ break;
+ case PHASE_EXEC:
+ msr |= 0x10;
+ break;
+
+ case PHASE_RESULT:
+ msr |= 0xd0;
+ break;
+ }
+ for(int i=0; i<4; i++)
+ if(flopi[i].main_state == RECALIBRATE || flopi[i].main_state == SEEK)
+ msr |= 1<<i;
+
+ if(data_irq) {
+ data_irq = false;
+ check_irq();
+ }
+
+ return msr;
+}
+
+WRITE8_MEMBER(n82077aa_device::dsr_w)
+{
+ dsr = data;
+}
+
+READ8_MEMBER(n82077aa_device::fifo_r)
+{
+ UINT8 r = 0;
+ switch(main_phase) {
+ case PHASE_RESULT:
+ r = result[0];
+ result_pos--;
+ memmove(result, result+1, result_pos);
+ if(!result_pos)
+ main_phase = PHASE_CMD;
+ break;
+ default:
+ logerror("%s: fifo_r in phase %d\n", tag(), main_phase);
+ // exit(1);
+ }
+
+ return r;
+}
+
+WRITE8_MEMBER(n82077aa_device::fifo_w)
+{
+ switch(main_phase) {
+ case PHASE_CMD: {
+ command[command_pos++] = data;
+ int cmd = check_command();
+ if(cmd == C_INCOMPLETE)
+ break;
+ if(cmd == C_INVALID) {
+ logerror("%s: Invalid on %02x\n", tag(), command[0]);
+ exit(1);
+ command_pos = 0;
+ return;
+ }
+ start_command(cmd);
+ break;
+ }
+ default:
+ logerror("%s: fifo_w in phase %d\n", tag(), main_phase);
+ exit(1);
+ }
+}
+
+READ8_MEMBER(n82077aa_device::dir_r)
+{
+ return 0x78;
+}
+
+WRITE8_MEMBER(n82077aa_device::ccr_w)
+{
+ dsr = (dsr & 0xfc) | (data & 3);
+}
+
+void n82077aa_device::set_drq(bool state)
+{
+ if(state != drq) {
+ drq = state;
+ if(!drq_cb.isnull())
+ drq_cb(drq);
+ }
+}
+
+bool n82077aa_device::get_drq() const
+{
+ return drq;
+}
+
+void n82077aa_device::fifo_push(UINT8 data)
+{
+ if(fifo_pos == 16) {
+ logerror("%s: Overflow\n", tag());
+ return;
+ }
+ fifo[fifo_pos++] = data;
+ fifo_expected--;
+ if(!drq) {
+ int thr = (fifocfg & 15)+1;
+ if(!fifo_expected || fifo_pos >= thr || (fifocfg & 0x20))
+ set_drq(true);
+ }
+}
+
+void n82077aa_device::fifo_expect(int size, bool write)
+{
+ fifo_expected = size;
+ fifo_write = write;
+}
+
+UINT8 n82077aa_device::dma_r()
+{
+ if(!fifo_pos)
+ return 0;
+ UINT8 r = fifo[0];
+ fifo_pos--;
+ memmove(fifo, fifo+1, fifo_pos);
+ if(!fifo_pos)
+ set_drq(false);
+ return r;
+}
+
+void n82077aa_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(rates[dsr & 3]*2));
+ checkpoint_live = cur_live;
+ fi.live = true;
+
+ live_run();
+}
+
+void n82077aa_device::checkpoint()
+{
+ if(cur_live.fi)
+ cur_live.pll.commit(cur_live.fi->dev, cur_live.tm);
+ checkpoint_live = cur_live;
+}
+
+void n82077aa_device::rollback()
+{
+ cur_live = checkpoint_live;
+}
+
+void n82077aa_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());
+}
+
+void n82077aa_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);
+ }
+ if(cur_live.tm == machine().time()) {
+ 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.tm = attotime::never;
+ cur_live.fi->live = false;
+ cur_live.fi = 0;
+ }
+ }
+ cur_live.next_state = -1;
+ checkpoint();
+ }
+}
+
+void n82077aa_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 n82077aa_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).cstr(), 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.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;
+ }
+ 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).cstr(), 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_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;
+ 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).cstr(), 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(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;
+ }
+ 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).cstr(), 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 != 0xfd) {
+ 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:
+ // 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:
+ fifo_push(cur_live.data_reg);
+ cur_live.state = READ_SECTOR_DATA;
+ checkpoint();
+ break;
+
+ default:
+ logerror("%s: Unknown live state %d\n", tts(cur_live.tm).cstr(), cur_live.state);
+ return;
+ }
+ }
+}
+
+int n82077aa_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
+ // 00001111 seek
+ // 00010000 version
+ // ...10001 scan equal
+ // 00010010 perpendicular mode
+ // 00010011 configure
+ // .0010100 lock
+ // ...10110 verify
+ // ...11001 scan low or equal
+ // ...11101 scan high or equal
+ // 1.001111 relative seek
+
+ switch(command[0]) {
+ case 0x03:
+ return command_pos == 3 ? C_SPECIFY : C_INCOMPLETE;
+
+ case 0x06: case 0x26: case 0x46: case 0x66: case 0x86: case 0xa6: case 0xc6: case 0xe6:
+ 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: case 0x4a:
+ return command_pos == 2 ? C_READ_ID : C_INCOMPLETE;
+
+ case 0x0f:
+ return command_pos == 3 ? C_SEEK : C_INCOMPLETE;
+
+ case 0x12:
+ return command_pos == 2 ? C_PERPENDICULAR : C_INCOMPLETE;
+
+ case 0x13:
+ return command_pos == 4 ? C_CONFIGURE : C_INCOMPLETE;
+
+ default:
+ return C_INVALID;
+ }
+}
+
+void n82077aa_device::start_command(int cmd)
+{
+ command_pos = 0;
+ result_pos = 0;
+ main_phase = PHASE_EXEC;
+ 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];
+ main_phase = PHASE_CMD;
+ break;
+
+ case C_PERPENDICULAR:
+ logerror("%s: command perpendicular\n", tag());
+ 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_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_INTERRUPT_STATUS: {
+ logerror("%s: command sense interrupt status\n", tag());
+ main_phase = PHASE_RESULT;
+
+ int fid;
+ for(fid=0; fid<4 && !flopi[fid].irq; fid++);
+ if(fid == 4) {
+ result[0] = 0x80;
+ result_pos = 1;
+ break;
+ }
+ floppy_info &fi = flopi[fid];
+ fi.irq = false;
+ result[0] = (fi.status << 6) | 0x20 | fid;
+ result[1] = fi.pcn;
+ result_pos = 2;
+ 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;
+
+ default:
+ fprintf(stderr, "start command %d\n", cmd);
+ exit(1);
+ }
+}
+
+void n82077aa_device::command_end(floppy_info &fi, bool data_completion, int status)
+{
+ fi.main_state = fi.sub_state = IDLE;
+ if(data_completion)
+ data_irq = true;
+ else
+ fi.irq = true;
+ fi.status = status;
+ check_irq();
+}
+
+void n82077aa_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;
+ seek_continue(fi);
+}
+
+void n82077aa_device::seek_start(floppy_info &fi)
+{
+ logerror("%s: command seek %d\n", tag(), 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 n82077aa_device::delay_cycles(emu_timer *tm, int cycles)
+{
+ tm->adjust(attotime::from_double(double(cycles)/rates[dsr & 3]));
+}
+
+void n82077aa_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:
+ done = !fi.dev || !fi.dev->trk00_r();
+ if(done)
+ fi.pcn = 0;
+ break;
+ case SEEK:
+ done = fi.pcn == command[2];
+ break;
+ }
+ if(done) {
+ command_end(fi, false, 0);
+ return;
+ }
+ fi.sub_state = SEEK_MOVE;
+ break;
+ }
+ }
+ }
+}
+
+void n82077aa_device::read_data_start(floppy_info &fi)
+{
+ fi.main_state = READ_DATA;
+ fi.sub_state = HEAD_LOAD_DONE;
+
+ logerror("%s: command read data%s%s%s cmd=%02x sel=%x chrn=(%d, %d, %d, %d) eot=%02x gpl=%02x dtl=%02x rate=%d\n",
+ tag(),
+ command[0] & 0x80 ? " mt" : "",
+ command[0] & 0x40 ? " mfm" : "",
+ command[0] & 0x20 ? " sk" : "",
+ command[0],
+ command[1],
+ command[2],
+ command[3],
+ command[4],
+ 128 << (command[5] & 7),
+ command[6],
+ command[7],
+ command[8],
+ rates[dsr & 3]);
+
+ if(fi.dev)
+ fi.dev->ss_w(command[1] & 4 ? 1 : 0);
+ read_data_continue(fi);
+}
+
+void n82077aa_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;
+ }
+ 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:
+ 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) {
+ fprintf(stderr, "Header CRC error\n");
+ live_start(fi, SEARCH_ADDRESS_MARK_HEADER);
+ return;
+ }
+ sector_size = 128 << (cur_live.idbuf[3] & 3);
+ fifo_expect(sector_size, false);
+ fi.sub_state = SECTOR_READ;
+ live_start(fi, SEARCH_ADDRESS_MARK_DATA);
+ return;
+
+ case SCAN_ID_FAILED:
+ fprintf(stderr, "RNF\n");
+ command_end(fi, true, 1);
+ return;
+
+ case SECTOR_READ:
+ if(cur_live.crc) {
+ fprintf(stderr, "CRC error\n");
+ }
+ if(command[4] < command[6]) {
+ command[4]++;
+ fi.sub_state = HEAD_LOAD_DONE;
+ break;
+ }
+
+ main_phase = PHASE_RESULT;
+ result[0] = 0;
+ result[1] = 0;
+ result[2] = 0;
+ result[3] = command[2];
+ result[4] = command[3];
+ result[5] = command[4];
+ result[6] = command[5];
+ result_pos = 7;
+ command_end(fi, true, 0);
+ return;
+
+ default:
+ logerror("%s: read sector unknown sub-state %d\n", ttsn().cstr(), fi.sub_state);
+ return;
+ }
+ }
+}
+
+void n82077aa_device::read_id_start(floppy_info &fi)
+{
+ fi.main_state = READ_DATA;
+ fi.sub_state = HEAD_LOAD_DONE;
+
+ logerror("%s: command read id%s, rate=%d\n",
+ tag(),
+ command[0] & 0x40 ? " mfm" : "",
+ rates[dsr & 3]);
+
+ if(fi.dev)
+ fi.dev->ss_w(command[1] & 4 ? 1 : 0);
+ read_id_continue(fi);
+}
+
+void n82077aa_device::read_id_continue(floppy_info &fi)
+{
+ for(;;) {
+ switch(fi.sub_state) {
+ case HEAD_LOAD_DONE:
+ counter = 0;
+ fi.sub_state = SCAN_ID;
+ live_start(fi, SEARCH_ADDRESS_MARK_HEADER);
+ return;
+
+ case SCAN_ID:
+ if(cur_live.crc) {
+ fprintf(stderr, "Header CRC error\n");
+ live_start(fi, SEARCH_ADDRESS_MARK_HEADER);
+ return;
+ }
+
+ main_phase = PHASE_RESULT;
+ result[0] = 0;
+ result[1] = 0;
+ result[2] = 0;
+ 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, 0);
+ return;
+
+ default:
+ logerror("%s: read id unknown sub-state %d\n", ttsn().cstr(), fi.sub_state);
+ return;
+ }
+ }
+}
+
+void n82077aa_device::check_irq()
+{
+ bool old_irq = cur_irq;
+ cur_irq = data_irq;
+ for(int i=0; i<4; i++)
+ cur_irq = cur_irq || flopi[i].irq;
+ if(cur_irq != old_irq && !intrq_cb.isnull())
+ intrq_cb(cur_irq);
+}
+
+astring n82077aa_device::tts(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;
+}
+
+astring n82077aa_device::ttsn()
+{
+ return tts(machine().time());
+}
+
+void n82077aa_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ 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 n82077aa_device::index_callback(floppy_image_device *floppy, int state)
+{
+ int fid;
+ for(fid=0; fid<4; fid++)
+ if(flopi[fid].dev == floppy)
+ break;
+
+ assert(fid != 4);
+ floppy_info &fi = flopi[fid];
+
+ live_sync();
+ fi.index = state;
+
+ if(!state) {
+ general_continue(fi);
+ return;
+ }
+
+ 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 SCAN_ID:
+ counter++;
+ if(counter == 2)
+ fi.sub_state = SCAN_ID_FAILED;
+ break;
+
+ default:
+ logerror("%s: Index pulse on unknown sub-state %d\n", ttsn().cstr(), fi.sub_state);
+ break;
+ }
+
+ general_continue(fi);
+}
+
+
+void n82077aa_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:
+ read_data_continue(fi);
+ break;
+
+ case READ_ID:
+ read_id_continue(fi);
+ break;
+
+ default:
+ logerror("%s: general_continue on unknown main-state %d\n", ttsn().cstr(), fi.main_state);
+ break;
+ }
+}
+
+bool n82077aa_device::read_one_bit(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 n82077aa_device::write_one_bit(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;
+}
+
+bool n82077aa_device::sector_matches() const
+{
+ 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];
+}
+
+void n82077aa_device::pll_t::set_clock(attotime _period)
+{
+ period = _period;
+ period_adjust_base = period * 0.05;
+ min_period = period * 0.75;
+ max_period = period * 1.25;
+}
+
+void n82077aa_device::pll_t::reset(attotime when)
+{
+ ctime = when;
+ phase_adjust = attotime::zero;
+ freq_hist = 0;
+ write_position = 0;
+ write_start_time = attotime::never;
+}
+
+void n82077aa_device::pll_t::start_writing(attotime tm)
+{
+ write_start_time = tm;
+ write_position = 0;
+}
+
+void n82077aa_device::pll_t::stop_writing(floppy_image_device *floppy, attotime tm)
+{
+ commit(floppy, tm);
+ write_start_time = attotime::never;
+}
+
+void n82077aa_device::pll_t::commit(floppy_image_device *floppy, 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 n82077aa_device::pll_t::get_next_bit(attotime &tm, floppy_image_device *floppy, 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, "transition_time=%s, next=%s\n", tts(edge).cstr(), tts(next).cstr());
+#endif
+
+ if(next > limit)
+ return -1;
+
+ ctime = next;
+
+ if(edge.is_never() || edge >= next) {
+ // No transition in the window means 0 and pll in free run mode
+ phase_adjust = attotime::zero;
+ tm = next;
+ return 0;
+ }
+
+ // Transition in the window means 1, and the pll is adjusted
+
+ attotime delta = edge - (next - period/2);
+
+ phase_adjust = 0.65*delta;
+
+ 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 n82077aa_device::pll_t::write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, 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(write_position < ARRAY_LENGTH(write_buffer))
+ write_buffer[write_position++] = ctime + period/2;
+
+ tm = etime;
+ ctime = etime;
+ return false;
+}
diff --git a/src/mess/machine/n82077aa.h b/src/mess/machine/n82077aa.h
new file mode 100644
index 00000000000..0e045a3202d
--- /dev/null
+++ b/src/mess/machine/n82077aa.h
@@ -0,0 +1,203 @@
+#ifndef __N82077AA_H__
+#define __N82077AA_H__
+
+#include "emu.h"
+#include "imagedev/floppy.h"
+
+#define MCFG_N82077AA_ADD(_tag, _mode) \
+ MCFG_DEVICE_ADD(_tag, N82077AA, 0) \
+ downcast<n82077aa_device *>(device)->set_mode(_mode);
+
+class n82077aa_device : public device_t {
+public:
+ typedef delegate<void (bool state)> line_cb;
+
+ enum { MODE_AT, MODE_PS2, MODE_M30 };
+
+ n82077aa_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ void set_mode(int mode);
+ void setup_intrq_cb(line_cb cb);
+ void setup_drq_cb(line_cb cb);
+
+ DECLARE_ADDRESS_MAP(amap, 8);
+
+ 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);
+
+ UINT8 dma_r();
+ void dma_w(UINT8 data);
+ bool get_drq() const;
+
+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 {
+ PHASE_CMD, PHASE_EXEC, PHASE_RESULT
+ };
+
+ enum {
+ // General "doing nothing" state
+ IDLE,
+
+ // Main states
+ RECALIBRATE,
+ SEEK,
+ READ_DATA,
+ READ_ID,
+
+ // Sub-states
+ 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,
+
+ SCAN_ID,
+ SCAN_ID_FAILED,
+
+ SECTOR_READ,
+
+ // Live states
+ SEARCH_ADDRESS_MARK_HEADER,
+ READ_HEADER_BLOCK_HEADER,
+ READ_DATA_BLOCK_HEADER,
+ READ_ID_BLOCK_TO_LOCAL,
+ SEARCH_ADDRESS_MARK_DATA,
+ SEARCH_ADDRESS_MARK_DATA_FAILED,
+ READ_SECTOR_DATA,
+ READ_SECTOR_DATA_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(attotime period);
+ void reset(attotime when);
+ int get_next_bit(attotime &tm, floppy_image_device *floppy, attotime limit);
+ bool write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, attotime limit);
+ void start_writing(attotime tm);
+ void commit(floppy_image_device *floppy, attotime tm);
+ void stop_writing(floppy_image_device *floppy, attotime tm);
+ };
+
+ struct floppy_info {
+ emu_timer *tm;
+ floppy_image_device *dev;
+ int id;
+ int main_state, sub_state;
+ int dir, status;
+ UINT8 pcn;
+ bool irq, live, index;
+ };
+
+ 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];
+ pll_t pll;
+ };
+
+ static int rates[4];
+
+ int mode;
+ int main_phase;
+ int counter;
+
+ live_info cur_live, checkpoint_live;
+ line_cb intrq_cb, drq_cb;
+ bool cur_irq, data_irq, drq;
+ floppy_info flopi[4];
+
+ int fifo_pos, fifo_expected, command_pos, result_pos;
+ bool fifo_write;
+ UINT8 dor, dsr, msr, fifo[16], command[16], result[16];
+ UINT8 fifocfg;
+ UINT16 spec;
+ int sector_size;
+
+ static astring tts(attotime t);
+ astring ttsn();
+
+ enum {
+ C_CONFIGURE,
+ C_PERPENDICULAR,
+ C_READ_DATA,
+ C_READ_ID,
+ C_RECALIBRATE,
+ C_SEEK,
+ C_SENSE_INTERRUPT_STATUS,
+ C_SPECIFY,
+
+ 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);
+ void set_drq(bool state);
+
+ int check_command();
+ void start_command(int cmd);
+ void command_end(floppy_info &fi, bool data_completion, int status);
+
+ 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 read_id_start(floppy_info &fi);
+ void read_id_continue(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);
+
+ bool read_one_bit(attotime limit);
+ bool write_one_bit(attotime limit);
+};
+
+extern const device_type N82077AA;
+
+#endif
diff --git a/src/mess/machine/nascom1.c b/src/mess/machine/nascom1.c
new file mode 100644
index 00000000000..8acca936a9c
--- /dev/null
+++ b/src/mess/machine/nascom1.c
@@ -0,0 +1,295 @@
+/**********************************************************************
+
+ machine/nascom1.c
+
+**********************************************************************/
+
+/* Core includes */
+#include "emu.h"
+#include "includes/nascom1.h"
+
+/* Components */
+#include "cpu/z80/z80.h"
+#include "machine/wd17xx.h"
+#include "machine/ay31015.h"
+
+/* Devices */
+#include "imagedev/snapquik.h"
+#include "imagedev/cassette.h"
+#include "imagedev/flopdrv.h"
+#include "machine/ram.h"
+
+#define NASCOM1_KEY_RESET 0x02
+#define NASCOM1_KEY_INCR 0x01
+
+
+
+/*************************************
+ *
+ * Global variables
+ *
+ *************************************/
+
+
+
+
+/*************************************
+ *
+ * Floppy
+ *
+ *************************************/
+
+static WRITE_LINE_DEVICE_HANDLER( nascom2_fdc_intrq_w )
+{
+ nascom1_state *drvstate = device->machine().driver_data<nascom1_state>();
+ drvstate->m_nascom2_fdc.irq = state;
+}
+
+static WRITE_LINE_DEVICE_HANDLER( nascom2_fdc_drq_w )
+{
+ nascom1_state *drvstate = device->machine().driver_data<nascom1_state>();
+ drvstate->m_nascom2_fdc.drq = state;
+}
+
+const wd17xx_interface nascom2_wd17xx_interface =
+{
+ DEVCB_LINE_VCC,
+ DEVCB_LINE(nascom2_fdc_intrq_w),
+ DEVCB_LINE(nascom2_fdc_drq_w),
+ {FLOPPY_0, FLOPPY_1, FLOPPY_2, FLOPPY_3}
+};
+
+
+READ8_MEMBER(nascom1_state::nascom2_fdc_select_r)
+{
+ return m_nascom2_fdc.select | 0xa0;
+}
+
+
+WRITE8_MEMBER(nascom1_state::nascom2_fdc_select_w)
+{
+ device_t *fdc = machine().device("wd1793");
+ m_nascom2_fdc.select = data;
+
+ logerror("nascom2_fdc_select_w: %02x\n", data);
+
+ if (data & 0x01) wd17xx_set_drive(fdc,0);
+ if (data & 0x02) wd17xx_set_drive(fdc,1);
+ if (data & 0x04) wd17xx_set_drive(fdc,2);
+ if (data & 0x08) wd17xx_set_drive(fdc,3);
+ if (data & 0x10) wd17xx_set_side(fdc,(data & 0x10) >> 4);
+}
+
+
+/*
+ * D0 -- WD1793 IRQ
+ * D1 -- NOT READY
+ * D2 to D6 -- 0
+ * D7 -- WD1793 DRQ
+ *
+ */
+READ8_MEMBER(nascom1_state::nascom2_fdc_status_r)
+{
+ return (m_nascom2_fdc.drq << 7) | m_nascom2_fdc.irq;
+}
+
+/*************************************
+ *
+ * Keyboard
+ *
+ *************************************/
+
+READ8_MEMBER(nascom1_state::nascom1_port_00_r)
+{
+ static const char *const keynames[] = { "KEY0", "KEY1", "KEY2", "KEY3", "KEY4", "KEY5", "KEY6", "KEY7", "KEY8" };
+
+ if (m_portstat.stat_count < 9)
+ return (ioport(keynames[m_portstat.stat_count])->read() | ~0x7f);
+
+ return (0xff);
+}
+
+
+WRITE8_MEMBER(nascom1_state::nascom1_port_00_w)
+{
+
+ machine().device<cassette_image_device>(CASSETTE_TAG)->change_state(
+ ( data & 0x10 ) ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED,CASSETTE_MASK_MOTOR );
+
+ if (!(data & NASCOM1_KEY_RESET))
+ {
+ if (m_portstat.stat_flags & NASCOM1_KEY_RESET)
+ m_portstat.stat_count = 0;
+ }
+ else
+ m_portstat.stat_flags = NASCOM1_KEY_RESET;
+
+ if (!(data & NASCOM1_KEY_INCR))
+ {
+ if (m_portstat.stat_flags & NASCOM1_KEY_INCR)
+ m_portstat.stat_count++;
+ }
+ else
+ m_portstat.stat_flags = NASCOM1_KEY_INCR;
+}
+
+
+
+
+/*************************************
+ *
+ * Cassette
+ *
+ *************************************/
+
+
+READ8_MEMBER(nascom1_state::nascom1_port_01_r)
+{
+ return ay31015_get_received_data( m_hd6402 );
+}
+
+
+WRITE8_MEMBER(nascom1_state::nascom1_port_01_w)
+{
+ ay31015_set_transmit_data( m_hd6402, data );
+}
+
+READ8_MEMBER(nascom1_state::nascom1_port_02_r)
+{
+ UINT8 data = 0x31;
+
+ ay31015_set_input_pin( m_hd6402, AY31015_SWE, 0 );
+ data |= ay31015_get_output_pin( m_hd6402, AY31015_OR ) ? 0x02 : 0;
+ data |= ay31015_get_output_pin( m_hd6402, AY31015_PE ) ? 0x04 : 0;
+ data |= ay31015_get_output_pin( m_hd6402, AY31015_FE ) ? 0x08 : 0;
+ data |= ay31015_get_output_pin( m_hd6402, AY31015_TBMT ) ? 0x40 : 0;
+ data |= ay31015_get_output_pin( m_hd6402, AY31015_DAV ) ? 0x80 : 0;
+ ay31015_set_input_pin( m_hd6402, AY31015_SWE, 1 );
+
+ return data;
+}
+
+
+READ8_DEVICE_HANDLER( nascom1_hd6402_si )
+{
+ return 1;
+}
+
+
+WRITE8_DEVICE_HANDLER( nascom1_hd6402_so )
+{
+}
+
+
+DEVICE_IMAGE_LOAD( nascom1_cassette )
+{
+ nascom1_state *state = image.device().machine().driver_data<nascom1_state>();
+ state->m_tape_size = image.length();
+ state->m_tape_image = (UINT8*)image.ptr();
+ if (!state->m_tape_image)
+ return IMAGE_INIT_FAIL;
+
+ state->m_tape_index = 0;
+ return IMAGE_INIT_PASS;
+}
+
+
+DEVICE_IMAGE_UNLOAD( nascom1_cassette )
+{
+ nascom1_state *state = image.device().machine().driver_data<nascom1_state>();
+ state->m_tape_image = NULL;
+ state->m_tape_size = state->m_tape_index = 0;
+}
+
+
+
+/*************************************
+ *
+ * Snapshots
+ *
+ * ASCII .nas format
+ *
+ *************************************/
+
+SNAPSHOT_LOAD( nascom1 )
+{
+ UINT8 line[35];
+
+ while (image.fread( &line, sizeof(line)) == sizeof(line))
+ {
+ int addr, b0, b1, b2, b3, b4, b5, b6, b7, dummy;
+
+ if (sscanf((char *)line, "%x %x %x %x %x %x %x %x %x %x\010\010\n",
+ &addr, &b0, &b1, &b2, &b3, &b4, &b5, &b6, &b7, &dummy) == 10)
+ {
+ image.device().machine().device("maincpu")->memory().space(AS_PROGRAM)->write_byte(addr++, b0);
+ image.device().machine().device("maincpu")->memory().space(AS_PROGRAM)->write_byte(addr++, b1);
+ image.device().machine().device("maincpu")->memory().space(AS_PROGRAM)->write_byte(addr++, b2);
+ image.device().machine().device("maincpu")->memory().space(AS_PROGRAM)->write_byte(addr++, b3);
+ image.device().machine().device("maincpu")->memory().space(AS_PROGRAM)->write_byte(addr++, b4);
+ image.device().machine().device("maincpu")->memory().space(AS_PROGRAM)->write_byte(addr++, b5);
+ image.device().machine().device("maincpu")->memory().space(AS_PROGRAM)->write_byte(addr++, b6);
+ image.device().machine().device("maincpu")->memory().space(AS_PROGRAM)->write_byte(addr++, b7);
+ }
+ }
+
+ return IMAGE_INIT_PASS;
+}
+
+
+
+/*************************************
+ *
+ * Initialization
+ *
+ *************************************/
+
+MACHINE_RESET( nascom1 )
+{
+ nascom1_state *state = machine.driver_data<nascom1_state>();
+ state->m_hd6402 = machine.device("hd6402");
+
+ /* Set up hd6402 pins */
+ ay31015_set_input_pin( state->m_hd6402, AY31015_SWE, 1 );
+
+ ay31015_set_input_pin( state->m_hd6402, AY31015_CS, 0 );
+ ay31015_set_input_pin( state->m_hd6402, AY31015_NP, 1 );
+ ay31015_set_input_pin( state->m_hd6402, AY31015_NB1, 1 );
+ ay31015_set_input_pin( state->m_hd6402, AY31015_NB2, 1 );
+ ay31015_set_input_pin( state->m_hd6402, AY31015_EPS, 1 );
+ ay31015_set_input_pin( state->m_hd6402, AY31015_TSB, 1 );
+ ay31015_set_input_pin( state->m_hd6402, AY31015_CS, 1 );
+}
+
+DRIVER_INIT_MEMBER(nascom1_state,nascom1)
+{
+ switch (machine().device<ram_device>(RAM_TAG)->size())
+ {
+ case 1 * 1024:
+ machine().device("maincpu")->memory().space(AS_PROGRAM)->nop_readwrite(
+ 0x1400, 0x9000);
+ break;
+
+ case 16 * 1024:
+ machine().device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(
+ 0x1400, 0x4fff, "bank1");
+ machine().device("maincpu")->memory().space(AS_PROGRAM)->nop_readwrite(
+ 0x5000, 0xafff);
+ membank("bank1")->set_base(machine().device<ram_device>(RAM_TAG)->pointer());
+ break;
+
+ case 32 * 1024:
+ machine().device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(
+ 0x1400, 0x8fff, "bank1");
+ machine().device("maincpu")->memory().space(AS_PROGRAM)->nop_readwrite(
+ 0x9000, 0xafff);
+ membank("bank1")->set_base(machine().device<ram_device>(RAM_TAG)->pointer());
+ break;
+
+ case 40 * 1024:
+ machine().device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(
+ 0x1400, 0xafff, "bank1");
+ membank("bank1")->set_base(machine().device<ram_device>(RAM_TAG)->pointer());
+ break;
+ }
+}
diff --git a/src/mess/machine/nc.c b/src/mess/machine/nc.c
new file mode 100644
index 00000000000..f70b2fc1f0f
--- /dev/null
+++ b/src/mess/machine/nc.c
@@ -0,0 +1,144 @@
+/***************************************************************************
+
+ nc.c
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/nc.h"
+#include "machine/i8251.h"
+
+/*************************************************************************************************/
+/* PCMCIA Ram Card management */
+
+/* the data is stored as a simple memory dump, there is no header or other information */
+
+/* stores size of actual file on filesystem */
+
+/* save card data back */
+static void nc_card_save(device_image_interface &image)
+{
+ nc_state *state = image.device().machine().driver_data<nc_state>();
+ /* if there is no data to write, quit */
+ if (!state->m_card_ram || !state->m_card_size)
+ return;
+
+ logerror("attempting card save\n");
+
+ /* write data */
+ image.fwrite(state->m_card_ram, state->m_card_size);
+
+ logerror("write succeeded!\r\n");
+}
+
+/* this mask will prevent overwrites from end of data */
+static int nc_card_calculate_mask(int size)
+{
+ int i;
+
+ /* memory block is visible as 16k blocks */
+ /* mask can only operate on power of two sizes */
+ /* memory cards normally in power of two sizes */
+ /* maximum of 64 16k blocks can be accessed using memory paging of nc computer */
+ /* max card size is therefore 1mb */
+ for (i=14; i<20; i++)
+ {
+ if (size<(1<<i))
+ return 0x03f>>(19-i);
+ }
+
+ return 0x03f;
+}
+
+
+/* load card image */
+static int nc_card_load(device_image_interface &image, unsigned char **ptr)
+{
+ nc_state *state = image.device().machine().driver_data<nc_state>();
+ int datasize;
+ unsigned char *data;
+
+ /* get file size */
+ datasize = image.length();
+
+ if (datasize!=0)
+ {
+ /* malloc memory for this data */
+ data = (unsigned char *)malloc(datasize);
+
+ if (data!=NULL)
+ {
+ state->m_card_size = datasize;
+
+ /* read whole file */
+ image.fread(data, datasize);
+
+ *ptr = data;
+
+ logerror("File loaded!\r\n");
+
+ state->m_membank_card_ram_mask = nc_card_calculate_mask(datasize);
+
+ logerror("Mask: %02x\n",state->m_membank_card_ram_mask);
+
+ /* ok! */
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+DEVICE_START( nc_pcmcia_card )
+{
+ nc_state *state = device->machine().driver_data<nc_state>();
+ /* card not present */
+ nc_set_card_present_state(device->machine(), 0);
+ /* card ram NULL */
+ state->m_card_ram = NULL;
+ state->m_card_size = 0;
+}
+
+/* load pcmcia card */
+DEVICE_IMAGE_LOAD( nc_pcmcia_card )
+{
+ nc_state *state = image.device().machine().driver_data<nc_state>();
+ /* filename specified */
+
+ /* attempt to load file */
+ if (nc_card_load(image, &state->m_card_ram))
+ {
+ if (state->m_card_ram!=NULL)
+ {
+ /* card present! */
+ if (state->m_membank_card_ram_mask!=0)
+ {
+ nc_set_card_present_state(image.device().machine(), 1);
+ }
+ return IMAGE_INIT_PASS;
+ }
+ }
+
+ /* nc100 can run without a image */
+ return IMAGE_INIT_FAIL;
+}
+
+DEVICE_IMAGE_UNLOAD( nc_pcmcia_card )
+{
+ nc_state *state = image.device().machine().driver_data<nc_state>();
+ /* save card data if there is any */
+ nc_card_save(image);
+
+ /* free ram allocated to card */
+ if (state->m_card_ram!=NULL)
+ {
+ free(state->m_card_ram);
+ state->m_card_ram = NULL;
+ }
+ state->m_card_size = 0;
+
+ /* set card not present state */
+ nc_set_card_present_state(image.device().machine(), 0);
+}
+
+
diff --git a/src/mess/machine/ncr5380.c b/src/mess/machine/ncr5380.c
new file mode 100644
index 00000000000..7589631a161
--- /dev/null
+++ b/src/mess/machine/ncr5380.c
@@ -0,0 +1,485 @@
+/*
+ * 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"
+#include "machine/devhelpr.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", group);
+
+ return 6;
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void ncr5380_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const NCR5380interface *intf = reinterpret_cast<const NCR5380interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<NCR5380interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ scsidevs = NULL;
+ irq_callback = NULL;
+ }
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+const device_type NCR5380 = &device_creator<ncr5380_device>;
+
+//-------------------------------------------------
+// ncr5380_device - constructor/destructor
+//-------------------------------------------------
+
+ncr5380_device::ncr5380_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, NCR5380, "5380 SCSI", tag, owner, clock)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void ncr5380_device::device_start()
+{
+ memset(m_5380_Registers, 0, sizeof(m_5380_Registers));
+ memset(m_5380_Data, 0, sizeof(m_5380_Data));
+ memset(m_scsi_devices, 0, sizeof(m_scsi_devices));
+
+ m_next_req_flag = 0;
+
+ 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));
+
+ int i;
+
+ // try to open the devices
+ for (i = 0; i < scsidevs->devs_present; i++)
+ {
+ m_scsi_devices[scsidevs->devices[i].scsiID] = machine().device<scsidev_device>( scsidevs->devices[i].tag );
+ }
+}
+
+//-------------------------------------------------
+// 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
+//-------------------------------------------------
+READ8_DEVICE_HANDLER_TRAMPOLINE(ncr5380, ncr5380_read_reg)
+{
+ 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)
+ {
+ ncr5380_read_data((m_d_limit < 512) ? m_d_limit : 512, m_5380_Data);
+ }
+ 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("NCR5380: read %s (reg %d) = %02x [PC=%x]\n", rnames[reg], reg, rv, cpu_get_pc(machine().firstcpu));
+
+ return rv;
+}
+
+WRITE8_DEVICE_HANDLER_TRAMPOLINE(ncr5380, ncr5380_write_reg)
+{
+ int reg = offset & 7;
+
+ if (VERBOSE)
+ logerror("NCR5380: %02x to %s (reg %d) [PC=%x]\n", data, wnames[reg], reg, cpu_get_pc(machine().firstcpu));
+
+ 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)
+ {
+ ncr5380_write_data(512, &m_5380_Data[0]);
+
+ 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("NCR5380: Command (to ID %d): %x %x %x %x %x %x %x %x %x %x (PC %x)\n", 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], cpu_get_pc(machine().firstcpu));
+
+ m_scsi_devices[m_last_id]->SetCommand(&m_5380_Command[0], 16);
+ m_scsi_devices[m_last_id]->ExecCommand(&m_d_limit);
+
+ 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
+ ncr5380_read_data((m_d_limit < 512) ? m_d_limit : 512, m_5380_Data);
+
+ // 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 (m_scsi_devices[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;
+ }
+}
+
+
+void ncr5380_device::ncr5380_read_data(int bytes, UINT8 *pData)
+{
+ if (m_scsi_devices[m_last_id])
+ {
+ if (VERBOSE)
+ logerror("NCR5380: issuing read for %d bytes\n", bytes);
+ m_scsi_devices[m_last_id]->ReadData(pData, bytes);
+ }
+ else
+ {
+ logerror("ncr5380: read unknown device SCSI ID %d\n", m_last_id);
+ }
+}
+
+
+void ncr5380_device::ncr5380_write_data(int bytes, UINT8 *pData)
+{
+ if (m_scsi_devices[m_last_id])
+ {
+ m_scsi_devices[m_last_id]->WriteData(pData, bytes);
+ }
+ else
+ {
+ logerror("ncr5380: write to unknown device SCSI ID %d\n", m_last_id);
+ }
+}
+
+void ncr5380_read_data(device_t *dev, UINT8 bytes, UINT8 *pData)
+{
+ return downcast<ncr5380_device*>(dev)->ncr5380_read_data(bytes, pData);
+}
+
+void ncr5380_write_data(device_t *dev, UINT8 bytes, UINT8 *pData)
+{
+ downcast<ncr5380_device*>(dev)->ncr5380_write_data(bytes, pData);
+}
diff --git a/src/mess/machine/ncr5380.h b/src/mess/machine/ncr5380.h
new file mode 100644
index 00000000000..7e1fcd96627
--- /dev/null
+++ b/src/mess/machine/ncr5380.h
@@ -0,0 +1,89 @@
+/*
+ * ncr5380.h SCSI controller
+ *
+ */
+
+#ifndef _NCR5380_H_
+#define _NCR5380_H_
+
+#include "machine/scsi.h"
+#include "machine/scsidev.h"
+
+struct NCR5380interface
+{
+ const SCSIConfigTable *scsidevs; /* SCSI devices */
+ void (*irq_callback)(running_machine &machine, int state); /* irq callback */
+};
+
+// 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_ADD(_tag, _clock, _intrf) \
+ MCFG_DEVICE_ADD(_tag, NCR5380, _clock) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+class ncr5380_device : public device_t,
+ public NCR5380interface
+{
+public:
+ // construction/destruction
+ ncr5380_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // our API
+ UINT8 ncr5380_read_reg(UINT32 offset);
+ void ncr5380_write_reg(UINT32 offset, UINT8 data);
+
+ void ncr5380_read_data(int bytes, UINT8 *pData);
+ void ncr5380_write_data(int bytes, UINT8 *pData);
+
+ void *ncr5380_get_scsi_device(int id);
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_stop();
+ virtual void device_config_complete();
+
+private:
+ scsidev_device *m_scsi_devices[8];
+
+ 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];
+};
+
+// device type definition
+extern const device_type NCR5380;
+
+/***************************************************************************
+ PROTOTYPES
+***************************************************************************/
+READ8_DEVICE_HANDLER(ncr5380_read_reg);
+WRITE8_DEVICE_HANDLER(ncr5380_write_reg);
+
+void ncr5380_read_data(device_t *dev, int bytes, UINT8 *pData);
+void ncr5380_write_data(device_t *dev, int bytes, UINT8 *pData);
+
+#endif
diff --git a/src/mess/machine/ncr5390.c b/src/mess/machine/ncr5390.c
new file mode 100644
index 00000000000..162ad08134e
--- /dev/null
+++ b/src/mess/machine/ncr5390.c
@@ -0,0 +1,870 @@
+
+#include "emu.h"
+#include "ncr5390.h"
+
+#define DELAY_HACK
+
+const device_type NCR5390 = &device_creator<ncr5390_device>;
+
+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)
+{
+}
+
+void ncr5390_device::device_start()
+{
+ save_item(NAME(command));
+ save_item(NAME(config));
+ save_item(NAME(status));
+ save_item(NAME(istatus));
+ save_item(NAME(fifo_pos));
+ save_item(NAME(fifo));
+ save_item(NAME(tcount));
+ save_item(NAME(mode));
+ save_item(NAME(command_pos));
+ save_item(NAME(irq));
+ save_item(NAME(drq));
+ save_item(NAME(clock_conv));
+
+ m_irq_func.resolve(m_irq_cb, *this);
+ m_drq_func.resolve(m_drq_cb, *this);
+
+ 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;
+ if(!m_irq_func.isnull())
+ m_irq_func(irq);
+ reset_soft();
+}
+
+void ncr5390_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const ncr5390_interface *intf = reinterpret_cast<const ncr5390_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<ncr5390_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_irq_cb, 0, sizeof(m_irq_cb));
+ memset(&m_drq_cb, 0, sizeof(m_drq_cb));
+ }
+ m_shortname = "ncr5390";
+}
+
+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;
+ if(!m_drq_func.isnull())
+ m_drq_func(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<<win)); win--);
+ if(win != scsi_id) {
+ scsi_bus->data_w(scsi_refid, 0);
+ scsi_bus->ctrl_w(scsi_refid, 0, S_ALL);
+ fatalerror("need to wait for bus free");
+ break;
+ }
+ 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<<scsi_id) | (1<<bus_id));
+ state = (state & STATE_MASK) | (ARB_SET_DEST << SUB_SHIFT);
+ delay_cycles(4);
+ break;
+
+ case ARB_SET_DEST << SUB_SHIFT:
+ if(!timeout)
+ break;
+
+ state = (state & STATE_MASK) | (ARB_RELEASE_BUSY << SUB_SHIFT);
+ scsi_bus->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");
+
+ 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, cpu_get_pc(&space.device()));
+ 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, cpu_get_pc(&space.device()));
+}
+
+READ8_MEMBER(ncr5390_device::tcount_hi_r)
+{
+ logerror("%s: tcount_hi_r %02x (%08x)\n", tag(), tcount >> 8, cpu_get_pc(&space.device()));
+ 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, cpu_get_pc(&space.device()));
+}
+
+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(), cpu_get_pc(&space.device()));
+ return command[0];
+}
+
+WRITE8_MEMBER(ncr5390_device::command_w)
+{
+ // logerror("%s: command_w %02x (%08x)\n", tag(), data, cpu_get_pc(&space.device()));
+ 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_func.isnull())
+ m_irq_func(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, cpu_get_pc(&space.device()));
+ 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, cpu_get_pc(&space.device()));
+ 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, cpu_get_pc(&space.device()));
+ 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;
+ if(!m_drq_func.isnull())
+ m_drq_func(drq);
+ }
+}
+
+void ncr5390_device::drq_clear()
+{
+ if(drq) {
+ drq = false;
+ if(!m_drq_func.isnull())
+ m_drq_func(drq);
+ }
+}
diff --git a/src/mess/machine/ncr5390.h b/src/mess/machine/ncr5390.h
new file mode 100644
index 00000000000..931ccc2ec82
--- /dev/null
+++ b/src/mess/machine/ncr5390.h
@@ -0,0 +1,228 @@
+#ifndef NCR5390_H
+#define NCR5390_H
+
+#include "machine/nscsi_bus.h"
+
+struct ncr5390_interface
+{
+ devcb_write_line m_irq_cb;
+ devcb_write_line m_drq_cb;
+};
+
+class ncr5390_device : public nscsi_device,
+ public ncr5390_interface
+{
+public:
+ ncr5390_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ 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_config_complete();
+ 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/recieve 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;
+
+ devcb_resolved_write_line m_irq_func;
+ devcb_resolved_write_line m_drq_func;
+
+ 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);
+};
+
+extern const device_type NCR5390;
+
+#endif
diff --git a/src/mess/machine/ne1000.c b/src/mess/machine/ne1000.c
new file mode 100644
index 00000000000..51cda5f98e2
--- /dev/null
+++ b/src/mess/machine/ne1000.c
@@ -0,0 +1,101 @@
+#include "emu.h"
+#include "machine/ne1000.h"
+#include "machine/devhelpr.h"
+
+static const dp8390_interface ne1000_dp8390_interface = {
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ne1000_device, ne1000_irq_w),
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ne1000_device, ne1000_mem_read),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ne1000_device, ne1000_mem_write)
+};
+
+static MACHINE_CONFIG_FRAGMENT(ne1000_config)
+ MCFG_DP8390D_ADD("dp8390d", ne1000_dp8390_interface)
+MACHINE_CONFIG_END
+
+const device_type NE1000 = &device_creator<ne1000_device>;
+
+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),
+ 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);
+}
+
+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) {
+ m_isa->irq3_w(state);
+}
+
+READ8_MEMBER(ne1000_device::ne1000_mem_read) {
+ 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) {
+ if((offset < (8*1024)) || (offset >= (16*1024))) {
+ logerror("ne1000: invalid memory write %04X\n", offset);
+ return;
+ }
+ m_board_ram[offset - (8*1024)] = data;
+}
diff --git a/src/mess/machine/ne1000.h b/src/mess/machine/ne1000.h
new file mode 100644
index 00000000000..56fff80292e
--- /dev/null
+++ b/src/mess/machine/ne1000.h
@@ -0,0 +1,34 @@
+#ifndef __NE1000_H__
+#define __NE1000_H__
+
+// NE1000 is 8bit has 8KB ram; NE2000 is 16bit has 16KB ram
+
+#include "emu.h"
+#include "machine/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;
+
+ 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();
+ virtual void device_config_complete() { m_shortname = "ne1000"; }
+private:
+ required_device<dp8390d_device> m_dp8390;
+ UINT8 m_board_ram[8*1024];
+ UINT8 m_prom[16];
+};
+
+extern const device_type NE1000;
+
+#endif
diff --git a/src/mess/machine/ne2000.c b/src/mess/machine/ne2000.c
new file mode 100644
index 00000000000..84bb73eb770
--- /dev/null
+++ b/src/mess/machine/ne2000.c
@@ -0,0 +1,111 @@
+#include "emu.h"
+#include "machine/ne2000.h"
+#include "machine/devhelpr.h"
+
+static const dp8390_interface ne2000_dp8390_interface = {
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ne2000_device, ne2000_irq_w),
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ne2000_device, ne2000_mem_read),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ne2000_device, ne2000_mem_write)
+};
+
+static MACHINE_CONFIG_FRAGMENT(ne2000_config)
+ MCFG_DP8390D_ADD("dp8390d", ne2000_dp8390_interface)
+MACHINE_CONFIG_END
+
+const device_type NE2000 = &device_creator<ne2000_device>;
+
+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),
+ 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);
+}
+
+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) {
+ m_isa->irq3_w(state);
+}
+
+READ8_MEMBER(ne2000_device::ne2000_mem_read) {
+ 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) {
+ if((offset < (16*1024)) || (offset >= (32*1024))) {
+ logerror("ne2000: invalid memory write %04X\n", offset);
+ return;
+ }
+ m_board_ram[offset - (16*1024)] = data;
+}
diff --git a/src/mess/machine/ne2000.h b/src/mess/machine/ne2000.h
new file mode 100644
index 00000000000..e8967370a30
--- /dev/null
+++ b/src/mess/machine/ne2000.h
@@ -0,0 +1,32 @@
+#ifndef __NE2000_H__
+#define __NE2000_H__
+
+#include "emu.h"
+#include "machine/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;
+
+ 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();
+ virtual void device_config_complete() { m_shortname = "ne2000"; }
+private:
+ required_device<dp8390d_device> m_dp8390;
+ UINT8 m_board_ram[16*1024];
+ UINT8 m_prom[16];
+};
+
+extern const device_type NE2000;
+
+#endif
diff --git a/src/mess/machine/nes.c b/src/mess/machine/nes.c
new file mode 100644
index 00000000000..90aaf95b693
--- /dev/null
+++ b/src/mess/machine/nes.c
@@ -0,0 +1,1711 @@
+#include "emu.h"
+#include "crsshair.h"
+#include "cpu/m6502/m6502.h"
+#include "video/ppu2c0x.h"
+#include "includes/nes.h"
+#include "machine/nes_mmc.h"
+#include "imagedev/cartslot.h"
+#include "imagedev/flopdrv.h"
+#include "hashfile.h"
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* Set to dump info about the inputs to the errorlog */
+#define LOG_JOY 0
+
+/* Set to generate prg & chr files when the cart is loaded */
+#define SPLIT_PRG 0
+#define SPLIT_CHR 0
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static void init_nes_core(running_machine &machine);
+static void nes_machine_stop(running_machine &machine);
+
+
+static void fds_irq(device_t *device, int scanline, int vblank, int blanked);
+
+/***************************************************************************
+ FUNCTIONS
+***************************************************************************/
+
+static void init_nes_core( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ static const char *const bank_names[] = { "bank1", "bank2", "bank3", "bank4" };
+ int prg_banks = (state->m_prg_chunks == 1) ? (2 * 2) : (state->m_prg_chunks * 2);
+ int i;
+
+ state->m_rom = machine.root_device().memregion("maincpu")->base();
+ state->m_ciram = machine.root_device().memregion("ciram")->base();
+ // other pointers got set in the loading routine
+
+ /* Brutal hack put in as a consequence of the new memory system; we really need to fix the NES code */
+ space->install_readwrite_bank(0x0000, 0x07ff, 0, 0x1800, "bank10");
+
+ machine.device("ppu")->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler(0, 0x1fff, FUNC(nes_chr_r), FUNC(nes_chr_w));
+ machine.device("ppu")->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler(0x2000, 0x3eff, FUNC(nes_nt_r), FUNC(nes_nt_w));
+
+ state->membank("bank10")->set_base(state->m_rom);
+
+ /* If there is Disk Expansion and no cart has been loaded, setup memory accordingly */
+ if (state->m_disk_expansion && state->m_pcb_id == NO_BOARD)
+ {
+ /* If we are loading a disk we have already filled state->m_fds_data and we don't want to overwrite it,
+ if we are loading a cart image identified as mapper 20 (probably wrong mapper...) we need to alloc
+ memory for use in nes_fds_r/nes_fds_w. Same goes for allocation of fds_ram (used for bank2) */
+ if (state->m_fds_data == NULL)
+ {
+ UINT32 size = (state->m_prg_chunks == 1) ? 2 * 0x4000 : state->m_prg_chunks * 0x4000;
+ state->m_fds_data = auto_alloc_array_clear(machine, UINT8, size);
+ memcpy(state->m_fds_data, state->m_prg, size); // copy in fds_data the cart PRG
+ }
+ if (state->m_fds_ram == NULL)
+ state->m_fds_ram = auto_alloc_array(machine, UINT8, 0x8000);
+
+ space->install_read_handler(0x4030, 0x403f, read8_delegate(FUNC(nes_state::nes_fds_r),state));
+ space->install_read_bank(0x6000, 0xdfff, "bank2");
+ space->install_read_bank(0xe000, 0xffff, "bank1");
+
+ space->install_write_handler(0x4020, 0x402f, write8_delegate(FUNC(nes_state::nes_fds_w),state));
+ space->install_write_bank(0x6000, 0xdfff, "bank2");
+
+ state->membank("bank1")->set_base(&state->m_rom[0xe000]);
+ state->membank("bank2")->set_base(state->m_fds_ram);
+ return;
+ }
+
+ /* Set up the mapper callbacks */
+ pcb_handlers_setup(machine);
+
+ /* Set up the memory handlers for the mapper */
+ space->install_read_bank(0x8000, 0x9fff, "bank1");
+ space->install_read_bank(0xa000, 0xbfff, "bank2");
+ space->install_read_bank(0xc000, 0xdfff, "bank3");
+ space->install_read_bank(0xe000, 0xffff, "bank4");
+ space->install_readwrite_bank(0x6000, 0x7fff, "bank5");
+
+ /* configure banks 1-4 */
+ for (i = 0; i < 4; i++)
+ {
+ state->membank(bank_names[i])->configure_entries(0, prg_banks, state->m_prg, 0x2000);
+ // some mappers (e.g. MMC5) can map PRG RAM in 0x8000-0xffff as well
+ if (state->m_prg_ram)
+ state->membank(bank_names[i])->configure_entries(prg_banks, state->m_wram_size / 0x2000, state->m_wram, 0x2000);
+ // however, at start we point to PRG ROM
+ state->membank(bank_names[i])->set_entry(i);
+ state->m_prg_bank[i] = i;
+ }
+
+ /* bank 5 configuration is more delicate, since it can have PRG RAM, PRG ROM or SRAM mapped to it */
+ /* we first map PRG ROM banks, then the battery bank (if a battery is present), and finally PRG RAM (state->m_wram) */
+ state->membank("bank5")->configure_entries(0, prg_banks, state->m_prg, 0x2000);
+ state->m_battery_bank5_start = prg_banks;
+ state->m_prgram_bank5_start = prg_banks;
+ state->m_empty_bank5_start = prg_banks;
+
+ /* add battery ram, but only if there's no trainer since they share overlapping memory. */
+ if (state->m_battery && !state->m_trainer)
+ {
+ UINT32 bank_size = (state->m_battery_size > 0x2000) ? 0x2000 : state->m_battery_size;
+ int bank_num = (state->m_battery_size > 0x2000) ? state->m_battery_size / 0x2000 : 1;
+ state->membank("bank5")->configure_entries(prg_banks, bank_num, state->m_battery_ram, bank_size);
+ state->m_prgram_bank5_start += bank_num;
+ state->m_empty_bank5_start += bank_num;
+ }
+ /* add prg ram. */
+ if (state->m_prg_ram)
+ {
+ state->membank("bank5")->configure_entries(state->m_prgram_bank5_start, state->m_wram_size / 0x2000, state->m_wram, 0x2000);
+ state->m_empty_bank5_start += state->m_wram_size / 0x2000;
+ }
+
+ state->membank("bank5")->configure_entry(state->m_empty_bank5_start, state->m_rom + 0x6000);
+
+ /* if we have any additional PRG RAM, point bank5 to its first bank */
+ if (state->m_battery || state->m_prg_ram)
+ state->m_prg_bank[4] = state->m_battery_bank5_start;
+ else
+ state->m_prg_bank[4] = state->m_empty_bank5_start; // or shall we point to "maincpu" region at 0x6000? point is that we should never access this region if no sram or wram is present!
+
+ state->membank("bank5")->set_entry(state->m_prg_bank[4]);
+
+ if (state->m_four_screen_vram)
+ {
+ state->m_extended_ntram = auto_alloc_array_clear(machine, UINT8, 0x2000);
+ state->save_pointer(NAME(state->m_extended_ntram), 0x2000);
+ }
+
+ if (state->m_four_screen_vram)
+ set_nt_mirroring(machine, PPU_MIRROR_4SCREEN);
+ else
+ {
+ switch (state->m_hard_mirroring)
+ {
+ case PPU_MIRROR_HORZ:
+ case PPU_MIRROR_VERT:
+ case PPU_MIRROR_HIGH:
+ case PPU_MIRROR_LOW:
+ set_nt_mirroring(machine, state->m_hard_mirroring);
+ break;
+ default:
+ set_nt_mirroring(machine, PPU_MIRROR_NONE);
+ break;
+ }
+ }
+
+ // there are still some quirk about writes to bank5... I hope to fix them soon. (mappers 34,45,52,246 have both mid_w and WRAM-->check)
+ if (state->m_mmc_write_mid)
+ space->install_legacy_write_handler(0x6000, 0x7fff, state->m_mmc_write_mid,state->m_mmc_write_mid_name);
+ if (state->m_mmc_write)
+ space->install_legacy_write_handler(0x8000, 0xffff, state->m_mmc_write, state->m_mmc_write_name);
+
+ // In fact, we also allow single pcbs to overwrite the bank read handlers defined above,
+ // because some pcbs (mainly pirate ones) require protection values to be read instead of
+ // the expected ROM banks: these handlers, though, must take care of the ROM access as well
+ if (state->m_mmc_read_mid)
+ space->install_legacy_read_handler(0x6000, 0x7fff, state->m_mmc_read_mid,state->m_mmc_read_mid_name);
+ if (state->m_mmc_read)
+ space->install_legacy_read_handler(0x8000, 0xffff, state->m_mmc_read,state->m_mmc_read_name);
+
+ // install additional handlers
+ if (state->m_pcb_id == BTL_SMB2B || state->m_mapper == 50)
+ {
+ space->install_legacy_write_handler(0x4020, 0x403f, FUNC(smb2jb_extra_w));
+ space->install_legacy_write_handler(0x40a0, 0x40bf, FUNC(smb2jb_extra_w));
+ }
+
+ if (state->m_pcb_id == KAISER_KS7017)
+ {
+ space->install_legacy_read_handler(0x4030, 0x4030, FUNC(ks7017_extra_r));
+ space->install_legacy_write_handler(0x4020, 0x40ff, FUNC(ks7017_extra_w));
+ }
+
+ if (state->m_pcb_id == UNL_603_5052)
+ {
+ space->install_legacy_read_handler(0x4020, 0x40ff, FUNC(unl_6035052_extra_r));
+ space->install_legacy_write_handler(0x4020, 0x40ff, FUNC(unl_6035052_extra_w));
+ }
+
+ if (state->m_pcb_id == WAIXING_SH2)
+ machine.device("ppu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0, 0x1fff, FUNC(waixing_sh2_chr_r));
+}
+
+// to be probably removed (it does nothing since a long time)
+int nes_ppu_vidaccess( device_t *device, int address, int data )
+{
+ return data;
+}
+
+MACHINE_RESET( nes )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ /* Reset the mapper variables. Will also mark the char-gen ram as dirty */
+ if (state->m_disk_expansion && state->m_pcb_id == NO_BOARD)
+ state->m_ppu->set_hblank_callback(fds_irq);
+ else
+ nes_pcb_reset(machine);
+
+ /* Reset the serial input ports */
+ state->m_in_0.shift = 0;
+ state->m_in_1.shift = 0;
+
+ machine.device("maincpu")->reset();
+}
+
+static TIMER_CALLBACK( nes_irq_callback )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE);
+ state->m_irq_timer->adjust(attotime::never);
+}
+
+static void nes_banks_restore(nes_state *state)
+{
+ state->membank("bank1")->set_entry(state->m_prg_bank[0]);
+ state->membank("bank2")->set_entry(state->m_prg_bank[1]);
+ state->membank("bank3")->set_entry(state->m_prg_bank[2]);
+ state->membank("bank4")->set_entry(state->m_prg_bank[3]);
+ state->membank("bank5")->set_entry(state->m_prg_bank[4]);
+}
+
+static void nes_state_register( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ state->save_item(NAME(state->m_prg_bank));
+
+ state->save_item(NAME(state->m_MMC5_floodtile));
+ state->save_item(NAME(state->m_MMC5_floodattr));
+ state->save_item(NAME(state->m_mmc5_vram_control));
+
+ state->save_item(NAME(state->m_nes_vram_sprite));
+ state->save_item(NAME(state->m_last_frame_flip));
+
+ // shared mapper variables
+ state->save_item(NAME(state->m_IRQ_enable));
+ state->save_item(NAME(state->m_IRQ_enable_latch));
+ state->save_item(NAME(state->m_IRQ_count));
+ state->save_item(NAME(state->m_IRQ_count_latch));
+ state->save_item(NAME(state->m_IRQ_toggle));
+ state->save_item(NAME(state->m_IRQ_reset));
+ state->save_item(NAME(state->m_IRQ_status));
+ state->save_item(NAME(state->m_IRQ_mode));
+ state->save_item(NAME(state->m_mult1));
+ state->save_item(NAME(state->m_mult2));
+ state->save_item(NAME(state->m_mmc_chr_source));
+ state->save_item(NAME(state->m_mmc_cmd1));
+ state->save_item(NAME(state->m_mmc_cmd2));
+ state->save_item(NAME(state->m_mmc_count));
+ state->save_item(NAME(state->m_mmc_prg_base));
+ state->save_item(NAME(state->m_mmc_prg_mask));
+ state->save_item(NAME(state->m_mmc_chr_base));
+ state->save_item(NAME(state->m_mmc_chr_mask));
+ state->save_item(NAME(state->m_mmc_prg_bank));
+ state->save_item(NAME(state->m_mmc_vrom_bank));
+ state->save_item(NAME(state->m_mmc_extra_bank));
+
+ state->save_item(NAME(state->m_fds_motor_on));
+ state->save_item(NAME(state->m_fds_door_closed));
+ state->save_item(NAME(state->m_fds_current_side));
+ state->save_item(NAME(state->m_fds_head_position));
+ state->save_item(NAME(state->m_fds_status0));
+ state->save_item(NAME(state->m_fds_read_mode));
+ state->save_item(NAME(state->m_fds_write_reg));
+ state->save_item(NAME(state->m_fds_last_side));
+ state->save_item(NAME(state->m_fds_count));
+
+ state->save_pointer(NAME(state->m_wram), state->m_wram_size);
+ if (state->m_battery)
+ state->save_pointer(NAME(state->m_battery_ram), state->m_battery_size);
+
+ machine.save().register_postload(save_prepost_delegate(FUNC(nes_banks_restore), state));
+}
+
+MACHINE_START( nes )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ state->m_ppu = machine.device<ppu2c0x_device>("ppu");
+ init_nes_core(machine);
+ machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(nes_machine_stop),&machine));
+
+ state->m_maincpu = machine.device("maincpu");
+ state->m_sound = machine.device("nessound");
+ state->m_cart = machine.device("cart");
+
+ // If we're starting famicom with no disk inserted, we still haven't initialized the VRAM needed for
+ // video emulation, so we need to take care of it now
+ if (!state->m_vram)
+ {
+ state->m_vram = auto_alloc_array(machine, UINT8, 0x4000);
+ for (int i = 0; i < 8; i++)
+ {
+ state->m_chr_map[i].source = CHRRAM;
+ state->m_chr_map[i].origin = i * 0x400; // for save state uses!
+ state->m_chr_map[i].access = &state->m_vram[state->m_chr_map[i].origin];
+ }
+ }
+
+ state->m_irq_timer = machine.scheduler().timer_alloc(FUNC(nes_irq_callback));
+ nes_state_register(machine);
+}
+
+static void nes_machine_stop( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ device_image_interface *image = dynamic_cast<device_image_interface *>(state->m_cart);
+ /* Write out the battery file if necessary */
+ if (state->m_battery)
+ image->battery_save(state->m_battery_ram, state->m_battery_size);
+
+ if (state->m_mapper_bram_size)
+ image->battery_save(state->m_mapper_bram, state->m_mapper_bram_size);
+}
+
+
+
+READ8_MEMBER(nes_state::nes_IN0_r)
+{
+ int cfg = ioport("CTRLSEL")->read();
+ int ret;
+
+ if ((cfg & 0x000f) >= 0x07) // for now we treat the FC keyboard separately from other inputs!
+ {
+ // here we should have the tape input
+ ret = 0;
+ }
+ else
+ {
+ /* Some games expect bit 6 to be set because the last entry on the data bus shows up */
+ /* in the unused upper 3 bits, so typically a read from $4016 leaves 0x40 there. */
+ ret = 0x40;
+
+ ret |= ((m_in_0.i0 >> m_in_0.shift) & 0x01);
+
+ /* zapper */
+ if ((cfg & 0x000f) == 0x0002)
+ {
+ int x = m_in_0.i1; /* read Zapper x-position */
+ int y = m_in_0.i2; /* read Zapper y-position */
+ UINT32 pix, color_base;
+
+ /* get the pixel at the gun position */
+ pix = m_ppu->get_pixel(x, y);
+
+ /* get the color base from the ppu */
+ color_base = m_ppu->get_colorbase();
+
+ /* look at the screen and see if the cursor is over a bright pixel */
+ if ((pix == color_base + 0x20) || (pix == color_base + 0x30) ||
+ (pix == color_base + 0x33) || (pix == color_base + 0x34))
+ {
+ ret &= ~0x08; /* sprite hit */
+ }
+ else
+ ret |= 0x08; /* no sprite hit */
+
+ /* If button 1 is pressed, indicate the light gun trigger is pressed */
+ ret |= ((m_in_0.i0 & 0x01) << 4);
+ }
+
+ if (LOG_JOY)
+ logerror("joy 0 read, val: %02x, pc: %04x, bits read: %d, chan0: %08x\n", ret, cpu_get_pc(&space.device()), m_in_0.shift, m_in_0.i0);
+
+ m_in_0.shift++;
+ }
+
+ return ret;
+}
+
+// row of the keyboard matrix are read 4-bits at time, and gets returned as bit1->bit4
+static UINT8 nes_read_fc_keyboard_line( running_machine &machine, UINT8 scan, UINT8 mode )
+{
+ static const char *const fc_keyport_names[] = { "FCKEY0", "FCKEY1", "FCKEY2", "FCKEY3", "FCKEY4", "FCKEY5", "FCKEY6", "FCKEY7", "FCKEY8" };
+ return ((machine.root_device().ioport(fc_keyport_names[scan])->read() >> (mode * 4)) & 0x0f) << 1;
+}
+
+static UINT8 nes_read_subor_keyboard_line( running_machine &machine, UINT8 scan, UINT8 mode )
+{
+ static const char *const sub_keyport_names[] = { "SUBKEY0", "SUBKEY1", "SUBKEY2", "SUBKEY3", "SUBKEY4",
+ "SUBKEY5", "SUBKEY6", "SUBKEY7", "SUBKEY8", "SUBKEY9", "SUBKEY10", "SUBKEY11", "SUBKEY12" };
+ return ((machine.root_device().ioport(sub_keyport_names[scan])->read() >> (mode * 4)) & 0x0f) << 1;
+}
+
+READ8_MEMBER(nes_state::nes_IN1_r)
+{
+ int cfg = ioport("CTRLSEL")->read();
+ int ret;
+
+ if ((cfg & 0x000f) == 0x07) // for now we treat the FC keyboard separately from other inputs!
+ {
+ if (m_fck_scan < 9)
+ ret = ~nes_read_fc_keyboard_line(machine(), m_fck_scan, m_fck_mode) & 0x1e;
+ else
+ ret = 0x1e;
+ }
+ else if ((cfg & 0x000f) == 0x08) // for now we treat the Subor keyboard separately from other inputs!
+ {
+ if (m_fck_scan < 12)
+ ret = ~nes_read_subor_keyboard_line(machine(), m_fck_scan, m_fck_mode) & 0x1e;
+ else
+ ret = 0x1e;
+ }
+ else
+ {
+ /* Some games expect bit 6 to be set because the last entry on the data bus shows up */
+ /* in the unused upper 3 bits, so typically a read from $4017 leaves 0x40 there. */
+ ret = 0x40;
+
+ /* Handle data line 0's serial output */
+ ret |= ((m_in_1.i0 >> m_in_1.shift) & 0x01);
+
+ /* zapper */
+ if ((cfg & 0x00f0) == 0x0030)
+ {
+ int x = m_in_1.i1; /* read Zapper x-position */
+ int y = m_in_1.i2; /* read Zapper y-position */
+ UINT32 pix, color_base;
+
+ /* get the pixel at the gun position */
+ pix = m_ppu->get_pixel(x, y);
+
+ /* get the color base from the ppu */
+ color_base = m_ppu->get_colorbase();
+
+ /* look at the screen and see if the cursor is over a bright pixel */
+ if ((pix == color_base + 0x20) || (pix == color_base + 0x30) ||
+ (pix == color_base + 0x33) || (pix == color_base + 0x34))
+ {
+ ret &= ~0x08; /* sprite hit */
+ }
+ else
+ ret |= 0x08; /* no sprite hit */
+
+ /* If button 1 is pressed, indicate the light gun trigger is pressed */
+ ret |= ((m_in_1.i0 & 0x01) << 4);
+ }
+
+ /* arkanoid dial */
+ else if ((cfg & 0x00f0) == 0x0040)
+ {
+ /* Handle data line 2's serial output */
+ ret |= ((m_in_1.i2 >> m_in_1.shift) & 0x01) << 3;
+
+ /* Handle data line 3's serial output - bits are reversed */
+ /* NPW 27-Nov-2007 - there is no third subscript! commenting out */
+ /* ret |= ((m_in_1[3] >> m_in_1.shift) & 0x01) << 4; */
+ /* ret |= ((m_in_1[3] << m_in_1.shift) & 0x80) >> 3; */
+ }
+
+ if (LOG_JOY)
+ logerror("joy 1 read, val: %02x, pc: %04x, bits read: %d, chan0: %08x\n", ret, cpu_get_pc(&space.device()), m_in_1.shift, m_in_1.i0);
+
+ m_in_1.shift++;
+ }
+
+ return ret;
+}
+
+
+// FIXME: this is getting messier and messier (no pun intended). inputs reading should be simplified and port_categories cleaned up
+// to also emulate the fact that nothing should be in Port 2 if there is a Crazy Climber pad, etc.
+static void nes_read_input_device( running_machine &machine, int cfg, nes_input *vals, int pad_port, int supports_zapper )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ static const char *const padnames[] = { "PAD1", "PAD2", "PAD3", "PAD4", "CC_LEFT", "CC_RIGHT" };
+
+ vals->i0 = 0;
+ vals->i1 = 0;
+ vals->i2 = 0;
+
+ switch (cfg & 0x0f)
+ {
+ case 0x01: /* gamepad */
+ if (pad_port >= 0)
+ vals->i0 = machine.root_device().ioport(padnames[pad_port])->read();
+ break;
+
+ case 0x02: /* zapper 1 */
+ if (supports_zapper)
+ {
+ vals->i0 = machine.root_device().ioport("ZAPPER1_T")->read();
+ vals->i1 = machine.root_device().ioport("ZAPPER1_X")->read();
+ vals->i2 = machine.root_device().ioport("ZAPPER1_Y")->read();
+ }
+ break;
+
+ case 0x03: /* zapper 2 */
+ if (supports_zapper)
+ {
+ vals->i0 = machine.root_device().ioport("ZAPPER2_T")->read();
+ vals->i1 = machine.root_device().ioport("ZAPPER2_X")->read();
+ vals->i2 = machine.root_device().ioport("ZAPPER2_Y")->read();
+ }
+ break;
+
+ case 0x04: /* arkanoid paddle */
+ if (pad_port == 1)
+ vals->i0 = (UINT8) ((UINT8) machine.root_device().ioport("PADDLE")->read() + (UINT8)0x52) ^ 0xff;
+ break;
+
+ case 0x06: /* crazy climber controller */
+ if (pad_port == 0)
+ {
+ state->m_in_0.i0 = machine.root_device().ioport(padnames[4])->read();
+ state->m_in_1.i0 = machine.root_device().ioport(padnames[5])->read();
+ }
+ break;
+ }
+}
+
+
+static TIMER_CALLBACK( lightgun_tick )
+{
+ if ((machine.root_device().ioport("CTRLSEL")->read() & 0x000f) == 0x0002)
+ {
+ /* enable lightpen crosshair */
+ crosshair_set_screen(machine, 0, CROSSHAIR_SCREEN_ALL);
+ }
+ else
+ {
+ /* disable lightpen crosshair */
+ crosshair_set_screen(machine, 0, CROSSHAIR_SCREEN_NONE);
+ }
+
+ if ((machine.root_device().ioport("CTRLSEL")->read() & 0x00f0) == 0x0030)
+ {
+ /* enable lightpen crosshair */
+ crosshair_set_screen(machine, 1, CROSSHAIR_SCREEN_ALL);
+ }
+ else
+ {
+ /* disable lightpen crosshair */
+ crosshair_set_screen(machine, 1, CROSSHAIR_SCREEN_NONE);
+ }
+}
+
+WRITE8_MEMBER(nes_state::nes_IN0_w)
+{
+ int cfg = ioport("CTRLSEL")->read();
+
+ /* Check if lightgun has been chosen as input: if so, enable crosshair */
+ machine().scheduler().timer_set(attotime::zero, FUNC(lightgun_tick));
+
+ if ((cfg & 0x000f) >= 0x07) // for now we treat the FC keyboard separately from other inputs!
+ {
+ // here we should also have the tape output
+
+ if (BIT(data, 2)) // keyboard active
+ {
+ int lines = ((cfg & 0x000f) == 0x04) ? 9 : 12;
+ UINT8 out = BIT(data, 1); // scan
+
+ if (m_fck_mode && !out && ++m_fck_scan > lines)
+ m_fck_scan = 0;
+
+ m_fck_mode = out; // access lower or upper 4 bits
+
+ if (BIT(data, 0)) // reset
+ m_fck_scan = 0;
+ }
+ }
+ else
+ {
+ if (data & 0x01)
+ return;
+
+ if (LOG_JOY)
+ logerror("joy 0 bits read: %d\n", m_in_0.shift);
+
+ /* Toggling bit 0 high then low resets both controllers */
+ m_in_0.shift = 0;
+ m_in_1.shift = 0;
+
+ /* Read the input devices */
+ if ((cfg & 0x000f) != 0x06)
+ {
+ nes_read_input_device(machine(), cfg >> 0, &m_in_0, 0, TRUE);
+ nes_read_input_device(machine(), cfg >> 4, &m_in_1, 1, TRUE);
+ nes_read_input_device(machine(), cfg >> 8, &m_in_2, 2, FALSE);
+ nes_read_input_device(machine(), cfg >> 12, &m_in_3, 3, FALSE);
+ }
+ else // crazy climber pad
+ {
+ nes_read_input_device(machine(), 0, &m_in_1, 1, TRUE);
+ nes_read_input_device(machine(), 0, &m_in_2, 2, FALSE);
+ nes_read_input_device(machine(), 0, &m_in_3, 3, FALSE);
+ nes_read_input_device(machine(), cfg >> 0, &m_in_0, 0, TRUE);
+ }
+
+ if (cfg & 0x0f00)
+ m_in_0.i0 |= (m_in_2.i0 << 8) | (0x08 << 16);
+
+ if (cfg & 0xf000)
+ m_in_1.i0 |= (m_in_3.i0 << 8) | (0x04 << 16);
+ }
+}
+
+
+WRITE8_MEMBER(nes_state::nes_IN1_w)
+{
+}
+
+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;
+}
+
+DEVICE_IMAGE_LOAD( nes_cart )
+{
+ nes_state *state = image.device().machine().driver_data<nes_state>();
+ state->m_pcb_id = NO_BOARD; // initialization
+
+ if (image.software_entry() == NULL)
+ {
+ const char *mapinfo = NULL;
+ int mapint1 = 0, mapint2 = 0, mapint3 = 0, mapint4 = 0; //, goodcrcinfo = 0;
+ char magic[4], extend[5];
+ int local_options = 0;
+ char m;
+
+ /* 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 */
+ memset(magic, '\0', sizeof(magic));
+ image.fread(magic, 4);
+
+ if ((magic[0] == 'N') && (magic[1] == 'E') && (magic[2] == 'S')) /* If header starts with 'NES' it is iNES */
+ {
+ UINT32 prg_size;
+ state->m_ines20 = 0;
+ state->m_battery_size = NES_BATTERY_SIZE; // with iNES we can only support 8K WRAM battery (iNES 2.0 might fix this)
+ state->m_prg_ram = 1; // always map state->m_wram in bank5 (eventually, this should be enabled only for some mappers)
+
+ // check if the image is recognized by nes.hsi
+ mapinfo = hashfile_extrainfo(image);
+
+ // image_extrainfo() resets the file position back to start.
+ // Let's skip past the magic header once again.
+ image.fseek(4, SEEK_SET);
+
+ image.fread(&state->m_prg_chunks, 1);
+ image.fread(&state->m_chr_chunks, 1);
+ /* Read the first ROM option byte (offset 6) */
+ image.fread(&m, 1);
+
+ /* Interpret the iNES header flags */
+ state->m_mapper = (m & 0xf0) >> 4;
+ local_options = m & 0x0f;
+
+ /* Read the second ROM option byte (offset 7) */
+ image.fread(&m, 1);
+
+ switch (m & 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
+ state->m_ines20 = 1;
+ case 0x0:
+ default:
+ state->m_mapper = state->m_mapper | (m & 0xf0);
+ break;
+ }
+
+ if (mapinfo /* && !state->m_ines20 */)
+ {
+ if (4 == sscanf(mapinfo,"%d %d %d %d", &mapint1, &mapint2, &mapint3, &mapint4))
+ {
+ /* image is present in nes.hsi: overwrite the header settings with these */
+ state->m_mapper = mapint1;
+ local_options = mapint2 & 0x0f;
+ state->m_crc_hack = (mapint2 & 0xf0) >> 4; // this is used to differentiate among variants of the same Mapper (see below)
+ state->m_prg_chunks = mapint3;
+ state->m_chr_chunks = mapint4;
+ logerror("NES.HSI info: %d %d %d %d\n", mapint1, mapint2, mapint3, mapint4);
+// mame_printf_error("NES.HSI info: %d %d %d %d\n", mapint1, mapint2, mapint3, mapint4);
+// goodcrcinfo = 1;
+ state->m_ines20 = 0;
+ }
+ else
+ {
+ logerror("NES: [%s], Invalid mapinfo found\n", mapinfo);
+ }
+ }
+ else
+ {
+ logerror("NES: No extrainfo found\n");
+ }
+
+ state->m_hard_mirroring = (local_options & 0x01) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ;
+// mame_printf_error("%s\n", state->m_hard_mirroring & 0x01 ? "Vertical" : "Horizontal");
+ state->m_battery = local_options & 0x02;
+ state->m_trainer = local_options & 0x04;
+ state->m_four_screen_vram = local_options & 0x08;
+
+ if (state->m_battery)
+ logerror("-- Battery found\n");
+
+ if (state->m_trainer)
+ logerror("-- Trainer found\n");
+
+ if (state->m_four_screen_vram)
+ logerror("-- 4-screen VRAM\n");
+
+ if (state->m_ines20)
+ {
+ logerror("Extended iNES format:\n");
+ image.fread(&extend, 5);
+ state->m_mapper |= (extend[0] & 0x0f) << 8;
+ logerror("-- mapper: %d\n", state->m_mapper);
+ logerror("-- submapper: %d\n", (extend[0] & 0xf0) >> 4);
+ state->m_prg_chunks |= ((extend[1] & 0x0f) << 8);
+ state->m_chr_chunks |= ((extend[1] & 0xf0) << 4);
+ logerror("-- PRG chunks: %d\n", state->m_prg_chunks);
+ logerror("-- CHR chunks: %d\n", state->m_chr_chunks);
+ logerror("-- PRG NVWRAM: %d\n", extend[2] & 0x0f);
+ logerror("-- PRG WRAM: %d\n", (extend[2] & 0xf0) >> 4);
+ logerror("-- CHR NVWRAM: %d\n", extend[3] & 0x0f);
+ logerror("-- CHR WRAM: %d\n", (extend[3] & 0xf0) >> 4);
+ logerror("-- TV System: %d\n", extend[4] & 3);
+ }
+
+ // Allocate class pointers for PRG/VROM/VRAM/WRAM
+ prg_size = (state->m_prg_chunks == 1) ? 2 * 0x4000 : state->m_prg_chunks * 0x4000;
+ state->m_prg = auto_alloc_array(image.device().machine(), UINT8, prg_size);
+ if (state->m_chr_chunks)
+ state->m_vrom = auto_alloc_array(image.device().machine(), UINT8, state->m_chr_chunks * 0x2000);
+
+ state->m_vram_chunks = 2;
+ state->m_vram = auto_alloc_array(image.device().machine(), UINT8, 0x4000);
+
+ // FIXME: this should only be allocated if there is actual wram in the cart (i.e. if state->m_prg_ram = 1)!
+ // or if there is a trainer, I think
+ state->m_wram_size = 0x10000;
+ state->m_wram = auto_alloc_array(image.device().machine(), UINT8, state->m_wram_size);
+
+ /* Setup PCB type (needed to add proper handlers later) */
+ state->m_pcb_id = nes_get_mmc_id(image.device().machine(), state->m_mapper);
+
+ // a few mappers correspond to multiple PCBs, so we need a few additional checks
+ switch (state->m_pcb_id)
+ {
+ case STD_CNROM:
+ if (state->m_mapper == 185)
+ {
+ switch (state->m_crc_hack)
+ {
+ case 0x0: // pin26: CE, pin27: CE (B-Wings, Bird Week)
+ state->m_ce_mask = 0x03;
+ state->m_ce_state = 0x03;
+ break;
+ case 0x4: // pin26: CE, pin27: /CE (Mighty Bomb Jack, Spy Vs. Spy)
+ state->m_ce_mask = 0x03;
+ state->m_ce_state = 0x01;
+ break;
+ case 0x8: // pin26: /CE, pin27: CE (Sansu 1, 2, 3 Nen)
+ state->m_ce_mask = 0x03;
+ state->m_ce_state = 0x02;
+ break;
+ case 0xc: // pin26: /CE, pin27: /CE (Seicross v2.0)
+ state->m_ce_mask = 0x03;
+ state->m_ce_state = 0x00;
+ break;
+ }
+ }
+ break;
+ case KONAMI_VRC2:
+ if (state->m_mapper == 22)
+ {
+ state->m_vrc_ls_prg_a = 0;
+ state->m_vrc_ls_prg_b = 1;
+ state->m_vrc_ls_chr = 1;
+ }
+ if (state->m_mapper == 23 && !state->m_crc_hack)
+ {
+ state->m_vrc_ls_prg_a = 1;
+ state->m_vrc_ls_prg_b = 0;
+ state->m_vrc_ls_chr = 0;
+ }
+ if (state->m_mapper == 23 && state->m_crc_hack)
+ {
+ // here there are also Akumajou Special, Crisis Force, Parodius da!, Tiny Toons which are VRC-4
+ state->m_vrc_ls_prg_a = 3;
+ state->m_vrc_ls_prg_b = 2;
+ state->m_pcb_id = KONAMI_VRC4; // this allows for konami_irq to be installed at reset
+ }
+ break;
+ case KONAMI_VRC4:
+ if (state->m_mapper == 21)
+ {
+ // Wai Wai World 2 & Ganbare Goemon Gaiden 2 (the latter with crc_hack)
+ state->m_vrc_ls_prg_a = state->m_crc_hack ? 7 : 2;
+ state->m_vrc_ls_prg_b = state->m_crc_hack ? 6 : 1;
+ }
+ if (state->m_mapper == 25) // here there is also Ganbare Goemon Gaiden which is VRC-2
+ {
+ state->m_vrc_ls_prg_a = state->m_crc_hack ? 2 : 0;
+ state->m_vrc_ls_prg_b = state->m_crc_hack ? 3 : 1;
+ }
+ break;
+ case KONAMI_VRC6:
+ if (state->m_mapper == 24)
+ {
+ state->m_vrc_ls_prg_a = 1;
+ state->m_vrc_ls_prg_b = 0;
+ }
+ if (state->m_mapper == 26)
+ {
+ state->m_vrc_ls_prg_a = 0;
+ state->m_vrc_ls_prg_b = 1;
+ }
+ break;
+ case IREM_G101:
+ if (state->m_crc_hack)
+ state->m_hard_mirroring = PPU_MIRROR_HIGH; // Major League has hardwired mirroring
+ break;
+ case DIS_74X161X161X32:
+ if (state->m_mapper == 70)
+ state->m_hard_mirroring = PPU_MIRROR_VERT; // only hardwired mirroring makes different mappers 70 & 152
+ break;
+ case SUNSOFT_2:
+ if (state->m_mapper == 93)
+ state->m_hard_mirroring = PPU_MIRROR_VERT; // only hardwired mirroring makes different mappers 89 & 93
+ break;
+ case STD_BXROM:
+ if (state->m_crc_hack)
+ state->m_pcb_id = AVE_NINA01; // Mapper 34 is used for 2 diff boards
+ break;
+ case BANDAI_LZ93:
+ if (state->m_crc_hack)
+ state->m_pcb_id = BANDAI_JUMP2; // Mapper 153 is used for 2 diff boards
+ break;
+ case IREM_HOLYDIV:
+ if (state->m_crc_hack)
+ state->m_pcb_id = JALECO_JF16; // Mapper 78 is used for 2 diff boards
+ break;
+ case CAMERICA_BF9093:
+ if (state->m_crc_hack)
+ state->m_pcb_id = CAMERICA_BF9097; // Mapper 71 is used for 2 diff boards
+ break;
+ case HES_BOARD:
+ if (state->m_crc_hack)
+ state->m_pcb_id = HES6IN1_BOARD; // Mapper 113 is used for 2 diff boards
+ break;
+ case WAIXING_ZS:
+ if (state->m_crc_hack)
+ state->m_pcb_id = WAIXING_DQ8; // Mapper 242 is used for 2 diff boards
+ break;
+ case BMC_GOLD_7IN1:
+ if (state->m_crc_hack)
+ state->m_pcb_id = BMC_MARIOPARTY_7IN1; // Mapper 52 is used for 2 diff boards
+ break;
+ //FIXME: we also have to fix Action 52 PRG loading somewhere...
+ }
+
+ /* Allocate internal Mapper RAM for boards which require it */
+ if (state->m_pcb_id == STD_EXROM)
+ state->m_mapper_ram = auto_alloc_array(image.device().machine(), UINT8, 0x400);
+
+ if (state->m_pcb_id == TAITO_X1_005 || state->m_pcb_id == TAITO_X1_005_A)
+ state->m_mapper_bram = auto_alloc_array(image.device().machine(), UINT8, 0x80);
+
+ if (state->m_pcb_id == TAITO_X1_017)
+ state->m_mapper_bram = auto_alloc_array(image.device().machine(), UINT8, 0x1400);
+
+ if (state->m_pcb_id == NAMCOT_163)
+ state->m_mapper_ram = auto_alloc_array(image.device().machine(), UINT8, 0x2000);
+
+ if (state->m_pcb_id == FUKUTAKE_BOARD)
+ state->m_mapper_ram = auto_alloc_array(image.device().machine(), UINT8, 2816);
+
+ /* Position past the header */
+ image.fseek(16, SEEK_SET);
+
+ /* Load the 0x200 byte trainer at 0x7000 if it exists */
+ if (state->m_trainer)
+ image.fread(&state->m_wram[0x1000], 0x200);
+
+ /* Read in the program chunks */
+ image.fread(&state->m_prg[0], 0x4000 * state->m_prg_chunks);
+ if (state->m_prg_chunks == 1)
+ memcpy(&state->m_prg[0x4000], &state->m_prg[0], 0x4000);
+
+#if SPLIT_PRG
+ {
+ FILE *prgout;
+ char outname[255];
+
+ sprintf(outname, "%s.prg", image.filename());
+ prgout = fopen(outname, "wb");
+ if (prgout)
+ {
+ fwrite(&state->m_prg[0], 1, 0x4000 * state->m_prg_chunks, prgout);
+ mame_printf_error("Created PRG chunk\n");
+ }
+
+ fclose(prgout);
+ }
+#endif
+
+ logerror("**\n");
+ logerror("Mapper: %d\n", state->m_mapper);
+ logerror("PRG chunks: %02x, size: %06x\n", state->m_prg_chunks, 0x4000 * state->m_prg_chunks);
+ // mame_printf_error("Mapper: %d\n", state->m_mapper);
+ // mame_printf_error("PRG chunks: %02x, size: %06x\n", state->m_prg_chunks, 0x4000 * state->m_prg_chunks);
+
+ /* Read in any chr chunks */
+ if (state->m_chr_chunks > 0)
+ {
+ image.fread(state->m_vrom, state->m_chr_chunks * 0x2000);
+ if (state->m_mapper == 2)
+ logerror("Warning: VROM has been found in VRAM-based mapper. Either the mapper is set wrong or the ROM image is incorrect.\n");
+ }
+
+#if SPLIT_CHR
+ if (state->m_chr_chunks > 0)
+ {
+ FILE *chrout;
+ char outname[255];
+
+ sprintf(outname, "%s.chr", image.filename());
+ chrout= fopen(outname, "wb");
+ if (chrout)
+ {
+ fwrite(state->m_vrom, 1, 0x2000 * state->m_chr_chunks, chrout);
+ mame_printf_error("Created CHR chunk\n");
+ }
+ fclose(chrout);
+ }
+#endif
+
+ logerror("CHR chunks: %02x, size: %06x\n", state->m_chr_chunks, 0x2000 * state->m_chr_chunks);
+ logerror("**\n");
+ // mame_printf_error("CHR chunks: %02x, size: %06x\n", state->m_chr_chunks, 0x2000 * state->m_chr_chunks);
+ // mame_printf_error("**\n");
+ }
+ else if ((magic[0] == 'U') && (magic[1] == 'N') && (magic[2] == 'I') && (magic[3] == 'F')) /* If header starts with 'UNIF' it is UNIF */
+ {
+ UINT32 unif_ver = 0;
+ char magic2[4];
+ UINT8 buffer[4];
+ UINT32 chunk_length = 0, read_length = 0x20;
+ UINT32 prg_start = 0, chr_start = 0, prg_size;
+ char unif_mapr[32]; // here we should store MAPR chunks
+ UINT32 size = image.length();
+ int mapr_chunk_found = 0;
+ // allocate space to temporarily store PRG & CHR banks
+ UINT8 *temp_prg = auto_alloc_array(image.device().machine(), UINT8, 256 * 0x4000);
+ UINT8 *temp_chr = auto_alloc_array(image.device().machine(), UINT8, 256 * 0x2000);
+ UINT8 temp_byte = 0;
+
+ /* init prg/chr chunks to 0: the exact number of chunks will be determined while reading the file */
+ state->m_prg_chunks = 0;
+ state->m_chr_chunks = 0;
+
+ image.fread(&buffer, 4);
+ unif_ver = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
+ logerror("UNIF file found, version %d\n", unif_ver);
+
+ if (size <= 0x20)
+ {
+ logerror("%s only contains the UNIF header and no data.\n", image.filename());
+ return IMAGE_INIT_FAIL;
+ }
+
+ do
+ {
+ image.fseek(read_length, SEEK_SET);
+
+ memset(magic2, '\0', sizeof(magic2));
+ image.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 = 1;
+ logerror("[MAPR] chunk found: ");
+ image.fread(&buffer, 4);
+ chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
+
+ if (chunk_length <= 0x20)
+ image.fread(&unif_mapr, chunk_length);
+
+ // find out prg/chr size, battery, wram, etc.
+ unif_mapr_setup(image.device().machine(), unif_mapr);
+
+ /* now that we found the MAPR chunk, we can go back to load other chunks */
+ image.fseek(0x20, SEEK_SET);
+ read_length = 0x20;
+ }
+ else
+ {
+ logerror("Skip this chunk. We need a [MAPR] chunk before anything else.\n");
+ image.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");
+ image.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");
+ image.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");
+ image.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");
+ image.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");
+ image.fread(&buffer, 4);
+ chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
+
+ image.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");
+ image.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");
+ image.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");
+ image.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");
+ image.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");
+ image.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");
+ image.fread(&buffer, 4);
+ chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
+
+ image.fread(&temp_byte, 1);
+ switch (temp_byte)
+ {
+ case 0: // Horizontal Mirroring (Hard Wired)
+ state->m_hard_mirroring = PPU_MIRROR_HORZ;
+ break;
+ case 1: // Vertical Mirroring (Hard Wired)
+ state->m_hard_mirroring = PPU_MIRROR_VERT;
+ break;
+ case 2: // Mirror All Pages From $2000 (Hard Wired)
+ state->m_hard_mirroring = PPU_MIRROR_LOW;
+ break;
+ case 3: // Mirror All Pages From $2400 (Hard Wired)
+ state->m_hard_mirroring = PPU_MIRROR_HIGH;
+ break;
+ case 4: // Four Screens of VRAM (Hard Wired)
+ state->m_four_screen_vram = 1;
+ break;
+ case 5: // Mirroring Controlled By Mapper Hardware
+ logerror("Mirroring handled by the board hardware.\n");
+ // default to horizontal at start
+ state->m_hard_mirroring = PPU_MIRROR_HORZ;
+ break;
+ default:
+ logerror("Undocumented mirroring value.\n");
+ // default to horizontal
+ state->m_hard_mirroring = PPU_MIRROR_HORZ;
+ break;
+ }
+
+ 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]);
+ image.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]);
+ image.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]);
+ image.fread(&buffer, 4);
+ chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
+
+ // FIXME: we currently don't support PRG chunks smaller than 16K!
+ state->m_prg_chunks += (chunk_length / 0x4000);
+
+ if (chunk_length / 0x4000)
+ logerror("It consists of %d 16K-blocks.\n", chunk_length / 0x4000);
+ else
+ 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 */
+ image.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]);
+ image.fread(&buffer, 4);
+ chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
+
+ state->m_chr_chunks += (chunk_length / 0x2000);
+
+ logerror("It consists of %d 8K-blocks.\n", chunk_length / 0x2000);
+
+ /* Read in the vrom chunks */
+ image.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)
+ {
+ auto_free(image.device().machine(), temp_prg);
+ auto_free(image.device().machine(), temp_chr);
+ fatalerror("UNIF should have a [MAPR] chunk to work. Check if your image has been corrupted");
+ }
+
+ if (!prg_start)
+ {
+ auto_free(image.device().machine(), temp_prg);
+ auto_free(image.device().machine(), temp_chr);
+ fatalerror("Unsupported UNIF chunk or corrupted header. Please report the problem at MESS Board.\n");
+ }
+
+ // Allocate class pointers for PRG/VROM/VRAM/WRAM and copy data there from the temp copies
+
+ /* Take care of PRG */
+ prg_size = (state->m_prg_chunks == 1) ? 2 * 0x4000 : state->m_prg_chunks * 0x4000;
+ state->m_prg = auto_alloc_array(image.device().machine(), UINT8, prg_size);
+
+ memcpy(&state->m_prg[0], &temp_prg[0], state->m_prg_chunks * 0x4000);
+ /* If only a single 16K PRG chunk is present, mirror it! */
+ if (state->m_prg_chunks == 1)
+ memcpy(&state->m_prg[0x4000], &state->m_prg[0], 0x4000);
+
+ /* Take care of CHR ROM */
+ if (state->m_chr_chunks)
+ {
+ state->m_vrom = auto_alloc_array(image.device().machine(), UINT8, state->m_chr_chunks * 0x2000);
+ memcpy(&state->m_vrom[0x00000], &temp_chr[0x00000], state->m_chr_chunks * 0x2000);
+ }
+
+ /* Take care of CHR RAM */
+ if (state->m_vram_chunks)
+ state->m_vram = auto_alloc_array(image.device().machine(), UINT8, state->m_vram_chunks * 0x2000);
+
+ // FIXME: this should only be allocated if there is actual wram in the cart (i.e. if state->m_prg_ram = 1)!
+ state->m_wram_size = 0x10000;
+ state->m_wram = auto_alloc_array(image.device().machine(), UINT8, state->m_wram_size);
+
+#if SPLIT_PRG
+ {
+ FILE *prgout;
+ char outname[255];
+
+ sprintf(outname, "%s.prg", image.filename());
+ prgout = fopen(outname, "wb");
+ if (prgout)
+ {
+ fwrite(&state->m_prg[0], 1, 0x4000 * state->m_prg_chunks, prgout);
+ mame_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", image.filename());
+ chrout= fopen(outname, "wb");
+ if (chrout)
+ {
+ fwrite(state->m_vrom, 1, 0x2000 * state->m_chr_chunks, chrout);
+ mame_printf_error("Created CHR chunk\n");
+ }
+ fclose(chrout);
+ }
+#endif
+ // free the temporary copy of PRG/CHR
+ auto_free(image.device().machine(), temp_prg);
+ auto_free(image.device().machine(), temp_chr);
+ logerror("UNIF support is only very preliminary.\n");
+ }
+ else
+ {
+ logerror("%s is NOT a file in either iNES or UNIF format.\n", image.filename());
+ return IMAGE_INIT_FAIL;
+ }
+ }
+ else
+ {
+ UINT32 prg_size = image.get_software_region_length("prg");
+ UINT32 chr_size = image.get_software_region_length("chr");
+ UINT32 vram_size = image.get_software_region_length("vram");
+ vram_size += image.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");
+ if (prg_size < 0x8000)
+ fatalerror("PRG entry is too small! Please check if the xml list got corrupted");
+
+ // Allocate class pointers for PRG/VROM/VRAM/WRAM and copy data there from the temp copies
+ state->m_prg = auto_alloc_array(image.device().machine(), UINT8, prg_size);
+
+ if (chr_size)
+ state->m_vrom = auto_alloc_array(image.device().machine(), UINT8, chr_size);
+
+ if (vram_size)
+ state->m_vram = auto_alloc_array(image.device().machine(), UINT8, vram_size);
+
+ memcpy(state->m_prg, image.get_software_region("prg"), prg_size);
+
+ if (chr_size)
+ memcpy(state->m_vrom, image.get_software_region("chr"), chr_size);
+
+ state->m_prg_chunks = prg_size / 0x4000;
+ state->m_chr_chunks = chr_size / 0x2000;
+ state->m_vram_chunks = vram_size / 0x2000;
+
+ state->m_pcb_id = nes_get_pcb_id(image.device().machine(), image.get_feature("pcb"));
+
+ if (state->m_pcb_id == STD_TVROM || state->m_pcb_id == STD_DRROM || state->m_pcb_id == IREM_LROG017)
+ state->m_four_screen_vram = 1;
+ else
+ state->m_four_screen_vram = 0;
+
+ state->m_battery = (image.get_software_region("bwram") != NULL) ? 1 : 0;
+ state->m_battery_size = image.get_software_region_length("bwram");
+
+ if (state->m_pcb_id == BANDAI_LZ93EX)
+ {
+ // allocate the 24C01 or 24C02 EEPROM
+ state->m_battery = 1;
+ state->m_battery_size += 0x2000;
+ }
+
+ if (state->m_pcb_id == BANDAI_DATACH)
+ {
+ // allocate the 24C01 and 24C02 EEPROM
+ state->m_battery = 1;
+ state->m_battery_size += 0x4000;
+ }
+
+ state->m_prg_ram = (image.get_software_region("wram") != NULL) ? 1 : 0;
+ state->m_wram_size = image.get_software_region_length("wram");
+ state->m_mapper_ram_size = image.get_software_region_length("mapper_ram");
+ state->m_mapper_bram_size = image.get_software_region_length("mapper_bram");
+
+ if (state->m_prg_ram)
+ state->m_wram = auto_alloc_array(image.device().machine(), UINT8, state->m_wram_size);
+ if (state->m_mapper_ram_size)
+ state->m_mapper_ram = auto_alloc_array(image.device().machine(), UINT8, state->m_mapper_ram_size);
+ if (state->m_mapper_bram_size)
+ state->m_mapper_bram = auto_alloc_array(image.device().machine(), UINT8, state->m_mapper_bram_size);
+
+ /* Check for mirroring */
+ if (image.get_feature("mirroring") != NULL)
+ {
+ const char *mirroring = image.get_feature("mirroring");
+ if (!strcmp(mirroring, "horizontal"))
+ state->m_hard_mirroring = PPU_MIRROR_HORZ;
+ if (!strcmp(mirroring, "vertical"))
+ state->m_hard_mirroring = PPU_MIRROR_VERT;
+ if (!strcmp(mirroring, "high"))
+ state->m_hard_mirroring = PPU_MIRROR_HIGH;
+ if (!strcmp(mirroring, "low"))
+ state->m_hard_mirroring = PPU_MIRROR_LOW;
+ }
+
+ state->m_chr_open_bus = 0;
+ state->m_ce_mask = 0;
+ state->m_ce_state = 0;
+ state->m_vrc_ls_prg_a = 0;
+ state->m_vrc_ls_prg_b = 0;
+ state->m_vrc_ls_chr = 0;
+
+ /* Check for pins in specific boards which require them */
+ if (state->m_pcb_id == STD_CNROM)
+ {
+ if (image.get_feature("chr-pin26") != NULL)
+ {
+ state->m_ce_mask |= 0x01;
+ state->m_ce_state |= !strcmp(image.get_feature("chr-pin26"), "CE") ? 0x01 : 0;
+ }
+ if (image.get_feature("chr-pin27") != NULL)
+ {
+ state->m_ce_mask |= 0x02;
+ state->m_ce_state |= !strcmp(image.get_feature("chr-pin27"), "CE") ? 0x02 : 0;
+ }
+ }
+
+ if (state->m_pcb_id == TAITO_X1_005 && image.get_feature("x1-pin17") != NULL && image.get_feature("x1-pin31") != NULL)
+ {
+ if (!strcmp(image.get_feature("x1-pin17"), "CIRAM A10") && !strcmp(image.get_feature("x1-pin31"), "NC"))
+ state->m_pcb_id = TAITO_X1_005_A;
+ }
+
+ if (state->m_pcb_id == KONAMI_VRC2)
+ {
+ state->m_vrc_ls_prg_a = nes_cart_get_line(image.get_feature("vrc2-pin3"));
+ state->m_vrc_ls_prg_b = nes_cart_get_line(image.get_feature("vrc2-pin4"));
+ state->m_vrc_ls_chr = (nes_cart_get_line(image.get_feature("vrc2-pin21")) != 10) ? 1 : 0;
+// mame_printf_error("VRC-2, pin3: A%d, pin4: A%d, pin21: %s\n", state->m_vrc_ls_prg_a, state->m_vrc_ls_prg_b, state->m_vrc_ls_chr ? "NC" : "A10");
+ }
+
+ if (state->m_pcb_id == KONAMI_VRC4)
+ {
+ state->m_vrc_ls_prg_a = nes_cart_get_line(image.get_feature("vrc4-pin3"));
+ state->m_vrc_ls_prg_b = nes_cart_get_line(image.get_feature("vrc4-pin4"));
+// mame_printf_error("VRC-4, pin3: A%d, pin4: A%d\n", state->m_vrc_ls_prg_a, state->m_vrc_ls_prg_b);
+ }
+
+ if (state->m_pcb_id == KONAMI_VRC6)
+ {
+ state->m_vrc_ls_prg_a = nes_cart_get_line(image.get_feature("vrc6-pin9"));
+ state->m_vrc_ls_prg_b = nes_cart_get_line(image.get_feature("vrc6-pin10"));
+// mame_printf_error("VRC-6, pin9: A%d, pin10: A%d\n", state->m_vrc_ls_prg_a, state->m_vrc_ls_prg_b);
+ }
+
+ /* Check for other misc board variants */
+ if (state->m_pcb_id == STD_SOROM)
+ {
+ if (image.get_feature("mmc1_type") != NULL && !strcmp(image.get_feature("mmc1_type"), "MMC1A"))
+ state->m_pcb_id = STD_SOROM_A; // in MMC1-A PRG RAM is always enabled
+ }
+
+ if (state->m_pcb_id == STD_SXROM)
+ {
+ if (image.get_feature("mmc1_type") != NULL && !strcmp(image.get_feature("mmc1_type"), "MMC1A"))
+ state->m_pcb_id = STD_SXROM_A; // in MMC1-A PRG RAM is always enabled
+ }
+
+ if (state->m_pcb_id == STD_NXROM || state->m_pcb_id == SUNSOFT_DCS)
+ {
+ if (image.get_software_region("minicart") != NULL) // check for dual minicart
+ {
+ state->m_pcb_id = SUNSOFT_DCS;
+ // we shall load somewhere the minicart, but we still do not support this
+ }
+ }
+
+#if 0
+ if (state->m_pcb_id == UNSUPPORTED_BOARD)
+ mame_printf_error("This board (%s) is currently not supported by MESS\n", image.get_feature("pcb"));
+ mame_printf_error("PCB Feature: %s\n", image.get_feature("pcb"));
+ mame_printf_error("PRG chunks: %d\n", state->m_prg_chunks);
+ mame_printf_error("CHR chunks: %d\n", state->m_chr_chunks);
+ mame_printf_error("VRAM: Present %s, size: %d\n", state->m_vram_chunks ? "Yes" : "No", vram_size);
+ mame_printf_error("NVWRAM: Present %s, size: %d\n", state->m_battery ? "Yes" : "No", state->m_battery_size);
+ mame_printf_error("WRAM: Present %s, size: %d\n", state->m_prg_ram ? "Yes" : "No", state->m_wram_size);
+#endif
+ }
+
+ // 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 (state->m_battery || state->m_mapper_bram_size)
+ {
+ UINT8 *temp_nvram = auto_alloc_array(image.device().machine(), UINT8, state->m_battery_size + state->m_mapper_bram_size);
+ image.battery_load(temp_nvram, state->m_battery_size + state->m_mapper_bram_size, 0x00);
+ if (state->m_battery)
+ {
+ state->m_battery_ram = auto_alloc_array(image.device().machine(), UINT8, state->m_battery_size);
+ memcpy(state->m_battery_ram, temp_nvram, state->m_battery_size);
+ }
+ if (state->m_mapper_bram_size)
+ memcpy(state->m_mapper_bram, temp_nvram + state->m_battery_size, state->m_mapper_bram_size);
+
+ auto_free(image.device().machine(), temp_nvram);
+ }
+
+ return IMAGE_INIT_PASS;
+}
+
+
+
+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);
+}
+
+/**************************
+
+ Disk System emulation
+
+**************************/
+
+static void fds_irq( device_t *device, int scanline, int vblank, int blanked )
+{
+ nes_state *state = device->machine().driver_data<nes_state>();
+
+ if (state->m_IRQ_enable_latch)
+ device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE);
+
+ if (state->m_IRQ_enable)
+ {
+ if (state->m_IRQ_count <= 114)
+ {
+ device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE);
+ state->m_IRQ_enable = 0;
+ state->m_fds_status0 |= 0x01;
+ }
+ else
+ state->m_IRQ_count -= 114;
+ }
+}
+
+READ8_MEMBER(nes_state::nes_fds_r)
+{
+ UINT8 ret = 0x00;
+
+ switch (offset)
+ {
+ case 0x00: /* $4030 - disk status 0 */
+ ret = m_fds_status0;
+ /* clear the disk IRQ detect flag */
+ m_fds_status0 &= ~0x01;
+ break;
+ case 0x01: /* $4031 - data latch */
+ /* don't read data if disk is unloaded */
+ if (m_fds_data == NULL)
+ ret = 0;
+ else if (m_fds_current_side)
+ {
+ // a bunch of games (e.g. bshashsc and fairypin) keep reading beyond the last track
+ // what is the expected behavior?
+ if (m_fds_head_position > 65500)
+ m_fds_head_position = 0;
+ ret = m_fds_data[(m_fds_current_side - 1) * 65500 + m_fds_head_position++];
+ }
+ else
+ ret = 0;
+ break;
+ case 0x02: /* $4032 - disk status 1 */
+ /* return "no disk" status if disk is unloaded */
+ if (m_fds_data == NULL)
+ 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); /* 0 if a disk is inserted */
+ break;
+ case 0x03: /* $4033 */
+ ret = 0x80;
+ break;
+ default:
+ ret = 0x00;
+ break;
+ }
+
+ return ret;
+}
+
+WRITE8_MEMBER(nes_state::nes_fds_w)
+{
+
+ 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 = data;
+ break;
+ case 0x03:
+ // d0 = sound io (1 = enable)
+ // d1 = disk io (1 = enable)
+ break;
+ case 0x04:
+ /* write data out to disk */
+ break;
+ case 0x05:
+ m_fds_motor_on = BIT(data, 0);
+
+ if (BIT(data, 1))
+ m_fds_head_position = 0;
+
+ m_fds_read_mode = BIT(data, 2);
+ set_nt_mirroring(machine(), BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+
+ if ((!(data & 0x40)) && (m_fds_write_reg & 0x40))
+ m_fds_head_position -= 2; // ???
+
+ m_IRQ_enable_latch = BIT(data, 7);
+ m_fds_write_reg = data;
+ break;
+ }
+}
+
+static void nes_load_proc( device_image_interface &image )
+{
+ nes_state *state = image.device().machine().driver_data<nes_state>();
+ int header = 0;
+ state->m_fds_sides = 0;
+
+ if (image.length() % 65500)
+ header = 0x10;
+
+ state->m_fds_sides = (image.length() - header) / 65500;
+
+ if (state->m_fds_data == NULL)
+ state->m_fds_data = auto_alloc_array(image.device().machine(),UINT8,state->m_fds_sides * 65500); // I don't think we can arrive here ever, probably it can be removed...
+
+ /* if there is an header, skip it */
+ image.fseek(header, SEEK_SET);
+
+ image.fread(state->m_fds_data, 65500 * state->m_fds_sides);
+ return;
+}
+
+static void nes_unload_proc( device_image_interface &image )
+{
+ nes_state *state = image.device().machine().driver_data<nes_state>();
+
+ /* TODO: should write out changes here as well */
+ state->m_fds_sides = 0;
+}
+
+DRIVER_INIT_MEMBER(nes_state,famicom)
+{
+
+ /* clear some of the variables we don't use */
+ m_trainer = 0;
+ m_battery = 0;
+ m_prg_ram = 0;
+ m_four_screen_vram = 0;
+ m_hard_mirroring = 0;
+ m_prg_chunks = m_chr_chunks = 0;
+
+ /* initialize the disk system */
+ m_disk_expansion = 1;
+ m_pcb_id = NO_BOARD;
+
+ m_fds_sides = 0;
+ m_fds_last_side = 0;
+ m_fds_count = 0;
+ 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_fds_read_mode = m_fds_write_reg = 0;
+
+ m_fds_data = auto_alloc_array_clear(machine(), UINT8, 65500 * 2);
+ m_fds_ram = auto_alloc_array_clear(machine(), UINT8, 0x8000);
+ save_pointer(NAME(m_fds_ram), 0x8000);
+
+ floppy_install_load_proc(floppy_get_device(machine(), 0), nes_load_proc);
+ floppy_install_unload_proc(floppy_get_device(machine(), 0), nes_unload_proc);
+}
diff --git a/src/mess/machine/nes_ines.c b/src/mess/machine/nes_ines.c
new file mode 100644
index 00000000000..cb0850d7bed
--- /dev/null
+++ b/src/mess/machine/nes_ines.c
@@ -0,0 +1,465 @@
+/*****************************************************************************************
+
+ NES MMC Emulation
+
+ Support for iNES Mappers
+
+****************************************************************************************/
+
+typedef struct _nes_mmc nes_mmc;
+struct _nes_mmc
+{
+ int iNesMapper; /* iNES Mapper # */
+ int pcb_id;
+};
+
+/*************************************************************
+
+ 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.
+
+*************************************************************/
+
+/* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline,
+we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC,
+there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */
+static void ffe_irq( device_t *device, int scanline, int vblank, int blanked )
+{
+ nes_state *state = device->machine().driver_data<nes_state>();
+
+ /* 114 is the number of cycles per scanline */
+ /* TODO: change to reflect the actual number of cycles spent */
+ if (state->m_IRQ_enable)
+ {
+ if ((0xffff - state->m_IRQ_count) < 114)
+ {
+ device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE);
+ state->m_IRQ_count = 0xffff;
+ state->m_IRQ_enable = 0;
+ }
+ state->m_IRQ_count -= 114;
+ }
+}
+
+static WRITE8_HANDLER( mapper6_l_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("mapper6_l_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset)
+ {
+ case 0x1fe:
+ state->m_mmc_latch1 = data & 0x80;
+ set_nt_mirroring(space->machine(), BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
+ break;
+ case 0x1ff:
+ set_nt_mirroring(space->machine(), BIT(data, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+
+ case 0x401:
+ state->m_IRQ_enable = data & 0x01;
+ break;
+ case 0x402:
+ state->m_IRQ_count = (state->m_IRQ_count & 0xff00) | data;
+ break;
+ case 0x403:
+ state->m_IRQ_enable = 1;
+ state->m_IRQ_count = (state->m_IRQ_count & 0x00ff) | (data << 8);
+ break;
+ }
+}
+
+static WRITE8_HANDLER( mapper6_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("mapper6_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (!state->m_mmc_latch1) // when in "FFE mode" we are forced to use CHRRAM/EXRAM bank?
+ {
+ prg16_89ab(space->machine(), data >> 2);
+ // chr8(space->machine(), data & 0x03, ???);
+ // due to lack of info on the exact behavior, we simply act as if mmc_latch1=1
+ if (state->m_mmc_chr_source == CHRROM)
+ chr8(space->machine(), data & 0x03, CHRROM);
+ }
+ else if (state->m_mmc_chr_source == CHRROM) // otherwise, we can use CHRROM (when present)
+ chr8(space->machine(), data, CHRROM);
+}
+
+/*************************************************************
+
+ Mapper 8
+
+ Known Boards: FFE3 Copier Board
+ Games: Hacked versions of games
+
+ In MESS: Supported? (I have no games to test this)
+
+*************************************************************/
+
+static WRITE8_HANDLER( mapper8_w )
+{
+ LOG_MMC(("mapper8_w, offset: %04x, data: %02x\n", offset, data));
+
+ chr8(space->machine(), data & 0x07, CHRROM);
+ prg16_89ab(space->machine(), data >> 3);
+}
+
+/*************************************************************
+
+ Mapper 17
+
+ Known Boards: FFE8 Copier Board
+ Games: Hacked versions of games
+
+ In MESS: Supported?. IRQ support is just a guess (used to
+ use MMC3 IRQ but it was wrong and it never enabled it)
+
+*************************************************************/
+
+static WRITE8_HANDLER( mapper17_l_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("mapper17_l_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset)
+ {
+ case 0x1fe:
+ set_nt_mirroring(space->machine(), BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
+ break;
+ case 0x1ff:
+ set_nt_mirroring(space->machine(), BIT(data, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+
+ case 0x401:
+ state->m_IRQ_enable = data & 0x01;
+ break;
+ case 0x402:
+ state->m_IRQ_count = (state->m_IRQ_count & 0xff00) | data;
+ break;
+ case 0x403:
+ state->m_IRQ_enable = 1;
+ state->m_IRQ_count = (state->m_IRQ_count & 0x00ff) | (data << 8);
+ break;
+
+ case 0x404:
+ prg8_89(space->machine(), data);
+ break;
+ case 0x405:
+ prg8_ab(space->machine(), data);
+ break;
+ case 0x406:
+ prg8_cd(space->machine(), data);
+ break;
+ case 0x407:
+ prg8_ef(space->machine(), data);
+ break;
+
+ case 0x410:
+ case 0x411:
+ case 0x412:
+ case 0x413:
+ case 0x414:
+ case 0x415:
+ case 0x416:
+ case 0x417:
+ chr1_x(space->machine(), offset & 7, data, CHRROM);
+ break;
+ }
+}
+
+/*************************************************************
+
+ mmc_list
+
+ Supported mappers and corresponding 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, FFE_MAPPER6 },
+ { 7, STD_AXROM },
+ { 8, FFE_MAPPER8 },
+ { 9, STD_PXROM },
+ { 10, STD_FXROM },
+ { 11, DIS_74X377 },
+ { 12, REXSOFT_DBZ5 },
+ { 13, STD_CPROM },
+ { 14, REXSOFT_SL1632 },
+ { 15, WAIXING_PS2 },
+ { 16, BANDAI_LZ93EX }, // with 24c02
+ { 17, FFE_MAPPER17 },
+ { 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 World Hero board - Unsupported
+ // 28 Unused
+ // 29 Unused
+ // 30 Unused
+ // 31 Unused
+ { 32, IREM_G101 },
+ { 33, TAITO_TC0190FMC },
+ { 34, STD_BXROM },
+ { 35, UNL_SC127 },
+ { 36, TXC_STRIKEWOLF },
+ { 37, PAL_ZZ },
+ { 38, DIS_74X161X138 },
+ { 39, UNL_STUDYNGAME },
+ { 40, BTL_SMB2A },
+ { 41, CALTRON_6IN1 },
+ { 42, BTL_MARIOBABY }, // ai senshi nicol?
+ { 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_SMB2B },
+ { 51, BMC_BALLGAMES_11IN1 },
+ { 52, BMC_GOLD_7IN1 },
+ // 53 Supervision 16-in-1 - Unsupported
+ { 54, BMC_NOVELDIAMOND },
+ // 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_TETRISFAMILY },
+ { 62, BMC_SUPER_700IN1 },
+ // 63 CH001 X-in-1 - No info (nor images) available
+ { 64, TENGEN_800032 },
+ { 65, IREM_H3001 },
+ { 66, STD_GXROM },
+ { 67, SUNSOFT_3 },
+ { 68, STD_NXROM },
+ { 69, STD_JXROM },
+ { 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_HOLYDIV },
+ { 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 JY Company Type A (Aladdin, Final Fight 3, Super Mario World, Tekken 2) - Unsupported
+ { 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 Bootleg cart 2708 (Doki Doki Panic - FDS Conversion) - Unsupported
+ { 104, CAMERICA_GOLDENFIVE },
+ // 105 Nintendo World Championship - Unsupported
+ { 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, SOMERI_SL12 },
+ { 117, FUTUREMEDIA_BOARD },
+ { 118, STD_TXSROM },
+ { 119, STD_TQROM },
+ { 120, BTL_TOBIDASE },
+ { 121, KAY_PANDAPRINCE },
+ // 122 Unused
+ { 123, UNL_H2288 },
+ // 124 Unused
+ // 125 Unused
+ { 126, BMC_PJOY84 },
+ // 127 Unused
+ // 128 Unused
+ // 129 Unused
+ // 130 Unused
+ // 131 Unused
+ { 132, TXC_22211B },
+ { 133, SACHEN_SA72008 },
+ { 134, BMC_FAMILY_4646B },
+ // 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_3453 },
+ { 155, STD_SXROM_A }, // diff compared to MMC1 concern WRAM
+ { 156, OPENCORP_DAOU306 },
+ { 157, BANDAI_DATACH }, // no Datach Reader -> we fall back to mapper 16
+ { 158, TENGEN_800037 },
+ { 159, BANDAI_LZ93EX }, // with 24c01
+ { 160, SACHEN_SA009 },
+ // 161 Unused
+ // 162 Unused
+ { 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_22211B },
+ { 173, TXC_22211C },
+ // 174 Unused
+ { 175, KAISER_KS7022},
+ { 176, UNL_XZY },
+ { 177, HENGEDIANZI_BOARD },
+ { 178, WAIXING_SGZLZ },
+ { 179, HENGEDIANZI_XJZB },
+ { 180, UXROM_CC },
+ // 181 Unused
+ { 182, HOSENKAN_BOARD },
+ // 183 FDS bootleg (Shui Guan Pipe) - Unsupported
+ { 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_SUPERBROS11 },
+ { 197, UNL_SUPERFIGHTER3 },
+ { 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, STD_DXROM },
+ { 207, TAITO_X1_005_A },
+ { 208, GOUDER_37017 },
+ // 209 JY Company Type B (Power Rangers 3 & 4, Shin Samurai Spirits 2) - Unsupported
+ // 210 Some emu uses this as Mapper 19 without some features
+ // 211 JY Company Type C (Tiny Toon Adventures 6, Donkey Kong Country 4) - Unsupported
+ { 212, BMC_SUPERHIK_300IN1 },
+ { 213, BMC_9999999IN1 },
+ { 214, BMC_SUPERGUN_20IN1 },
+ { 215, SUPERGAME_BOOGERMAN },
+ { 216, RCM_GS2015 },
+ { 217, BMC_GOLDENCARD_6IN1 },
+ // 218 Unused
+ // 219 Bootleg A9746 - Unsupported
+ // 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 Super 22 Games - Unsupported
+ // 234 AVE Maxi 15 - Unsupported
+ // 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_MXMDHTWO },
+ { 242, WAIXING_ZS },
+ { 243, SACHEN_74LS374_A },
+ { 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;
+}
+
+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", mapper);
+
+ return mmc->pcb_id;
+}
diff --git a/src/mess/machine/nes_mmc.c b/src/mess/machine/nes_mmc.c
new file mode 100644
index 00000000000..c427aa6f66f
--- /dev/null
+++ b/src/mess/machine/nes_mmc.c
@@ -0,0 +1,707 @@
+/*****************************************************************************************
+
+ NES MMC Emulation
+
+
+ MESS source file to handle various Multi-Memory Controllers (aka Mappers) used by NES carts.
+
+ Many information about the mappers below 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/
+
+
+ Missing components:
+ * Currently, we are not emulating 4-screen mirroring (only 3 games use it)
+ * We need a better way to implement CPU cycle based IRQ. Currently we update their counter once every scanline
+ but, with this approach, every time 114 clocks have passed and for certain games it is too much!
+ * We need to emulate additional sound hardware in mappers 019, 024, 026, 069, 085 (and possibly other ones)
+ * We need to emulate EEPROM in mapper 016 and 159
+ * Barcode World (mapper 069) and Datach games (mapper 157) need Barcode Reader emulation
+ Notice that for mapper 157, the barcode reader enters in the irq, so glitches may be related to this!
+ * Karaoke Studio (mapper 188) misses input devices
+
+ Known issues on specific mappers:
+
+ * 000 F1 Race requires more precise PPU timing. It currently has plenty of 1-line glitches.
+ * 001 Yoshi flashes in-game. Back to the Future have heavily corrupted graphics (since forever).
+ * 001 SOROM boards do not properly handle the two WRAM/Battery banks
+ * 002, 003, 094, 097, 152 Bus conflict?
+ * 003 Firehouse Rescue has flashing graphics
+ * 004 Mendel Palace has never worked properly
+ * 004 Ninja Gaiden 2 has flashing bg graphics in the second level
+ * 005 has issues (see e.g. Just Breed or Metal Slader Glory), RAM banking needs hardware flags to determine size
+ * 007 Marble Madness has small graphics corruptions
+ * 014 in-game graphics is glitched
+ * 015 Shanghai Tycoon has corrupted graphics
+ * 033 has still some graphics problem (e.g. missing text in Akira)
+ * 034 Impossible Mission II does not show graphics
+ * 038 seems to miss inputs. separate reads?
+ * 042 Ai Senshi Nicol has broken graphics (our Mapper 42 implementation does not handle CHR banks)
+ * 048 Don Doko Don 2 freezes when you reach the first boss
+ * 051 only half of the games work
+ * 064 has many IRQ problems (due to the way we implement CPU based IRQ) - see Skull & Crossbones.
+ Klax has problems as well (even if it uses scanline based IRQ, according to Disch's docs).
+ * 067 some 1-line glitches that cannot be solved without a better implementation for cycle-based IRQs
+ * 071 Fire Hawk is flashing all the times.
+ * 072, 086, 092 lack samples support (maybe others as well)
+ * 073 16 bit IRQ mode is not implemented
+ * 077 Requires 4-screen mirroring. Currently, it is very glitchy
+ * 083 has serious glitches
+ * 088 Quinty has never worked properly
+ * 096 is preliminary (no correct chr switch in connection to PPU)
+ * 104 Not all the games work
+ * 107 Are the scrolling glitches (check status bar) correct? NEStopia behaves similarly
+ * 112 Master Shooter is not working and misses some graphics
+ * 117 In-game glitches
+ * 119 Pin Bot has glitches when the ball is in the upper half of the screen
+ * 133 Qi Wang starts with corrupted graphics (ingame seems better)
+ * 143 are Dancing Block borders (in the intro) correct?
+ * 158 In addition to IRQ problems (same as 64), mirroring was just a guess (wrong?). info needed!
+ * 164 preliminary - no sprites?
+ * 176 has some graphics problem
+ * 178 Fan Kong Jin Ying is not working (but not even in NEStopia)
+ * 180 Crazy Climber controller?
+ * 187, 198, 208, 215 have some PRG banking issues - preliminary!
+ * 188 needs mic input (reads from 0x6000-0x7fff)
+ * 197 Super Fighter 3 has some glitch in-game (maybe mirroring?)
+ * 222 is only preliminar (wrong IRQ, mirroring or CHR banking?)
+ * 225 115-in-1 has glitches in the menu (games seem fine)
+ * 229 is preliminary
+ * 230 not working yet (needs a value to flip at reset)
+ * 232 has graphics glitches
+ * 241 Commandos is not working (but not even in NEStopia)
+ * 242 In Dragon Quest VIII graphics of the main character is not drawn (it seems similar to Shanghai Tycoon [map15]
+ because in place of the missing graphics we get glitches in the left border)
+ * 249 only half of the games work (and Du Bao Ying Hao seems to suffer the same problem as DQ8 and Shanghai Tycoon)
+ * 255 does not really select game (same in NEStopia apparently)
+
+ 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
+
+ Known issues on specific UNIF boards:
+ * BMC-GS2004 is not working
+ * BMC-GS2013 is not working
+ * BMC-WS some games have corrupted graphics (e.g. Galaxian)
+ * UNL-8237 is not working
+ * UNL-KOF97 is not working
+
+ Details to investigate:
+ * 034 writes to 0x8000-0xffff should not be used for NINA-001 and BNROM, only unlicensed BxROM...
+ * 144 we ignore writes to 0x8000 while NEStopia does not. is it a problem?
+ * 240 we do not map writes to 0x4020-0x40ff. is this a problem?
+ * some other emus uses mapper 210 for mapper 019 games without additional sound hardware and mirroring capabilities
+ (in 210 mirroring is hardwired). However, simply initializing mirroring to Vertical in 019 seems to fix all glitches
+ in 210 games, so there seems to be no reason to have this duplicate mapper
+
+ Some mappers copy PRG rom in SRAM region. Below is a list of those which does it (in MESS) to further
+ investigate if we are supporting them in the right way (e.g. do any of the following have conflicts with SRAM?):
+ * 065 (Gimmick! breaks badly without it)
+ * 040, 042, 050
+
+ 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?
+
+ TODO:
+ - add more info
+ - add missing mappers
+
+****************************************************************************************/
+
+#include "emu.h"
+#include "cpu/m6502/m6502.h"
+#include "video/ppu2c0x.h"
+#include "includes/nes.h"
+#include "nes_mmc.h"
+#include "sound/nes_apu.h"
+
+#ifdef MAME_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+#define LOG_FDS(x) do { if (VERBOSE) logerror x; } while (0)
+
+static void ffe_irq( device_t *device, int scanline, int vblank, int blanked );
+static WRITE8_HANDLER( mapper6_l_w );
+static WRITE8_HANDLER( mapper6_w );
+static WRITE8_HANDLER( mapper8_w );
+static WRITE8_HANDLER( mapper17_l_w );
+
+/*************************************************************
+
+ Base emulation (see drivers/nes.c):
+ memory 0x0000-0x1fff RAM
+ 0x2000-0x3fff PPU
+ 0x4000-0x4017 APU
+ 0x4018-0x5fff Expansion Area
+ 0x6000-0x7fff PRG RAM
+ 0x8000-0xffff PRG ROM
+
+ nes_chr_r/w take care of RAM, nes_nt_r/w take care of PPU.
+ for mapper specific emulation, we generically setup the
+ following handlers:
+ - nes_low_mapper_r/w take care of accesses to 0x4100-0x5fff
+ (calling state->m_mmc_write_low/state->m_mmc_read_low)
+ - state->m_mmc_write/read_mid take care of 0x6000-0x7fff
+ - state->m_mmc_write/read take care of access to 0x8000-0xffff
+ (most mappers only writes in this area)
+ some mappers may access 0x4018-0x4100: this must be taken
+ care separately in init_nes_core
+
+*************************************************************/
+
+WRITE8_HANDLER( nes_chr_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ int bank = offset >> 10;
+
+ if (state->m_chr_map[bank].source == CHRRAM)
+ {
+ state->m_chr_map[bank].access[offset & 0x3ff] = data;
+ }
+}
+
+READ8_HANDLER( nes_chr_r )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ 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 (state->m_chr_open_bus)
+ return 0xff;
+
+ return state->m_chr_map[bank].access[offset & 0x3ff];
+}
+
+WRITE8_HANDLER( nes_nt_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ int page = ((offset & 0xc00) >> 10);
+
+ if (state->m_nt_page[page].writable == 0)
+ return;
+
+ state->m_nt_page[page].access[offset & 0x3ff] = data;
+}
+
+READ8_HANDLER( nes_nt_r )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ int page = ((offset & 0xc00) >> 10);
+
+ if (state->m_nt_page[page].source == MMC5FILL)
+ {
+ if ((offset & 0x3ff) >= 0x3c0)
+ return state->m_MMC5_floodattr;
+
+ return state->m_MMC5_floodtile;
+ }
+ return state->m_nt_page[page].access[offset & 0x3ff];
+}
+
+WRITE8_HANDLER( nes_low_mapper_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+
+ if (state->m_mmc_write_low)
+ (*state->m_mmc_write_low)(space, offset, data);
+ else
+ logerror("Unimplemented LOW mapper write, offset: %04x, data: %02x\n", offset + 0x4100, data);
+}
+
+READ8_HANDLER( nes_low_mapper_r )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+
+ if (state->m_mmc_read_low)
+ return (*state->m_mmc_read_low)(space, offset);
+ else
+ logerror("Unimplemented LOW mapper read, offset: %04x\n", offset + 0x4100);
+
+ return 0;
+}
+
+/*************************************************************
+
+ Helpers to handle MMC
+
+*************************************************************/
+
+static void wram_bank( running_machine &machine, int bank, int source )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ assert(state->m_battery || state->m_prg_ram);
+ if (source == NES_BATTERY)
+ {
+ bank &= (state->m_battery_size / 0x2000) - 1;
+ state->m_prg_bank[4] = state->m_battery_bank5_start + bank;
+ }
+ else
+ {
+ bank &= (state->m_wram_size / 0x2000) - 1;
+ state->m_prg_bank[4] = state->m_prgram_bank5_start + bank;
+ }
+ state->membank("bank5")->set_entry(state->m_prg_bank[4]);
+}
+
+INLINE void prg_bank_refresh( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ state->membank("bank1")->set_entry(state->m_prg_bank[0]);
+ state->membank("bank2")->set_entry(state->m_prg_bank[1]);
+ state->membank("bank3")->set_entry(state->m_prg_bank[2]);
+ state->membank("bank4")->set_entry(state->m_prg_bank[3]);
+}
+
+/* PRG ROM in 8K, 16K or 32K blocks */
+
+static void prg32( running_machine &machine, int bank )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ /* if there is only 16k PRG, return */
+ if (!(state->m_prg_chunks >> 1))
+ return;
+
+ /* assumes that bank references a 32k chunk */
+ bank &= ((state->m_prg_chunks >> 1) - 1);
+
+ state->m_prg_bank[0] = bank * 4 + 0;
+ state->m_prg_bank[1] = bank * 4 + 1;
+ state->m_prg_bank[2] = bank * 4 + 2;
+ state->m_prg_bank[3] = bank * 4 + 3;
+ prg_bank_refresh(machine);
+}
+
+static void prg16_89ab( running_machine &machine, int bank )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ /* assumes that bank references a 16k chunk */
+ bank &= (state->m_prg_chunks - 1);
+
+ state->m_prg_bank[0] = bank * 2 + 0;
+ state->m_prg_bank[1] = bank * 2 + 1;
+ prg_bank_refresh(machine);
+}
+
+static void prg16_cdef( running_machine &machine, int bank )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ /* assumes that bank references a 16k chunk */
+ bank &= (state->m_prg_chunks - 1);
+
+ state->m_prg_bank[2] = bank * 2 + 0;
+ state->m_prg_bank[3] = bank * 2 + 1;
+ prg_bank_refresh(machine);
+}
+
+static void prg8_89( running_machine &machine, int bank )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ /* assumes that bank references an 8k chunk */
+ bank &= ((state->m_prg_chunks << 1) - 1);
+
+ state->m_prg_bank[0] = bank;
+ prg_bank_refresh(machine);
+}
+
+static void prg8_ab( running_machine &machine, int bank )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ /* assumes that bank references an 8k chunk */
+ bank &= ((state->m_prg_chunks << 1) - 1);
+
+ state->m_prg_bank[1] = bank;
+ prg_bank_refresh(machine);
+}
+
+static void prg8_cd( running_machine &machine, int bank )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ /* assumes that bank references an 8k chunk */
+ bank &= ((state->m_prg_chunks << 1) - 1);
+
+ state->m_prg_bank[2] = bank;
+ prg_bank_refresh(machine);
+}
+
+static void prg8_ef( running_machine &machine, int bank )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ /* assumes that bank references an 8k chunk */
+ bank &= ((state->m_prg_chunks << 1) - 1);
+
+ state->m_prg_bank[3] = bank;
+ prg_bank_refresh(machine);
+}
+
+/* We define an additional helper to map PRG-ROM to 0x6000-0x7000 */
+// TODO: are we implementing this correctly in the mappers which uses it? check!
+
+static void prg8_67( running_machine &machine, int bank )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ /* assumes that bank references an 8k chunk */
+ bank &= ((state->m_prg_chunks << 1) - 1);
+
+ state->m_prg_bank[4] = bank;
+ state->membank("bank5")->set_entry(state->m_prg_bank[4]);
+}
+
+/* We also define an additional helper to map 8k PRG-ROM to one of the banks (passed as parameter) */
+static void prg8_x( running_machine &machine, int start, int bank )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ assert(start < 4);
+
+ /* assumes that bank references an 8k chunk */
+ bank &= ((state->m_prg_chunks << 1) - 1);
+
+ state->m_prg_bank[start] = bank;
+ prg_bank_refresh(machine);
+}
+
+/* CHR ROM in 1K, 2K, 4K or 8K blocks */
+
+// this can be probably removed later, but it is useful while testing xml and unf handling with VRAM & VROM
+INLINE void chr_sanity_check( running_machine &machine, int source )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ if (source == CHRRAM && state->m_vram == NULL)
+ fatalerror("CHRRAM bankswitch with no VRAM");
+
+ if (source == CHRROM && state->m_vrom == NULL)
+ fatalerror("CHRROM bankswitch with no VROM");
+}
+
+static void chr8( running_machine &machine, int bank, int source )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ int i;
+
+ chr_sanity_check(machine, source);
+
+ if (source == CHRRAM)
+ {
+ bank &= (state->m_vram_chunks - 1);
+ for (i = 0; i < 8; i++)
+ {
+ state->m_chr_map[i].source = source;
+ state->m_chr_map[i].origin = (bank * 0x2000) + (i * 0x400); // for save state uses!
+ state->m_chr_map[i].access = &state->m_vram[state->m_chr_map[i].origin];
+ }
+ }
+ else
+ {
+ bank &= (state->m_chr_chunks - 1);
+ for (i = 0; i < 8; i++)
+ {
+ state->m_chr_map[i].source = source;
+ state->m_chr_map[i].origin = (bank * 0x2000) + (i * 0x400); // for save state uses!
+ state->m_chr_map[i].access = &state->m_vrom[state->m_chr_map[i].origin];
+ }
+ }
+}
+
+static void chr4_x( running_machine &machine, int start, int bank, int source )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ int i;
+
+ chr_sanity_check(machine, source);
+
+ if (source == CHRRAM)
+ {
+ bank &= ((state->m_vram_chunks << 1) - 1);
+ for (i = 0; i < 4; i++)
+ {
+ state->m_chr_map[i + start].source = source;
+ state->m_chr_map[i + start].origin = (bank * 0x1000) + (i * 0x400); // for save state uses!
+ state->m_chr_map[i + start].access = &state->m_vram[state->m_chr_map[i + start].origin];
+ }
+ }
+ else
+ {
+ bank &= ((state->m_chr_chunks << 1) - 1);
+ for (i = 0; i < 4; i++)
+ {
+ state->m_chr_map[i + start].source = source;
+ state->m_chr_map[i + start].origin = (bank * 0x1000) + (i * 0x400); // for save state uses!
+ state->m_chr_map[i + start].access = &state->m_vrom[state->m_chr_map[i + start].origin];
+ }
+ }
+}
+
+static void chr4_0( running_machine &machine, int bank, int source )
+{
+ chr4_x(machine, 0, bank, source);
+}
+
+static void chr4_4( running_machine &machine, int bank, int source )
+{
+ chr4_x(machine, 4, bank, source);
+}
+
+static void chr2_x( running_machine &machine, int start, int bank, int source )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ int i;
+
+ chr_sanity_check(machine, source);
+
+ if (source == CHRRAM)
+ {
+ bank &= ((state->m_vram_chunks << 2) - 1);
+ for (i = 0; i < 2; i++)
+ {
+ state->m_chr_map[i + start].source = source;
+ state->m_chr_map[i + start].origin = (bank * 0x800) + (i * 0x400); // for save state uses!
+ state->m_chr_map[i + start].access = &state->m_vram[state->m_chr_map[i + start].origin];
+ }
+ }
+ else
+ {
+ bank &= ((state->m_chr_chunks << 2) - 1);
+ for (i = 0; i < 2; i++)
+ {
+ state->m_chr_map[i + start].source = source;
+ state->m_chr_map[i + start].origin = (bank * 0x800) + (i * 0x400); // for save state uses!
+ state->m_chr_map[i + start].access = &state->m_vrom[state->m_chr_map[i + start].origin];
+ }
+ }
+}
+
+static void chr2_0( running_machine &machine, int bank, int source )
+{
+ chr2_x(machine, 0, bank, source);
+}
+
+static void chr2_2( running_machine &machine, int bank, int source )
+{
+ chr2_x(machine, 2, bank, source);
+}
+
+static void chr2_4( running_machine &machine, int bank, int source )
+{
+ chr2_x(machine, 4, bank, source);
+}
+
+static void chr2_6( running_machine &machine, int bank, int source )
+{
+ chr2_x(machine, 6, bank, source);
+}
+
+static void chr1_x( running_machine &machine, int start, int bank, int source )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ chr_sanity_check(machine, source);
+
+ if (source == CHRRAM)
+ {
+ bank &= ((state->m_vram_chunks << 3) - 1);
+ state->m_chr_map[start].source = source;
+ state->m_chr_map[start].origin = (bank * 0x400); // for save state uses!
+ state->m_chr_map[start].access = &state->m_vram[state->m_chr_map[start].origin];
+ }
+ else
+ {
+ bank &= ((state->m_chr_chunks << 3) - 1);
+ state->m_chr_map[start].source = source;
+ state->m_chr_map[start].origin = (bank * 0x400); // for save state uses!
+ state->m_chr_map[start].access = &state->m_vrom[state->m_chr_map[start].origin];
+ }
+}
+
+static void chr1_0 (running_machine &machine, int bank, int source)
+{
+ chr1_x(machine, 0, bank, source);
+}
+
+static void chr1_1( running_machine &machine, int bank, int source )
+{
+ chr1_x(machine, 1, bank, source);
+}
+
+static void chr1_2( running_machine &machine, int bank, int source )
+{
+ chr1_x(machine, 2, bank, source);
+}
+
+static void chr1_3( running_machine &machine, int bank, int source )
+{
+ chr1_x(machine, 3, bank, source);
+}
+
+static void chr1_4( running_machine &machine, int bank, int source )
+{
+ chr1_x(machine, 4, bank, source);
+}
+
+static void chr1_5( running_machine &machine, int bank, int source )
+{
+ chr1_x(machine, 5, bank, source);
+}
+
+static void chr1_6( running_machine &machine, int bank, int source )
+{
+ chr1_x(machine, 6, bank, source);
+}
+
+static void chr1_7( running_machine &machine, int bank, int source )
+{
+ chr1_x(machine, 7, bank, source);
+}
+
+
+/* NameTable paging and mirroring */
+
+static void set_nt_page( running_machine &machine, int page, int source, int bank, int writable )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ UINT8* base_ptr;
+
+ switch (source)
+ {
+ case CART_NTRAM:
+ base_ptr = state->m_extended_ntram;
+ break;
+ case MMC5FILL:
+ base_ptr = NULL;
+ break;
+ case ROM:
+ base_ptr = state->m_vrom;
+ break;
+ case EXRAM:
+ base_ptr = state->m_mapper_ram;
+ break;
+ case CIRAM:
+ default:
+ base_ptr = state->m_ciram;
+ break;
+ }
+
+ page &= 3; /* mask down to the 4 logical pages */
+ state->m_nt_page[page].source = source;
+
+ if (base_ptr != NULL)
+ {
+ state->m_nt_page[page].origin = bank * 0x400;
+ state->m_nt_page[page].access = base_ptr + state->m_nt_page[page].origin;
+ }
+
+ state->m_nt_page[page].writable = writable;
+}
+
+void set_nt_mirroring( running_machine &machine, int mirroring )
+{
+ /* setup our videomem handlers based on mirroring */
+ switch (mirroring)
+ {
+ case PPU_MIRROR_VERT:
+ set_nt_page(machine, 0, CIRAM, 0, 1);
+ set_nt_page(machine, 1, CIRAM, 1, 1);
+ set_nt_page(machine, 2, CIRAM, 0, 1);
+ set_nt_page(machine, 3, CIRAM, 1, 1);
+ break;
+
+ case PPU_MIRROR_HORZ:
+ set_nt_page(machine, 0, CIRAM, 0, 1);
+ set_nt_page(machine, 1, CIRAM, 0, 1);
+ set_nt_page(machine, 2, CIRAM, 1, 1);
+ set_nt_page(machine, 3, CIRAM, 1, 1);
+ break;
+
+ case PPU_MIRROR_HIGH:
+ set_nt_page(machine, 0, CIRAM, 1, 1);
+ set_nt_page(machine, 1, CIRAM, 1, 1);
+ set_nt_page(machine, 2, CIRAM, 1, 1);
+ set_nt_page(machine, 3, CIRAM, 1, 1);
+ break;
+
+ case PPU_MIRROR_LOW:
+ set_nt_page(machine, 0, CIRAM, 0, 1);
+ set_nt_page(machine, 1, CIRAM, 0, 1);
+ set_nt_page(machine, 2, CIRAM, 0, 1);
+ set_nt_page(machine, 3, CIRAM, 0, 1);
+ break;
+
+ case PPU_MIRROR_NONE:
+ case PPU_MIRROR_4SCREEN:
+ default:
+ /* external RAM needs to be used somehow. */
+ /* but as a default, we'll arbitrarily set vertical so as not to crash*/
+ /* mappers should use set_nt_page and assign which pages are which */
+
+ logerror("Mapper set 4-screen mirroring without supplying external nametable memory!\n");
+
+ set_nt_page(machine, 0, CIRAM, 0, 1);
+ set_nt_page(machine, 1, CIRAM, 0, 1);
+ set_nt_page(machine, 2, CIRAM, 1, 1);
+ set_nt_page(machine, 3, CIRAM, 1, 1);
+ break;
+ }
+}
+
+/* Other custom mirroring helpers are defined below: Waixing games use waixing_set_mirror (which swaps
+ MIRROR_HIGH and MIRROR_LOW compared to the above) and Sachen games use sachen_set_mirror (which has
+ a slightly different MIRROR_HIGH, with page 0 set to 0) */
+
+
+/*************************************************************
+
+ Support for xml list
+
+ *************************************************************/
+
+/* Include emulation of NES PCBs for softlist */
+#include "machine/nes_pcb.c"
+
+
+/*************************************************************
+
+ Support for .unf Files
+
+*************************************************************/
+
+/* Include emulation of UNIF Boards for .unf files */
+#include "machine/nes_unif.c"
+
+
+/*************************************************************
+
+ Support for .nes Files
+
+ *************************************************************/
+
+/* Include emulation of iNES Mappers for .nes files */
+#include "machine/nes_ines.c"
+
diff --git a/src/mess/machine/nes_mmc.h b/src/mess/machine/nes_mmc.h
new file mode 100644
index 00000000000..6a75c019336
--- /dev/null
+++ b/src/mess/machine/nes_mmc.h
@@ -0,0 +1,147 @@
+#ifndef __MMC_H
+#define __MMC_H
+
+/* Boards */
+enum
+{
+ STD_NROM = 0,
+ STD_AXROM, STD_BXROM, STD_CNROM, STD_CPROM,
+ STD_DXROM, STD_EXROM, STD_FXROM, STD_GXROM,
+ STD_HKROM, STD_JXROM, STD_MXROM, STD_NXROM,
+ STD_PXROM, STD_SXROM, STD_TXROM, STD_TXSROM,
+ STD_TKROM, STD_TQROM, STD_TVROM,
+ STD_UN1ROM, STD_UXROM,
+ HVC_FAMBASIC, NES_QJ, PAL_ZZ, UXROM_CC,
+ STD_DRROM, STD_SXROM_A, STD_SOROM, STD_SOROM_A,
+ /* 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,
+ /* Bandai */
+ BANDAI_JUMP2, BANDAI_PT554,
+ BANDAI_DATACH, BANDAI_KARAOKE, BANDAI_OEKAKIDS,
+ BANDAI_FCG, BANDAI_LZ93, BANDAI_LZ93EX,
+ /* Caltron */
+ CALTRON_6IN1,
+ /* Camerica */
+ CAMERICA_BF9093, CAMERICA_BF9097, CAMERICA_BF9096,
+ CAMERICA_GOLDENFIVE, GG_NROM,
+ /* Dreamtech */
+ DREAMTECH_BOARD,
+ /* Irem */
+ IREM_G101, IREM_H3001, IREM_LROG017,
+ IREM_TAM_S1, IREM_HOLYDIV,
+ /* Jaleco */
+ JALECO_SS88006, JALECO_JF11, JALECO_JF13,
+ JALECO_JF16, JALECO_JF17, JALECO_JF19,
+ /* Konami */
+ KONAMI_VRC1, KONAMI_VRC2, KONAMI_VRC3,
+ KONAMI_VRC4, KONAMI_VRC6, KONAMI_VRC7,
+ /* Namcot */
+ NAMCOT_163, NAMCOT_3453,
+ 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_74LS374, SACHEN_74LS374_A,
+ /* Sunsoft */
+ SUNSOFT_1, SUNSOFT_2, SUNSOFT_3, SUNSOFT_4,
+ SUNSOFT_DCS, SUNSOFT_5B, SUNSOFT_FME7,
+ /* Taito */
+ TAITO_TC0190FMC, TAITO_TC0190FMCP,
+ TAITO_X1_005, TAITO_X1_005_A, TAITO_X1_017,
+ /* Tengen */
+ TENGEN_800008, TENGEN_800032, TENGEN_800037,
+ /* TXC */
+ TXC_22211A, TXC_22211B, TXC_22211C,
+ TXC_MXMDHTWO, TXC_TW, TXC_STRIKEWOLF,
+ /* Multigame Carts */
+ BMC_64IN1NR, BMC_190IN1, BMC_A65AS, BMC_GS2004, BMC_GS2013,
+ BMC_HIK8IN1, BMC_NOVELDIAMOND, 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_4646B,
+ BMC_36IN1, BMC_21IN1, BMC_150IN1, BMC_35IN1, BMC_64IN1,
+ BMC_15IN1, BMC_SUPERHIK_300IN1, BMC_9999999IN1, BMC_SUPERGUN_20IN1,
+ BMC_GOLDENCARD_6IN1, BMC_72IN1, BMC_SUPER_42IN1, BMC_76IN1,
+ BMC_1200IN1, BMC_31IN1, BMC_22GAMES, BMC_20IN1, BMC_110IN1,
+ BMC_GKA, BMC_GKB, BMC_VT5201, BMC_BENSHENG_BS5, BMC_810544,
+ BMC_NTD_03, BMC_G63IN1, BMC_FK23C, BMC_FK23CA, BMC_PJOY84,
+ BMC_POWERFUL_255,
+ /* Unlicensed */
+ UNL_8237, UNL_CC21, UNL_AX5705, UNL_KOF97, UNL_KS7057,
+ UNL_N625092, UNL_SC127, UNL_SMB2J, UNL_T230, UNL_FS304,
+ UNL_UXROM, UNL_MK2, UNL_XZY, UNL_KOF96,
+ UNL_SUPERFIGHTER3, UNL_RACERMATE, UNL_EDU2K,
+ UNL_SHJY3, UNL_STUDYNGAME, UNL_603_5052, UNL_H2288,
+ /* Bootleg boards */
+ BTL_SMB2A, BTL_MARIOBABY, BTL_AISENSHINICOL, BTL_TOBIDASE,
+ BTL_SMB2B, BTL_SMB3, BTL_SUPERBROS11, BTL_DRAGONNINJA,
+ BTL_PIKACHUY2K,
+ /* Misc: these are needed to convert mappers to boards, I will sort them later */
+ OPENCORP_DAOU306, HES_BOARD, HES6IN1_BOARD, RUMBLESTATION_BOARD,
+ MAGICSERIES_MD, KASING_BOARD, FUTUREMEDIA_BOARD, FUKUTAKE_BOARD, SOMERI_SL12,
+ HENGEDIANZI_BOARD, HENGEDIANZI_XJZB, SUBOR_TYPE0, SUBOR_TYPE1,
+ KAISER_KS7058, KAISER_KS7032, KAISER_KS7022, KAISER_KS7017, KAISER_KS7012, KAISER_KS202,
+ CNE_DECATHLON, CNE_FSB, CNE_SHLZ, CONY_BOARD, YOKO_BOARD, RCM_GS2015, RCM_TETRISFAMILY,
+ WAIXING_TYPE_A, WAIXING_TYPE_A_1, WAIXING_TYPE_B, WAIXING_TYPE_C, WAIXING_TYPE_D,
+ WAIXING_TYPE_E, WAIXING_TYPE_F, WAIXING_TYPE_G, WAIXING_TYPE_H,
+ WAIXING_TYPE_I, WAIXING_TYPE_J,
+ WAIXING_SGZLZ, WAIXING_SGZ, WAIXING_ZS, WAIXING_SECURITY, WAIXING_SH2,
+ WAIXING_DQ8, WAIXING_FFV, WAIXING_PS2, SUPERGAME_LIONKING, SUPERGAME_BOOGERMAN,
+ KAY_PANDAPRINCE, HOSENKAN_BOARD, NITRA_TDA, GOUDER_37017, NANJING_BOARD,
+ WHIRLWIND_2706,
+ /* FFE boards, for mappers 6, 8, 17 */
+ FFE_MAPPER6, FFE_MAPPER8, FFE_MAPPER17,
+ /* Unsupported (for place-holder boards, with no working emulation) & no-board (at init) */
+ UNSUPPORTED_BOARD, UNKNOWN_BOARD, NO_BOARD
+};
+
+// these are used to setup the proper PCB ID, for each supported type of files
+int nes_get_pcb_id(running_machine &machine, const char *feature); // for softlist
+void unif_mapr_setup(running_machine &machine, const char *board); // for UNIF files
+int nes_get_mmc_id(running_machine &machine, int mapper); // for iNES files
+
+// these are used to setup handlers and callbacks necessary to the emulation (resp. at start and reset)
+void pcb_handlers_setup(running_machine &machine);
+int nes_pcb_reset(running_machine &machine);
+
+
+WRITE8_HANDLER( nes_low_mapper_w );
+READ8_HANDLER( nes_low_mapper_r );
+WRITE8_HANDLER( nes_chr_w );
+READ8_HANDLER( nes_chr_r );
+WRITE8_HANDLER( nes_nt_w );
+READ8_HANDLER( nes_nt_r );
+
+WRITE8_HANDLER( smb2jb_extra_w );
+WRITE8_HANDLER( ks7017_extra_w );
+READ8_HANDLER( ks7017_extra_r );
+WRITE8_HANDLER( unl_6035052_extra_w );
+READ8_HANDLER( unl_6035052_extra_r );
+READ8_HANDLER( waixing_sh2_chr_r );
+
+//TEMPORARY PPU STUFF
+
+/* mirroring types */
+#define PPU_MIRROR_NONE 0
+#define PPU_MIRROR_VERT 1
+#define PPU_MIRROR_HORZ 2
+#define PPU_MIRROR_HIGH 3
+#define PPU_MIRROR_LOW 4
+#define PPU_MIRROR_4SCREEN 5 // Same effect as NONE, but signals that we should never mirror
+
+void set_nt_mirroring(running_machine &machine, int mirroring);
+
+
+#endif
diff --git a/src/mess/machine/nes_pcb.c b/src/mess/machine/nes_pcb.c
new file mode 100644
index 00000000000..05670c8abe7
--- /dev/null
+++ b/src/mess/machine/nes_pcb.c
@@ -0,0 +1,13270 @@
+/*****************************************************************************************
+
+ NES Cart PCBs Emulation
+
+****************************************************************************************/
+
+typedef struct _nes_pcb nes_pcb;
+struct _nes_pcb
+{
+ const char *pcb_name;
+ 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[] =
+{
+ /* Nintendo HROM, NROM, RROM, SROM & STROM */
+ { "HVC-HROM", STD_NROM },
+ { "HVC-NROM", STD_NROM },
+ { "HVC-NROM-128", STD_NROM },
+ { "HVC-NROM-256", STD_NROM },
+ { "HVC-RROM", STD_NROM },
+ { "HVC-RROM-128", STD_NROM },
+ { "HVC-RTROM", STD_NROM },
+ { "HVC-SROM", STD_NROM },
+ { "HVC-STROM", STD_NROM },
+ { "NES-HROM", STD_NROM },
+ { "NES-NROM", STD_NROM },
+ { "NES-NROM-128", STD_NROM },
+ { "NES-NROM-256", STD_NROM },
+ { "NES-RROM", STD_NROM },
+ { "NES-RROM-128", STD_NROM },
+ { "NES-SROM", STD_NROM },
+ { "NES-STROM", STD_NROM },
+ /* "No mapper" boards by other manufacturer */
+ { "IREM-NROM-128", STD_NROM },
+ { "IREM-NROM-256", STD_NROM },
+ { "BANDAI-NROM-128", STD_NROM },
+ { "BANDAI-NROM-256", STD_NROM },
+ { "KONAMI-NROM-128", STD_NROM },
+ { "SETA-NROM-128", STD_NROM },
+ { "SUNSOFT-NROM-128", STD_NROM },
+ { "SUNSOFT-NROM-256", STD_NROM },
+ { "TAITO-NROM-128", STD_NROM },
+ { "TAITO-NROM-256", STD_NROM },
+ { "NAMCOT-3301", STD_NROM },
+ { "NAMCOT-3302", STD_NROM },
+ { "NAMCOT-3303", STD_NROM },
+ { "NAMCOT-3304", STD_NROM },
+ { "NAMCOT-3305", STD_NROM },
+ { "NAMCOT-3311", STD_NROM },
+ { "NAMCOT-3312", STD_NROM },
+ { "NAMCOT-3411", STD_NROM },
+ { "JALECO-JF-01", STD_NROM },
+ { "JALECO-JF-02", STD_NROM },
+ { "JALECO-JF-03", STD_NROM },
+ { "JALECO-JF-04", STD_NROM },
+ { "TENGEN-800003", STD_NROM },
+ { "SACHEN-NROM", STD_NROM },
+ /* Nintendo Family BASIC pcb (NROM + 2K or 4K WRAM) */
+ { "HVC-FAMILYBASIC", HVC_FAMBASIC },
+ /* Game Genie */
+ { "CAMERICA-GAMEGENIE", GG_NROM },
+//
+ /* Nintendo UNROM/UOROM */
+ { "HVC-UNROM", STD_UXROM },
+ { "HVC-UNEPROM", STD_UXROM },
+ { "HVC-UOROM", STD_UXROM },
+ { "NES-UNROM", STD_UXROM },
+ { "NES-UNEPROM", STD_UXROM },
+ { "NES-UOROM", STD_UXROM },
+ { "HVC-UNROM+74HC08", UXROM_CC },
+ /* UxROM boards by other manufacturer */
+ { "IREM-UNROM", STD_UXROM },
+ { "KONAMI-UNROM", STD_UXROM },
+ { "TAITO-UNROM", STD_UXROM },
+ { "JALECO-JF-15", STD_UXROM },
+ { "JALECO-JF-18", STD_UXROM },
+ { "JALECO-JF-39", STD_UXROM },
+//
+ /* Nintendo CNROM */
+ { "HVC-CNROM", STD_CNROM },
+ { "NES-CNROM", STD_CNROM },
+ /* CxROM boards by other manufacturer */
+ { "BANDAI-CNROM", STD_CNROM },
+ { "BANDAI-74*161/32", STD_CNROM },
+ { "KONAMI-CNROM", STD_CNROM },
+ { "NAMCOT-CNROM+WRAM", STD_CNROM },
+ { "TAITO-CNROM", STD_CNROM },
+ { "AVE-74*161", STD_CNROM },
+ { "NTDEC-N715061", STD_CNROM },
+ { "NTDEC-N715062", STD_CNROM },
+ { "SACHEN-CNROM", STD_CNROM },
+ /* Bandai Aerobics Studio (CNROM boards + special audio chip) */
+ { "BANDAI-PT-554", BANDAI_PT554 },
+ /* FIXME: Is this the same as mapper 3? */
+ { "TENGEN-800008", TENGEN_800008 },
+//
+ /* Nintendo AxROM */
+ { "HVC-AMROM", STD_AXROM },
+ { "HVC-AN1ROM", STD_AXROM },
+ { "HVC-ANROM", STD_AXROM },
+ { "HVC-AOROM", STD_AXROM },
+ { "NES-AMROM", STD_AXROM },
+ { "NES-AN1ROM", STD_AXROM },
+ { "NES-ANROM", STD_AXROM },
+ { "NES-AOROM", STD_AXROM },
+ /* AxROM boards by other manufacturer */
+ { "ACCLAIM-AOROM", STD_AXROM },
+//
+ /* Nintendo PxROM */
+ { "HVC-PEEOROM", STD_PXROM },
+ { "HVC-PNROM", STD_PXROM },
+ { "NES-PEEOROM", STD_PXROM },
+ { "NES-PNROM", STD_PXROM },
+//
+ /* Nintendo FxROM */
+ { "HVC-FJROM", STD_FXROM },
+ { "HVC-FKROM", STD_FXROM },
+ { "NES-FJROM", STD_FXROM },
+ { "NES-FKROM", STD_FXROM },
+//
+ /* Nintendo BXROM */
+ { "HVC-BNROM", STD_BXROM },
+ { "NES-BNROM", STD_BXROM },
+ /* BxROM boards by other manufacturer */
+ { "IREM-BNROM", STD_BXROM },
+//
+ /* Nintendo CPROM */
+ { "HVC-CPROM", STD_CPROM },
+ { "NES-CPROM", STD_CPROM },
+//
+ /* Nintendo GNROM & MHROM */
+ { "HVC-GNROM", STD_GXROM },
+ { "NES-GNROM", STD_GXROM },
+ { "HVC-MHROM", STD_MXROM },
+ { "NES-MHROM", STD_MXROM },
+ { "PAL-MH", STD_MXROM },
+ /* GxROM boards by other manufacturer */
+ { "BANDAI-GNROM", STD_GXROM },
+//
+ /* Nintendo NxROM */
+ { "HVC-NTBROM", STD_NXROM },
+ { "NES-NTBROM", STD_NXROM },
+ /* NxROM boards by other manufacturer (this board was mainly used by Sunsoft?) */
+ { "SUNSOFT-4", STD_NXROM },
+ { "SUNSOFT-DCS", SUNSOFT_DCS },
+ { "TENGEN-800042", STD_NXROM },
+//
+ /* Nintendo JxROM */
+ { "HVC-JLROM", STD_JXROM },
+ { "HVC-JSROM", STD_JXROM },
+ { "NES-JLROM", STD_JXROM },
+ { "NES-JSROM", STD_JXROM },
+ { "NES-BTR", STD_JXROM },
+ /* JxROM boards by other manufacturer (this board was mainly used by Sunsoft?) */
+ { "SUNSOFT-5A", STD_JXROM },
+ { "SUNSOFT-5B", STD_JXROM },
+ { "SUNSOFT-FME-7", STD_JXROM },
+//
+ /* Nintendo UN1ROM */
+ { "HVC-UN1ROM", STD_UN1ROM },
+ { "NES-UN1ROM", STD_UN1ROM },
+//
+ /* Nintendo SxROM */
+ { "HVC-SAROM", STD_SXROM },
+ { "HVC-SBROM", STD_SXROM },
+ { "HVC-SC1ROM", STD_SXROM },
+ { "HVC-SCROM", STD_SXROM },
+ { "HVC-SEROM", STD_SXROM },
+ { "HVC-SF1ROM", STD_SXROM },
+ { "HVC-SFROM", STD_SXROM },
+ { "HVC-SGROM", STD_SXROM },
+ { "HVC-SH1ROM", STD_SXROM },
+ { "HVC-SHROM", STD_SXROM },
+ { "HVC-SIROM", STD_SXROM },
+ { "HVC-SJROM", STD_SXROM },
+ { "HVC-SKROM", STD_SXROM },
+ { "HVC-SKEPROM", STD_SXROM },
+ { "HVC-SL1ROM", STD_SXROM },
+ { "HVC-SL2ROM", STD_SXROM },
+ { "HVC-SL3ROM", STD_SXROM },
+ { "HVC-SLROM", STD_SXROM },
+ { "HVC-SLRROM", STD_SXROM },
+ { "HVC-SMROM", STD_SXROM },
+ { "HVC-SNROM", STD_SXROM },
+ { "HVC-SUROM", STD_SXROM },
+ { "HVC-SXROM", STD_SXROM },
+ { "NES-SAROM", STD_SXROM },
+ { "NES-SBROM", STD_SXROM },
+ { "NES-SC1ROM", STD_SXROM },
+ { "NES-SCROM", STD_SXROM },
+ { "NES-SEROM", STD_SXROM },
+ { "NES-SF1ROM", STD_SXROM },
+ { "NES-SFROM", STD_SXROM },
+ { "NES-SGROM", STD_SXROM },
+ { "NES-SH1ROM", STD_SXROM },
+ { "NES-SHROM", STD_SXROM },
+ { "NES-SIROM", STD_SXROM },
+ { "NES-SJROM", STD_SXROM },
+ { "NES-SKROM", STD_SXROM },
+ { "NES-SKEPROM", STD_SXROM },
+ { "NES-SL1ROM", STD_SXROM },
+ { "NES-SL2ROM", STD_SXROM },
+ { "NES-SL3ROM", STD_SXROM },
+ { "NES-SLROM", STD_SXROM },
+ { "NES-SLRROM", STD_SXROM },
+ { "NES-SMROM", STD_SXROM },
+ { "NES-SNROM", STD_SXROM },
+ { "NES-SUROM", STD_SXROM },
+ { "NES-SXROM", STD_SXROM },
+ { "NES-WH", STD_SXROM },
+ { "NES-SOROM", STD_SOROM },
+ { "HVC-SOROM", STD_SOROM },
+ /* SxROM boards by other manufacturer */
+ { "KONAMI-SLROM", STD_SXROM },
+ { "VIRGIN-SNROM", STD_SXROM },
+//
+ /* Nintendo TxROM */
+ { "HVC-TBROM", STD_TXROM },
+ { "HVC-TEROM", STD_TXROM },
+ { "HVC-TFROM", STD_TXROM },
+ { "HVC-TGROM", STD_TXROM },
+ { "HVC-TKROM", STD_TXROM },
+ { "HVC-TKEPROM", STD_TXROM },
+ { "HVC-TL1ROM", STD_TXROM },
+ { "HVC-TL2ROM", STD_TXROM },
+ { "HVC-TLROM", STD_TXROM },
+ { "HVC-TNROM", STD_TXROM },
+ { "HVC-TR1ROM", STD_TVROM },
+ { "HVC-TSROM", STD_TXROM },
+ { "HVC-TVROM", STD_TVROM },
+ { "NES-B4", STD_TXROM },
+ { "NES-TBROM", STD_TXROM },
+ { "NES-TEROM", STD_TXROM },
+ { "NES-TFROM", STD_TXROM },
+ { "NES-TGROM", STD_TXROM },
+ { "NES-TKROM", STD_TXROM },
+ { "NES-TKEPROM", STD_TXROM },
+ { "NES-TL1ROM", STD_TXROM },
+ { "NES-TL2ROM", STD_TXROM },
+ { "NES-TLROM", STD_TXROM },
+ { "NES-TNROM", STD_TXROM },
+ { "NES-TR1ROM", STD_TVROM },
+ { "NES-TSROM", STD_TXROM },
+ { "NES-TVROM", STD_TVROM },
+ /* TxROM boards by other manufacturer */
+ { "ACCLAIM-MC-ACC", STD_TXROM },
+ { "ACCLAIM-TLROM", STD_TXROM },
+ { "KONAMI-TLROM", STD_TXROM },
+//
+ /* Nintendo DxROM */
+ { "HVC-DE1ROM", STD_DXROM },
+ { "HVC-DEROM", STD_DXROM },
+ { "HVC-DRROM", STD_DRROM },
+ { "NES-DE1ROM", STD_DXROM },
+ { "NES-DEROM", STD_DXROM },
+ { "NES-DRROM", STD_DRROM },
+ /* DxROM boards by other manufacturer */
+ { "NAMCOT-3401", STD_DXROM },
+ { "NAMCOT-3405", STD_DXROM },
+ { "NAMCOT-3406", STD_DXROM },
+ { "NAMCOT-3407", STD_DXROM },
+ { "NAMCOT-3413", STD_DXROM },
+ { "NAMCOT-3414", STD_DXROM },
+ { "NAMCOT-3415", STD_DXROM },
+ { "NAMCOT-3416", STD_DXROM },
+ { "NAMCOT-3417", STD_DXROM },
+ { "NAMCOT-3451", STD_DXROM },
+ { "TENGEN-800002", STD_DXROM },
+ { "TENGEN-800004", STD_DRROM },
+ { "TENGEN-800030", STD_DXROM },
+//
+ /* Nintendo HKROM */
+ { "HVC-HKROM", STD_HKROM },
+ { "NES-HKROM", STD_HKROM },
+//
+ /* Nintendo BNROM */
+ { "HVC-TQROM", STD_TQROM },
+ { "NES-TQROM", STD_TQROM },
+//
+ /* Nintendo TxSROM */
+ { "HVC-TKSROM", STD_TXSROM },
+ { "HVC-TLSROM", STD_TXSROM },
+ { "NES-TKSROM", STD_TXSROM },
+ { "NES-TLSROM", STD_TXSROM },
+//
+ /* Nintendo ExROM */
+ { "HVC-EKROM", STD_EXROM },
+ { "HVC-ELROM", STD_EXROM },
+ { "HVC-ETROM", STD_EXROM },
+ { "HVC-EWROM", STD_EXROM },
+ { "NES-EKROM", STD_EXROM },
+ { "NES-ELROM", STD_EXROM },
+ { "NES-ETROM", STD_EXROM },
+ { "NES-EWROM", STD_EXROM },
+//
+ /* Nintendo Custom boards */
+ { "PAL-ZZ", PAL_ZZ },
+ { "NES-QJ", NES_QJ },
+ { "NES-EVENT", UNSUPPORTED_BOARD },
+//
+ /* Discrete board IC_74x139x74 */
+ { "JALECO-JF-05", DIS_74X139X74 },
+ { "JALECO-JF-06", DIS_74X139X74 },
+ { "JALECO-JF-07", DIS_74X139X74 },
+ { "JALECO-JF-08", DIS_74X139X74 },
+ { "JALECO-JF-09", DIS_74X139X74 },
+ { "JALECO-JF-10", DIS_74X139X74 },
+ { "KONAMI-74*139/74", DIS_74X139X74 },
+ { "TAITO-74*139/74", DIS_74X139X74 },
+ /* Discrete board IC_74x377 */
+ { "AGCI-47516", DIS_74X377 },
+ { "AVE-NINA-07", DIS_74X377 },
+ { "COLORDREAMS-74*377", DIS_74X377 },
+ /* Discrete board IC_74x161x161x32 */
+ { "BANDAI-74*161/161/32", DIS_74X161X161X32 },
+ { "TAITO-74*161/161/32", DIS_74X161X161X32 },
+ /* Discrete board IC_74x161x138 */
+ { "BIT-CORP-74*161/138", DIS_74X161X138 },
+//
+ { "BANDAI-LZ93D50", BANDAI_LZ93 },
+ { "BANDAI-LZ93D50+24C01", BANDAI_LZ93EX },
+ { "BANDAI-LZ93D50+24C02", BANDAI_LZ93EX },
+ { "BANDAI-FCG-1", BANDAI_FCG },
+ { "BANDAI-FCG-2", BANDAI_FCG },
+ { "BANDAI-JUMP2", BANDAI_JUMP2 },
+ { "BANDAI-DATACH", BANDAI_DATACH },
+ { "BANDAI-KARAOKE", BANDAI_KARAOKE },
+ { "BANDAI-OEKAKIDS", BANDAI_OEKAKIDS },
+ { "IREM-FCG-1", BANDAI_FCG },
+//
+ { "IREM-G101", IREM_G101 },
+ { "IREM-74*161/161/21/138", IREM_LROG017 },
+ { "IREM-H-3001", IREM_H3001 },
+ { "IREM-H3001", IREM_H3001 },
+ { "IREM-HOLYDIVER", IREM_HOLYDIV },
+ { "IREM-TAM-S1", IREM_TAM_S1 },
+//
+ { "JALECO-JF-23", JALECO_SS88006 },
+ { "JALECO-JF-24", JALECO_SS88006 },
+ { "JALECO-JF-25", JALECO_SS88006 },
+ { "JALECO-JF-27", JALECO_SS88006 },
+ { "JALECO-JF-29", JALECO_SS88006 },
+ { "JALECO-JF-30", JALECO_SS88006 },
+ { "JALECO-JF-31", JALECO_SS88006 },
+ { "JALECO-JF-32", JALECO_SS88006 },
+ { "JALECO-JF-33", JALECO_SS88006 },
+ { "JALECO-JF-34", JALECO_SS88006 },
+ { "JALECO-JF-35", JALECO_SS88006 },
+ { "JALECO-JF-36", JALECO_SS88006 },
+ { "JALECO-JF-37", JALECO_SS88006 },
+ { "JALECO-JF-38", JALECO_SS88006 },
+ { "JALECO-JF-40", JALECO_SS88006 },
+ { "JALECO-JF-41", JALECO_SS88006 },
+ { "JALECO-JF-11", JALECO_JF11 },
+ { "JALECO-JF-12", JALECO_JF11 },
+ { "JALECO-JF-14", JALECO_JF11 },
+ { "JALECO-JF-13", JALECO_JF13 },
+ { "JALECO-JF-16", JALECO_JF16 },
+ { "JALECO-JF-17", JALECO_JF17 },
+ { "JALECO-JF-26", JALECO_JF17 },
+ { "JALECO-JF-28", JALECO_JF17 },
+ { "JALECO-JF-19", JALECO_JF19 },
+ { "JALECO-JF-21", JALECO_JF19 },
+//
+ { "KONAMI-VRC-1", KONAMI_VRC1 },
+ { "JALECO-JF-20", KONAMI_VRC1 },
+ { "JALECO-JF-22", KONAMI_VRC1 },
+ { "KONAMI-VRC-2", KONAMI_VRC2 },
+ { "KONAMI-VRC-3", KONAMI_VRC3 },
+ { "KONAMI-VRC-4", KONAMI_VRC4 },
+ { "KONAMI-VRC-6", KONAMI_VRC6 },
+ { "KONAMI-VRC-7", KONAMI_VRC7 },
+ { "UNL-VRC7", KONAMI_VRC7 },
+//
+ { "NAMCOT-163", NAMCOT_163 },
+ { "NAMCOT-175", NAMCOT_163 },
+ { "NAMCOT-340", NAMCOT_163 },
+ { "NAMCOT-3425", NAMCOT_3425 },
+ { "NAMCOT-3433", NAMCOT_34X3 },
+ { "NAMCOT-3443", NAMCOT_34X3 },
+ { "NAMCOT-3446", NAMCOT_3446 },
+ { "NAMCOT-3453", NAMCOT_3453 },
+//
+ { "SUNSOFT-1", SUNSOFT_1 },
+ { "SUNSOFT-2", SUNSOFT_2 },
+ { "SUNSOFT-3", SUNSOFT_3 },
+ //
+ { "TAITO-TC0190FMC", TAITO_TC0190FMC },
+ { "TAITO-TC0190FMC+PAL16R4", TAITO_TC0190FMCP },
+ { "TAITO-TC0350FMR", TAITO_TC0190FMC },
+ { "TAITO-X1-005", TAITO_X1_005 }, // two variants exist, depending on pin17 & pin31 connections
+ { "TAITO-X1-017", TAITO_X1_017 },
+//
+ { "AGCI-50282", AGCI_50282 },
+ { "AVE-NINA-01", AVE_NINA01 },
+ { "AVE-NINA-02", AVE_NINA01 },
+ { "AVE-NINA-03", AVE_NINA06 },
+ { "AVE-NINA-06", AVE_NINA06 },
+ { "AVE-MB-91", AVE_NINA06 },
+ { "TXC-74*138/175", AVE_NINA06 },
+ { "UNL-SA-016-1M", AVE_NINA06 },
+ { "CAMERICA-ALGN", CAMERICA_BF9093 },
+ { "CAMERICA-BF9093", CAMERICA_BF9093 },
+ { "CODEMASTERS-NR8N", CAMERICA_BF9093 },
+ { "NR8NV1-1", CAMERICA_BF9093 },
+ { "CAMERICA-BF9097", CAMERICA_BF9097 },
+ { "CAMERICA-ALGQ", CAMERICA_BF9096 },
+ { "CAMERICA-BF9096", CAMERICA_BF9096 },
+ { "CAMERICA-GOLDENFIVE", CAMERICA_GOLDENFIVE },
+ { "CNE-DECATHLON", CNE_DECATHLON },
+ { "CNE-PSB", CNE_FSB },
+ { "CNE-SHLZ", CNE_SHLZ },
+ { "JYCOMPANY-A", UNSUPPORTED_BOARD }, // mapper 90
+ { "JYCOMPANY-B", UNSUPPORTED_BOARD }, // mapper 209
+ { "JYCOMPANY-C", UNSUPPORTED_BOARD }, // mapper 211
+ { "NTDEC-112", NTDEC_ASDER }, // mapper 112 (better rename this board tag, to avoid confusion with TC-112!!
+ { "NTDEC-TC-112", NTDEC_FIGHTINGHERO },
+ { "NTDEC-193", NTDEC_FIGHTINGHERO }, // mapper 193
+ { "UNL-TEK90", UNSUPPORTED_BOARD }, // related to JY Company? (i.e. mappers 90, 209, 211?)
+ { "UNL-SA-002", SACHEN_TCU02 },
+ { "UNL-SA-009", SACHEN_SA009 },
+ { "UNL-SA-0036", SACHEN_SA0036 },
+ { "UNL-SA-0037", SACHEN_SA0037 },
+ { "UNL-SA-72007", SACHEN_SA72007 },
+ { "UNL-SA-72008", SACHEN_SA72008 },
+ { "UNL-SA-NROM", SACHEN_TCA01 },
+ { "UNL-SACHEN-TCA01", SACHEN_TCA01 },
+ { "SACHEN-8259A", SACHEN_8259A },
+ { "UNL-SACHEN-8259A", SACHEN_8259A },
+ { "SACHEN-8259B", SACHEN_8259B },
+ { "UNL-SACHEN-8259B", SACHEN_8259B },
+ { "SACHEN-8259C", SACHEN_8259C },
+ { "UNL-SACHEN-8259C", SACHEN_8259C },
+ { "SACHEN-8259D", SACHEN_8259D },
+ { "UNL-SACHEN-8259D", SACHEN_8259D },
+ { "UNL-SACHEN-74LS374N", SACHEN_74LS374 },
+ { "UNL-SACHEN-74LS374N-A", SACHEN_74LS374_A }, /* FIXME: Made up boards the different mirroring handling */
+ { "UNL-TC-U01-1.5M", SACHEN_TCU01 },
+ { "UNL-SA-9602B", UNSUPPORTED_BOARD },
+ { "TENGEN-800032", TENGEN_800032 },
+ { "TENGEN-800037", TENGEN_800037 },
+ { "WAIXING-A", WAIXING_TYPE_A },
+ { "WAIXING-A-1", WAIXING_TYPE_A_1 }, /* 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-I", WAIXING_TYPE_I },
+ { "WAIXING-J", WAIXING_TYPE_J },
+ { "WAIXING-SGZLZ", WAIXING_SGZLZ },
+ { "WAIXING-SEC", WAIXING_SECURITY },
+ { "WAIXING-SGZ", WAIXING_SGZ },
+ { "WAIXING-PS2", WAIXING_PS2 },
+ { "WAIXING-FFV", WAIXING_FFV },
+ { "WAIXING-ZS", WAIXING_ZS },
+ { "WAIXING-DQ8", WAIXING_DQ8 },
+ { "WAIXING-SH2", WAIXING_SH2 },
+//
+ { "TXC-TW", TXC_TW },
+ { "TXC-STRIKEWOLF", TXC_STRIKEWOLF },
+ { "TXC-MXMDHTWO", TXC_MXMDHTWO },
+ { "UNL-22211", TXC_22211A },
+ /* FIXME: Made up boards the different mirroring handling */
+ { "UNL-22211-A", TXC_22211A },
+ { "UNL-22211-B", TXC_22211B },
+ { "UNL-22211-C", TXC_22211C },
+ { "UNL-REXSOFT-DBZ5", REXSOFT_DBZ5 },
+ { "UNL-SL1632", REXSOFT_SL1632 },
+ { "SUBOR-BOARD-0", SUBOR_TYPE0 },
+ { "SUBOR-BOARD-1", SUBOR_TYPE1 },
+ { "SOMERITEAM-SL-12", SOMERI_SL12 }, // mapper 116
+ { "UNL-CONY", CONY_BOARD },
+ { "UNL-YOKO", YOKO_BOARD },
+ { "UNL-GOUDER", GOUDER_37017 },
+ { "UNL-NITRA", NITRA_TDA },
+ { "UNL-HOSENKAN", HOSENKAN_BOARD },
+ { "UNL-SUPERGAME", SUPERGAME_LIONKING },
+ { "UNL-PANDAPRINCE", KAY_PANDAPRINCE },
+ { "DREAMTECH01", DREAMTECH_BOARD },
+ { "DAOU-306", OPENCORP_DAOU306 },
+ { "HES", HES_BOARD },
+ /* FIXME: Made up boards the different mirroring handling? */
+ { "HES-6IN1", HES6IN1_BOARD },
+ { "SUPERGAME-BOOGERMAN", SUPERGAME_BOOGERMAN },
+ { "FUTUREMEDIA", FUTUREMEDIA_BOARD },
+ { "FUKUTAKE", FUKUTAKE_BOARD },
+ { "MAGICSERIES", MAGICSERIES_MD },
+ { "KASING", KASING_BOARD },
+ { "HENGGEDIANZI", HENGEDIANZI_BOARD },
+ { "HENGGEDIANZI-XJZB", HENGEDIANZI_XJZB },
+ { "KAISER-KS7058", KAISER_KS7058 },
+ { "KAISER-KS202", KAISER_KS202 },// mapper 56
+ { "KAISER-KS7022", KAISER_KS7022 },// mapper 175
+ { "UNL-KS7012", UNSUPPORTED_BOARD /*KAISER_KS7012*/ }, // used in Zanac (FDS Conversion) (support missing atm)
+ { "UNL-KS7013B", UNSUPPORTED_BOARD }, // used in Highway Star (FDS Conversion) (support missing atm)
+ { "UNL-KS7017", KAISER_KS7017 },
+ { "UNL-KS7032", KAISER_KS7032 }, // mapper 142
+ { "RCM-GS2015", RCM_GS2015 },
+ { "RCM-TETRISFAMILY", RCM_TETRISFAMILY },
+ { "UNL-NINJARYU", UNSUPPORTED_BOARD },// mapper 111
+ { "UNL-NANJING", NANJING_BOARD },// mapper 163
+ { "WHIRLWIND-2706", WHIRLWIND_2706 },
+ { "UNL-H2288", UNL_H2288 },
+ { "UNL-DANCE", UNSUPPORTED_BOARD },
+ { "UNL-EDU2000", UNL_EDU2K },
+ { "UNL-SHERO", UNSUPPORTED_BOARD /*SACHEN_SHERO*/ },
+ { "UNL-TF1201", UNSUPPORTED_BOARD /*UNL_TF1201*/ },
+ { "RUMBLESTATION", RUMBLESTATION_BOARD }, // mapper 46
+ { "UNL-WORLDHERO", UNSUPPORTED_BOARD },// mapper 27
+ { "UNL-A9746", UNSUPPORTED_BOARD },// mapper 219
+ { "UNL-603-5052", UNL_603_5052 },// mapper 238?
+ { "UNL-SHJY3", UNL_SHJY3 },// mapper 253
+ { "UNL-RACERMATE", UNL_RACERMATE },// mapper 168
+ { "UNL-N625092", UNL_N625092 },
+ { "BMC-N625092", UNL_N625092 },
+ { "UNL-SC-127", UNL_SC127 },
+ { "UNL-SMB2J", UNL_SMB2J },
+ { "BTL-SMB2C", UNL_SMB2J },
+ { "UNL-MK2", UNL_MK2 },
+ { "UNL-XZY", UNL_XZY },
+ { "UNL-KOF96", UNL_KOF96 },
+ { "UNL-SUPERFIGHTER3", UNL_SUPERFIGHTER3 },
+ { "UNL-8237", UNL_8237 },
+ { "UNL-8237A", UNSUPPORTED_BOARD },
+ { "UNL-AX5705", UNL_AX5705 },
+ { "UNL-CC-21", UNL_CC21 },
+ { "UNL-KOF97", UNL_KOF97 },
+ { "UNL-KS7057", UNL_KS7057 }, // mapper 196 alt (for Street Fighter VI / Fight Street VI)
+ { "UNL-T-230", UNL_T230 },
+ { "UNL-STUDYNGAME", UNL_STUDYNGAME }, // mapper 39
+ { "UNL-OneBus", UNSUPPORTED_BOARD },
+ { "UNL-FS304", UNL_FS304 }, // used in Zelda 3 by Waixing
+ { "UNL-43272", UNSUPPORTED_BOARD }, // used in Gaau Hok Gwong Cheung (support missing atm)
+ { "UNL-LH10", UNSUPPORTED_BOARD }, // used in Fuuun Shaolin Kyo (FDS Conversion) (support missing atm)
+//
+ { "BTL-SMB2A", BTL_SMB2A },
+ { "BTL-MARIOBABY", BTL_MARIOBABY },
+ { "BTL-AISENSHINICOL", BTL_AISENSHINICOL },
+ { "BTL-SMB2B", BTL_SMB2B },
+ { "BTL-SMB3", BTL_SMB3 },
+ { "BTL-SUPERBROS11", BTL_SUPERBROS11 },
+ { "BTL-DRAGONNINJA", BTL_DRAGONNINJA },
+ { "BTL-MARIO1-MALEE2", UNSUPPORTED_BOARD }, // mapper 55?
+ { "BTL-2708", UNSUPPORTED_BOARD },// mapper 103
+ { "BTL-TOBIDASEDAISAKUSEN", BTL_TOBIDASE },// mapper 120
+ { "BTL-SHUIGUANPIPE", UNSUPPORTED_BOARD },// mapper 183
+ { "BTL-PIKACHUY2K", BTL_PIKACHUY2K },// mapper 254
+//
+ { "BMC-190IN1", BMC_190IN1 },
+ { "BMC-64IN1NOREPEAT", BMC_64IN1NR },
+ { "BMC-A65AS", BMC_A65AS },
+ { "BMC-GS-2004", BMC_GS2004 },
+ { "BMC-GS-2013", BMC_GS2013 },
+ { "BMC-NOVELDIAMOND9999999IN1", BMC_NOVELDIAMOND },
+ { "BMC-9999999IN1", BMC_9999999IN1 }, // mapper 213... same as BMC-NOVELDIAMOND9999999IN1 ??
+ { "BMC-SUPER24IN1SC03", BMC_S24IN1SC03 },
+ { "BMC-SUPERHIK8IN1", BMC_HIK8IN1 },
+ { "BMC-T-262", BMC_T262 },
+ { "BMC-WS", BMC_WS },
+ { "MLT-ACTION52", ACTENT_ACT52 },
+ { "MLT-CALTRON6IN1", CALTRON_6IN1 },
+ { "MLT-MAXI15", UNSUPPORTED_BOARD}, // mapper 234
+ { "BMC-SUPERBIG-7IN1", BMC_SUPERBIG_7IN1 },
+ { "BMC-SUPERHIK-4IN1", BMC_SUPERHIK_4IN1 },
+ { "BMC-BALLGAMES-11IN1", BMC_BALLGAMES_11IN1 },
+ { "BMC-MARIOPARTY-7IN1", BMC_MARIOPARTY_7IN1 },
+ { "BMC-GOLD-7IN1", BMC_GOLD_7IN1 },
+ { "BMC-GKA", BMC_GKA },
+ { "BMC-GKB", BMC_GKB },
+ { "BMC-SUPER700IN1", BMC_SUPER_700IN1 },
+ { "BMC-FAMILY-4646B", BMC_FAMILY_4646B },
+ { "BMC-36IN1", BMC_36IN1 },
+ { "BMC-21IN1", BMC_21IN1 },
+ { "BMC-150IN1", BMC_150IN1 },
+ { "BMC-35IN1", BMC_35IN1 },
+ { "BMC-64IN1", BMC_64IN1 },
+ { "BMC-15IN1", BMC_15IN1 },
+ { "BMC-SUPERHIK-300IN1", BMC_SUPERHIK_300IN1 },
+ { "BMC-SUPERGUN-20IN1", BMC_SUPERGUN_20IN1 },
+ { "BMC-GOLDENCARD-6IN1", BMC_GOLDENCARD_6IN1 },
+ { "BMC-72IN1", BMC_72IN1 },
+ { "BMC-76IN1", BMC_76IN1 },
+ { "BMC-SUPER42IN1", BMC_SUPER_42IN1 },
+ { "BMC-1200IN1", BMC_1200IN1 },
+ { "BMC-31IN1", BMC_31IN1 },
+ { "BMC-22GAMES", BMC_22GAMES },
+ { "BMC-20IN1", BMC_20IN1 },
+ { "BMC-110IN1", BMC_110IN1 },
+ { "BMC-810544-C-A1", BMC_810544 },
+ { "BMC-411120-C", UNSUPPORTED_BOARD },
+ { "BMC-830118C", UNSUPPORTED_BOARD },
+ { "BMC-12-IN-1", UNSUPPORTED_BOARD },
+ { "BMC-NTD-03", BMC_NTD_03 },
+ { "BMC-8157", UNSUPPORTED_BOARD /*BMC_8157*/ },
+ { "BMC-BS-5", BMC_BENSHENG_BS5 },
+ { "BMC-FK23C", BMC_FK23C },
+ { "BMC-FK23CA", BMC_FK23CA },
+ { "BMC-GHOSTBUSTERS63IN1", BMC_G63IN1 },
+ { "BMC-SUPERVISION16IN1", UNSUPPORTED_BOARD }, // mapper 53
+ { "BMC-RESETBASED-4IN1", UNSUPPORTED_BOARD },// mapper 60 with 64k prg and 32k chr
+ { "BMC-VT5201", BMC_VT5201 },// mapper 60 otherwise
+ { "BMC-D1038", BMC_VT5201 }, // mapper 60?
+ { "BMC-42IN1RESETSWITCH", UNSUPPORTED_BOARD }, // mapper 60?
+ { "BMC-SUPER22GAMES", UNSUPPORTED_BOARD },// mapper 233
+ { "BMC-GOLDENGAME-150IN1", UNSUPPORTED_BOARD },// mapper 235 with 2M PRG
+ { "BMC-GOLDENGAME-260IN1", UNSUPPORTED_BOARD },// mapper 235 with 4M PRG
+ { "BMC-70IN1", UNSUPPORTED_BOARD }, // mapper 236?
+ { "BMC-70IN1B", UNSUPPORTED_BOARD }, // mapper 236?
+ { "BMC-SUPERHIK-KOF", UNSUPPORTED_BOARD },// mapper 251
+ { "BMC-POWERJOY", BMC_PJOY84 },
+ { "BMC-POWERFUL-255", UNSUPPORTED_BOARD }, // mapper 63?
+// are there dumps of games with these boards?
+ { "BMC-13IN1JY110", UNSUPPORTED_BOARD }, // [mentioned in FCEUMM source - we need more info]
+ { "BMC-GK-192", UNSUPPORTED_BOARD }, // [mentioned in FCEUMM source - we need more info]
+ { "KONAMI-QTAI", UNSUPPORTED_BOARD }, // [mentioned in FCEUMM source - we need more info]
+ { "UNL-3D-BLOCK", UNSUPPORTED_BOARD }, // [mentioned in FCEUMM source - we need more info]
+ { "UNL-C-N22M", UNSUPPORTED_BOARD }, // [mentioned in FCEUMM source - we need more info]
+ { "UNL-PEC-586", UNSUPPORTED_BOARD }, // [mentioned in FCEUMM source - we need more info]
+//
+ { "UNKNOWN", UNKNOWN_BOARD } // a few pirate dumps uses the wrong mapper...
+};
+
+const nes_pcb *nes_pcb_lookup( const char *board )
+{
+ int i;
+ for (i = 0; i < ARRAY_LENGTH(pcb_list); i++)
+ {
+ if (!mame_stricmp(pcb_list[i].pcb_name, board))
+ return &pcb_list[i];
+ }
+ return NULL;
+}
+
+int nes_get_pcb_id( running_machine &machine, const char *feature )
+{
+ const nes_pcb *pcb = nes_pcb_lookup(feature);
+
+ if (pcb == NULL)
+ fatalerror("Unimplemented PCB type %s\n", feature);
+
+ return pcb->pcb_id;
+}
+
+/************************************************
+
+ PCB Emulation (to be moved to MAME later)
+
+ In the end, iNES, UNIF and xml should be
+ simply handled through a look-up table
+ which associates the mapper/board/feature
+ to the correct pcb_id and then the core
+ function pcb_handlers_setup should be called
+ to set-up the expected handlers and callbacks
+
+ Similarly, PC-10, VSNES and NES-based
+ multigame boards, should simply call
+ pcb_handlers_setup with the proper pcb_id
+ at the beginning, rather than use ad hoc
+ implementations.
+
+************************************************/
+
+// helper function for the few mappers reading from 0x8000-0xffff for protection
+INLINE UINT8 mmc_hi_access_rom( running_machine &machine, UINT32 offset )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ // usual ROM access
+ switch (offset & 0x6000)
+ {
+ case 0x0000:
+ return state->m_prg[state->m_prg_bank[0] * 0x2000 + (offset & 0x1fff)];
+ case 0x2000:
+ return state->m_prg[state->m_prg_bank[1] * 0x2000 + (offset & 0x1fff)];
+ case 0x4000:
+ return state->m_prg[state->m_prg_bank[2] * 0x2000 + (offset & 0x1fff)];
+ case 0x6000:
+ return state->m_prg[state->m_prg_bank[3] * 0x2000 + (offset & 0x1fff)];
+ }
+ return 0;
+}
+
+/*************************************************************
+
+ 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
+
+ *************************************************************/
+
+/*************************************************************
+
+ UxROM board emulation
+
+ Games: Castlevania, Dragon Quest II, Duck Tales, MegaMan,
+ Metal Gear
+
+ writes to 0x8000-0xffff change PRG 16K lower banks
+
+ missing BC?
+
+ iNES: mapper 2
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( uxrom_w )
+{
+ LOG_MMC(("uxrom_w, offset: %04x, data: %02x\n", offset, data));
+
+ prg16_89ab(space->machine(), 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.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( uxrom_cc_w )
+{
+ LOG_MMC(("uxrom_cc_w, offset: %04x, data: %02x\n", offset, data));
+
+ prg16_cdef(space->machine(), data);
+}
+
+/*************************************************************
+
+ UN1ROM board emulation
+
+ Games: Senjou no Okami
+
+ writes to 0x8000-0xffff change PRG 16K lower banks
+
+ missing BC?
+
+ iNES: mapper 94
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( un1rom_w )
+{
+ LOG_MMC(("un1rom_w, offset: %04x, data: %02x\n", offset, data));
+
+ prg16_89ab(space->machine(), data >> 2);
+}
+
+/*************************************************************
+
+ 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
+
+ *************************************************************/
+
+static WRITE8_HANDLER( cnrom_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("cnrom_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (state->m_ce_mask)
+ {
+ chr8(space->machine(), data & ~state->m_ce_mask, CHRROM);
+
+ if ((data & state->m_ce_mask) == state->m_ce_state)
+ state->m_chr_open_bus = 0;
+ else
+ state->m_chr_open_bus = 1;
+ }
+ else
+ chr8(space->machine(), data, CHRROM);
+}
+
+/*************************************************************
+
+ Bandai PT-554 board emulation
+
+ This is used by Aerobics Studio. It is basically a CNROM board
+ with an additional sound chip which is not currently emulated by
+ MESS
+
+ iNES: mapper 3?
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bandai_pt554_m_w )
+{
+ LOG_MMC(("Bandai PT-554 Sound write, data: %02x\n", data));
+
+ // according to NEStopia, this is the effect
+ if (!BIT(data, 6))
+ {
+ // send command (data & 0x07) to sound chip
+ }
+}
+
+/*************************************************************
+
+ CPROM board emulation
+
+ Games: Videomation
+
+ writes to 0x8000-0xffff change CHR 4K lower banks
+
+ iNES: mapper 13
+
+ In MESS: Supported
+
+ *************************************************************/
+
+static WRITE8_HANDLER( cprom_w )
+{
+ LOG_MMC(("cprom_w, offset: %04x, data: %02x\n", offset, data));
+ chr4_4(space->machine(), data, CHRRAM);
+}
+
+/*************************************************************
+
+ AxROM board emulation
+
+ Games: Arch Rivals, Battletoads, Cabal, Commando, Solstice
+
+ writes to 0x8000-0xffff change PRG banks + sets mirroring
+
+ missing BC for AMROM?
+
+ iNES: mapper 7
+
+ In MESS: Supported
+
+ *************************************************************/
+
+static WRITE8_HANDLER( axrom_w )
+{
+ LOG_MMC(("axrom_w, offset: %04x, data: %02x\n", offset, data));
+
+ set_nt_mirroring(space->machine(), BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
+ prg32(space->machine(), data);
+}
+
+/*************************************************************
+
+ BxROM board emulation
+
+ writes to 0x8000-0xffff change PRG banks
+
+ missing BC?
+
+ iNES: mapper 34
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bxrom_w )
+{
+ /* 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_w, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(space->machine(), data);
+}
+
+/*************************************************************
+
+ GxROM/MxROM board emulation
+
+ writes to 0x8000-0xffff change PRG and CHR banks
+
+ missing BC?
+
+ iNES: mapper 66
+
+ *************************************************************/
+
+static WRITE8_HANDLER( gxrom_w )
+{
+ LOG_MMC(("gxrom_w, offset %04x, data: %02x\n", offset, data));
+
+ prg32(space->machine(), (data & 0xf0) >> 4);
+ chr8(space->machine(), data & 0x0f, CHRROM);
+}
+
+/*************************************************************
+
+ SxROM (MMC1 based) board emulation
+
+ iNES: mapper 1 (and 155 for the MMC1A variant which does not
+ have WRAM disable bit)
+
+ *************************************************************/
+
+static TIMER_CALLBACK( mmc1_resync_callback )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ state->m_mmc1_reg_write_enable = 1;
+}
+
+
+static void mmc1_set_wram( address_space *space, int board )
+{
+ running_machine &machine = space->machine();
+ nes_state *state = machine.driver_data<nes_state>();
+ UINT8 bank = BIT(state->m_mmc_reg[0], 4) ? BIT(state->m_mmc_reg[1], 4) : BIT(state->m_mmc_reg[1], 3);
+
+ switch (board)
+ {
+ case STD_SXROM: // here also reads are disabled!
+ if (!BIT(state->m_mmc_reg[3], 4))
+ space->install_readwrite_bank(0x6000, 0x7fff, "bank5");
+ else
+ {
+ space->unmap_readwrite(0x6000, 0x7fff);
+ break;
+ }
+ case STD_SXROM_A: // ignore WRAM enable bit
+ if (state->m_battery_size > 0x2000)
+ wram_bank(machine, ((state->m_mmc_reg[1] & 3) >> 2), NES_BATTERY);
+ else if (state->m_battery_size)
+ wram_bank(machine, 0, NES_BATTERY);
+ break;
+ case STD_SOROM: // there are 2 WRAM banks only and battery is bank 2 for the cart (hence, we invert bank, because we have battery first)
+ if (!BIT(state->m_mmc_reg[3], 4))
+ space->install_readwrite_bank(0x6000, 0x7fff, "bank5");
+ else
+ {
+ space->unmap_readwrite(0x6000, 0x7fff);
+ break;
+ }
+ case STD_SOROM_A: // ignore WRAM enable bit
+ wram_bank(machine, 0, bank ? NES_BATTERY : NES_WRAM);
+ break;
+ }
+}
+
+static void mmc1_set_prg( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ UINT8 prg_mode, prg_offset;
+
+ prg_mode = state->m_mmc_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,
+ mmc_reg[3] sets banks at 0x8000; if it is 0, mmc_reg[3] sets banks at 0xc000. */
+
+ prg_offset = state->m_mmc_reg[1] & 0x10;
+ /* In principle, mmc_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 mmc_reg[1]&0x10 for prg_offset */
+
+ switch (prg_mode)
+ {
+ case 0x00:
+ case 0x04:
+// printf("PRG 32 bank %d \n", (prg_offset + state->m_mmc_reg[3]) >> 1);
+ prg32(machine, (prg_offset + state->m_mmc_reg[3]) >> 1);
+ break;
+ case 0x08:
+// printf("PRG 16 bank %d (high) \n", prg_offset + state->m_mmc_reg[3]);
+ prg16_89ab(machine, prg_offset + 0);
+ prg16_cdef(machine, prg_offset + state->m_mmc_reg[3]);
+ break;
+ case 0x0c:
+// printf("PRG 16 bank %d (low) \n", prg_offset + state->m_mmc_reg[3]);
+ prg16_89ab(machine, prg_offset + state->m_mmc_reg[3]);
+ prg16_cdef(machine, prg_offset + 0x0f);
+ break;
+ }
+}
+
+static void mmc1_set_prg_wram( address_space *space, int board )
+{
+ mmc1_set_prg(space->machine());
+ mmc1_set_wram(space, board);
+}
+
+static void mmc1_set_chr( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ UINT8 chr_mode = BIT(state->m_mmc_reg[0], 4);
+
+ if (chr_mode)
+ {
+ chr4_0(machine, state->m_mmc_reg[1] & 0x1f, state->m_mmc_chr_source);
+ chr4_4(machine, state->m_mmc_reg[2] & 0x1f, state->m_mmc_chr_source);
+ }
+ else
+ chr8(machine, (state->m_mmc_reg[1] & 0x1f) >> 1, state->m_mmc_chr_source);
+}
+
+static void common_sxrom_write_handler( address_space *space, offs_t offset, UINT8 data, int board )
+{
+ running_machine &machine = space->machine();
+ nes_state *state = machine.driver_data<nes_state>();
+ /* Note that there is only one latch and shift counter, shared amongst the 4 regs */
+ /* Space Shuttle will not work if they have independent variables. */
+
+ /* 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 (state->m_mmc1_reg_write_enable == 0)
+ {
+ return;
+ }
+ else
+ {
+ state->m_mmc1_reg_write_enable = 0;
+ space->machine().scheduler().synchronize(FUNC(mmc1_resync_callback));
+ }
+
+ if (data & 0x80)
+ {
+ state->m_mmc1_count = 0;
+ state->m_mmc1_latch = 0;
+
+ /* Set reg at 0x8000 to size 16k and lower half swap - needed for Robocop 3, Dynowars */
+ state->m_mmc_reg[0] |= 0x0c;
+ mmc1_set_prg_wram(space, board);
+ return;
+ }
+
+ if (state->m_mmc1_count < 5)
+ {
+ if (state->m_mmc1_count == 0) state->m_mmc1_latch = 0;
+ state->m_mmc1_latch >>= 1;
+ state->m_mmc1_latch |= (data & 0x01) ? 0x10 : 0x00;
+ state->m_mmc1_count++;
+ }
+
+ if (state->m_mmc1_count == 5)
+ {
+ switch (offset & 0x6000) /* Which reg shall we write to? */
+ {
+ case 0x0000:
+ state->m_mmc_reg[0] = state->m_mmc1_latch;
+
+ switch (state->m_mmc_reg[0] & 0x03)
+ {
+ case 0: set_nt_mirroring(machine, PPU_MIRROR_LOW); break;
+ case 1: set_nt_mirroring(machine, PPU_MIRROR_HIGH); break;
+ case 2: set_nt_mirroring(machine, PPU_MIRROR_VERT); break;
+ case 3: set_nt_mirroring(machine, PPU_MIRROR_HORZ); break;
+ }
+ mmc1_set_chr(machine);
+ mmc1_set_prg_wram(space, board);
+ break;
+ case 0x2000:
+ state->m_mmc_reg[1] = state->m_mmc1_latch;
+ mmc1_set_chr(machine);
+ mmc1_set_prg_wram(space, board);
+ break;
+ case 0x4000:
+ state->m_mmc_reg[2] = state->m_mmc1_latch;
+ mmc1_set_chr(machine);
+ break;
+ case 0x6000:
+ state->m_mmc_reg[3] = state->m_mmc1_latch;
+ mmc1_set_prg_wram(space, board);
+ break;
+ }
+ state->m_mmc1_count = 0;
+ }
+}
+
+static WRITE8_HANDLER( sxrom_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+
+ LOG_MMC(("sxrom_w, offset: %04x, data: %02x\n", offset, data));
+ common_sxrom_write_handler(space, offset, data, state->m_pcb_id);
+}
+
+/*************************************************************
+
+ PxROM (MMC2 based) board emulation
+
+ Games: Punch Out!!, Mike Tyson's Punch Out!!
+
+ iNES: mapper 9
+
+ In MESS: Supported
+
+ *************************************************************/
+
+static void mmc2_latch( device_t *device, offs_t offset )
+{
+ nes_state *state = device->machine().driver_data<nes_state>();
+ if ((offset & 0x3ff0) == 0x0fd0)
+ {
+ LOG_MMC(("mmc2 vrom latch switch (bank 0 low): %02x\n", state->m_mmc_reg[0]));
+ state->m_mmc_latch1 = 0xfd;
+ chr4_0(device->machine(), state->m_mmc_reg[0], CHRROM);
+ }
+ else if ((offset & 0x3ff0) == 0x0fe0)
+ {
+ LOG_MMC(("mmc2 vrom latch switch (bank 0 high): %02x\n", state->m_mmc_reg[1]));
+ state->m_mmc_latch1 = 0xfe;
+ chr4_0(device->machine(), state->m_mmc_reg[1], CHRROM);
+ }
+ else if ((offset & 0x3ff0) == 0x1fd0)
+ {
+ LOG_MMC(("mmc2 vrom latch switch (bank 1 low): %02x\n", state->m_mmc_reg[2]));
+ state->m_mmc_latch2 = 0xfd;
+ chr4_4(device->machine(), state->m_mmc_reg[2], CHRROM);
+ }
+ else if ((offset & 0x3ff0) == 0x1fe0)
+ {
+ LOG_MMC(("mmc2 vrom latch switch (bank 0 high): %02x\n", state->m_mmc_reg[3]));
+ state->m_mmc_latch2 = 0xfe;
+ chr4_4(device->machine(), state->m_mmc_reg[3], CHRROM);
+ }
+}
+
+static WRITE8_HANDLER( pxrom_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("pxrom_w, offset: %04x, data: %02x\n", offset, data));
+ switch (offset & 0x7000)
+ {
+ case 0x2000:
+ prg8_89(space->machine(), data);
+ break;
+ case 0x3000:
+ state->m_mmc_reg[0] = data;
+ if (state->m_mmc_latch1 == 0xfd)
+ chr4_0(space->machine(), state->m_mmc_reg[0], CHRROM);
+ break;
+ case 0x4000:
+ state->m_mmc_reg[1] = data;
+ if (state->m_mmc_latch1 == 0xfe)
+ chr4_0(space->machine(), state->m_mmc_reg[1], CHRROM);
+ break;
+ case 0x5000:
+ state->m_mmc_reg[2] = data;
+ if (state->m_mmc_latch2 == 0xfd)
+ chr4_4(space->machine(), state->m_mmc_reg[2], CHRROM);
+ break;
+ case 0x6000:
+ state->m_mmc_reg[3] = data;
+ if (state->m_mmc_latch2 == 0xfe)
+ chr4_4(space->machine(), state->m_mmc_reg[3], CHRROM);
+ break;
+ case 0x7000:
+ set_nt_mirroring(space->machine(), 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
+
+ iNES: mapper 10
+
+ In MESS: Supported
+
+*************************************************************/
+
+static WRITE8_HANDLER( fxrom_w )
+{
+ LOG_MMC(("fxrom_w, offset: %04x, data: %02x\n", offset, data));
+ switch (offset & 0x7000)
+ {
+ case 0x2000:
+ prg16_89ab(space->machine(), data);
+ break;
+ default:
+ pxrom_w(space, offset, data);
+ break;
+ }
+}
+
+/*************************************************************
+
+ TxROM (MMC3 based) board emulation
+
+ iNES: mapper 4
+
+ *************************************************************/
+
+static void mmc3_set_wram( address_space *space )
+{
+ running_machine &machine = space->machine();
+ nes_state *state = machine.driver_data<nes_state>();
+
+ // skip this function if we are emulating a MMC3 clone with mid writes
+ if (state->m_mmc_write_mid != NULL)
+ return;
+
+ if (BIT(state->m_mmc3_wram_protect, 7))
+ space->install_readwrite_bank(0x6000, 0x7fff, "bank5");
+ else
+ {
+ space->unmap_readwrite(0x6000, 0x7fff);
+ return;
+ }
+
+ if (!BIT(state->m_mmc3_wram_protect, 6))
+ space->install_write_bank(0x6000, 0x7fff, "bank5");
+ else
+ {
+ space->unmap_write(0x6000, 0x7fff);
+ return;
+ }
+}
+
+static void mmc3_set_prg( running_machine &machine, int prg_base, int prg_mask )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ UINT8 prg_flip = (state->m_mmc3_latch & 0x40) ? 2 : 0;
+
+ state->m_mmc3_prg_cb(machine, 0, prg_base | (state->m_mmc_prg_bank[0 ^ prg_flip] & prg_mask));
+ state->m_mmc3_prg_cb(machine, 1, prg_base | (state->m_mmc_prg_bank[1] & prg_mask));
+ state->m_mmc3_prg_cb(machine, 2, prg_base | (state->m_mmc_prg_bank[2 ^ prg_flip] & prg_mask));
+ state->m_mmc3_prg_cb(machine, 3, prg_base | (state->m_mmc_prg_bank[3] & prg_mask));
+}
+
+static void mmc3_set_chr( running_machine &machine, UINT8 chr, int chr_base, int chr_mask )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ UINT8 chr_page = (state->m_mmc3_latch & 0x80) >> 5;
+
+ state->m_mmc3_chr_cb(machine, chr_page ^ 0, chr_base | ((state->m_mmc_vrom_bank[0] & ~0x01) & chr_mask), chr);
+ state->m_mmc3_chr_cb(machine, chr_page ^ 1, chr_base | ((state->m_mmc_vrom_bank[0] | 0x01) & chr_mask), chr);
+ state->m_mmc3_chr_cb(machine, chr_page ^ 2, chr_base | ((state->m_mmc_vrom_bank[1] & ~0x01) & chr_mask), chr);
+ state->m_mmc3_chr_cb(machine, chr_page ^ 3, chr_base | ((state->m_mmc_vrom_bank[1] | 0x01) & chr_mask), chr);
+ state->m_mmc3_chr_cb(machine, chr_page ^ 4, chr_base | (state->m_mmc_vrom_bank[2] & chr_mask), chr);
+ state->m_mmc3_chr_cb(machine, chr_page ^ 5, chr_base | (state->m_mmc_vrom_bank[3] & chr_mask), chr);
+ state->m_mmc3_chr_cb(machine, chr_page ^ 6, chr_base | (state->m_mmc_vrom_bank[4] & chr_mask), chr);
+ state->m_mmc3_chr_cb(machine, chr_page ^ 7, chr_base | (state->m_mmc_vrom_bank[5] & chr_mask), chr);
+}
+
+/* Here, IRQ counter decrements every scanline. */
+static void mmc3_irq( device_t *device, int scanline, int vblank, int blanked )
+{
+ nes_state *state = device->machine().driver_data<nes_state>();
+
+ if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE)
+ {
+ int priorCount = state->m_IRQ_count;
+ if ((state->m_IRQ_count == 0) || state->m_IRQ_clear)
+ state->m_IRQ_count = state->m_IRQ_count_latch;
+ else
+ state->m_IRQ_count--;
+
+ if (state->m_IRQ_enable && !blanked && (state->m_IRQ_count == 0) && (priorCount || state->m_IRQ_clear /*|| !state->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,
+ device->machine().primary_screen->vpos(), device->machine().primary_screen->hpos()));
+ device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE);
+ }
+ }
+ state->m_IRQ_clear = 0;
+}
+
+static WRITE8_HANDLER( txrom_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 mmc_helper, cmd;
+
+ LOG_MMC(("txrom_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6001)
+ {
+ case 0x0000:
+ mmc_helper = state->m_mmc3_latch ^ data;
+ state->m_mmc3_latch = data;
+
+ /* Has PRG Mode changed? */
+ if (mmc_helper & 0x40)
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+
+ /* Has CHR Mode changed? */
+ if (mmc_helper & 0x80)
+ mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ break;
+
+ case 0x0001:
+ cmd = state->m_mmc3_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:
+ state->m_mmc_vrom_bank[cmd] = data;
+ mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ break;
+ case 6:
+ case 7:
+ state->m_mmc_prg_bank[cmd - 6] = data;
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ break;
+ }
+ break;
+
+ case 0x2000:
+ set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+
+ case 0x2001:
+ state->m_mmc3_wram_protect = data;
+ mmc3_set_wram(space);
+ break;
+
+ case 0x4000:
+ state->m_IRQ_count_latch = data;
+ break;
+
+ case 0x4001:
+ state->m_IRQ_count = 0;
+ break;
+
+ case 0x6000:
+ state->m_IRQ_enable = 0;
+ break;
+
+ case 0x6001:
+ state->m_IRQ_enable = 1;
+ break;
+
+ default:
+ logerror("txrom_w uncaught: %04x value: %02x\n", offset + 0x8000, data);
+ break;
+ }
+}
+
+/*************************************************************
+
+ HKROM (MMC6 based) board emulation
+
+ iNES: mapper 4
+
+ *************************************************************/
+
+static WRITE8_HANDLER( hkrom_m_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 write_hi, write_lo;
+ LOG_MMC(("hkrom_m_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset < 0x1000)
+ return;
+
+ // banks can be written only if both read & write is enabled!
+ write_hi = ((state->m_mmc6_reg & 0xc0) == 0xc0);
+ write_lo = ((state->m_mmc6_reg & 0x30) == 0x30);
+
+ if (BIT(offset, 9) && write_hi) // access to upper 1k
+ state->m_mapper_bram[offset & (state->m_mapper_bram_size - 1)] = data;
+
+ if (!BIT(offset, 9) && write_lo) // access to lower 1k
+ state->m_mapper_bram[offset & (state->m_mapper_bram_size - 1)] = data;
+}
+
+static READ8_HANDLER( hkrom_m_r )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("hkrom_m_r, offset: %04x\n", offset));
+
+ if (offset < 0x1000)
+ return 0xff; // here it should be open bus
+
+ if (!(state->m_mmc6_reg & 0xa0))
+ return 0xff; // here it should be open bus
+
+ if (BIT(offset, 9) && BIT(state->m_mmc6_reg, 7)) // access to upper 1k when upper read is enabled
+ return state->m_mapper_bram[offset & (state->m_mapper_bram_size - 1)];
+
+ if (!BIT(offset, 9) && BIT(state->m_mmc6_reg, 5)) // access to lower 1k when lower read is enabled
+ return state->m_mapper_bram[offset & (state->m_mapper_bram_size - 1)];
+
+ // If only one bank is enabled for reading, the other reads back as zero
+ return 0x00;
+}
+
+static WRITE8_HANDLER( hkrom_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 mmc6_helper;
+ LOG_MMC(("hkrom_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6001)
+ {
+ case 0x0000:
+ mmc6_helper = state->m_mmc3_latch ^ data;
+ state->m_mmc3_latch = data;
+
+ if (!state->m_mmc_latch2 && BIT(data, 5)) // if WRAM is disabled and has to be enabled, write
+ state->m_mmc_latch2 = 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))
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+
+ /* Has CHR Mode changed? */
+ if (BIT(mmc6_helper, 7))
+ mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ break;
+
+ case 0x2001:
+ if (state->m_mmc_latch2)
+ state->m_mmc6_reg = data;
+ break;
+
+ case 0x4001:
+ state->m_IRQ_count = 0;
+ state->m_IRQ_clear = 1;
+ break;
+
+ default:
+ txrom_w(space, offset, data);
+ 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.
+
+ *************************************************************/
+
+static void txsrom_set_mirror( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ if (state->m_mmc3_latch & 0x80)
+ {
+ set_nt_page(machine, 0, CIRAM, (state->m_mmc_vrom_bank[2] & 0x80) >> 7, 1);
+ set_nt_page(machine, 1, CIRAM, (state->m_mmc_vrom_bank[3] & 0x80) >> 7, 1);
+ set_nt_page(machine, 2, CIRAM, (state->m_mmc_vrom_bank[4] & 0x80) >> 7, 1);
+ set_nt_page(machine, 3, CIRAM, (state->m_mmc_vrom_bank[5] & 0x80) >> 7, 1);
+ }
+ else
+ {
+ set_nt_page(machine, 0, CIRAM, (state->m_mmc_vrom_bank[0] & 0x80) >> 7, 1);
+ set_nt_page(machine, 1, CIRAM, (state->m_mmc_vrom_bank[0] & 0x80) >> 7, 1);
+ set_nt_page(machine, 2, CIRAM, (state->m_mmc_vrom_bank[1] & 0x80) >> 7, 1);
+ set_nt_page(machine, 3, CIRAM, (state->m_mmc_vrom_bank[1] & 0x80) >> 7, 1);
+ }
+}
+
+static void txsrom_chr_cb( running_machine &machine, int start, int bank, int source )
+{
+ txsrom_set_mirror(machine); // we could probably update only for one (e.g. the first) call, to slightly optimize the code
+ chr1_x(machine, start, bank, source);
+}
+
+static WRITE8_HANDLER( txsrom_w )
+{
+ LOG_MMC(("txsrom_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6001)
+ {
+ case 0x2000:
+ break;
+
+ default:
+ txrom_w(space, offset, data);
+ break;
+ }
+}
+
+/*************************************************************
+
+ TQROM (MMC3 based) board emulation
+
+ Games: Pin Bot, High Speed
+
+ iNES: mapper 119
+
+ In MESS: Supported. It also uses mmc3_irq.
+
+ *************************************************************/
+
+static void tqrom_set_chr( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ UINT8 chr_page = (state->m_mmc3_latch & 0x80) >> 5;
+ UINT8 chr_src[6], chr_mask[6];
+ int i;
+
+ for (i = 0; i < 6; i++)
+ {
+ chr_src[i] = (state->m_mmc_vrom_bank[i] & 0x40) ? CHRRAM : CHRROM;
+ chr_mask[i] = (state->m_mmc_vrom_bank[i] & 0x40) ? 0x07 : 0x3f;
+ }
+
+ chr1_x(machine, chr_page ^ 0, ((state->m_mmc_vrom_bank[0] & ~0x01) & chr_mask[0]), chr_src[0]);
+ chr1_x(machine, chr_page ^ 1, ((state->m_mmc_vrom_bank[0] | 0x01) & chr_mask[0]), chr_src[0]);
+ chr1_x(machine, chr_page ^ 2, ((state->m_mmc_vrom_bank[1] & ~0x01) & chr_mask[1]), chr_src[1]);
+ chr1_x(machine, chr_page ^ 3, ((state->m_mmc_vrom_bank[1] | 0x01) & chr_mask[1]), chr_src[1]);
+ chr1_x(machine, chr_page ^ 4, (state->m_mmc_vrom_bank[2] & chr_mask[2]), chr_src[2]);
+ chr1_x(machine, chr_page ^ 5, (state->m_mmc_vrom_bank[3] & chr_mask[3]), chr_src[3]);
+ chr1_x(machine, chr_page ^ 6, (state->m_mmc_vrom_bank[4] & chr_mask[4]), chr_src[4]);
+ chr1_x(machine, chr_page ^ 7, (state->m_mmc_vrom_bank[5] & chr_mask[5]), chr_src[5]);
+}
+
+static WRITE8_HANDLER( tqrom_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 mmc_helper, cmd;
+ LOG_MMC(("tqrom_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6001)
+ {
+ case 0x0000:
+ mmc_helper = state->m_mmc3_latch ^ data;
+ state->m_mmc3_latch = data;
+
+ /* Has PRG Mode changed? */
+ if (mmc_helper & 0x40)
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+
+ /* Has CHR Mode changed? */
+ if (mmc_helper & 0x80)
+ tqrom_set_chr(space->machine());
+ break;
+ case 0x0001: /* $8001 */
+ cmd = state->m_mmc3_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:
+ state->m_mmc_vrom_bank[cmd] = data;
+ tqrom_set_chr(space->machine());
+ break;
+ case 6:
+ case 7:
+ state->m_mmc_prg_bank[cmd - 6] = data;
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ break;
+ }
+ break;
+
+ default:
+ txrom_w(space, offset, data);
+ break;
+ }
+}
+
+/*************************************************************
+
+ PAL-ZZ board (MMC3 variant for European 3-in-1 Nintendo cart
+ Super Mario Bros. + Tetris + Nintendo World Cup)
+
+ iNES: mapper 37
+
+ *************************************************************/
+
+static WRITE8_HANDLER( zz_m_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 mmc_helper = data & 0x07;
+ LOG_MMC(("zz_m_w, offset: %04x, data: %02x\n", offset, data));
+
+ state->m_mmc_prg_base = (BIT(mmc_helper, 2) << 4) | (((mmc_helper & 0x03) == 0x03) ? 0x08 : 0);
+ state->m_mmc_prg_mask = (mmc_helper << 1) | 0x07;
+ state->m_mmc_chr_base = BIT(mmc_helper, 2) << 7;
+ state->m_mmc_chr_mask = 0x7f;
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+}
+
+/*************************************************************
+
+ NES-QJ board (MMC3 variant for US 2-in-1 Nintendo cart
+ Super Spike V'Ball + Nintendo World Cup)
+
+ iNES: mapper 47
+
+ *************************************************************/
+
+static WRITE8_HANDLER( qj_m_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("qj_m_w, offset: %04x, data: %02x\n", offset, data));
+
+ state->m_mmc_prg_base = BIT(data, 0) << 4;
+ state->m_mmc_prg_mask = 0x0f;
+ state->m_mmc_chr_base = BIT(data, 0) << 7;
+ state->m_mmc_chr_mask = 0x7f;
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+}
+
+/*************************************************************
+
+ ExROM (MMC5 based) board emulation
+
+ Games: Castlevania III, Just Breed, many Koei titles
+
+ iNES: mapper 5
+
+ MESS status: Mostly Unsupported
+
+ *************************************************************/
+
+#if 0
+static void mmc5_update_chr_a( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ switch (state->m_mmc5_chr_mode)
+ {
+ case 0: // 8k banks
+ chr8(machine, state->m_mmc5_vrom_regA[7] & 0xff, CHRROM);
+ break;
+
+ case 1: // 4k banks
+ chr4_0(machine, state->m_mmc5_vrom_regA[3] & 0xff, CHRROM);
+ chr4_4(machine, state->m_mmc5_vrom_regA[7] & 0xff, CHRROM);
+ break;
+
+ case 2: // 2k banks
+ chr2_0(machine, state->m_mmc5_vrom_regA[1], CHRROM);
+ chr2_2(machine, state->m_mmc5_vrom_regA[3], CHRROM);
+ chr2_4(machine, state->m_mmc5_vrom_regA[5], CHRROM);
+ chr2_6(machine, state->m_mmc5_vrom_regA[7], CHRROM);
+ break;
+
+ case 3: // 1k banks
+ chr1_0(machine, state->m_mmc5_vrom_regA[0], CHRROM);
+ chr1_1(machine, state->m_mmc5_vrom_regA[1], CHRROM);
+ chr1_2(machine, state->m_mmc5_vrom_regA[2], CHRROM);
+ chr1_3(machine, state->m_mmc5_vrom_regA[3], CHRROM);
+ chr1_4(machine, state->m_mmc5_vrom_regA[4], CHRROM);
+ chr1_5(machine, state->m_mmc5_vrom_regA[5], CHRROM);
+ chr1_6(machine, state->m_mmc5_vrom_regA[6], CHRROM);
+ chr1_7(machine, state->m_mmc5_vrom_regA[7], CHRROM);
+ break;
+ }
+}
+
+static void mmc5_update_chr_b( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ switch (state->m_mmc5_chr_mode)
+ {
+ case 0: // 8k banks
+ chr8(machine, state->m_mmc5_vrom_regB[3] & 0xff, CHRROM);
+ break;
+
+ case 1: // 4k banks
+ chr4_0(machine, state->m_mmc5_vrom_regB[3] & 0xff, CHRROM);
+ chr4_4(machine, state->m_mmc5_vrom_regB[3] & 0xff, CHRROM);
+ break;
+
+ case 2: // 2k banks
+ chr2_0(machine, state->m_mmc5_vrom_regB[1], CHRROM);
+ chr2_2(machine, state->m_mmc5_vrom_regB[3], CHRROM);
+ chr2_4(machine, state->m_mmc5_vrom_regB[1], CHRROM);
+ chr2_6(machine, state->m_mmc5_vrom_regB[3], CHRROM);
+ break;
+
+ case 3: // 1k banks
+ chr1_0(machine, state->m_mmc5_vrom_regB[0], CHRROM);
+ chr1_1(machine, state->m_mmc5_vrom_regB[1], CHRROM);
+ chr1_2(machine, state->m_mmc5_vrom_regB[2], CHRROM);
+ chr1_3(machine, state->m_mmc5_vrom_regB[3], CHRROM);
+ chr1_4(machine, state->m_mmc5_vrom_regB[0], CHRROM);
+ chr1_5(machine, state->m_mmc5_vrom_regB[1], CHRROM);
+ chr1_6(machine, state->m_mmc5_vrom_regB[2], CHRROM);
+ chr1_7(machine, state->m_mmc5_vrom_regB[3], CHRROM);
+ break;
+ }
+}
+#endif
+
+static void mmc5_update_prg( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ int bank1, bank2, bank3;
+
+ switch (state->m_mmc5_prg_mode)
+ {
+ case 0: // 32k banks
+ prg32(machine, state->m_mmc5_prg_regs[3] >> 2);
+ break;
+
+ case 1: // 16k banks
+ // printf("problema 1: %x\n", state->m_mmc5_prg_regs[1]);
+ bank1 = state->m_mmc5_prg_regs[1];
+
+ if (!BIT(bank1, 7))
+ {
+ state->m_prg_bank[0] = state->m_prg_chunks + (bank1 & 0x06);
+ state->m_prg_bank[1] = state->m_prg_chunks + (bank1 & 0x06) + 1;
+ state->membank("bank1")->set_entry(state->m_prg_bank[0]);
+ state->membank("bank2")->set_entry(state->m_prg_bank[1]);
+ }
+ else
+ prg16_89ab(machine, bank1 >> 1);
+
+ prg16_cdef(machine, state->m_mmc5_prg_regs[3] >> 1);
+ break;
+
+ case 2: // 16k-8k banks
+ // printf("problema 2: %x %x\n", state->m_mmc5_prg_regs[1], state->m_mmc5_prg_regs[2]);
+ bank1 = state->m_mmc5_prg_regs[1];
+ bank3 = state->m_mmc5_prg_regs[2];
+
+ if (!BIT(bank1, 7))
+ {
+ state->m_prg_bank[0] = state->m_prg_chunks + (bank1 & 0x06);
+ state->m_prg_bank[1] = state->m_prg_chunks + (bank1 & 0x06) + 1;
+ state->membank("bank1")->set_entry(state->m_prg_bank[0]);
+ state->membank("bank2")->set_entry(state->m_prg_bank[1]);
+ }
+ else
+ prg16_89ab(machine, (bank1 & 0x7f) >> 1);
+
+ if (!BIT(bank3, 7))
+ {
+ state->m_prg_bank[2] = state->m_prg_chunks + (bank3 & 0x07);
+ state->membank("bank3")->set_entry(state->m_prg_bank[2]);
+ }
+ else
+ prg8_cd(machine, bank3 & 0x7f);
+
+ prg8_ef(machine, state->m_mmc5_prg_regs[3]);
+ break;
+
+ case 3: // 8k banks
+ // printf("problema 3: %x %x %x\n", state->m_mmc5_prg_regs[0], state->m_mmc5_prg_regs[1], state->m_mmc5_prg_regs[2]);
+ bank1 = state->m_mmc5_prg_regs[0];
+ bank2 = state->m_mmc5_prg_regs[1];
+ bank3 = state->m_mmc5_prg_regs[2];
+
+ if (!BIT(bank1, 7))
+ {
+ state->m_prg_bank[0] = state->m_prg_chunks + (bank1 & 0x07);
+ state->membank("bank1")->set_entry(state->m_prg_bank[0]);
+ }
+ else
+ prg8_89(machine, bank1 & 0x7f);
+
+ if (!BIT(bank2, 7))
+ {
+ state->m_prg_bank[1] = state->m_prg_chunks + (bank2 & 0x07);
+ state->membank("bank2")->set_entry(state->m_prg_bank[1]);
+ }
+ else
+ prg8_ab(machine, bank2 & 0x7f);
+
+ if (!BIT(bank3, 7))
+ {
+ state->m_prg_bank[2] = state->m_prg_chunks + (bank3 & 0x07);
+ state->membank("bank3")->set_entry(state->m_prg_bank[2]);
+ }
+ else
+ prg8_cd(machine, bank3 & 0x7f);
+
+ prg8_ef(machine, state->m_mmc5_prg_regs[3]);
+ break;
+ }
+}
+
+static void mmc5_update_render_mode( running_machine &machine )
+{
+}
+
+static void mmc5_irq( device_t *device, int scanline, int vblank, int blanked )
+{
+ nes_state *state = device->machine().driver_data<nes_state>();
+
+#if 1
+ if (scanline == 0)
+ state->m_IRQ_status |= 0x40;
+ else if (scanline > PPU_BOTTOM_VISIBLE_SCANLINE)
+ state->m_IRQ_status &= ~0x40;
+#endif
+
+ if (scanline == state->m_IRQ_count)
+ {
+ if (state->m_IRQ_enable)
+ device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE);
+
+ state->m_IRQ_status = 0xff;
+ }
+
+ /* FIXME: this is ok, but then we would need to update them again when we have the BG Hblank
+ I leave it commented out until the PPU is updated for this */
+ // if (ppu2c0x_is_sprite_8x16(state->m_ppu) || state->m_mmc5_last_chr_a)
+ // mmc5_update_chr_a(device->machine());
+ // else
+ // mmc5_update_chr_b(device->machine());
+}
+
+static void mmc5_ppu_mirror( running_machine &machine, int page, int src )
+{
+ switch (src)
+ {
+ case 0: /* CIRAM0 */
+ set_nt_page(machine, page, CIRAM, 0, 1);
+ break;
+ case 1: /* CIRAM1 */
+ set_nt_page(machine, page, CIRAM, 1, 1);
+ break;
+ case 2: /* ExRAM */
+ set_nt_page(machine, page, EXRAM, 0, 1); // actually only works during rendering.
+ break;
+ case 3: /* Fill Registers */
+ set_nt_page(machine, page, MMC5FILL, 0, 0);
+ break;
+ default:
+ fatalerror("This should never happen");
+ break;
+ }
+}
+
+static READ8_HANDLER( exrom_l_r )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ int retVal;
+
+ /* $5c00 - $5fff: extended videoram attributes */
+ if ((offset >= 0x1b00) && (offset <= 0x1eff))
+ {
+ return state->m_mapper_ram[offset - 0x1b00];
+ }
+
+ switch (offset)
+ {
+ case 0x1104: /* $5204 */
+#if 0
+ if (current_scanline == MMC5_scanline)
+ return 0x80;
+ else
+ return 0x00;
+#else
+ retVal = state->m_IRQ_status;
+ state->m_IRQ_status &= ~0x80;
+ return retVal;
+#endif
+
+ case 0x1105: /* $5205 */
+ return (state->m_mult1 * state->m_mult2) & 0xff;
+ case 0x1106: /* $5206 */
+ return ((state->m_mult1 * state->m_mult2) & 0xff00) >> 8;
+
+ default:
+ logerror("** MMC5 uncaught read, offset: %04x\n", offset + 0x4100);
+ return 0x00;
+ }
+}
+
+
+static WRITE8_HANDLER( exrom_l_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+
+ // LOG_MMC(("Mapper 5 write, offset: %04x, data: %02x\n", offset + 0x4100, data));
+ /* Send $5000-$5015 to the sound chip */
+ if ((offset >= 0xf00) && (offset <= 0xf15))
+ {
+ nes_psg_w(state->m_sound, offset & 0x1f, data);
+ return;
+ }
+
+ /* $5c00 - $5fff: extended videoram attributes */
+ if ((offset >= 0x1b00) && (offset <= 0x1eff))
+ {
+ if (state->m_MMC5_vram_protect == 0x03)
+ state->m_mapper_ram[offset - 0x1b00] = data;
+ return;
+ }
+
+ switch (offset)
+ {
+ case 0x1000: /* $5100 */
+ state->m_mmc5_prg_mode = data & 0x03;
+ // mmc5_update_prg(space->machine());
+ LOG_MMC(("MMC5 rom bank mode: %02x\n", data));
+ break;
+
+ case 0x1001: /* $5101 */
+ state->m_mmc5_chr_mode = data & 0x03;
+ // update chr
+ LOG_MMC(("MMC5 vrom bank mode: %02x\n", data));
+ break;
+
+ case 0x1002: /* $5102 */
+ if (data == 0x02)
+ state->m_MMC5_vram_protect |= 1;
+ else
+ state->m_MMC5_vram_protect = 0;
+ LOG_MMC(("MMC5 vram protect 1: %02x\n", data));
+ break;
+ case 0x1003: /* 5103 */
+ if (data == 0x01)
+ state->m_MMC5_vram_protect |= 2;
+ else
+ state->m_MMC5_vram_protect = 0;
+ LOG_MMC(("MMC5 vram protect 2: %02x\n", data));
+ break;
+
+ case 0x1004: /* $5104 - Extra VRAM (EXRAM) control */
+ state->m_mmc5_vram_control = data & 0x03;
+ // update render
+ mmc5_update_render_mode(space->machine());
+ LOG_MMC(("MMC5 exram control: %02x\n", data));
+ break;
+
+ case 0x1005: /* $5105 */
+ mmc5_ppu_mirror(space->machine(), 0, data & 0x03);
+ mmc5_ppu_mirror(space->machine(), 1, (data & 0x0c) >> 2);
+ mmc5_ppu_mirror(space->machine(), 2, (data & 0x30) >> 4);
+ mmc5_ppu_mirror(space->machine(), 3, (data & 0xc0) >> 6);
+ // update render
+ mmc5_update_render_mode(space->machine());
+ break;
+
+ /* tile data for MMC5 flood-fill NT mode */
+ case 0x1006:
+ state->m_MMC5_floodtile = data;
+ break;
+
+ /* attr data for MMC5 flood-fill NT mode */
+ case 0x1007:
+ switch (data & 3)
+ {
+ default:
+ case 0: state->m_MMC5_floodattr = 0x00; break;
+ case 1: state->m_MMC5_floodattr = 0x55; break;
+ case 2: state->m_MMC5_floodattr = 0xaa; break;
+ case 3: state->m_MMC5_floodattr = 0xff; break;
+ }
+ break;
+
+ case 0x1013: /* $5113 */
+ LOG_MMC(("MMC5 mid RAM bank select: %02x\n", data & 0x07));
+ // FIXME: a few Koei games have both WRAM & BWRAM but here we don't support this (yet)
+ if (state->m_battery)
+ wram_bank(space->machine(), data, NES_BATTERY);
+ else
+ wram_bank(space->machine(), data, NES_WRAM);
+ break;
+
+
+ case 0x1014: /* $5114 */
+ case 0x1015: /* $5115 */
+ case 0x1016: /* $5116 */
+ case 0x1017: /* $5117 */
+ state->m_mmc5_prg_regs[offset & 3] = data;
+ mmc5_update_prg(space->machine());
+ break;
+
+#if 0
+ // these do not work as expected... I guess we definitely need the bank update at proper times (with BG vs. sprite timing)
+ case 0x1020: /* $5120 */
+ case 0x1021: /* $5121 */
+ case 0x1022: /* $5122 */
+ case 0x1023: /* $5123 */
+ case 0x1024: /* $5124 */
+ case 0x1025: /* $5125 */
+ case 0x1026: /* $5126 */
+ case 0x1027: /* $5127 */
+ data |= (state->m_mmc5_chr_high << 8);
+ if (!state->m_mmc5_last_chr_a)
+ {
+ state->m_mmc5_vrom_regA[offset & 0x07] = data;
+ state->m_mmc5_last_chr_a = 1;
+ if (state->m_ppu->get_current_scanline() == 240 || !state->m_ppu->is_sprite_8x16())
+ mmc5_update_chr_a(space->machine());
+ }
+ break;
+
+
+ case 0x1028: /* $5128 */
+ case 0x1029: /* $5129 */
+ case 0x102a: /* $512a */
+ case 0x102b: /* $512b */
+ data |= (state->m_mmc5_chr_high << 8);
+ state->m_mmc5_vrom_regB[offset & 0x03] = data;
+ state->m_mmc5_last_chr_a = 0;
+ if (state->m_ppu->get_current_scanline() == 240 || !state->m_ppu->is_sprite_8x16())
+ mmc5_update_chr_b(space->machine());
+ break;
+
+ case 0x1030: /* $5130 */
+ state->m_mmc5_chr_high = data & 0x03;
+ if (state->m_mmc5_vram_control == 1)
+ {
+ // in this case state->m_mmc5_chr_high selects which 256KB of CHR ROM
+ // is to be used for all background tiles on the screen.
+ }
+ break;
+
+#endif
+
+ case 0x1020: /* $5120 */
+ LOG_MMC(("MMC5 $5120 vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode));
+ switch (state->m_mmc5_chr_mode)
+ {
+ case 0x03:
+ /* 1k switch */
+ state->m_MMC5_vrom_bank[0] = data | (state->m_mmc5_high_chr << 8);
+ // mapper5_sync_vrom(0);
+ chr1_0(space->machine(), state->m_MMC5_vrom_bank[0], CHRROM);
+ // state->m_nes_vram_sprite[0] = state->m_MMC5_vrom_bank[0] * 64;
+ // vrom_next[0] = 4;
+ // vrom_page_a = 1;
+ // vrom_page_b = 0;
+ break;
+ }
+ break;
+ case 0x1021: /* $5121 */
+ LOG_MMC(("MMC5 $5121 vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode));
+ switch (state->m_mmc5_chr_mode)
+ {
+ case 0x02:
+ /* 2k switch */
+ chr2_0(space->machine(), data | (state->m_mmc5_high_chr << 8), CHRROM);
+ break;
+ case 0x03:
+ /* 1k switch */
+ state->m_MMC5_vrom_bank[1] = data | (state->m_mmc5_high_chr << 8);
+ // mapper5_sync_vrom(0);
+ chr1_1(space->machine(), state->m_MMC5_vrom_bank[1], CHRROM);
+ // state->m_nes_vram_sprite[1] = state->m_MMC5_vrom_bank[0] * 64;
+ // vrom_next[1] = 5;
+ // vrom_page_a = 1;
+ // vrom_page_b = 0;
+ break;
+ }
+ break;
+ case 0x1022: /* $5122 */
+ LOG_MMC(("MMC5 $5122 vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode));
+ switch (state->m_mmc5_chr_mode)
+ {
+ case 0x03:
+ /* 1k switch */
+ state->m_MMC5_vrom_bank[2] = data | (state->m_mmc5_high_chr << 8);
+ // mapper5_sync_vrom(0);
+ chr1_2(space->machine(), state->m_MMC5_vrom_bank[2], CHRROM);
+ // state->m_nes_vram_sprite[2] = state->m_MMC5_vrom_bank[0] * 64;
+ // vrom_next[2] = 6;
+ // vrom_page_a = 1;
+ // vrom_page_b = 0;
+ break;
+ }
+ break;
+ case 0x1023: /* $5123 */
+ LOG_MMC(("MMC5 $5123 vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode));
+ switch (state->m_mmc5_chr_mode)
+ {
+ case 0x01:
+ chr4_0(space->machine(), data, CHRROM);
+ break;
+ case 0x02:
+ /* 2k switch */
+ chr2_2(space->machine(), data | (state->m_mmc5_high_chr << 8), CHRROM);
+ break;
+ case 0x03:
+ /* 1k switch */
+ state->m_MMC5_vrom_bank[3] = data | (state->m_mmc5_high_chr << 8);
+ // mapper5_sync_vrom(0);
+ chr1_3(space->machine(), state->m_MMC5_vrom_bank[3], CHRROM);
+ // state->m_nes_vram_sprite[3] = state->m_MMC5_vrom_bank[0] * 64;
+ // vrom_next[3] = 7;
+ // vrom_page_a = 1;
+ // vrom_page_b = 0;
+ break;
+ }
+ break;
+ case 0x1024: /* $5124 */
+ LOG_MMC(("MMC5 $5124 vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode));
+ switch (state->m_mmc5_chr_mode)
+ {
+ case 0x03:
+ /* 1k switch */
+ state->m_MMC5_vrom_bank[4] = data | (state->m_mmc5_high_chr << 8);
+ // mapper5_sync_vrom(0);
+ chr1_4(space->machine(), state->m_MMC5_vrom_bank[4], CHRROM);
+ // state->m_nes_vram_sprite[4] = state->m_MMC5_vrom_bank[0] * 64;
+ // vrom_next[0] = 0;
+ // vrom_page_a = 0;
+ // vrom_page_b = 0;
+ break;
+ }
+ break;
+ case 0x1025: /* $5125 */
+ LOG_MMC(("MMC5 $5125 vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode));
+ switch (state->m_mmc5_chr_mode)
+ {
+ case 0x02:
+ /* 2k switch */
+ chr2_4(space->machine(), data | (state->m_mmc5_high_chr << 8), CHRROM);
+ break;
+ case 0x03:
+ /* 1k switch */
+ state->m_MMC5_vrom_bank[5] = data | (state->m_mmc5_high_chr << 8);
+ // mapper5_sync_vrom(0);
+ chr1_5(space->machine(), state->m_MMC5_vrom_bank[5], CHRROM);
+ // state->m_nes_vram_sprite[5] = state->m_MMC5_vrom_bank[0] * 64;
+ // vrom_next[1] = 1;
+ // vrom_page_a = 0;
+ // vrom_page_b = 0;
+ break;
+ }
+ break;
+ case 0x1026: /* $5126 */
+ LOG_MMC(("MMC5 $5126 vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode));
+ switch (state->m_mmc5_chr_mode)
+ {
+ case 0x03:
+ /* 1k switch */
+ state->m_MMC5_vrom_bank[6] = data | (state->m_mmc5_high_chr << 8);
+ // mapper5_sync_vrom(0);
+ chr1_6(space->machine(), state->m_MMC5_vrom_bank[6], CHRROM);
+ // state->m_nes_vram_sprite[6] = state->m_MMC5_vrom_bank[0] * 64;
+ // vrom_next[2] = 2;
+ // vrom_page_a = 0;
+ // vrom_page_b = 0;
+ break;
+ }
+ break;
+ case 0x1027: /* $5127 */
+ LOG_MMC(("MMC5 $5127 vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode));
+ switch (state->m_mmc5_chr_mode)
+ {
+ case 0x00:
+ /* 8k switch */
+ chr8(space->machine(), data, CHRROM);
+ break;
+ case 0x01:
+ /* 4k switch */
+ chr4_4(space->machine(), data, CHRROM);
+ break;
+ case 0x02:
+ /* 2k switch */
+ chr2_6(space->machine(), data | (state->m_mmc5_high_chr << 8), CHRROM);
+ break;
+ case 0x03:
+ /* 1k switch */
+ state->m_MMC5_vrom_bank[7] = data | (state->m_mmc5_high_chr << 8);
+ // mapper5_sync_vrom(0);
+ chr1_7(space->machine(), state->m_MMC5_vrom_bank[7], CHRROM);
+ // state->m_nes_vram_sprite[7] = state->m_MMC5_vrom_bank[0] * 64;
+ // vrom_next[3] = 3;
+ // vrom_page_a = 0;
+ // vrom_page_b = 0;
+ break;
+ }
+ break;
+ case 0x1028: /* $5128 */
+ LOG_MMC(("MMC5 $5128 vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode));
+ switch (state->m_mmc5_chr_mode)
+ {
+ case 0x03:
+ /* 1k switch */
+ state->m_MMC5_vrom_bank[8] = data | (state->m_mmc5_high_chr << 8);
+ // nes_vram[vrom_next[0]] = data * 64;
+ // nes_vram[0 + (vrom_page_a*4)] = data * 64;
+ // nes_vram[0] = data * 64;
+ chr1_4(space->machine(), state->m_MMC5_vrom_bank[8], CHRROM);
+ // mapper5_sync_vrom(1);
+ if (!state->m_vrom_page_b)
+ {
+ state->m_vrom_page_a ^= 0x01;
+ state->m_vrom_page_b = 1;
+ }
+ break;
+ }
+ break;
+ case 0x1029: /* $5129 */
+ LOG_MMC(("MMC5 $5129 vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode));
+ switch (state->m_mmc5_chr_mode)
+ {
+ case 0x02:
+ /* 2k switch */
+ chr2_0(space->machine(), data | (state->m_mmc5_high_chr << 8), CHRROM);
+ chr2_4(space->machine(), data | (state->m_mmc5_high_chr << 8), CHRROM);
+ break;
+ case 0x03:
+ /* 1k switch */
+ state->m_MMC5_vrom_bank[9] = data | (state->m_mmc5_high_chr << 8);
+ // nes_vram[vrom_next[1]] = data * 64;
+ // nes_vram[1 + (vrom_page_a*4)] = data * 64;
+ // nes_vram[1] = data * 64;
+ chr1_5(space->machine(), state->m_MMC5_vrom_bank[9], CHRROM);
+ // mapper5_sync_vrom(1);
+ if (!state->m_vrom_page_b)
+ {
+ state->m_vrom_page_a ^= 0x01;
+ state->m_vrom_page_b = 1;
+ }
+ break;
+ }
+ break;
+ case 0x102a: /* $512a */
+ LOG_MMC(("MMC5 $512a vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode));
+ switch (state->m_mmc5_chr_mode)
+ {
+ case 0x03:
+ /* 1k switch */
+ state->m_MMC5_vrom_bank[10] = data | (state->m_mmc5_high_chr << 8);
+ // nes_vram[vrom_next[2]] = data * 64;
+ // nes_vram[2 + (vrom_page_a*4)] = data * 64;
+ // nes_vram[2] = data * 64;
+ chr1_6(space->machine(), state->m_MMC5_vrom_bank[10], CHRROM);
+ // mapper5_sync_vrom(1);
+ if (!state->m_vrom_page_b)
+ {
+ state->m_vrom_page_a ^= 0x01;
+ state->m_vrom_page_b = 1;
+ }
+ break;
+ }
+ break;
+ case 0x102b: /* $512b */
+ LOG_MMC(("MMC5 $512b vrom select: %02x (mode: %d)\n", data, state->m_mmc5_chr_mode));
+ switch (state->m_mmc5_chr_mode)
+ {
+ case 0x00:
+ /* 8k switch */
+ /* switches in first half of an 8K bank!) */
+ chr4_0(space->machine(), data << 1, CHRROM);
+ chr4_4(space->machine(), data << 1, CHRROM);
+ break;
+ case 0x01:
+ /* 4k switch */
+ chr4_0(space->machine(), data, CHRROM);
+ chr4_4(space->machine(), data, CHRROM);
+ break;
+ case 0x02:
+ /* 2k switch */
+ chr2_2(space->machine(), data | (state->m_mmc5_high_chr << 8), CHRROM);
+ chr2_6(space->machine(), data | (state->m_mmc5_high_chr << 8), CHRROM);
+ break;
+ case 0x03:
+ /* 1k switch */
+ state->m_MMC5_vrom_bank[11] = data | (state->m_mmc5_high_chr << 8);
+ // nes_vram[vrom_next[3]] = data * 64;
+ // nes_vram[3 + (vrom_page_a*4)] = data * 64;
+ // nes_vram[3] = data * 64;
+ chr1_7(space->machine(), state->m_MMC5_vrom_bank[11], CHRROM);
+ // mapper5_sync_vrom(1);
+ if (!state->m_vrom_page_b)
+ {
+ state->m_vrom_page_a ^= 0x01;
+ state->m_vrom_page_b = 1;
+ }
+ break;
+ }
+ break;
+
+ case 0x1030: /* $5130 */
+ state->m_mmc5_high_chr = data & 0x03;
+ if (state->m_mmc5_vram_control == 1)
+ {
+ // in this case state->m_mmc5_high_chr selects which 256KB of CHR ROM
+ // is to be used for all background tiles on the screen.
+ }
+ break;
+
+
+ case 0x1100: /* $5200 */
+ state->m_mmc5_split_scr = data;
+ // in EX2 and EX3 modes, no split screen
+ if (state->m_mmc5_vram_control & 0x02)
+ state->m_mmc5_split_scr &= 0x7f;
+ state->m_mmc5_split_ctrl = data;
+ break;
+
+ case 0x1101: /* $5201 */
+ state->m_mmc5_split_yst = (data >= 240) ? data - 16 : data;
+ break;
+
+ case 0x1102: /* $5202 */
+ state->m_mmc5_split_bank = data;
+ break;
+
+ case 0x1103: /* $5203 */
+ state->m_IRQ_count = data;
+ state->m_MMC5_scanline = data;
+ LOG_MMC(("MMC5 irq scanline: %d\n", state->m_IRQ_count));
+ break;
+ case 0x1104: /* $5204 */
+ state->m_IRQ_enable = data & 0x80;
+ LOG_MMC(("MMC5 irq enable: %02x\n", data));
+ break;
+ case 0x1105: /* $5205 */
+ state->m_mult1 = data;
+ break;
+ case 0x1106: /* $5206 */
+ state->m_mult2 = data;
+ break;
+
+ default:
+ logerror("** MMC5 uncaught write, offset: %04x, data: %02x\n", offset + 0x4100, data);
+ break;
+ }
+}
+
+/*************************************************************
+
+ NTBROM & Sunsoft-4 board emulation
+
+ Part of this can be used also for Sunsoft Double Cassette
+ System... which games use it?
+
+ iNES: mapper 68
+
+ *************************************************************/
+
+static void ntbrom_mirror( running_machine &machine, int mirror, int mirr0, int mirr1 )
+{
+ switch (mirror)
+ {
+ case 0x00:
+ set_nt_mirroring(machine, PPU_MIRROR_HORZ);
+ break;
+ case 0x01:
+ set_nt_mirroring(machine, PPU_MIRROR_VERT);
+ break;
+ case 0x02:
+ set_nt_mirroring(machine, PPU_MIRROR_LOW);
+ break;
+ case 0x03:
+ set_nt_mirroring(machine, PPU_MIRROR_HIGH);
+ break;
+ case 0x10:
+ set_nt_page(machine, 0, ROM, mirr0 | 0x80, 0);
+ set_nt_page(machine, 1, ROM, mirr1 | 0x80, 0);
+ set_nt_page(machine, 2, ROM, mirr0 | 0x80, 0);
+ set_nt_page(machine, 3, ROM, mirr1 | 0x80, 0);
+ break;
+ case 0x11:
+ set_nt_page(machine, 0, ROM, mirr0 | 0x80, 0);
+ set_nt_page(machine, 1, ROM, mirr0 | 0x80, 0);
+ set_nt_page(machine, 2, ROM, mirr1 | 0x80, 0);
+ set_nt_page(machine, 3, ROM, mirr1 | 0x80, 0);
+ break;
+ case 0x12:
+ set_nt_page(machine, 0, ROM, mirr0 | 0x80, 0);
+ set_nt_page(machine, 1, ROM, mirr0 | 0x80, 0);
+ set_nt_page(machine, 2, ROM, mirr0 | 0x80, 0);
+ set_nt_page(machine, 3, ROM, mirr0 | 0x80, 0);
+ break;
+ case 0x13:
+ set_nt_page(machine, 0, ROM, mirr1 | 0x80, 0);
+ set_nt_page(machine, 1, ROM, mirr1 | 0x80, 0);
+ set_nt_page(machine, 2, ROM, mirr1 | 0x80, 0);
+ set_nt_page(machine, 3, ROM, mirr1 | 0x80, 0);
+ break;
+ }
+}
+
+static WRITE8_HANDLER( ntbrom_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+
+ LOG_MMC(("ntbrom_w, offset %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7000)
+ {
+ case 0x0000:
+ chr2_0(space->machine(), data, CHRROM);
+ break;
+ case 0x1000:
+ chr2_2(space->machine(), data, CHRROM);
+ break;
+ case 0x2000:
+ chr2_4(space->machine(), data, CHRROM);
+ break;
+ case 0x3000:
+ chr2_6(space->machine(), data, CHRROM);
+ break;
+ case 0x4000:
+ state->m_mmc_latch1 = data & 0x7f;
+ ntbrom_mirror(space->machine(), state->m_mmc_reg[0], state->m_mmc_latch1, state->m_mmc_latch2);
+ break;
+ case 0x5000:
+ state->m_mmc_latch2 = data & 0x7f;
+ ntbrom_mirror(space->machine(), state->m_mmc_reg[0], state->m_mmc_latch1, state->m_mmc_latch2);
+ break;
+ case 0x6000:
+ state->m_mmc_reg[0] = data & 0x13;
+ ntbrom_mirror(space->machine(), state->m_mmc_reg[0], state->m_mmc_latch1, state->m_mmc_latch2);
+ break;
+ case 0x7000:
+ prg16_89ab(space->machine(), data);
+ break;
+ default:
+ LOG_MMC(("ntbrom_w uncaught write, offset: %04x, data: %02x\n", offset, data));
+ break;
+ }
+}
+
+/*************************************************************
+
+ JxROM & Sunsoft 5A / 5B / FME7 board emulation
+
+ Notice that Sunsoft-5B = FME7 + sound chip (the latter being
+ currently unemulated in MESS)
+
+ iNES: mapper 69
+
+ *************************************************************/
+
+/* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline,
+ we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC,
+ there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */
+static void jxrom_irq( device_t *device, int scanline, int vblank, int blanked )
+{
+ nes_state *state = device->machine().driver_data<nes_state>();
+
+ /* TODO: change to reflect the actual number of cycles spent */
+ if ((state->m_IRQ_enable & 0x80) && (state->m_IRQ_enable & 0x01))
+ {
+ if (state->m_IRQ_count <= 114)
+ {
+ state->m_IRQ_count = 0xffff;
+ device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE);
+ }
+ else
+ state->m_IRQ_count -= 114;
+ }
+ else if (state->m_IRQ_enable & 0x01) // if enable bit 7 is not set, only decrement the counter!
+ {
+ if (state->m_IRQ_count <= 114)
+ state->m_IRQ_count = 0xffff;
+ else
+ state->m_IRQ_count -= 114;
+ }
+}
+
+static WRITE8_HANDLER( jxrom_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("jxrom_w, offset %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6000)
+ {
+ case 0x0000:
+ state->m_mmc_latch1 = data & 0x0f;
+ break;
+
+ case 0x2000:
+ switch (state->m_mmc_latch1)
+ {
+ case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
+ chr1_x(space->machine(), state->m_mmc_latch1, data, CHRROM);
+ break;
+
+ case 8:
+ if (!(data & 0x40))
+ {
+ // is PRG ROM
+ space->unmap_write(0x6000, 0x7fff);
+ prg8_67(space->machine(), data & 0x3f);
+ }
+ else if (data & 0x80)
+ {
+ // is PRG RAM
+ space->install_write_bank(0x6000, 0x7fff, "bank5");
+ state->m_prg_bank[4] = state->m_battery_bank5_start + (data & 0x3f);
+ state->membank("bank5")->set_entry(state->m_prg_bank[4]);
+ }
+ break;
+
+ case 9:
+ prg8_89(space->machine(), data);
+ break;
+ case 0x0a:
+ prg8_ab(space->machine(), data);
+ break;
+ case 0x0b:
+ prg8_cd(space->machine(), data);
+ break;
+ case 0x0c:
+ switch (data & 0x03)
+ {
+ case 0x00: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break;
+ case 0x01: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break;
+ case 0x02: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break;
+ case 0x03: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break;
+ }
+ break;
+ case 0x0d:
+ state->m_IRQ_enable = data;
+ break;
+ case 0x0e:
+ state->m_IRQ_count = (state->m_IRQ_count & 0xff00) | data;
+ break;
+ case 0x0f:
+ state->m_IRQ_count = (state->m_IRQ_count & 0x00ff) | (data << 8);
+ break;
+ }
+ break;
+
+ /* Here we would have sound command for Sunsoft 5b variant */
+ // case 0x4000:
+ // case 0x6000:
+
+ case 0x4000:
+ LOG_MMC(("Sunsoft-5B Sound: Register select write, data: %02x\n", data));
+ break;
+ case 0x6000:
+ LOG_MMC(("Sunsoft-5B Sound: Register write, data: %02x\n", data));
+ break;
+ default:
+ logerror("jxrom_w uncaught %04x value: %02x\n", offset + 0x8000, data);
+ break;
+ }
+}
+
+/*************************************************************
+
+ DxROM & Namcot 3433 - 3443 board emulation
+
+ Games: Dragon Spirit - Aratanaru Densetsu, Namcot Mahjong, Quinty
+
+ 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)
+
+ *************************************************************/
+
+static WRITE8_HANDLER( dxrom_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("dxrom_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset >= 0x2000)
+ return;
+
+ switch (offset & 1)
+ {
+ case 1:
+ switch (state->m_mmc_latch1 & 0x07)
+ {
+ case 0: chr2_0(space->machine(), data >> 1, CHRROM); break;
+ case 1: chr2_2(space->machine(), data >> 1, CHRROM); break;
+ case 2: chr1_4(space->machine(), data | 0x40, CHRROM); break;
+ case 3: chr1_5(space->machine(), data | 0x40, CHRROM); break;
+ case 4: chr1_6(space->machine(), data | 0x40, CHRROM); break;
+ case 5: chr1_7(space->machine(), data | 0x40, CHRROM); break;
+ case 6: prg8_89(space->machine(), data); break;
+ case 7: prg8_ab(space->machine(), data); break;
+ }
+ break;
+ case 0:
+ state->m_mmc_latch1 = data;
+ break;
+ }
+}
+
+
+/*************************************************************
+
+ Namcot 3453 board emulation
+
+ Games: Devil Man
+
+ These are the same as Namcot 34x3, but with additional mirroring
+ control
+
+ iNES: mapper 154
+
+ *************************************************************/
+
+static WRITE8_HANDLER( namcot3453_w )
+{
+ LOG_MMC(("namcot3453_w, offset: %04x, data: %02x\n", offset, data));
+
+ // additional mirroring control when writing to even addresses
+ if (!(offset & 1))
+ set_nt_mirroring(space->machine(), BIT(data, 6) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
+
+ dxrom_w(space, offset, data);
+}
+
+/*************************************************************
+
+ Namcot 3446 board emulation
+
+ Games: Digital Devil Monogatari - Megami Tensei
+
+ These are similar Namcot 34x3, but different bankswitch capabilities
+
+ iNES: mapper 76
+
+ *************************************************************/
+
+static WRITE8_HANDLER( namcot3446_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("namcot3446_w, offset: %04x, data: %02x\n", offset, data));
+
+ // NEStopia does not have this!
+ if (offset >= 0x2000)
+ {
+ if (!(offset & 1))
+ set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ return;
+ }
+
+ switch (offset & 1)
+ {
+ case 1:
+ switch (state->m_mmc_latch1 & 0x07)
+ {
+ case 2: chr2_0(space->machine(), data, CHRROM); break;
+ case 3: chr2_2(space->machine(), data, CHRROM); break;
+ case 4: chr2_4(space->machine(), data, CHRROM); break;
+ case 5: chr2_6(space->machine(), data, CHRROM); break;
+ case 6: BIT(state->m_mmc_latch1, 6) ? prg8_cd(space->machine(), data) : prg8_89(space->machine(), data); break;
+ case 7: prg8_ab(space->machine(), data); break;
+ }
+ break;
+ case 0:
+ state->m_mmc_latch1 = data;
+ break;
+ }
+}
+
+/*************************************************************
+
+ Namcot 3425 board emulation
+
+ Games: Dragon Buster
+
+ These are similar Namcot 34x3, but with NT mirroring (two
+ different modes)
+
+ iNES: mapper 95
+
+ *************************************************************/
+
+static WRITE8_HANDLER( namcot3425_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 mode;
+ LOG_MMC(("namcot3425_w, offset: %04x, data: %02x\n", offset, data));
+ if (offset >= 0x2000)
+ return;
+
+ switch (offset & 1)
+ {
+ case 1:
+ mode = state->m_mmc_latch1 & 0x07;
+ switch (mode)
+ {
+ case 0: chr2_0(space->machine(), data >> 1, CHRROM); break;
+ case 1: chr2_2(space->machine(), data >> 1, CHRROM); break;
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ chr1_x(space->machine(), 2 + mode, data, CHRROM);
+ state->m_mmc_reg[mode - 2] = BIT(data, 5);
+ if (!BIT(state->m_mmc_latch1, 7))
+ {
+ set_nt_page(space->machine(), 0, CIRAM, state->m_mmc_reg[0], 1);
+ set_nt_page(space->machine(), 1, CIRAM, state->m_mmc_reg[1], 1);
+ set_nt_page(space->machine(), 2, CIRAM, state->m_mmc_reg[2], 1);
+ set_nt_page(space->machine(), 3, CIRAM, state->m_mmc_reg[3], 1);
+ }
+ else
+ set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ);
+ break;
+ case 6: prg8_89(space->machine(), data); break;
+ case 7: prg8_ab(space->machine(), data); break;
+ }
+ break;
+ case 0:
+ state->m_mmc_latch1 = data;
+ break;
+ }
+}
+
+/*************************************************************
+
+ 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
+
+ *************************************************************/
+
+static WRITE8_HANDLER( dis_74x377_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("dis_74x377_w, offset: %04x, data: %02x\n", offset, data));
+
+ chr8(space->machine(), data >> 4, state->m_mmc_chr_source);
+ prg32(space->machine(), data & 0x0f);
+}
+
+/*************************************************************
+
+ Discrete Logic board IC 74x139x74 by Konami & Jaleco
+
+ iNES: mapper 87
+
+ *************************************************************/
+
+static WRITE8_HANDLER( dis_74x139x74_m_w )
+{
+ LOG_MMC(("dis_74x139x74_m_w, offset: %04x, data: %02x\n", offset, data));
+
+ chr8(space->machine(), ((data & 0x02) >> 1) | ((data & 0x01) << 1), CHRROM);
+}
+
+/*************************************************************
+
+ Discrete Logic board IC 74x161x138
+
+ Games: Crime Busters
+
+ iNES: mapper 38
+
+ *************************************************************/
+
+static WRITE8_HANDLER( dis_74x161x138_m_w )
+{
+ LOG_MMC(("dis_74x161x138_m_w, offset: %04x, data: %02x\n", offset, data));
+
+ chr8(space->machine(), data >> 2, CHRROM);
+ prg32(space->machine(), data);
+}
+
+/*************************************************************
+
+ 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
+
+ *************************************************************/
+
+static WRITE8_HANDLER( dis_74x161x161x32_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("dis_74x161x161x32_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (!state->m_hard_mirroring) // there are two 'variants' depending on hardwired or mapper ctrl mirroring
+ set_nt_mirroring(space->machine(), BIT(data, 7) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
+ chr8(space->machine(), data, CHRROM);
+ prg16_89ab(space->machine(), data >> 4);
+}
+
+/*************************************************************
+
+ Bandai 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, 157 & 159
+
+ In MESS: Supported
+
+ *************************************************************/
+
+/* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline,
+ we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC,
+ there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */
+static void bandai_lz_irq( device_t *device, int scanline, int vblank, int blanked )
+{
+ nes_state *state = device->machine().driver_data<nes_state>();
+
+ /* 114 is the number of cycles per scanline */
+ /* TODO: change to reflect the actual number of cycles spent */
+ if (state->m_IRQ_enable)
+ {
+ if (state->m_IRQ_count <= 114)
+ {
+ device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE);
+ state->m_IRQ_count = (0xffff - 114 + state->m_IRQ_count); // wrap around the 16 bits counter
+ }
+ state->m_IRQ_count -= 114;
+ }
+}
+
+static WRITE8_HANDLER( lz93d50_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("lz93d50_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x000f)
+ {
+ case 0: case 1: case 2: case 3:
+ case 4: case 5: case 6: case 7:
+ chr1_x(space->machine(), offset & 0x07, data, state->m_mmc_chr_source);
+ break;
+ case 8:
+ prg16_89ab(space->machine(), data);
+ break;
+ case 9:
+ switch (data & 0x03)
+ {
+ case 0: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break;
+ case 1: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break;
+ case 2: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break;
+ case 3: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break;
+ }
+ break;
+ case 0x0a:
+ state->m_IRQ_enable = data & 0x01;
+ break;
+ case 0x0b:
+ state->m_IRQ_count = (state->m_IRQ_count & 0xff00) | data;
+ break;
+ case 0x0c:
+ state->m_IRQ_count = (state->m_IRQ_count & 0x00ff) | (data << 8);
+ break;
+ default:
+ logerror("lz93d50_w uncaught write, offset: %04x, data: %02x\n", offset, data);
+ break;
+ }
+}
+
+static WRITE8_HANDLER( lz93d50_m_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("lz93d50_m_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (!state->m_battery && !state->m_wram)
+ lz93d50_w(space, offset & 0x0f, data);
+ else if (state->m_battery)
+ state->m_battery_ram[offset] = data;
+ else
+ state->m_wram[offset] = data;
+}
+
+static void fjump2_set_prg( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ UINT8 mmc_helper = 0;
+ int i;
+
+ for (i = 0; i < 8; i++)
+ mmc_helper |= ((state->m_mmc_reg[i] & 0x01) << 4);
+
+ prg16_89ab(machine, mmc_helper | state->m_mmc_latch1);
+ prg16_cdef(machine, mmc_helper | 0x0f);
+}
+
+static WRITE8_HANDLER( fjump2_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("fjump2_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x000f)
+ {
+ case 0: case 1: case 2: case 3:
+ case 4: case 5: case 6: case 7:
+ state->m_mmc_reg[offset & 0x000f] = data;
+ fjump2_set_prg(space->machine());
+ break;
+ case 8:
+ state->m_mmc_latch1 = (data & 0x0f);
+ fjump2_set_prg(space->machine());
+ break;
+ default:
+ lz93d50_m_w(space, offset & 0x0f, data);
+ break;
+ }
+}
+
+/*************************************************************
+
+ Bandai Karaoke Studio board emulation
+
+ Games: Karaoke Studio
+
+ Note: we currently do not emulate the mic
+
+ iNES: mapper 188
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bandai_ks_w )
+{
+ LOG_MMC(("bandai_ks_w, offset: %04x, data: %02x\n", offset, data));
+
+ prg16_89ab(space->machine(), data ^ 0x08);
+}
+
+/*************************************************************
+
+ Bandai Oeka Kids board emulation
+
+ Games: Oeka Kids - Anpanman no Hiragana Daisuki, Oeka
+ Kids - Anpanman to Oekaki Shiyou!!
+
+ iNES: mapper 96
+
+ In MESS: Preliminary Support.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bandai_ok_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 mmc_helper;
+ LOG_MMC(("mapper96_w, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(space->machine(), data);
+
+ state->m_mmc_latch1 = data;
+ mmc_helper = (state->m_mmc_latch1 & 0x03) | (data & 0x04);
+ chr4_0(space->machine(), mmc_helper, CHRRAM);
+ chr4_4(space->machine(), 0x03 | (data & 0x04), CHRRAM);
+}
+
+/*************************************************************
+
+ Irem LROG017 - Discrete board emulation (74*161/161/21/138)
+
+ Games: Napoleon Senki
+
+ iNES: mapper 77
+
+ *************************************************************/
+
+static WRITE8_HANDLER( lrog017_w )
+{
+ LOG_MMC(("lrog017_w, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(space->machine(), data);
+ chr2_0(space->machine(), (data >> 4), CHRROM);
+}
+
+/*************************************************************
+
+ Irem Holy Diver board emulation
+
+ iNES: mapper 78 (shared with JF-16)
+
+ *************************************************************/
+
+static WRITE8_HANDLER( irem_hd_w )
+{
+ LOG_MMC(("irem_hd_w, offset: %04x, data: %02x\n", offset, data));
+
+ set_nt_mirroring(space->machine(), BIT(data, 3) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ);
+ chr8(space->machine(), data >> 4, CHRROM);
+ prg16_89ab(space->machine(), data);
+}
+
+/*************************************************************
+
+ Irem TAM-S1 board emulation
+
+ Games: Kaiketsu Yanchamaru
+
+ iNES: mapper 97
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( tam_s1_w )
+{
+ LOG_MMC(("tam_s1_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset < 0x4000)
+ {
+ set_nt_mirroring(space->machine(), BIT(data, 7) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ);
+ prg16_cdef(space->machine(), data);
+ }
+}
+
+/*************************************************************
+
+ Irem G-101 board emulation
+
+ Major League uses hardwired mirroring
+
+ iNES: mapper 32
+
+ *************************************************************/
+
+static WRITE8_HANDLER( g101_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("g101_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7000)
+ {
+ case 0x0000:
+ // NEStopia here differs a little bit
+ state->m_mmc_latch1 ? prg8_cd(space->machine(), data) : prg8_89(space->machine(), data);
+ break;
+ case 0x1000:
+ state->m_mmc_latch1 = BIT(data, 1);
+ if (!state->m_hard_mirroring) // there are two 'variants' depending on hardwired or mapper ctrl mirroring
+ set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+ case 0x2000:
+ prg8_ab(space->machine(), data);
+ break;
+ case 0x3000:
+ chr1_x(space->machine(), offset & 0x07, data, 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.
+
+ *************************************************************/
+
+/* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline,
+ we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC,
+ there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */
+static void h3001_irq( device_t *device, int scanline, int vblank, int blanked )
+{
+ nes_state *state = device->machine().driver_data<nes_state>();
+ if (state->m_IRQ_enable)
+ {
+ state->m_IRQ_count -= 114;
+
+ if (state->m_IRQ_count <= 114)
+ {
+ state->m_IRQ_enable = 0;
+ device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE);
+ }
+ }
+}
+
+static WRITE8_HANDLER( h3001_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("h3001_w, offset %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7fff)
+ {
+ case 0x0000:
+ prg8_89(space->machine(), data);
+ break;
+
+ case 0x1001:
+ set_nt_mirroring(space->machine(), BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+
+ case 0x1003:
+ state->m_IRQ_enable = data & 0x80;
+ break;
+
+ case 0x1004:
+ state->m_IRQ_count = state->m_IRQ_count_latch;
+ break;
+
+ case 0x1005:
+ state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0x00ff) | (data << 8);
+ break;
+
+ case 0x1006:
+ state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0xff00) | data;
+ break;
+
+ case 0x2000:
+ prg8_ab(space->machine(), data);
+ break;
+
+ case 0x3000: case 0x3001: case 0x3002: case 0x3003:
+ case 0x3004: case 0x3005: case 0x3006: case 0x3007:
+ chr1_x(space->machine(), offset & 0x07, data, CHRROM);
+ break;
+
+ case 0x4000:
+ prg8_cd(space->machine(), data);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*************************************************************
+
+ 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
+
+ *************************************************************/
+
+/* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline,
+ we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC,
+ there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */
+static void ss88006_irq( device_t *device, int scanline, int vblank, int blanked )
+{
+ nes_state *state = device->machine().driver_data<nes_state>();
+
+ /* Increment & check the IRQ scanline counter */
+ if (state->m_IRQ_enable)
+ {
+ LOG_MMC(("scanline: %d, irq count: %04x\n", scanline, state->m_IRQ_count));
+ if (state->m_IRQ_mode & 0x08)
+ {
+ if ((state->m_IRQ_count & 0x000f) < 114) // always true, but we only update the IRQ once per scanlines so we cannot be more precise :(
+ {
+ device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE);
+ state->m_IRQ_count = (state->m_IRQ_count & ~0x000f) | (0x0f - (114 & 0x0f) + (state->m_IRQ_count & 0x000f)); // sort of wrap around the counter
+ }
+ // decrements should not affect upper bits, so we don't do anything here (114 > 0x0f)
+ }
+ else if (state->m_IRQ_mode & 0x04)
+ {
+ if ((state->m_IRQ_count & 0x00ff) < 114)
+ {
+ device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE);
+ state->m_IRQ_count = (state->m_IRQ_count & ~0x00ff) | (0xff - 114 + (state->m_IRQ_count & 0x00ff)); // wrap around the 8 bits counter
+ }
+ else
+ state->m_IRQ_count -= 114;
+ }
+ else if (state->m_IRQ_mode & 0x02)
+ {
+ if ((state->m_IRQ_count & 0x0fff) < 114)
+ {
+ device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE);
+ state->m_IRQ_count = (state->m_IRQ_count & ~0x0fff) | (0xfff - 114 + (state->m_IRQ_count & 0x0fff)); // wrap around the 12 bits counter
+ }
+ else
+ state->m_IRQ_count -= 114;
+ }
+ else if (state->m_IRQ_count < 114)
+ {
+ device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE);
+ state->m_IRQ_count = (0xffff - 114 + state->m_IRQ_count); // wrap around the 16 bits counter
+ }
+ else
+ state->m_IRQ_count -= 114;
+ }
+}
+
+static WRITE8_HANDLER( ss88006_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 bank;
+ LOG_MMC(("mapper18_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7003)
+ {
+ case 0x0000:
+ state->m_mmc_prg_bank[0] = (state->m_mmc_prg_bank[0] & 0xf0) | (data & 0x0f);
+ prg8_89(space->machine(), state->m_mmc_prg_bank[0]);
+ break;
+ case 0x0001:
+ state->m_mmc_prg_bank[0] = (state->m_mmc_prg_bank[0] & 0x0f) | (data << 4);
+ prg8_89(space->machine(), state->m_mmc_prg_bank[0]);
+ break;
+ case 0x0002:
+ state->m_mmc_prg_bank[1] = (state->m_mmc_prg_bank[1] & 0xf0) | (data & 0x0f);
+ prg8_ab(space->machine(), state->m_mmc_prg_bank[1]);
+ break;
+ case 0x0003:
+ state->m_mmc_prg_bank[1] = (state->m_mmc_prg_bank[1] & 0x0f) | (data << 4);
+ prg8_ab(space->machine(), state->m_mmc_prg_bank[1]);
+ break;
+ case 0x1000:
+ state->m_mmc_prg_bank[2] = (state->m_mmc_prg_bank[2] & 0xf0) | (data & 0x0f);
+ prg8_cd(space->machine(), state->m_mmc_prg_bank[2]);
+ break;
+ case 0x1001:
+ state->m_mmc_prg_bank[2] = (state->m_mmc_prg_bank[2] & 0x0f) | (data << 4);
+ prg8_cd(space->machine(), state->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)
+ state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f)<< 4);
+ else
+ state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f);
+
+ chr1_x(space->machine(), bank, state->m_mmc_vrom_bank[bank], CHRROM);
+ break;
+
+ case 0x6000:
+ state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0xfff0) | (data & 0x0f);
+ break;
+ case 0x6001:
+ state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0xff0f) | ((data & 0x0f) << 4);
+ break;
+ case 0x6002:
+ state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0xf0ff) | ((data & 0x0f) << 8);
+ break;
+ case 0x6003:
+ state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0x0fff) | ((data & 0x0f) << 12);
+ break;
+
+ case 0x7000:
+ state->m_IRQ_count = state->m_IRQ_count_latch;
+ break;
+ case 0x7001:
+ state->m_IRQ_enable = data & 0x01;
+ state->m_IRQ_mode = data & 0x0e;
+ break;
+
+ case 0x7002:
+ switch (data & 0x03)
+ {
+ case 0: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break;
+ case 1: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break;
+ case 2: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break;
+ case 3: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break;
+ }
+ break;
+
+ default:
+ logerror("Jaleco SS88006 uncaught write, addr: %04x, value: %02x\n", offset + 0x8000, data);
+ break;
+ }
+}
+
+/*************************************************************
+
+ Jaleco JF-11, JF-12 & JF-14 boards emulation
+
+ Games: Bio Senshi Dan, Mississippi Satsujin Jiken
+
+ iNES: mapper 140
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( jf11_m_w )
+{
+ LOG_MMC(("jf11_m_w, offset: %04x, data: %02x\n", offset, data));
+ chr8(space->machine(), data, CHRROM);
+ prg32(space->machine(), 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.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( jf13_m_w )
+{
+ LOG_MMC(("jf13_m_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset == 0)
+ {
+ prg32(space->machine(), (data >> 4) & 0x03);
+ chr8(space->machine(), ((data >> 4) & 0x04) | (data & 0x03), CHRROM);
+ }
+
+ if (offset == 0x1000)
+ {
+ LOG_MMC(("Jaleco JF-13 sound write, data: %02x\n", data));
+ // according to NEStopia, this is the effect
+ if ((data & 0x30) == 0x20)
+ {
+ // send command (data & 0x1f) to sound chip
+ }
+ }
+}
+
+/*************************************************************
+
+ Jaleco JF-16 board emulation
+
+ iNES: mapper 78 (shared with a diff Irem board)
+
+ *************************************************************/
+
+static WRITE8_HANDLER( jf16_w )
+{
+ LOG_MMC(("jf16_w, offset: %04x, data: %02x\n", offset, data));
+
+ set_nt_mirroring(space->machine(), BIT(data, 3) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
+ chr8(space->machine(), data >> 4, CHRROM);
+ prg16_89ab(space->machine(), data);
+}
+
+/*************************************************************
+
+ Jaleco JF-17, JF-26 & JF-28 boards emulation
+
+ Note: we don't emulate the additional sound hardware.
+
+ Games: Moero!! Juudou Warriors, Moero!! Pro Tennis, Pinball
+ Quest Jpn
+
+ iNES: mapper 72
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( jf17_w )
+{
+ LOG_MMC(("jf17_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (BIT(data, 7))
+ prg16_89ab(space->machine(), data & 0x0f);
+ if (BIT(data, 6))
+ chr8(space->machine(), data & 0x0f, CHRROM);
+ if (BIT(data, 5) && !BIT(data,4))
+ LOG_MMC(("Jaleco JF-17 sound write, data: %02x\n", data & 0x1f));
+}
+
+/*************************************************************
+
+ Jaleco JF-19 & JF-21 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 (no samples).
+
+ *************************************************************/
+
+static WRITE8_HANDLER( jf19_w )
+{
+ LOG_MMC(("jf19_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (BIT(data, 7))
+ prg16_cdef(space->machine(), data & 0x0f);
+ if (BIT(data, 6))
+ chr8(space->machine(), data & 0x0f, CHRROM);
+ if (BIT(data, 5) && !BIT(data,4))
+ LOG_MMC(("Jaleco JF-19 sound write, data: %02x\n", data & 0x1f));
+}
+
+/*************************************************************
+
+ Konami VRC1 and Jaleco JF20, JF22
+
+ Games: Exciting Boxing, Ganbare Goemon!, Tetsuwan Atom
+
+ iNES: mapper 75
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( konami_vrc1_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("konami_vrc1_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7000)
+ {
+ case 0x0000:
+ prg8_89(space->machine(), data);
+ break;
+ case 0x1000:
+ set_nt_mirroring(space->machine(), (data & 0x01) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ state->m_mmc_vrom_bank[0] = (state->m_mmc_vrom_bank[0] & 0x0f) | ((data & 0x02) << 3);
+ state->m_mmc_vrom_bank[1] = (state->m_mmc_vrom_bank[1] & 0x0f) | ((data & 0x04) << 2);
+ chr4_0(space->machine(), state->m_mmc_vrom_bank[0], CHRROM);
+ chr4_4(space->machine(), state->m_mmc_vrom_bank[1], CHRROM);
+ break;
+ case 0x2000:
+ prg8_ab(space->machine(), data);
+ break;
+ case 0x4000:
+ prg8_cd(space->machine(), data);
+ break;
+ case 0x6000:
+ state->m_mmc_vrom_bank[0] = (state->m_mmc_vrom_bank[0] & 0x10) | (data & 0x0f);
+ chr4_0(space->machine(), state->m_mmc_vrom_bank[0], CHRROM);
+ break;
+ case 0x7000:
+ state->m_mmc_vrom_bank[1] = (state->m_mmc_vrom_bank[1] & 0x10) | (data & 0x0f);
+ chr4_4(space->machine(), state->m_mmc_vrom_bank[1], CHRROM);
+ break;
+ }
+}
+
+/*************************************************************
+
+ Konami VRC-2
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( konami_vrc2_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 bank, shift, mask;
+ UINT32 shifted_offs = (offset & 0x7000)
+ | ((offset << (9 - state->m_vrc_ls_prg_a)) & 0x200)
+ | ((offset << (8 - state->m_vrc_ls_prg_b)) & 0x100);
+ LOG_MMC(("konami_vrc2_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset < 0x1000)
+ prg8_89(space->machine(), data);
+ else if (offset < 0x2000)
+ {
+ switch (data & 0x03)
+ {
+ case 0x00: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break;
+ case 0x01: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break;
+ case 0x02: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break;
+ case 0x03: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break;
+ }
+ }
+ else if (offset < 0x3000)
+ prg8_ab(space->machine(), data);
+ else if (offset < 0x7000)
+ {
+ bank = ((shifted_offs & 0x7000) - 0x3000) / 0x0800 + BIT(shifted_offs, 9);
+ shift = BIT(shifted_offs, 8) * 4;
+ mask = (0xf0 >> shift);
+ state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & mask)
+ | (((data >> state->m_vrc_ls_chr) & 0x0f) << shift);
+ chr1_x(space->machine(), bank, state->m_mmc_vrom_bank[bank], CHRROM);
+ }
+ else
+ logerror("konami_vrc2_w uncaught write, addr: %04x value: %02x\n", offset + 0x8000, data);
+}
+
+/*************************************************************
+
+ Konami VRC3
+
+ Games: Salamander
+
+ iNES: mapper 73
+
+ In MESS: Supported. It also uses konami_irq.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( konami_vrc3_w )
+{
+ LOG_MMC(("konami_vrc3_w, offset: %04x, data: %02x\n", offset, data));
+ nes_state *state = space->machine().driver_data<nes_state>();
+
+ switch (offset & 0x7000)
+ {
+ case 0x0000:
+ case 0x1000:
+ /* dunno which address controls these */
+ state->m_IRQ_count_latch = data;
+ state->m_IRQ_enable_latch = data;
+ break;
+ case 0x2000:
+ state->m_IRQ_enable = data;
+ break;
+ case 0x3000:
+ state->m_IRQ_count &= ~0x0f;
+ state->m_IRQ_count |= data & 0x0f;
+ break;
+ case 0x4000:
+ state->m_IRQ_count &= ~0xf0;
+ state->m_IRQ_count |= (data & 0x0f) << 4;
+ break;
+ case 0x7000:
+ prg16_89ab(space->machine(), data);
+ break;
+ default:
+ logerror("konami_vrc3_w uncaught write, offset %04x, data: %02x\n", offset, data);
+ break;
+ }
+}
+
+/*************************************************************
+
+ Konami VRC-4
+
+ In MESS: Supported
+
+ *************************************************************/
+
+static void vrc4_set_prg( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ if (state->m_mmc_latch1 & 0x02)
+ {
+ prg8_89(machine, 0xfe);
+ prg8_cd(machine, state->m_mmc_prg_bank[0]);
+ }
+ else
+ {
+ prg8_89(machine, state->m_mmc_prg_bank[0]);
+ prg8_cd(machine, 0xfe);
+ }
+}
+
+static void konami_irq( device_t *device, int scanline, int vblank, int blanked )
+{
+ nes_state *state = device->machine().driver_data<nes_state>();
+ /* Increment & check the IRQ scanline counter */
+ if (state->m_IRQ_enable && (++state->m_IRQ_count == 0x100))
+ {
+ state->m_IRQ_count = state->m_IRQ_count_latch;
+ state->m_IRQ_enable = state->m_IRQ_enable_latch;
+ device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE);
+ }
+}
+
+static WRITE8_HANDLER( konami_vrc4_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 bank, shift, mask;
+ UINT32 shifted_offs = (offset & 0x7000)
+ | ((offset << (9 - state->m_vrc_ls_prg_a)) & 0x200)
+ | ((offset << (8 - state->m_vrc_ls_prg_b)) & 0x100);
+ LOG_MMC(("konami_vrc4_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset < 0x1000)
+ {
+ state->m_mmc_prg_bank[0] = data;
+ vrc4_set_prg(space->machine());
+ }
+ else if (offset >= 0x2000 && offset < 0x3000)
+ prg8_ab(space->machine(), data);
+ else
+ {
+ switch (shifted_offs & 0x7300)
+ {
+ case 0x1000:
+ case 0x1100:
+ switch (data & 0x03)
+ {
+ case 0x00: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break;
+ case 0x01: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break;
+ case 0x02: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break;
+ case 0x03: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break;
+ }
+ break;
+ case 0x1200:
+ case 0x1300:
+ state->m_mmc_latch1 = data & 0x02;
+ vrc4_set_prg(space->machine());
+ break;
+ case 0x3000:
+ case 0x3100:
+ case 0x3200:
+ case 0x3300:
+ case 0x4000:
+ case 0x4100:
+ case 0x4200:
+ case 0x4300:
+ case 0x5000:
+ case 0x5100:
+ case 0x5200:
+ case 0x5300:
+ case 0x6000:
+ case 0x6100:
+ case 0x6200:
+ case 0x6300:
+ bank = ((shifted_offs & 0x7000) - 0x3000) / 0x0800 + BIT(shifted_offs, 9);
+ shift = BIT(shifted_offs, 8) * 4;
+ mask = (0xf0 >> shift);
+ state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & mask) | ((data & 0x0f) << shift);
+ chr1_x(space->machine(), bank, state->m_mmc_vrom_bank[bank], CHRROM);
+ break;
+ case 0x7000:
+ state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0xf0) | (data & 0x0f);
+ break;
+ case 0x7100:
+ state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0x0f) | ((data & 0x0f) << 4);
+ break;
+ case 0x7200:
+ state->m_IRQ_mode = data & 0x04; // currently not implemented: 0 = prescaler mode / 1 = CPU mode
+ state->m_IRQ_enable = data & 0x02;
+ state->m_IRQ_enable_latch = data & 0x01;
+ if (data & 0x02)
+ state->m_IRQ_count = state->m_IRQ_count_latch;
+ break;
+ case 0x7300:
+ state->m_IRQ_enable = state->m_IRQ_enable_latch;
+ break;
+ default:
+ logerror("konami_vrc4_w uncaught write, addr: %04x value: %02x\n", shifted_offs + 0x8000, data);
+ break;
+ }
+ }
+}
+
+/*************************************************************
+
+ Konami VRC-6
+
+ In MESS: Supported. It also uses konami_irq (there are IRQ
+ issues though: see Akumajou Densetsu intro).
+
+ *************************************************************/
+
+static WRITE8_HANDLER( konami_vrc6_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 bank;
+ UINT32 shifted_offs = (offset & 0x7000)
+ | ((offset << (9 - state->m_vrc_ls_prg_a)) & 0x200)
+ | ((offset << (8 - state->m_vrc_ls_prg_b)) & 0x100);
+ LOG_MMC(("konami_vrc6_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset < 0x1000)
+ prg16_89ab(space->machine(), data);
+ else if (offset >= 0x4000 && offset < 0x5000)
+ prg8_cd(space->machine(), data);
+ else
+ {
+ switch (shifted_offs & 0x7300)
+ {
+ case 0x1000:
+ case 0x1100:
+ case 0x1200:
+ case 0x2000:
+ case 0x2100:
+ case 0x2200:
+ case 0x3000:
+ case 0x3100:
+ case 0x3200:
+ LOG_MMC(("Konami VRC-6 Sound write, offset: %04x, data: %02x\n", shifted_offs & 0x7300, data));
+ break;
+ case 0x3300:
+ switch (data & 0x0c)
+ {
+ case 0x00: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break;
+ case 0x04: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break;
+ case 0x08: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break;
+ case 0x0c: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break;
+ }
+ break;
+ case 0x5000:
+ case 0x5100:
+ case 0x5200:
+ case 0x5300:
+ case 0x6000:
+ case 0x6100:
+ case 0x6200:
+ case 0x6300:
+ bank = ((shifted_offs & 0x7000) - 0x5000) / 0x0400 + ((shifted_offs & 0x0300) >> 8);
+ chr1_x(space->machine(), bank, data, CHRROM);
+ break;
+ case 0x7000:
+ state->m_IRQ_count_latch = data;
+ break;
+ case 0x7100:
+ state->m_IRQ_mode = data & 0x04; // currently not implemented: 0 = prescaler mode / 1 = CPU mode
+ state->m_IRQ_enable = data & 0x02;
+ state->m_IRQ_enable_latch = data & 0x01;
+ if (data & 0x02)
+ state->m_IRQ_count = state->m_IRQ_count_latch;
+ break;
+ case 0x7200:
+ state->m_IRQ_enable = state->m_IRQ_enable_latch;
+ break;
+ default:
+ logerror("konami_vrc6_w uncaught write, addr: %04x value: %02x\n", shifted_offs + 0x8000, data);
+ break;
+ }
+ }
+}
+
+/*************************************************************
+
+ Konami VRC7
+
+ Games: Lagrange Point, Tiny Toon Adventures 2
+
+ iNES: mapper 85
+
+ In MESS: Supported. It also uses konami_irq.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( konami_vrc7_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 bank;
+ LOG_MMC(("konami_vrc7_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7018)
+ {
+ case 0x0000:
+ prg8_89(space->machine(), data);
+ break;
+ case 0x0008:
+ case 0x0010:
+ case 0x0018:
+ prg8_ab(space->machine(), data);
+ break;
+
+ case 0x1000:
+ prg8_cd(space->machine(), data);
+ break;
+
+ /* TODO: there are sound regs in here */
+
+ 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(space->machine(), bank, data, state->m_mmc_chr_source);
+ break;
+
+ case 0x6000:
+ switch (data & 0x03)
+ {
+ case 0x00: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break;
+ case 0x01: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break;
+ case 0x02: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break;
+ case 0x03: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break;
+ }
+ break;
+ case 0x6008: case 0x6010: case 0x6018:
+ state->m_IRQ_count_latch = data;
+ break;
+ case 0x7000:
+ state->m_IRQ_mode = data & 0x04; // currently not implemented: 0 = prescaler mode / 1 = CPU mode
+ state->m_IRQ_enable = data & 0x02;
+ state->m_IRQ_enable_latch = data & 0x01;
+ if (data & 0x02)
+ state->m_IRQ_count = state->m_IRQ_count_latch;
+ break;
+ case 0x7008: case 0x7010: case 0x7018:
+ state->m_IRQ_enable = state->m_IRQ_enable_latch;
+ break;
+
+ default:
+ logerror("konami_vrc7_w uncaught write, addr: %04x value: %02x\n", offset + 0x8000, data);
+ break;
+ }
+}
+
+/*************************************************************
+
+ Namcot-163 board emulation
+
+ Games: Battle Fleet, Family Circuit '91, Famista '90, '91,
+ '92 & '94, Megami Tensei II, Top Striker, Wagyan Land 2 & 3
+
+ iNES: mapper 19
+
+ In MESS: Supported
+
+ *************************************************************/
+
+/* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline,
+ we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC,
+ there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */
+static void namcot_irq( device_t *device, int scanline, int vblank, int blanked )
+{
+ nes_state *state = device->machine().driver_data<nes_state>();
+
+ if (state->m_IRQ_enable)
+ {
+ if (state->m_IRQ_count >= (0x7fff - 114))
+ {
+ device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE);
+ state->m_IRQ_count = 0;
+ }
+ else
+ state->m_IRQ_count += 114;
+ }
+}
+
+static WRITE8_HANDLER( namcot163_l_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("namcot163_l_w, 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;
+ case 0x1000: /* low byte of IRQ */
+ state->m_IRQ_count = (state->m_IRQ_count & 0x7f00) | data;
+ break;
+ case 0x1800: /* high byte of IRQ, IRQ enable in high bit */
+ state->m_IRQ_count = (state->m_IRQ_count & 0xff) | ((data & 0x7f) << 8);
+ state->m_IRQ_enable = data & 0x80;
+ break;
+ }
+}
+
+static READ8_HANDLER( namcot163_l_r )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("namcot163_l_r, offset: %04x\n", offset));
+ offset += 0x100;
+
+ switch (offset & 0x1800)
+ {
+ case 0x1000:
+ return state->m_IRQ_count & 0xff;
+ case 0x1800:
+ return (state->m_IRQ_count >> 8) & 0xff;
+ case 0x0800:
+ LOG_MMC(("Namcot-163 sound reg read\n"));
+ default:
+ return 0x00;
+ }
+}
+
+static void namcot163_set_mirror( running_machine &machine, UINT8 page, UINT8 data )
+{
+ if (!(data < 0xe0))
+ set_nt_page(machine, page, CIRAM, data & 0x01, 1);
+ else
+ set_nt_page(machine, page, ROM, data, 0);
+}
+
+static WRITE8_HANDLER( namcot163_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("namcot163_w, 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(space->machine(), offset / 0x800, data, CHRROM);
+ break;
+ case 0x4000:
+ namcot163_set_mirror(space->machine(), 0, data);
+ break;
+ case 0x4800:
+ namcot163_set_mirror(space->machine(), 1, data);
+ break;
+ case 0x5000:
+ namcot163_set_mirror(space->machine(), 2, data);
+ break;
+ case 0x5800:
+ namcot163_set_mirror(space->machine(), 3, data);
+ break;
+ case 0x6000:
+ prg8_89(space->machine(), data & 0x3f);
+ break;
+ case 0x6800:
+ state->m_mmc_latch1 = data & 0xc0; // this should enable High CHRRAM, but we still have to properly implement it!
+ prg8_ab(space->machine(), data & 0x3f);
+ break;
+ case 0x7000:
+ prg8_cd(space->machine(), data & 0x3f);
+ break;
+ case 0x7800:
+ LOG_MMC(("Namcot-163 sound address write, data: %02x\n", data));
+ break;
+ }
+}
+
+/*************************************************************
+
+ 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)
+
+ *************************************************************/
+
+static WRITE8_HANDLER( sunsoft1_m_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("sunsoft1_m_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (state->m_chr_chunks)
+ {
+ chr4_0(space->machine(), data & 0x0f, CHRROM);
+ chr4_4(space->machine(), data >> 4, CHRROM);
+ }
+ else
+ prg16_89ab(space->machine(), data & 0x0f);
+}
+
+/*************************************************************
+
+ Sunsoft-2 board emulation
+
+ The two games using this board have incompatible mirroring
+ wiring, making necessary two distinct mappers & pcb_id
+
+ iNES: mapper 89 & 93
+
+ *************************************************************/
+
+static WRITE8_HANDLER( sunsoft2_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 sunsoft_helper = (data & 0x07) | ((data & 0x80) ? 0x08 : 0x00);
+ LOG_MMC(("sunsoft2_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (!state->m_hard_mirroring) // there are two 'variants' depending on hardwired or mapper ctrl mirroring
+ set_nt_mirroring(space->machine(), BIT(data, 3) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
+ if (state->m_chr_chunks)
+ chr8(space->machine(), sunsoft_helper, CHRROM);
+
+ prg16_89ab(space->machine(), 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
+
+ *************************************************************/
+
+/* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline,
+ we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC,
+ there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */
+static void sunsoft3_irq( device_t *device, int scanline, int vblank, int blanked )
+{
+ nes_state *state = device->machine().driver_data<nes_state>();
+
+ /* TODO: change to reflect the actual number of cycles spent: both using 114 or cycling 114,114,113
+ produces a 1-line glitch in Fantasy Zone 2: it really requires the counter to be updated each CPU cycle! */
+ if (state->m_IRQ_enable)
+ {
+ if (state->m_IRQ_count <= 114)
+ {
+ state->m_IRQ_enable = 0;
+ state->m_IRQ_count = 0xffff;
+ device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE);
+ }
+ else
+ state->m_IRQ_count -= 114;
+ }
+}
+
+static WRITE8_HANDLER( sunsoft3_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("sunsoft3_w, offset %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7800)
+ {
+ case 0x0800:
+ chr2_0(space->machine(), data, CHRROM);
+ break;
+ case 0x1800:
+ chr2_2(space->machine(), data, CHRROM);
+ break;
+ case 0x2800:
+ chr2_4(space->machine(), data, CHRROM);
+ break;
+ case 0x3800:
+ chr2_6(space->machine(), data, CHRROM);
+ break;
+ case 0x4000:
+ case 0x4800:
+ state->m_IRQ_toggle ^= 1;
+ if (state->m_IRQ_toggle)
+ state->m_IRQ_count = (state->m_IRQ_count & 0x00ff) | (data << 8);
+ else
+ state->m_IRQ_count = (state->m_IRQ_count & 0xff00) | data;
+ break;
+ case 0x5800:
+ state->m_IRQ_enable = BIT(data, 4);
+ state->m_IRQ_toggle = 0;
+ break;
+ case 0x6800:
+ switch (data & 3)
+ {
+ case 0x00: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break;
+ case 0x01: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break;
+ case 0x02: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break;
+ case 0x03: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break;
+ }
+ break;
+ case 0x7800:
+ prg16_89ab(space->machine(), data);
+ break;
+ default:
+ LOG_MMC(("sunsoft3_w uncaught write, offset: %04x, data: %02x\n", offset, data));
+ break;
+ }
+}
+
+/*************************************************************
+
+ 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.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( tc0190fmc_w )
+{
+ LOG_MMC(("tc0190fmc_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7003)
+ {
+ case 0x0000:
+ set_nt_mirroring(space->machine(), BIT(data, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ prg8_89(space->machine(), data);
+ break;
+ case 0x0001:
+ prg8_ab(space->machine(), data);
+ break;
+ case 0x0002:
+ chr2_0(space->machine(), data, CHRROM);
+ break;
+ case 0x0003:
+ chr2_2(space->machine(), data, CHRROM);
+ break;
+ case 0x2000:
+ chr1_4(space->machine(), data, CHRROM);
+ break;
+ case 0x2001:
+ chr1_5(space->machine(), data, CHRROM);
+ break;
+ case 0x2002:
+ chr1_6(space->machine(), data, CHRROM);
+ break;
+ case 0x2003:
+ chr1_7(space->machine(), 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.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( tc0190fmc_p16_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("tc0190fmc_p16_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7003)
+ {
+ case 0x0000:
+ prg8_89(space->machine(), data);
+ break;
+ case 0x0001:
+ case 0x0002:
+ case 0x0003:
+ case 0x2000:
+ case 0x2001:
+ case 0x2002:
+ case 0x2003:
+ tc0190fmc_w(space, offset, data);
+ break;
+ case 0x4000:
+ state->m_IRQ_count_latch = (0x100 - data) & 0xff;
+ break;
+ case 0x4001:
+ state->m_IRQ_count = state->m_IRQ_count_latch;
+ break;
+ case 0x4002:
+ state->m_IRQ_enable = 1;
+ break;
+ case 0x4003:
+ state->m_IRQ_enable = 0;
+ break;
+ case 0x6000:
+ set_nt_mirroring(space->machine(), 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
+
+ *************************************************************/
+
+static WRITE8_HANDLER( x1005_m_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("x1005_m_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset)
+ {
+ case 0x1ef0:
+ chr2_0(space->machine(), (data & 0x7f) >> 1, CHRROM);
+ break;
+ case 0x1ef1:
+ chr2_2(space->machine(), (data & 0x7f) >> 1, CHRROM);
+ break;
+ case 0x1ef2:
+ chr1_4(space->machine(), data, CHRROM);
+ break;
+ case 0x1ef3:
+ chr1_5(space->machine(), data, CHRROM);
+ break;
+ case 0x1ef4:
+ chr1_6(space->machine(), data, CHRROM);
+ break;
+ case 0x1ef5:
+ chr1_7(space->machine(), data, CHRROM);
+ break;
+ case 0x1ef6:
+ case 0x1ef7:
+ set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ);
+ break;
+ case 0x1ef8:
+ case 0x1ef9:
+ state->m_mmc_latch1 = data;
+ break;
+ case 0x1efa:
+ case 0x1efb:
+ prg8_89(space->machine(), data);
+ break;
+ case 0x1efc:
+ case 0x1efd:
+ prg8_ab(space->machine(), data);
+ break;
+ case 0x1efe:
+ case 0x1eff:
+ prg8_cd(space->machine(), data);
+ break;
+ default:
+ logerror("mapper80_m_w uncaught addr: %04x, value: %02x\n", offset + 0x6000, data);
+ break;
+ }
+
+ if (offset >= 0x1f00 && state->m_mapper_ram != NULL && state->m_mmc_latch1 == 0xa3)
+ state->m_mapper_ram[offset & (state->m_mapper_ram_size - 1)] = data;
+ else if (offset >= 0x1f00 && state->m_mapper_bram != NULL && state->m_mmc_latch1 == 0xa3)
+ state->m_mapper_bram[offset & (state->m_mapper_bram_size - 1)] = data;
+}
+
+static READ8_HANDLER( x1005_m_r )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("x1005a_m_r, offset: %04x\n", offset));
+
+ if (offset >= 0x1f00 && state->m_mapper_ram != NULL && state->m_mmc_latch1 == 0xa3)
+ return state->m_mapper_ram[offset & (state->m_mapper_ram_size - 1)];
+ else if (offset >= 0x1f00 && state->m_mapper_bram != NULL && state->m_mmc_latch1 == 0xa3)
+ return state->m_mapper_bram[offset & (state->m_mapper_bram_size - 1)];
+
+ return 0xff;
+}
+
+static WRITE8_HANDLER( x1005a_m_w )
+{
+ LOG_MMC(("x1005a_m_w, offset: %04x, data: %02x\n", offset, data));
+
+ // similar to x1005_m_w but mirroring is handled differently
+ if (offset == 0x1ef6 || offset == 0x1ef7)
+ return;
+
+ switch (offset)
+ {
+ case 0x1ef0:
+ set_nt_page(space->machine(), 0, CIRAM, (data & 0x80) ? 1 : 0, 1);
+ set_nt_page(space->machine(), 1, CIRAM, (data & 0x80) ? 1 : 0, 1);
+ break;
+ case 0x1ef1:
+ set_nt_page(space->machine(), 2, CIRAM, (data & 0x80) ? 1 : 0, 1);
+ set_nt_page(space->machine(), 3, CIRAM, (data & 0x80) ? 1 : 0, 1);
+ break;
+ }
+
+ x1005_m_w(space, offset, data);
+}
+
+/*************************************************************
+
+ 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.
+
+ *************************************************************/
+
+static void x1017_set_chr( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ if (state->m_mmc_latch1)
+ {
+ chr2_4(machine, state->m_mmc_vrom_bank[0] >> 1, CHRROM);
+ chr2_6(machine, state->m_mmc_vrom_bank[1] >> 1, CHRROM);
+ }
+ else
+ {
+ chr2_0(machine, state->m_mmc_vrom_bank[0] >> 1, CHRROM);
+ chr2_2(machine, state->m_mmc_vrom_bank[1] >> 1, CHRROM);
+ }
+ chr1_x(machine, 4 ^ state->m_mmc_latch1, state->m_mmc_vrom_bank[2], CHRROM);
+ chr1_x(machine, 5 ^ state->m_mmc_latch1, state->m_mmc_vrom_bank[3], CHRROM);
+ chr1_x(machine, 6 ^ state->m_mmc_latch1, state->m_mmc_vrom_bank[4], CHRROM);
+ chr1_x(machine, 7 ^ state->m_mmc_latch1, state->m_mmc_vrom_bank[5], CHRROM);
+}
+
+static WRITE8_HANDLER( x1017_m_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 reg = offset & 0x07;
+ LOG_MMC(("x1017_m_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset)
+ {
+ case 0x1ef0:
+ case 0x1ef1:
+ if (state->m_mmc_vrom_bank[reg] != data)
+ {
+ state->m_mmc_vrom_bank[reg] = data;
+ x1017_set_chr(space->machine());
+ }
+ break;
+ case 0x1ef2:
+ case 0x1ef3:
+ case 0x1ef4:
+ case 0x1ef5:
+ if (state->m_mmc_vrom_bank[reg] != data)
+ {
+ state->m_mmc_vrom_bank[reg] = data;
+ x1017_set_chr(space->machine());
+ }
+ break;
+ case 0x1ef6:
+ set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ);
+ state->m_mmc_latch1 = ((data & 0x02) << 1);
+ x1017_set_chr(space->machine());
+ break;
+ case 0x1ef7:
+ case 0x1ef8:
+ case 0x1ef9:
+ state->m_mmc_reg[(offset & 0x0f) - 7] = data;
+ break;
+ case 0x1efa:
+ prg8_89(space->machine(), data >> 2);
+ break;
+ case 0x1efb:
+ prg8_ab(space->machine(), data >> 2);
+ break;
+ case 0x1efc:
+ prg8_cd(space->machine(), data >> 2);
+ break;
+ default:
+ logerror("x1017_m_w uncaught write, addr: %04x, value: %02x\n", offset + 0x6000, data);
+ break;
+ }
+}
+
+static READ8_HANDLER( x1017_m_r )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("x1017_m_r, offset: %04x\n", offset));
+
+ // 2+2+1 KB of Internal RAM can be independently enabled/disabled!
+ if (offset < 0x0800 && state->m_mapper_bram != NULL && state->m_mmc_reg[0] == 0xca)
+ return state->m_mapper_bram[offset & (state->m_mapper_bram_size - 1)];
+ if (offset < 0x1000 && state->m_mapper_bram != NULL && state->m_mmc_reg[1] == 0x69)
+ return state->m_mapper_bram[offset & (state->m_mapper_bram_size - 1)];
+ if (offset < 0x1800 && state->m_mapper_bram != NULL && state->m_mmc_reg[2] == 0x84)
+ return state->m_mapper_bram[offset & (state->m_mapper_bram_size - 1)];
+
+ return 0xff;
+}
+
+/*************************************************************
+
+ MISC UNLICENSED BOARDS
+
+ *************************************************************/
+
+/*************************************************************
+
+ AGCI 50282 bootleg board emulation
+
+ Games: Death Race
+
+ iNES: mapper 144
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( agci_50282_w )
+{
+ LOG_MMC(("agci_50282_w, offset: %04x, data: %02x\n", offset, data));
+
+ offset += 0x8000;
+ data |= (space->read_byte(offset) & 1);
+
+ chr8(space->machine(), data >> 4, CHRROM);
+ prg32(space->machine(), data);
+}
+
+/*************************************************************
+
+ AVE NINA-001 board emulation
+
+ iNES: mapper 34
+
+ *************************************************************/
+
+static WRITE8_HANDLER( nina01_m_w )
+{
+ LOG_MMC(("nina01_m_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset)
+ {
+ case 0x1ffd:
+ prg32(space->machine(), data);
+ break;
+ case 0x1ffe:
+ chr4_0(space->machine(), data, CHRROM);
+ break;
+ case 0x1fff:
+ chr4_4(space->machine(), data, CHRROM);
+ break;
+ }
+}
+
+/*************************************************************
+
+ 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.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( nina06_l_w )
+{
+ LOG_MMC(("nina06_l_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (!(offset & 0x0100))
+ {
+ prg32(space->machine(), data >> 3);
+ chr8(space->machine(), data, CHRROM);
+ }
+}
+
+/*************************************************************
+
+ Active Entertainment Action 52 board emulation
+
+ iNES: mapper 228
+
+ *************************************************************/
+
+static WRITE8_HANDLER( ae_act52_w )
+{
+ int pbank, cbank;
+ UINT8 pmode;
+ LOG_MMC(("ae_act52_w, offset: %04x, data: %02x\n", offset, data));
+
+ set_nt_mirroring(space->machine(), BIT(offset, 13) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+
+ cbank = (data & 0x03) | ((offset & 0x0f) << 2);
+ chr8(space->machine(), cbank, CHRROM);
+
+ pmode = offset & 0x20;
+ pbank = (offset & 0x1fc0) >> 6;
+ if (pmode)
+ {
+ prg16_89ab(space->machine(), pbank);
+ prg16_cdef(space->machine(), pbank);
+ }
+ else
+ prg32(space->machine(), pbank >> 1);
+}
+
+
+/*************************************************************
+
+ C & E Bootleg Board for Decathlon
+
+ Games: Decathlon
+
+ Pretty simple mapper: writes to 0x8065-0x80a4 set prg32 to
+ data & 3; writes to 0x80a5-0x80e4 set chr8 to data & 7
+
+ iNES: mapper 244
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( cne_decathl_w )
+{
+ LOG_MMC(("cne_decathl_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset < 0x0065)
+ return;
+ if (offset < 0x00a5)
+ {
+ prg32(space->machine(), (offset - 0x0065) & 0x03);
+ return;
+ }
+ if (offset < 0x00e5)
+ {
+ chr8(space->machine(), (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.
+
+ iNES: mapper 246
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( cne_fsb_m_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("cne_fsb_m_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset < 0x0800)
+ {
+ switch (offset & 0x0007)
+ {
+ case 0x0000:
+ prg8_89(space->machine(), data);
+ break;
+ case 0x0001:
+ prg8_ab(space->machine(), data);
+ break;
+ case 0x0002:
+ prg8_cd(space->machine(), data);
+ break;
+ case 0x0003:
+ prg8_ef(space->machine(), data);
+ break;
+ case 0x0004:
+ chr2_0(space->machine(), data, CHRROM);
+ break;
+ case 0x0005:
+ chr2_2(space->machine(), data, CHRROM);
+ break;
+ case 0x0006:
+ chr2_4(space->machine(), data, CHRROM);
+ break;
+ case 0x0007:
+ chr2_6(space->machine(), data, CHRROM);
+ break;
+ }
+ }
+ else
+ state->m_battery_ram[offset] = data;
+}
+
+/*************************************************************
+
+ 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.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( cne_shlz_l_w )
+{
+ LOG_MMC(("cne_shlz_l_w, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(space->machine(), data >> 4);
+ chr8(space->machine(), data & 0x0f, CHRROM);
+}
+
+/*************************************************************
+
+ Caltron 6 in 1 Board
+
+ Games: 6 in 1 by Caltron
+
+ iNES: mapper 41
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( caltron6in1_m_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("caltron6in1_m_w, offset: %04x, data: %02x\n", offset, data));
+
+ state->m_mmc_latch1 = offset & 0xff;
+ set_nt_mirroring(space->machine(), BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ prg32(space->machine(), offset & 0x07);
+}
+
+static WRITE8_HANDLER( caltron6in1_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("caltron6in1_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (state->m_mmc_latch1 & 0x04)
+ chr8(space->machine(), ((state->m_mmc_latch1 & 0x18) >> 1) | (data & 0x03), CHRROM);
+}
+
+/*************************************************************
+
+ 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.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bf9093_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("bf9093_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7000)
+ {
+ case 0x0000:
+ case 0x1000:
+ if (!state->m_hard_mirroring)
+ set_nt_mirroring(space->machine(), BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
+ break;
+ case 0x4000:
+ case 0x5000:
+ case 0x6000:
+ case 0x7000:
+ prg16_89ab(space->machine(), data);
+ break;
+ }
+}
+
+/*************************************************************
+
+ Camerica BF9096 & ALGQV11 Boards
+
+ Games: Quattro Adventure, Quattro Arcade, Quattro Sports
+
+ Writes to 0x8000-0x9fff set prg block to (data&0x18)>>1,
+ writes to 0xa000-0xbfff 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.
+
+ *************************************************************/
+
+static void bf9096_set_prg( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ prg16_89ab(machine, (state->m_mmc_latch2 & 0x03) | ((state->m_mmc_latch1 & 0x18) >> 1));
+ prg16_cdef(machine, 0x03 | ((state->m_mmc_latch1 & 0x18) >> 1));
+}
+
+static WRITE8_HANDLER( bf9096_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("bf9096_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset < 0x2000)
+ state->m_mmc_latch1 = data;
+ else
+ state->m_mmc_latch2 = data;
+
+ bf9096_set_prg(space->machine());
+}
+
+/*************************************************************
+
+ Camerica Golden Five board
+
+ Games: Pegasus 5 in 1
+
+ iNES: mapper 104
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( golden5_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("golden5_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset < 0x4000)
+ {
+ if (data & 0x08)
+ {
+ state->m_mmc_prg_bank[0] = ((data & 0x07) << 4) | (state->m_mmc_prg_bank[0] & 0x0f);
+ prg16_89ab(space->machine(), state->m_mmc_prg_bank[0]);
+ prg16_cdef(space->machine(), ((data & 0x07) << 4) | 0x0f);
+ }
+
+ }
+ else
+ {
+ state->m_mmc_prg_bank[0] = (state->m_mmc_prg_bank[0] & 0x70) | (data & 0x0f);
+ prg16_89ab(space->machine(), state->m_mmc_prg_bank[0]);
+ }
+}
+
+/*************************************************************
+
+ Cony Bootleg Board
+
+ Games: Dragon Ball Party, Fatal Fury 2, Street Blaster II
+ Pro, World Heroes 2
+
+ iNES: mapper 83
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( cony_l_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("cony_l_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset >= 0x1000 && offset < 0x1103) // from 0x5100-0x51ff
+ state->m_mapper83_low_reg[offset & 0x03] = data;
+}
+
+static READ8_HANDLER( cony_l_r )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("cony_l_r, offset: %04x\n", offset));
+
+ if (offset == 0x0f00) // 0x5000
+ {
+ // read dipswitch bit! - currently unimplemented
+ }
+ if (offset >= 0x1000 && offset < 0x1103) // from 0x5100-0x51ff
+ return state->m_mapper83_low_reg[offset & 0x03];
+ else
+ return 0x00;
+}
+
+static void cony_set_prg( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ prg16_89ab(machine, state->m_mapper83_reg[8] & 0x3f);
+ prg16_cdef(machine, (state->m_mapper83_reg[8] & 0x30) | 0x0f);
+}
+
+static void cony_set_chr( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ // 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 (state->m_mmc_latch1 && !state->m_mmc_latch2)
+ {
+ chr2_0(machine, state->m_mapper83_reg[0], CHRROM);
+ chr2_2(machine, state->m_mapper83_reg[1], CHRROM);
+ chr2_4(machine, state->m_mapper83_reg[6], CHRROM);
+ chr2_6(machine, state->m_mapper83_reg[7], CHRROM);
+ }
+ else
+ {
+ chr1_0(machine, state->m_mapper83_reg[0] | ((state->m_mapper83_reg[8] & 0x30) << 4), CHRROM);
+ chr1_1(machine, state->m_mapper83_reg[1] | ((state->m_mapper83_reg[8] & 0x30) << 4), CHRROM);
+ chr1_2(machine, state->m_mapper83_reg[2] | ((state->m_mapper83_reg[8] & 0x30) << 4), CHRROM);
+ chr1_3(machine, state->m_mapper83_reg[3] | ((state->m_mapper83_reg[8] & 0x30) << 4), CHRROM);
+ chr1_4(machine, state->m_mapper83_reg[4] | ((state->m_mapper83_reg[8] & 0x30) << 4), CHRROM);
+ chr1_5(machine, state->m_mapper83_reg[5] | ((state->m_mapper83_reg[8] & 0x30) << 4), CHRROM);
+ chr1_6(machine, state->m_mapper83_reg[6] | ((state->m_mapper83_reg[8] & 0x30) << 4), CHRROM);
+ chr1_7(machine, state->m_mapper83_reg[7] | ((state->m_mapper83_reg[8] & 0x30) << 4), CHRROM);
+ }
+}
+
+static WRITE8_HANDLER( cony_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("cony_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset)
+ {
+ case 0x0000:
+ state->m_mmc_latch1 = 1;
+ case 0x3000:
+ case 0x30ff:
+ case 0x31ff:
+ state->m_mapper83_reg[8] = data;
+ cony_set_prg(space->machine());
+ cony_set_chr(space->machine());
+ break;
+ case 0x0100:
+ state->m_mmc_reg[0] = data & 0x80;
+ switch (data & 0x03)
+ {
+ case 0:
+ set_nt_mirroring(space->machine(), PPU_MIRROR_VERT);
+ break;
+ case 1:
+ set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ);
+ break;
+ case 2:
+ set_nt_mirroring(space->machine(), PPU_MIRROR_LOW);
+ break;
+ case 3:
+ set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH);
+ break;
+ }
+ break;
+ case 0x0200:
+ state->m_IRQ_count = (state->m_IRQ_count & 0xff00) | data;
+ break;
+ case 0x0201:
+ state->m_IRQ_enable = state->m_mmc_reg[0];
+ state->m_IRQ_count = (data << 8) | (state->m_IRQ_count & 0xff);
+ break;
+ case 0x0300:
+ prg8_89(space->machine(), data);
+ break;
+ case 0x0301:
+ prg8_ab(space->machine(), data);
+ break;
+ case 0x0302:
+ prg8_cd(space->machine(), data);
+ break;
+ case 0x0312:
+ case 0x0313:
+ case 0x0314:
+ case 0x0315:
+ state->m_mmc_latch2 = 1;
+ case 0x0310:
+ case 0x0311:
+ case 0x0316:
+ case 0x0317:
+ state->m_mapper83_reg[offset - 0x0310] = data;
+ cony_set_chr(space->machine());
+ break;
+ case 0x0318:
+ state->m_mapper83_reg[9] = data;
+ cony_set_prg(space->machine());
+ break;
+ }
+}
+
+/*************************************************************
+
+ Yoko Bootleg Board
+
+ Games: Mortal Kombat II, Master Figther VI'
+
+
+ Very similar to Cony board
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( yoko_l_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("cony_l_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset >= 0x1300) // from 0x5400
+ state->m_mapper83_low_reg[offset & 0x03] = data;
+}
+
+static READ8_HANDLER( yoko_l_r )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("cony_l_r, offset: %04x\n", offset));
+
+ if (offset >= 0x0f00 && offset < 0x1300) // 0x5000
+ {
+ // read dipswitch bit! - currently unimplemented
+ }
+ if (offset >= 0x1300) // from 0x5400
+ return state->m_mapper83_low_reg[offset & 0x03];
+ else
+ return 0x00;
+}
+
+static void yoko_set_prg( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ if (state->m_mmc_reg[0] & 0x10)
+ {
+ int base = (state->m_mmc_reg[1] & 0x08) << 1;
+ prg8_89(machine, base | (state->m_mapper83_reg[0] & 0x0f));
+ prg8_ab(machine, base | (state->m_mapper83_reg[1] & 0x0f));
+ prg8_cd(machine, base | (state->m_mapper83_reg[2] & 0x0f));
+ prg8_ef(machine, base | 0x0f);
+ }
+ else if (state->m_mmc_reg[0] & 0x08)
+ prg32(machine, state->m_mmc_reg[1] >> 1);
+ else
+ {
+ prg16_89ab(machine, state->m_mmc_reg[1]);
+ prg16_cdef(machine, 0xff);
+ }
+}
+
+static void yoko_set_chr( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ chr2_0(machine, state->m_mapper83_reg[4], CHRROM);
+ chr2_2(machine, state->m_mapper83_reg[5], CHRROM);
+ chr2_4(machine, state->m_mapper83_reg[6], CHRROM);
+ chr2_6(machine, state->m_mapper83_reg[7], CHRROM);
+}
+
+static WRITE8_HANDLER( yoko_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("yoko_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x0c17)
+ {
+ case 0x0000:
+ state->m_mmc_reg[1] = data;
+ yoko_set_prg(space->machine());
+ break;
+ case 0x400:
+ state->m_mmc_reg[0] = data;
+ if (data & 1)
+ set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ);
+ else
+ set_nt_mirroring(space->machine(), PPU_MIRROR_VERT);
+ yoko_set_prg(space->machine());
+ break;
+ case 0x0800:
+ state->m_IRQ_count = (state->m_IRQ_count & 0xff00) | data;
+ break;
+ case 0x0801:
+ state->m_IRQ_enable = state->m_mmc_reg[0] & 0x80;
+ state->m_IRQ_count = (data << 8) | (state->m_IRQ_count & 0xff);
+ break;
+ case 0x0c00:
+ case 0x0c01:
+ case 0x0c02:
+ state->m_mapper83_reg[offset & 3] = data;
+ yoko_set_prg(space->machine());
+ break;
+ case 0x0c10:
+ case 0x0c11:
+ case 0x0c16:
+ case 0x0c17:
+ state->m_mapper83_reg[4 + (offset & 3)] = data;
+ yoko_set_chr(space->machine());
+ break;
+ }
+}
+
+/*************************************************************
+
+ Board DREAMTECH01
+
+ Games: Korean Igo
+
+ In MESS: Supported
+
+ *************************************************************/
+
+static WRITE8_HANDLER( dreamtech_l_w )
+{
+ LOG_MMC(("dreamtech_l_w offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+
+ if (offset == 0x1020) /* 0x5020 */
+ prg16_89ab(space->machine(), data);
+}
+
+/*************************************************************
+
+ Bootleg Board by Fukutake
+
+ Games: Study Box
+
+ iNES: mapper 186
+
+ In MESS: Unsupported.
+
+
+ *************************************************************/
+
+static WRITE8_HANDLER( fukutake_l_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("fukutake_l_w offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+
+ if (offset >= 0x200 && offset < 0x400)
+ {
+ if (offset & 1)
+ prg16_89ab(space->machine(), data);
+ else
+ wram_bank(space->machine(), data >> 6, NES_WRAM);
+ }
+ else if (offset >= 0x400 && offset < 0xf00)
+ state->m_mapper_ram[offset - 0x400] = data;
+}
+
+static READ8_HANDLER( fukutake_l_r )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("fukutake_l_r 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 state->m_mapper_ram[offset - 0x400];
+
+ return 0;
+}
+
+/*************************************************************
+
+ Bootleg Board by Future Media
+
+ Games: Crayon Shin-chan (C), San Guo Zhi 4 - Chi Bi Feng Yun
+
+ iNES: mapper 117
+
+ In MESS: Unsupported.
+
+ *************************************************************/
+
+static void futuremedia_irq( device_t *device, int scanline, int vblank, int blanked )
+{
+ nes_state *state = device->machine().driver_data<nes_state>();
+ // if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE)
+ {
+ if (state->m_IRQ_enable && state->m_IRQ_count)
+ {
+ state->m_IRQ_count--;
+ if (!state->m_IRQ_count)
+ device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE);
+ }
+ }
+}
+
+static WRITE8_HANDLER( futuremedia_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("futuremedia_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset)
+ {
+ case 0x0000:
+ prg8_89(space->machine(), data);
+ break;
+ case 0x0001:
+ prg8_ab(space->machine(), data);
+ break;
+ case 0x0002:
+ prg8_cd(space->machine(), data);
+ break;
+ case 0x0003:
+ prg8_ef(space->machine(), data);
+ break;
+ case 0x2000:
+ case 0x2001:
+ case 0x2002:
+ case 0x2003:
+ case 0x2004:
+ case 0x2005:
+ case 0x2006:
+ case 0x2007:
+ chr1_x(space->machine(), offset & 0x07, data, CHRROM);
+ break;
+
+ case 0x5000:
+ set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+
+ case 0x4001:
+ state->m_IRQ_count_latch = data;
+ break;
+ case 0x4002:
+ // IRQ cleared
+ break;
+ case 0x4003:
+ state->m_IRQ_count = state->m_IRQ_count_latch;
+ break;
+ case 0x6000:
+ state->m_IRQ_enable = data & 0x01;
+ 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.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( gouder_sf4_l_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ 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_sf4_l_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (!(offset < 0x1700))
+ state->m_mmc_reg[offset & 0x03] = data ^ conv_table[state->m_mmc_reg[4]];
+ else if (!(offset < 0xf00))
+ state->m_mmc_reg[4] = data;
+ else if (!(offset < 0x700))
+ prg32(space->machine(), ((data >> 3) & 0x02) | (data & 0x01));
+}
+
+static READ8_HANDLER( gouder_sf4_l_r )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("gouder_sf4_l_r, offset: %04x\n", offset));
+
+ if (!(offset < 0x1700))
+ return state->m_mmc_reg[offset & 0x03];
+
+ return 0x00;
+}
+
+/* writes to 0x8000-0xffff are like MMC3 but no PRG bankswitch (beacuse it is handled by low writes) */
+static void gouder_sf4_prg_cb( running_machine &machine, int start, int bank )
+{
+ return;
+}
+
+
+/*************************************************************
+
+ 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.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( henggedianzi_w )
+{
+ LOG_MMC(("henggedianzi_w, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(space->machine(), data);
+ set_nt_mirroring(space->machine(), 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
+
+ iNES: mapper 179
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( heng_xjzb_l_w )
+{
+ LOG_MMC(("heng_xjzb_l_w, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x4100;
+
+ if (offset & 0x5000)
+ prg32(space->machine(), data >> 1);
+}
+
+static WRITE8_HANDLER( heng_xjzb_w )
+{
+ LOG_MMC(("heng_xjzb_w, offset: %04x, data: %02x\n", offset, data));
+
+ set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+}
+
+/*************************************************************
+
+ 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.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( hes6in1_l_w )
+{
+ LOG_MMC(("hes6in1_l_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (!(offset & 0x100))
+ {
+ prg32(space->machine(), (data & 0x38) >> 3);
+ chr8(space->machine(), (data & 0x07) | ((data & 0x40) >> 3), CHRROM);
+ set_nt_mirroring(space->machine(), BIT(data, 7) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ);
+ }
+}
+
+static WRITE8_HANDLER( hes_l_w )
+{
+ LOG_MMC(("hes_l_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (!(offset & 0x100))
+ {
+ prg32(space->machine(), (data & 0x38) >> 3);
+ chr8(space->machine(), (data & 0x07) | ((data & 0x40) >> 3), CHRROM);
+ }
+}
+
+/*************************************************************
+
+ Bootleg Board by Hosenkan
+
+ Games: Pocahontas, Super Donkey Kong
+
+ iNES: mapper 182
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( hosenkan_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("hosenkan_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7003)
+ {
+ case 0x0001:
+ set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+ case 0x2000:
+ state->m_mmc_latch1 = data;
+ break;
+ case 0x4000:
+ switch (state->m_mmc_latch1)
+ {
+ case 0:
+ chr2_0(space->machine(), data >> 1, CHRROM);
+ break;
+ case 1:
+ chr1_5(space->machine(), data, CHRROM);
+ break;
+ case 2:
+ chr2_2(space->machine(), data >> 1, CHRROM);
+ break;
+ case 3:
+ chr1_7(space->machine(), data, CHRROM);
+ break;
+ case 4:
+ prg8_89(space->machine(), data);
+ break;
+ case 5:
+ prg8_ab(space->machine(), data);
+ break;
+ case 6:
+ chr1_4(space->machine(), data, CHRROM);
+ break;
+ case 7:
+ chr1_6(space->machine(), data, CHRROM);
+ break;
+ }
+ break;
+ case 0x6003:
+ if (data)
+ {
+ state->m_IRQ_count = data;
+ state->m_IRQ_enable = 1;
+ }
+ else
+ state->m_IRQ_enable = 0;
+ break;
+ }
+}
+
+/*************************************************************
+
+ 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.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( ks7058_w )
+{
+ LOG_MMC(("ks7058_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7080)
+ {
+ case 0x7000:
+ chr4_0(space->machine(), data, CHRROM);
+ break;
+ case 0x7080:
+ chr4_4(space->machine(), data, CHRROM);
+ break;
+ }
+}
+
+/*************************************************************
+
+ Kaiser Board KS7022
+
+ Games: 15 in 1
+
+ iNES: mapper 175
+
+ In MESS: Supported?
+
+ *************************************************************/
+
+static WRITE8_HANDLER( ks7022_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("ks7022_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset == 0)
+ set_nt_mirroring(space->machine(), BIT(data, 2) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+
+ if (offset == 0x2000)
+ state->m_mmc_latch1 = data & 0x0f;
+}
+
+static READ8_HANDLER( ks7022_r )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("ks7022_r, offset: %04x\n", offset));
+
+ if (offset == 0x7ffc)
+ {
+ chr8(space->machine(), state->m_mmc_latch1, CHRROM);
+ prg16_89ab(space->machine(), state->m_mmc_latch1);
+ prg16_cdef(space->machine(), state->m_mmc_latch1);
+ }
+
+ return mmc_hi_access_rom(space->machine(), offset);
+}
+
+/*************************************************************
+
+ Kaiser Board KS7032
+
+ Games:
+
+ iNES:
+
+ In MESS:
+
+ *************************************************************/
+
+static void ks7032_prg_update( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ prg8_67(machine, state->m_mmc_reg[4]);
+ prg8_89(machine, state->m_mmc_reg[1]);
+ prg8_ab(machine, state->m_mmc_reg[2]);
+ prg8_cd(machine, state->m_mmc_reg[3]);
+}
+
+static void ks7032_irq( device_t *device, int scanline, int vblank, int blanked )
+{
+ nes_state *state = device->machine().driver_data<nes_state>();
+
+ if (state->m_IRQ_enable)
+ {
+ if (state->m_IRQ_count >= (0xffff - 114))
+ {
+ state->m_IRQ_enable = 0;
+ state->m_IRQ_count = state->m_IRQ_count_latch;
+ device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE);
+ }
+ else
+ state->m_IRQ_count += 114;
+ }
+}
+
+static WRITE8_HANDLER( ks7032_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("ks7032_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7000)
+ {
+ case 0x0000:
+ state->m_IRQ_count = (state->m_IRQ_count & 0xfff0) | (data & 0x0f);
+ break;
+ case 0x1000:
+ state->m_IRQ_count = (state->m_IRQ_count & 0xff0f) | ((data & 0x0f) << 4);
+ break;
+ case 0x2000:
+ state->m_IRQ_count = (state->m_IRQ_count & 0xf0ff) | ((data & 0x0f) << 8);
+ break;
+ case 0x3000:
+ state->m_IRQ_count = (state->m_IRQ_count & 0x0fff) | ((data & 0x0f) << 12);
+ break;
+ case 0x4000:
+ state->m_IRQ_enable = 1;
+ break;
+ case 0x6000:
+ state->m_mmc_latch1 = data & 0x07;
+ break;
+ case 0x7000:
+ state->m_mmc_reg[state->m_mmc_latch1] = data;
+ ks7032_prg_update(space->machine());
+ break;
+ }
+}
+
+/*************************************************************
+
+ Kaiser Board KS202
+
+ Games:
+
+ iNES:
+
+ In MESS: Supported?
+
+ *************************************************************/
+
+
+static WRITE8_HANDLER( ks202_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("ks202_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7000)
+ {
+ case 0x0000:
+ state->m_IRQ_count = (state->m_IRQ_count & 0xfff0) | (data & 0x0f);
+ break;
+ case 0x1000:
+ state->m_IRQ_count = (state->m_IRQ_count & 0xff0f) | ((data & 0x0f) << 4);
+ break;
+ case 0x2000:
+ state->m_IRQ_count = (state->m_IRQ_count & 0xf0ff) | ((data & 0x0f) << 8);
+ break;
+ case 0x3000:
+ state->m_IRQ_count = (state->m_IRQ_count & 0x0fff) | ((data & 0x0f) << 12);
+ break;
+ case 0x4000:
+ state->m_IRQ_enable = 1;
+ break;
+ case 0x6000:
+ state->m_mmc_latch1 = data & 0x07;
+ break;
+ case 0x7000:
+ state->m_mmc_reg[state->m_mmc_latch1] = data;
+ ks7032_prg_update(space->machine());
+ switch (offset & 0xc00)
+ {
+ case 0x800:
+ set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ);
+ break;
+ case 0xc00:
+ chr1_x(space->machine(), offset & 0x07, data, CHRROM);
+ break;
+ }
+ break;
+ }
+}
+
+/*************************************************************
+
+ Kaiser Board KS7017
+
+ Games:
+
+ iNES:
+
+ In MESS: Not working
+
+ *************************************************************/
+
+static void mmc_fds_irq( device_t *device, int scanline, int vblank, int blanked )
+{
+ nes_state *state = device->machine().driver_data<nes_state>();
+
+ if (state->m_IRQ_enable)
+ {
+ if (state->m_IRQ_count <= 114)
+ {
+ device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE);
+ state->m_IRQ_enable = 0;
+ state->m_IRQ_status |= 0x01;
+ }
+ else
+ state->m_IRQ_count -= 114;
+ }
+}
+
+static WRITE8_HANDLER( ks7017_l_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("ks7022_w, offset: %04x, data: %02x\n", offset, data));
+
+ offset += 0x100;
+
+ if (offset >= 0xa00 && offset < 0xb00)
+ state->m_mmc_latch1 = ((offset >> 2) & 0x03) | ((offset >> 4) & 0x04);
+
+ if (offset >= 0x1000 && offset < 0x1100)
+ prg16_89ab(space->machine(), state->m_mmc_latch1);
+}
+
+WRITE8_HANDLER( ks7017_extra_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("ks7017_extra_w, offset: %04x, data: %02x\n", offset, data));
+
+ offset += 0x20;
+
+ if (offset == 0x0020) /* 0x4020 */
+ state->m_IRQ_count = (state->m_IRQ_count & 0xff00) | data;
+
+ if (offset == 0x0021) /* 0x4021 */
+ state->m_IRQ_count = (state->m_IRQ_count & 0x00ff) | (data << 8);
+
+ if (offset == 0x0025) /* 0x4025 */
+ set_nt_mirroring(space->machine(), BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+}
+
+READ8_HANDLER( ks7017_extra_r )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("ks7017_extra_r, offset: %04x\n", offset));
+
+ state->m_IRQ_status &= ~0x01;
+ return state->m_IRQ_status;
+}
+
+/*************************************************************
+
+ 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.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( kay_pp_l_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("kay_pp_l_w, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+
+ if (offset >= 0x1000)
+ {
+ switch (data & 0x03)
+ {
+ case 0x00:
+ case 0x01:
+ state->m_mmc_reg[0] = 0x83;
+ break;
+ case 0x02:
+ state->m_mmc_reg[0] = 0x42;
+ break;
+ case 0x03:
+ state->m_mmc_reg[0] = 0x00;
+ break;
+ }
+ }
+}
+
+static READ8_HANDLER( kay_pp_l_r )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("kay_pp_l_r, offset: %04x\n", offset));
+ offset += 0x100;
+
+ if (offset >= 0x1000)
+ return state->m_mmc_reg[0];
+ else
+ return 0xff;
+}
+
+static void kay_pp_update_regs( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ switch (state->m_mmc_reg[5] & 0x3f)
+ {
+ case 0x20:
+ case 0x29:
+ case 0x2b:
+ case 0x3f:
+ state->m_mmc_reg[7] = 1;
+ state->m_mmc_reg[1] = state->m_mmc_reg[6];
+ break;
+ case 0x26:
+ state->m_mmc_reg[7] = 0;
+ state->m_mmc_reg[1] = state->m_mmc_reg[6];
+ break;
+ case 0x2c:
+ state->m_mmc_reg[7] = 1;
+ if (state->m_mmc_reg[6])
+ state->m_mmc_reg[1] = state->m_mmc_reg[6];
+ break;
+
+ case 0x28:
+ state->m_mmc_reg[7] = 0;
+ state->m_mmc_reg[2] = state->m_mmc_reg[6];
+ break;
+
+ case 0x2a:
+ state->m_mmc_reg[7] = 0;
+ state->m_mmc_reg[3] = state->m_mmc_reg[6];
+ break;
+
+ case 0x2f:
+ break;
+
+ default:
+ state->m_mmc_reg[5] = 0;
+ break;
+ }
+}
+
+static void kay_pp_prg_cb( running_machine &machine, int start, int bank )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ if (state->m_mmc_reg[5] & 0x3f)
+ {
+ prg8_x(machine, start, bank & 0x3f);
+ prg8_ef(machine, state->m_mmc_reg[1]);
+ prg8_cd(machine, state->m_mmc_reg[2]);
+ prg8_ab(machine, state->m_mmc_reg[3]);
+ }
+ else
+ prg8_x(machine, start, bank & 0x3f);
+}
+
+static void kay_pp_chr_cb( running_machine &machine, int start, int bank, int source )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ UINT8 chr_page = (state->m_mmc3_latch & 0x80) >> 5;
+
+ if ((start & 0x04) == chr_page)
+ bank |= 0x100;
+
+ chr1_x(machine, start, bank, source);
+}
+
+static WRITE8_HANDLER( kay_pp_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("kay_pp_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6003)
+ {
+ case 0x0000:
+ txrom_w(space, offset, data);
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ break;
+
+ case 0x0001:
+ state->m_mmc_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 (!state->m_mmc_reg[7])
+ kay_pp_update_regs(space->machine());
+ txrom_w(space, offset, data);
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ break;
+
+ case 0x0003:
+ state->m_mmc_reg[5] = data;
+ kay_pp_update_regs(space->machine());
+ txrom_w(space, 0x0000, data);
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ break;
+
+ default:
+ txrom_w(space, offset, data);
+ break;
+ }
+}
+
+/*************************************************************
+
+ 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
+
+ *************************************************************/
+
+static void kasing_prg_cb( running_machine &machine, int start, int bank )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ if (BIT(state->m_mmc_reg[0], 7))
+ prg32(machine, state->m_mmc_reg[0] >> 1);
+ else
+ prg8_x(machine, start, bank);
+}
+
+static WRITE8_HANDLER( kasing_m_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("kasing_m_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x01)
+ {
+ case 0x00:
+ state->m_mmc_reg[0] = data;
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ break;
+ case 0x01:
+ state->m_mmc_chr_base = (data & 0x01) ? 0x100 : 0x000;
+ mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ 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.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( magics_md_w )
+{
+ LOG_MMC(("magics_md_w, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(space->machine(), data >> 1);
+ chr8(space->machine(), data, CHRROM);
+}
+
+/*************************************************************
+
+ Bootleg Board by Nanjing
+
+ Games: A lot of pirate originals
+
+ iNES: mapper 163
+
+ In MESS: Unsupported.
+
+ *************************************************************/
+
+static void nanjing_irq( device_t *device, int scanline, int vblank, int blanked )
+{
+ nes_state *state = device->machine().driver_data<nes_state>();
+
+ if (BIT(state->m_mmc_reg[0], 7))
+ {
+ if (scanline == 127)
+ {
+ chr4_0(device->machine(), 1, CHRRAM);
+ chr4_4(device->machine(), 1, CHRRAM);
+ }
+
+ if (scanline == 239)
+ {
+ chr4_0(device->machine(), 0, CHRRAM);
+ chr4_4(device->machine(), 0, CHRRAM);
+ }
+ }
+
+}
+
+static WRITE8_HANDLER( nanjing_l_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("nanjing_l_w, offset: %04x, data: %02x\n", offset, data));
+
+ offset += 0x100;
+
+ if (offset < 0x1000)
+ return;
+
+ if (offset == 0x1100) // 0x5100
+ {
+ if (data == 6)
+ prg32(space->machine(), 3);
+ return;
+ }
+
+ if (offset == 0x1101) // 0x5101
+ {
+ UINT8 temp = state->m_mmc_count;
+ state->m_mmc_count = data;
+
+ if (temp & !data)
+ state->m_mmc_latch2 ^= 0xff;
+ }
+
+ switch (offset & 0x300)
+ {
+ case 0x000:
+ case 0x200:
+ state->m_mmc_reg[BIT(offset, 9)] = data;
+ if (!BIT(state->m_mmc_reg[0], 7) && state->m_ppu->get_current_scanline() <= 127)
+ chr8(space->machine(), 0, CHRRAM);
+ break;
+ case 0x300:
+ state->m_mmc_latch1 = data;
+ break;
+ }
+
+ prg32(space->machine(), (state->m_mmc_reg[0] & 0x0f) | ((state->m_mmc_reg[1] & 0x0f) << 4));
+}
+
+static READ8_HANDLER( nanjing_l_r )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 value = 0;
+ LOG_MMC(("nanjing_l_r, offset: %04x\n", offset));
+
+ offset += 0x100;
+
+ if (offset < 0x1000)
+ return 0;
+
+ switch (offset & 0x700)
+ {
+ case 0x100:
+ value = state->m_mmc_latch1;
+ break;
+ case 0x500:
+ value = state->m_mmc_latch2 & state->m_mmc_latch1;
+ break;
+ case 0x000:
+ case 0x200:
+ case 0x300:
+ case 0x400:
+ case 0x600:
+ case 0x700:
+ value = 4;
+ break;
+ }
+ return value;
+}
+
+/*************************************************************
+
+ 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.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( nitra_w )
+{
+ LOG_MMC(("nitra_w, offset: %04x, data: %02x\n", offset, data));
+
+ txrom_w(space, (offset & 0x6000) | ((offset & 0x400) >> 10), offset & 0xff);
+}
+
+/*************************************************************
+
+ NTDEC ASDER Bootleg Board
+
+ Games: Cobra Mission, Fighting Hero III, Huang Di, Master
+ Shooter
+
+ iNES: mapper 112
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( ntdec_asder_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("ntdec_asder_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset)
+ {
+ case 0x0000:
+ state->m_mmc_latch1 = data & 0x07;
+ break;
+ case 0x2000:
+ switch (state->m_mmc_latch1)
+ {
+ case 0:
+ prg8_89(space->machine(), data);
+ break;
+ case 1:
+ prg8_ab(space->machine(), data);
+ break;
+ case 2:
+ data &= 0xfe;
+ chr1_0(space->machine(), data, CHRROM);
+ chr1_1(space->machine(), data + 1, CHRROM);
+ break;
+ case 3:
+ data &= 0xfe;
+ chr1_2(space->machine(), data, CHRROM);
+ chr1_3(space->machine(), data + 1, CHRROM);
+ break;
+ case 4:
+ chr1_4(space->machine(), data, CHRROM);
+ break;
+ case 5:
+ chr1_5(space->machine(), data, CHRROM);
+ break;
+ case 6:
+ chr1_6(space->machine(), data, CHRROM);
+ break;
+ case 7:
+ chr1_7(space->machine(), data, CHRROM);
+ break;
+ }
+ break;
+ case 0x6000:
+ set_nt_mirroring(space->machine(), 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.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( ntdec_fh_m_w )
+{
+ LOG_MMC(("ntdec_fh_m_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x03)
+ {
+ case 0:
+ chr4_0(space->machine(), data >> 2, CHRROM);
+ break;
+ case 1:
+ chr2_4(space->machine(), data >> 1, CHRROM);
+ break;
+ case 2:
+ chr2_6(space->machine(), data >> 1 , CHRROM);
+ break;
+ case 3:
+ prg8_89(space->machine(), data);
+ break;
+ }
+}
+
+/*************************************************************
+
+ Open Corp DAOU306 board
+
+ Games: Metal Force (K)
+
+ iNES: mapper 156
+
+ In MESS: Supported.
+
+ Notes: Metal Force and Buzz & Waldog only use the the first
+ 4 regs and no mirroring. Janggun ui Adeul uses all features
+
+ *************************************************************/
+
+static WRITE8_HANDLER( daou306_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("daou306_w, offset: %04x, data: %02x\n", offset, data));
+ int reg = BIT(offset, 2) ? 8 : 0;
+
+ switch (offset)
+ {
+ case 0x4000:
+ case 0x4004:
+ state->m_mmc_reg[reg + 0] = data;
+ chr1_0(space->machine(), state->m_mmc_reg[0] | (state->m_mmc_reg[8] << 8), CHRROM);
+ break;
+ case 0x4001:
+ case 0x4005:
+ state->m_mmc_reg[reg + 1] = data;
+ chr1_1(space->machine(), state->m_mmc_reg[1] | (state->m_mmc_reg[9] << 8), CHRROM);
+ break;
+ case 0x4002:
+ case 0x4006:
+ state->m_mmc_reg[reg + 2] = data;
+ chr1_2(space->machine(), state->m_mmc_reg[2] | (state->m_mmc_reg[10] << 8), CHRROM);
+ break;
+ case 0x4003:
+ case 0x4007:
+ state->m_mmc_reg[reg + 3] = data;
+ chr1_3(space->machine(), state->m_mmc_reg[3] | (state->m_mmc_reg[11] << 8), CHRROM);
+ break;
+ case 0x4008:
+ case 0x400c:
+ state->m_mmc_reg[reg + 4] = data;
+ chr1_4(space->machine(), state->m_mmc_reg[4] | (state->m_mmc_reg[12] << 8), CHRROM);
+ break;
+ case 0x4009:
+ case 0x400d:
+ state->m_mmc_reg[reg + 5] = data;
+ chr1_5(space->machine(), state->m_mmc_reg[5] | (state->m_mmc_reg[13] << 8), CHRROM);
+ break;
+ case 0x400a:
+ case 0x400e:
+ state->m_mmc_reg[reg + 6] = data;
+ chr1_6(space->machine(), state->m_mmc_reg[6] | (state->m_mmc_reg[14] << 8), CHRROM);
+ break;
+ case 0x400b:
+ case 0x400f:
+ state->m_mmc_reg[reg + 7] = data;
+ chr1_7(space->machine(), state->m_mmc_reg[7] | (state->m_mmc_reg[15] << 8), CHRROM);
+ break;
+ case 0x4010:
+ prg16_89ab(space->machine(), data);
+ break;
+ case 0x4014:
+ if (data & 1)
+ set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ);
+ else
+ set_nt_mirroring(space->machine(), PPU_MIRROR_VERT);
+ break;
+ }
+}
+
+/*************************************************************
+
+ 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.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( gs2015_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("gs2015_w, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(space->machine(), offset);
+ chr8(space->machine(), offset >> 1, state->m_mmc_chr_source);
+}
+
+/*************************************************************
+
+ 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.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( rcm_tf_w )
+{
+ LOG_MMC(("rcm_tf_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x30)
+ {
+ case 0x00:
+ case 0x30:
+ prg32(space->machine(), offset & 0x0f);
+ break;
+ case 0x10:
+ case 0x20:
+ prg16_89ab(space->machine(), ((offset & 0x0f) << 1) | ((offset & 0x20) >> 4));
+ prg16_cdef(space->machine(), ((offset & 0x0f) << 1) | ((offset & 0x20) >> 4));
+ break;
+ }
+ set_nt_mirroring(space->machine(), BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+}
+
+/*************************************************************
+
+ Bootleg Board by Rex Soft
+
+ Games: Dragon Ball Z 5, Dragon Ball Z Super
+
+ MMC3 clone
+
+ iNES: mapper 12
+
+ In MESS: Supported
+
+ *************************************************************/
+
+static WRITE8_HANDLER( rex_dbz_l_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("rex_dbz_l_w, offset: %04x, data: %02x\n", offset, data));
+
+ state->m_mmc_reg[0] = data;
+ mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+}
+
+/* we would need to use this read handler in 0x6000-0x7fff as well */
+static READ8_HANDLER( rex_dbz_l_r )
+{
+ LOG_MMC(("rex_dbz_l_r, offset: %04x\n", offset));
+ return 0x01;
+}
+
+static void rex_dbz_chr_cb( running_machine &machine, int start, int bank, int source )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ int shift = (start < 4) ? 8 : 4;
+
+ bank |= ((state->m_mmc_reg[0] << shift) & 0x100);
+ chr1_x(machine, start, bank, source);
+}
+
+/*************************************************************
+
+ Rex Soft SL1632 Board
+
+ Games: Samurai Spirits
+
+ MMC3 clone
+
+ iNES: mapper 14
+
+ In MESS: Supported
+
+ *************************************************************/
+
+static void rex_sl1632_set_prg( running_machine &machine, int prg_base, int prg_mask )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ if (state->m_mmc_reg[0] & 0x02)
+ {
+ mmc3_set_prg(machine, prg_base, prg_mask);
+ }
+ else
+ {
+ prg8_89(machine, state->m_mmc_extra_bank[0]);
+ prg8_ab(machine, state->m_mmc_extra_bank[1]);
+ prg8_cd(machine, state->m_mmc_extra_bank[2]);
+ prg8_ef(machine, state->m_mmc_extra_bank[3]);
+ }
+}
+
+static void rex_sl1632_set_chr( running_machine &machine, UINT8 chr, int chr_base, int chr_mask )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ static const UINT8 conv_table[8] = {5, 5, 5, 5, 3, 3, 1, 1};
+ UINT8 chr_page = (state->m_mmc3_latch & 0x80) >> 5;
+ UINT8 bank[8];
+ UINT8 chr_base2[8];
+ int i;
+
+ if (state->m_mmc_reg[0] & 0x02)
+ {
+ for(i = 0; i < 8; i++)
+ {
+ bank[i] = state->m_mmc_vrom_bank[i];
+ chr_base2[i] = chr_base | ((state->m_mmc_reg[0] << conv_table[i]) & 0x100);
+ }
+ }
+ else
+ {
+ for(i = 0; i < 8; i++)
+ {
+ bank[i] = state->m_mmc_extra_bank[i + 4]; // first 4 state->m_mmc_extra_banks are PRG
+ chr_base2[i] = chr_base;
+ }
+ }
+
+ chr1_x(machine, chr_page ^ 0, chr_base2[0] | (bank[0] & chr_mask), chr);
+ chr1_x(machine, chr_page ^ 1, chr_base2[1] | (bank[1] & chr_mask), chr);
+ chr1_x(machine, chr_page ^ 2, chr_base2[2] | (bank[2] & chr_mask), chr);
+ chr1_x(machine, chr_page ^ 3, chr_base2[3] | (bank[3] & chr_mask), chr);
+ chr1_x(machine, chr_page ^ 4, chr_base2[4] | (bank[4] & chr_mask), chr);
+ chr1_x(machine, chr_page ^ 5, chr_base2[5] | (bank[5] & chr_mask), chr);
+ chr1_x(machine, chr_page ^ 6, chr_base2[6] | (bank[6] & chr_mask), chr);
+ chr1_x(machine, chr_page ^ 7, chr_base2[7] | (bank[7] & chr_mask), chr);
+}
+
+static WRITE8_HANDLER( rex_sl1632_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 map14_helper1, map14_helper2, mmc_helper, cmd;
+ LOG_MMC(("rex_sl1632_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset == 0x2131)
+ {
+ state->m_mmc_reg[0] = data;
+ rex_sl1632_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ rex_sl1632_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+
+ if (!(state->m_mmc_reg[0] & 0x02))
+ set_nt_mirroring(space->machine(), BIT(state->m_mmc_reg[1], 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ }
+
+ if (state->m_mmc_reg[0] & 0x02)
+ {
+ switch (offset & 0x6001)
+ {
+ case 0x0000:
+ mmc_helper = state->m_mmc3_latch ^ data;
+ state->m_mmc3_latch = data;
+
+ /* Has PRG Mode changed? */
+ if (mmc_helper & 0x40)
+ rex_sl1632_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+
+ /* Has CHR Mode changed? */
+ if (mmc_helper & 0x80)
+ rex_sl1632_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ break;
+
+ case 0x0001:
+ cmd = state->m_mmc3_latch & 0x07;
+ switch (cmd)
+ {
+ case 0: case 1: // these have to be changed due to the different way rex_sl1632_set_chr works (it handles 1k banks)!
+ state->m_mmc_vrom_bank[2 * cmd] = data;
+ state->m_mmc_vrom_bank[2 * cmd + 1] = data;
+ rex_sl1632_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ break;
+ case 2: case 3: case 4: case 5:
+ state->m_mmc_vrom_bank[cmd + 2] = data;
+ rex_sl1632_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ break;
+ case 6:
+ case 7:
+ state->m_mmc_prg_bank[cmd - 6] = data;
+ rex_sl1632_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ break;
+ }
+ break;
+
+ case 0x2000:
+ set_nt_mirroring(space->machine(), BIT(state->m_mmc_reg[1], 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ);
+ break;
+
+ default:
+ txrom_w(space, offset, data);
+ break;
+ }
+ }
+ else if (offset >= 0x3000 && offset <= 0x6003 )
+ {
+ map14_helper1 = (offset & 0x01) << 2;
+ offset = ((offset & 0x02) | (offset >> 10)) >> 1;
+ map14_helper2 = ((offset + 2) & 0x07) + 4; // '+4' because first 4 state->m_mmc_extra_banks are for PRG!
+ state->m_mmc_extra_bank[map14_helper2] = (state->m_mmc_extra_bank[map14_helper2] & (0xf0 >> map14_helper1)) | ((data & 0x0f) << map14_helper1);
+ rex_sl1632_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ }
+ else
+ {
+ switch (offset & 0x7003)
+ {
+ case 0x0000:
+ case 0x2000:
+ state->m_mmc_extra_bank[offset >> 13] = data;
+ rex_sl1632_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ break;
+
+ case 0x1000:
+ state->m_mmc_reg[1] = data;
+ set_nt_mirroring(space->machine(), BIT(state->m_mmc_reg[1], 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+ }
+ }
+}
+
+/*************************************************************
+
+ Rumblestation Board
+
+ Games: Rumblestation 15 in 1
+
+ iNES: mapper 46
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( rumblestation_m_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("rumblestation_m_w, offset: %04x, data: %02x\n", offset, data));
+
+ state->m_mmc_prg_bank[0] = (state->m_mmc_prg_bank[0] & 0x01) | ((data & 0x0f) << 1);
+ state->m_mmc_vrom_bank[0] = (state->m_mmc_vrom_bank[0] & 0x07) | ((data & 0xf0) >> 1);
+ prg32(space->machine(), state->m_mmc_prg_bank[0]);
+ chr8(space->machine(), state->m_mmc_vrom_bank[0], CHRROM);
+}
+
+static WRITE8_HANDLER( rumblestation_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("rumblestation_w, offset: %04x, data: %02x\n", offset, data));
+
+ state->m_mmc_prg_bank[0] = (state->m_mmc_prg_bank[0] & ~0x01) | (data & 0x01);
+ state->m_mmc_vrom_bank[0] = (state->m_mmc_vrom_bank[0] & ~0x07) | ((data & 0x70) >> 4);
+ prg32(space->machine(), state->m_mmc_prg_bank[0]);
+ chr8(space->machine(), state->m_mmc_vrom_bank[0], CHRROM);
+}
+
+/*************************************************************
+
+ 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
+
+ *************************************************************/
+
+static void sachen_set_mirror( running_machine &machine, UINT8 nt ) // used by mappers 137, 138, 139, 141
+{
+ switch (nt)
+ {
+ case 0:
+ case 1:
+ set_nt_mirroring(machine, nt ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+ case 2:
+ set_nt_page(machine, 0, CIRAM, 0, 1);
+ set_nt_page(machine, 1, CIRAM, 1, 1);
+ set_nt_page(machine, 2, CIRAM, 1, 1);
+ set_nt_page(machine, 3, CIRAM, 1, 1);
+ break;
+ case 3:
+ set_nt_mirroring(machine, PPU_MIRROR_LOW);
+ break;
+ default:
+ LOG_MMC(("Mapper set NT to invalid value %02x", nt));
+ break;
+ }
+}
+
+static WRITE8_HANDLER( sachen_74x374_l_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("sachen_74x374_l_w, 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))
+ state->m_mmc_latch1 = data & 0x07;
+ else
+ {
+ switch (state->m_mmc_latch1)
+ {
+ case 0x02:
+ state->m_mmc_vrom_bank[0] = (state->m_mmc_vrom_bank[0] & ~0x08) | ((data << 3) & 0x08);
+ chr8(space->machine(), state->m_mmc_vrom_bank[0], CHRROM);
+ prg32(space->machine(), data & 0x01);
+ break;
+ case 0x04:
+ state->m_mmc_vrom_bank[0] = (state->m_mmc_vrom_bank[0] & ~0x04) | ((data << 2) & 0x04);
+ chr8(space->machine(), state->m_mmc_vrom_bank[0], CHRROM);
+ break;
+ case 0x05:
+ prg32(space->machine(), data & 0x07);
+ break;
+ case 0x06:
+ state->m_mmc_vrom_bank[0] = (state->m_mmc_vrom_bank[0] & ~0x03) | ((data << 0) & 0x03);
+ chr8(space->machine(), state->m_mmc_vrom_bank[0], CHRROM);
+ break;
+ case 0x07:
+ sachen_set_mirror(space->machine(), (data >> 1) & 0x03);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+static READ8_HANDLER( sachen_74x374_l_r )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("sachen_74x374_l_r, offset: %04x", offset));
+
+ /* read happens only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */
+ if (!(offset & 0x100))
+ return (~state->m_mmc_latch1 & 0x3f) /* ^ dips*/; // we would need to check the Dips here
+ else
+ return 0;
+}
+
+static WRITE8_HANDLER( sachen_74x374a_l_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("sachen_74x374a_l_w, 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))
+ state->m_mmc_latch1 = data;
+ else
+ {
+ switch (state->m_mmc_latch1 & 0x07)
+ {
+ case 0x00:
+ prg32(space->machine(), 0);
+ chr8(space->machine(), 3, CHRROM);
+ break;
+ case 0x02:
+ state->m_mmc_vrom_bank[0] = (state->m_mmc_vrom_bank[0] & ~0x08) | ((data << 3) & 0x08);
+ chr8(space->machine(), state->m_mmc_vrom_bank[0], CHRROM);
+ break;
+ case 0x04:
+ state->m_mmc_vrom_bank[0] = (state->m_mmc_vrom_bank[0] & ~0x01) | ((data << 0) & 0x01);
+ chr8(space->machine(), state->m_mmc_vrom_bank[0], CHRROM);
+ break;
+ case 0x05:
+ prg32(space->machine(), data & 0x01);
+ break;
+ case 0x06:
+ state->m_mmc_vrom_bank[0] = (state->m_mmc_vrom_bank[0] & ~0x06) | ((data << 1) & 0x06);
+ chr8(space->machine(), state->m_mmc_vrom_bank[0], CHRROM);
+ break;
+ case 0x07:
+ sachen_set_mirror(space->machine(), BIT(data, 0));
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+/*************************************************************
+
+ Sachen S8259 bootleg boards
+
+ iNES: mapper 141 (A), 138 (B), 139 (C), 137 (D)
+
+ *************************************************************/
+
+static void common_s8259_write_handler( address_space *space, offs_t offset, UINT8 data, int board )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 bank_helper1, bank_helper2, shift, add1, add2, add3;
+
+ /* write happens only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */
+ if (!(offset & 0x100))
+ {
+ if (!(offset & 0x01))
+ state->m_mmc_latch1 = data & 0x07;
+ else
+ {
+ state->m_sachen_reg[state->m_mmc_latch1] = data;
+
+ switch (state->m_mmc_latch1)
+ {
+ case 0x05:
+ prg32(space->machine(), data);
+ break;
+ case 0x07:
+ sachen_set_mirror(space->machine(), BIT(data, 0) ? 0 : (data >> 1) & 0x03);
+ break;
+ default:
+ if (board == SACHEN_8259D)
+ {
+ if (state->m_mmc_chr_source == CHRROM)
+ {
+ chr1_0(space->machine(), (state->m_sachen_reg[0] & 0x07), CHRROM);
+ chr1_1(space->machine(), (state->m_sachen_reg[1] & 0x07) | (state->m_sachen_reg[4] << 4 & 0x10), CHRROM);
+ chr1_2(space->machine(), (state->m_sachen_reg[2] & 0x07) | (state->m_sachen_reg[4] << 3 & 0x10), CHRROM);
+ chr1_3(space->machine(), (state->m_sachen_reg[3] & 0x07) | (state->m_sachen_reg[4] << 2 & 0x10) | (state->m_sachen_reg[6] << 3 & 0x08), CHRROM);
+ }
+ }
+ else
+ {
+ bank_helper1 = state->m_sachen_reg[7] & 0x01;
+ bank_helper2 = (state->m_sachen_reg[4] & 0x07) << 3;
+ shift = (board == SACHEN_8259A) ? 1 : (board == SACHEN_8259C) ? 2 : 0;
+ add1 = (board == SACHEN_8259B) ? 0 : 1;
+ add2 = (board == SACHEN_8259C) ? 2 : 0;
+ add3 = (board == SACHEN_8259A) ? 1 : (board == SACHEN_8259C) ? 3 : 0;
+
+ if (state->m_mmc_chr_source == CHRROM)
+ {
+ chr2_0(space->machine(), ((state->m_sachen_reg[bank_helper1 ? 0 : 0] & 0x07) | bank_helper2) << shift, CHRROM);
+ chr2_2(space->machine(), ((state->m_sachen_reg[bank_helper1 ? 0 : 1] & 0x07) | bank_helper2) << shift | add1, CHRROM);
+ chr2_4(space->machine(), ((state->m_sachen_reg[bank_helper1 ? 0 : 2] & 0x07) | bank_helper2) << shift | add2, CHRROM);
+ chr2_6(space->machine(), ((state->m_sachen_reg[bank_helper1 ? 0 : 3] & 0x07) | bank_helper2) << shift | add3, CHRROM);
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+
+static WRITE8_HANDLER( s8259_l_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("s8259_w, type: %d, offset: %04x, data: %02x\n", state->m_pcb_id, offset, data));
+
+ common_s8259_write_handler(space, offset, data, state->m_pcb_id);
+}
+
+static WRITE8_HANDLER( s8259_m_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("s8259_w, type: %d, offset: %04x, data: %02x\n", state->m_pcb_id, offset, data));
+
+ common_s8259_write_handler(space, (offset + 0x100) & 0xfff, data, state->m_pcb_id);
+}
+
+
+/*************************************************************
+
+ Sachen SA009 bootleg boards
+
+ Games: Pipe 5
+
+ iNES: mapper 160
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( sa009_l_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("sa009_l_w, offset: %04x, data: %02x\n", offset, data));
+
+ chr8(space->machine(), data, state->m_mmc_chr_source);
+}
+
+/*************************************************************
+
+ Sachen SA0036 bootleg boards
+
+ Games: Taiwan Mahjong 16
+
+ iNES: mapper 149
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( sa0036_w )
+{
+ LOG_MMC(("sa0036_w, offset: %04x, data: %02x\n", offset, data));
+
+ chr8(space->machine(), data >> 7, CHRROM);
+}
+
+/*************************************************************
+
+ Sachen SA0037 bootleg boards
+
+ Games: Mahjong World, Shisen Mahjong
+
+ iNES: mapper 148
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( sa0037_w )
+{
+ LOG_MMC(("sa0037_w, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(space->machine(), data >> 3);
+ chr8(space->machine(), data, CHRROM);
+}
+
+/*************************************************************
+
+ Sachen SA72007 bootleg boards
+
+ Games: Sidewinder
+
+ iNES: mapper 145
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( sa72007_l_w )
+{
+ LOG_MMC(("sa72007_l_w, offset: %04x, data: %02x\n", offset, data));
+
+ /* only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */
+ if (!(offset & 0x100))
+ chr8(space->machine(), data >> 7, CHRROM);
+}
+
+/*************************************************************
+
+ Sachen SA72008 bootleg boards
+
+ Games: Jovial Race, Qi Wang
+
+ iNES: mapper 133
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( sa72008_l_w )
+{
+ LOG_MMC(("sa72008_l_w, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(space->machine(), data >> 2);
+ chr8(space->machine(), data, CHRROM);
+}
+
+/*************************************************************
+
+ Sachen TCA-01 bootleg boards
+
+ iNES: mapper 143
+
+ Games: Dancing Blocks, Magic Mathematic
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static READ8_HANDLER( tca01_l_r )
+{
+ LOG_MMC(("tca01_l_r, 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.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( tcu01_l_w )
+{
+ LOG_MMC(("tcu01_l_w, offset: %04x, data: %02x\n", offset, data));
+
+ if ((offset & 0x103) == 0x002)
+ {
+ prg32(space->machine(), ((data >> 6) & 0x02) | ((data >> 2) & 0x01));
+ chr8(space->machine(), data >> 3, CHRROM);
+ }
+}
+
+static WRITE8_HANDLER( tcu01_m_w )
+{
+ LOG_MMC(("tcu01_m_w, offset: %04x, data: %02x\n", offset, data));
+
+ tcu01_l_w(space, (offset + 0x100) & 0xfff, data);
+}
+
+static WRITE8_HANDLER( tcu01_w )
+{
+ LOG_MMC(("tcu01_w, offset: %04x, data: %02x\n", offset, data));
+
+ tcu01_l_w(space, (offset + 0x100) & 0xfff, data);
+}
+
+/*************************************************************
+
+ Sachen TCU-02 bootleg boards
+
+ Games: Mei Loi Siu Ji
+
+ iNES: mapper 136
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( tcu02_l_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("tcu02_l_w, offset: %04x, data: %02x\n", offset, data));
+
+ if ((offset & 0x103) == 0x002)
+ {
+ state->m_mmc_latch1 = (data & 0x30) | ((data + 3) & 0x0f);
+ chr8(space->machine(), state->m_mmc_latch1, CHRROM);
+ }
+}
+
+static READ8_HANDLER( tcu02_l_r )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("tcu02_l_r, offset: %04x\n", offset));
+
+ if ((offset & 0x103) == 0x000)
+ return state->m_mmc_latch1 | 0x40;
+ else
+ return 0x00;
+}
+
+
+/*************************************************************
+
+ Subor bootleg board Type 0
+
+ iNES: mapper 167
+
+ *************************************************************/
+
+static WRITE8_HANDLER( subor0_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 subor_helper1, subor_helper2;
+ LOG_MMC(("subor0_w, offset: %04x, data: %02x\n", offset, data));
+
+ state->m_subor_reg[(offset >> 13) & 0x03] = data;
+ subor_helper1 = ((state->m_subor_reg[0] ^ state->m_subor_reg[1]) << 1) & 0x20;
+ subor_helper2 = ((state->m_subor_reg[2] ^ state->m_subor_reg[3]) << 0) & 0x1f;
+
+ if (state->m_subor_reg[1] & 0x08)
+ {
+ subor_helper1 += subor_helper2 & 0xfe;
+ subor_helper2 = subor_helper1;
+ subor_helper1 += 1;
+ }
+ else if (state->m_subor_reg[1] & 0x04)
+ {
+ subor_helper2 += subor_helper1;
+ subor_helper1 = 0x1f;
+ }
+ else
+ {
+ subor_helper1 += subor_helper2;
+ subor_helper2 = 0x20;
+ }
+
+ prg16_89ab(space->machine(), subor_helper1);
+ prg16_cdef(space->machine(), subor_helper2);
+}
+
+/*************************************************************
+
+ Subor bootleg board Type 1
+
+ iNES: mapper 166
+
+ *************************************************************/
+
+static WRITE8_HANDLER( subor1_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 subor_helper1, subor_helper2;
+ LOG_MMC(("subor1_w, offset: %04x, data: %02x\n", offset, data));
+
+ state->m_subor_reg[(offset >> 13) & 0x03] = data;
+ subor_helper1 = ((state->m_subor_reg[0] ^ state->m_subor_reg[1]) << 1) & 0x20;
+ subor_helper2 = ((state->m_subor_reg[2] ^ state->m_subor_reg[3]) << 0) & 0x1f;
+
+ if (state->m_subor_reg[1] & 0x08)
+ {
+ subor_helper1 += subor_helper2 & 0xfe;
+ subor_helper2 = subor_helper1;
+ subor_helper2 += 1;
+ }
+ else if (state->m_subor_reg[1] & 0x04)
+ {
+ subor_helper2 += subor_helper1;
+ subor_helper1 = 0x1f;
+ }
+ else
+ {
+ subor_helper1 += subor_helper2;
+ subor_helper2 = 0x07;
+ }
+
+ prg16_89ab(space->machine(), subor_helper1);
+ prg16_cdef(space->machine(), subor_helper2);
+}
+
+/*************************************************************
+
+ 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.
+
+ *************************************************************/
+
+static void sgame_boog_prg_cb( running_machine &machine, int start, int bank )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ if (!(state->m_mmc_reg[0] & 0x80)) // if this is != 0 we should never even arrive here
+ {
+ if (state->m_mmc_reg[1] & 0x08)
+ bank = (bank & 0x1f) | 0x20;
+ else
+ bank = (bank & 0x0f) | (state->m_mmc_reg[1] & 0x10);
+
+ prg8_x(machine, start, bank);
+ }
+}
+
+static void sgame_boog_chr_cb( running_machine &machine, int start, int bank, int source )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ if ((state->m_mmc_reg[1] & 0x04))
+ bank |= 0x100;
+ else
+ bank = (bank & 0x7f) | ((state->m_mmc_reg[1] & 0x10) << 3);
+
+ chr1_x(machine, start, bank, source);
+}
+
+static void sgame_boog_set_prg( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ if (state->m_mmc_reg[0] & 0x80)
+ {
+ prg16_89ab(machine, (state->m_mmc_reg[0] & 0xf0) | (state->m_mmc_reg[1] & 0x10));
+ prg16_cdef(machine, (state->m_mmc_reg[0] & 0xf0) | (state->m_mmc_reg[1] & 0x10));
+ }
+ else
+ mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask);
+}
+
+static WRITE8_HANDLER( sgame_boog_l_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("sgame_boog_l_w, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+
+ if (offset == 0x1000)
+ {
+ state->m_mmc_reg[0] = data;
+ sgame_boog_set_prg(space->machine());
+ }
+ else if (offset == 0x1001)
+ {
+ state->m_mmc_reg[1] = data;
+ mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ }
+ else if (offset == 0x1007)
+ {
+ state->m_mmc3_latch = 0;
+ state->m_mmc_reg[2] = data;
+ sgame_boog_set_prg(space->machine());
+ mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ }
+}
+
+static WRITE8_HANDLER( sgame_boog_m_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("sgame_boog_m_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset == 0x0000)
+ {
+ state->m_mmc_reg[0] = data;
+ sgame_boog_set_prg(space->machine());
+ }
+ else if (offset == 0x0001)
+ {
+ state->m_mmc_reg[1] = data;
+ mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ }
+ else if (offset == 0x0007)
+ {
+ state->m_mmc3_latch = 0;
+ state->m_mmc_reg[2] = data;
+ sgame_boog_set_prg(space->machine());
+ mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ }
+}
+
+static WRITE8_HANDLER( sgame_boog_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ static const UINT8 conv_table[8] = {0,2,5,3,6,1,7,4};
+ LOG_MMC(("sgame_boog_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6001)
+ {
+ case 0x0000:
+ if (!state->m_mmc_reg[2])
+ txrom_w(space, 0x0000, data);
+ break;
+
+ case 0x0001:
+ if (!state->m_mmc_reg[2])
+ txrom_w(space, 0x0001, data);
+ else if (state->m_mmc_reg[3] && ((state->m_mmc_reg[0] & 0x80) == 0 || (state->m_mmc_latch1 & 0x07) < 6)) // if we use the prg16 banks and cmd=6,7 DON'T enter!
+ {
+ state->m_mmc_reg[3] = 0;
+ txrom_w(space, 0x0001, data);
+ }
+ break;
+
+ case 0x2000:
+ if (!state->m_mmc_reg[2])
+ txrom_w(space, 0x2000, data);
+ else
+ {
+ data = (data & 0xc0) | conv_table[data & 0x07];
+ state->m_mmc_reg[3] = 1;
+ txrom_w(space, 0x0000, data);
+ break;
+ }
+ break;
+
+ case 0x4000:
+ if (!state->m_mmc_reg[2])
+ txrom_w(space, 0x4000, data);
+ else
+ set_nt_mirroring(space->machine(), ((data >> 7) | data) & 0x01 ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+
+ case 0x4001:
+ if (!state->m_mmc_reg[2])
+ txrom_w(space, 0x4001, data);
+ else
+ txrom_w(space, 0x6001, data);
+ break;
+
+ case 0x6001:
+ if (!state->m_mmc_reg[2])
+ txrom_w(space, 0x6001, data);
+ else
+ {
+ txrom_w(space, 0x4000, data);
+ txrom_w(space, 0x4001, data);
+ }
+ break;
+
+ default:
+ txrom_w(space, offset, data);
+ break;
+ }
+}
+
+/*************************************************************
+
+ Bootleg Board by Super Game
+
+ Games: The Lion King
+
+ MMC3 clone.
+
+ iNES: mapper 114
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( sgame_lion_m_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("sgame_lion_m_w, offset: %04x, data: %02x\n", offset, data));
+
+ state->m_map114_reg = data;
+
+ if (state->m_map114_reg & 0x80)
+ {
+ prg16_89ab(space->machine(), data & 0x1f);
+ prg16_cdef(space->machine(), data & 0x1f);
+ }
+ else
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+
+}
+
+static WRITE8_HANDLER( sgame_lion_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ static const UINT8 conv_table[8] = {0, 3, 1, 5, 6, 7, 2, 4};
+ LOG_MMC(("sgame_lion_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset < 0x6000)
+ {
+ switch (offset & 0x6000)
+ {
+ case 0x0000:
+ set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+ case 0x2000:
+ state->m_map114_reg_enabled = 1;
+ data = (data & 0xc0) | conv_table[data & 0x07];
+ txrom_w(space, 0x0000, data);
+ break;
+ case 0x4000:
+ if (state->m_map114_reg_enabled && (state->m_map114_reg & 0x80) == 0)
+ {
+ state->m_map114_reg_enabled = 0;
+ txrom_w(space, 0x0001, data);
+ }
+ break;
+ }
+ }
+ else
+ {
+ switch (offset & 0x03)
+ {
+ case 0x02:
+ txrom_w(space, 0x6000, data);
+ break;
+ case 0x03:
+ txrom_w(space, 0x6001, data);
+ txrom_w(space, 0x4000, data);
+ txrom_w(space, 0x4001, data);
+ break;
+ }
+ }
+}
+
+/*************************************************************
+
+ Tengen 800008 Board
+
+ iNES: mapper 3?
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( tengen_800008_w )
+{
+ LOG_MMC(("tengen_800008_w, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(space->machine(), data >> 3);
+ chr8(space->machine(), data, CHRROM);
+}
+
+/*************************************************************
+
+ Tengen 800032 Board
+
+ Games: Klax, Road Runner, Rolling Thunder, Shinobi, Skulls
+ & Croosbones, Xybots
+
+ iNES: mapper 64
+
+ In MESS: Partially Supported.
+
+ *************************************************************/
+
+static void tengen_800032_irq( device_t *device, int scanline, int vblank, int blanked )
+{
+ nes_state *state = device->machine().driver_data<nes_state>();
+ if (!state->m_IRQ_mode) // we are in scanline mode!
+ {
+ if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE)
+ {
+ if (!state->m_IRQ_reset)
+ {
+ if (!state->m_IRQ_count)
+ state->m_IRQ_count = state->m_IRQ_count_latch;
+ else
+ {
+ state->m_IRQ_count--;
+ if (state->m_IRQ_enable && !blanked && !state->m_IRQ_count)
+ {
+ LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline,
+ device->machine().primary_screen->vpos(), device->machine().primary_screen->hpos()));
+ device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE);
+ }
+ }
+ }
+ else
+ {
+ state->m_IRQ_reset = 0;
+ state->m_IRQ_count = state->m_IRQ_count_latch + 1;
+ }
+ }
+ }
+ /* otherwise, we are in CPU cycles mode --> decrement count of 114 every scanline
+ --> in the meanwhile anything can have happened to IRQ_reset and we would not know
+ --> Skulls and Crossbones does not show anything!! */
+ else
+ {
+ // if (!state->m_IRQ_reset)
+ {
+ if (state->m_IRQ_count <= 114)
+ state->m_IRQ_count = state->m_IRQ_count_latch;
+ else
+ {
+ state->m_IRQ_count -= 114;
+ if (state->m_IRQ_enable && !blanked && (state->m_IRQ_count <= 114))
+ {
+ LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline,
+ device->machine().primary_screen->vpos(), device->machine().primary_screen->hpos()));
+ device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE);
+ }
+ }
+ }
+ // else
+ // {
+ // state->m_IRQ_reset = 0;
+ // state->m_IRQ_count = state->m_IRQ_count_latch + 1;
+ // }
+ }
+}
+
+static void tengen_800032_set_prg( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ UINT8 prg_mode = state->m_mmc_latch1 & 0x40;
+
+ prg8_89(machine, state->m_mmc_prg_bank[prg_mode ? 2: 0]);
+ prg8_ab(machine, state->m_mmc_prg_bank[prg_mode ? 0: 1]);
+ prg8_cd(machine, state->m_mmc_prg_bank[prg_mode ? 1: 2]);
+}
+
+static void tengen_800032_set_chr( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ UINT8 chr_page = (state->m_mmc_latch1 & 0x80) >> 5;
+
+ if (state->m_mmc_latch1 & 0x20)
+ {
+ chr1_x(machine, 0 ^ chr_page, state->m_mmc_vrom_bank[0], CHRROM);
+ chr1_x(machine, 1 ^ chr_page, state->m_mmc_vrom_bank[8], CHRROM);
+ chr1_x(machine, 2 ^ chr_page, state->m_mmc_vrom_bank[1], CHRROM);
+ chr1_x(machine, 3 ^ chr_page, state->m_mmc_vrom_bank[9], CHRROM);
+ }
+ else
+ {
+ chr1_x(machine, 0 ^ chr_page, state->m_mmc_vrom_bank[0] & ~0x01, CHRROM);
+ chr1_x(machine, 1 ^ chr_page, state->m_mmc_vrom_bank[0] | 0x01, CHRROM);
+ chr1_x(machine, 2 ^ chr_page, state->m_mmc_vrom_bank[1] & ~0x01, CHRROM);
+ chr1_x(machine, 3 ^ chr_page, state->m_mmc_vrom_bank[1] | 0x01, CHRROM);
+ }
+
+ chr1_x(machine, 4 ^ chr_page, state->m_mmc_vrom_bank[2], CHRROM);
+ chr1_x(machine, 5 ^ chr_page, state->m_mmc_vrom_bank[3], CHRROM);
+ chr1_x(machine, 6 ^ chr_page, state->m_mmc_vrom_bank[4], CHRROM);
+ chr1_x(machine, 7 ^ chr_page, state->m_mmc_vrom_bank[5], CHRROM);
+}
+
+static WRITE8_HANDLER( tengen_800032_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 map64_helper, cmd;
+ LOG_MMC(("tengen_800032_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6001)
+ {
+ case 0x0000:
+ map64_helper = state->m_mmc_latch1 ^ data;
+ state->m_mmc_latch1 = data;
+
+ /* Has PRG Mode changed? */
+ if (map64_helper & 0x40)
+ tengen_800032_set_prg(space->machine());
+
+ /* Has CHR Mode changed? */
+ if (map64_helper & 0xa0)
+ tengen_800032_set_chr(space->machine());
+ break;
+
+ case 0x0001:
+ cmd = state->m_mmc_latch1 & 0x0f;
+ switch (cmd)
+ {
+ case 0: case 1:
+ case 2: case 3:
+ case 4: case 5:
+ state->m_mmc_vrom_bank[cmd] = data;
+ tengen_800032_set_chr(space->machine());
+ break;
+ case 6: case 7:
+ state->m_mmc_prg_bank[cmd - 6] = data;
+ tengen_800032_set_prg(space->machine());
+ break;
+ case 8: case 9:
+ state->m_mmc_vrom_bank[cmd - 2] = data;
+ tengen_800032_set_chr(space->machine());
+ break;
+ case 0x0f:
+ state->m_mmc_prg_bank[2] = data;
+ tengen_800032_set_prg(space->machine());
+ break;
+ }
+ break;
+
+ case 0x2000:
+ set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+
+ case 0x4000:
+ state->m_IRQ_count_latch = data;
+ break;
+
+ case 0x4001: /* $c001 - IRQ scanline latch */
+ state->m_IRQ_mode = data & 0x01;
+ state->m_IRQ_reset = 1;
+ break;
+
+ case 0x6000:
+ state->m_IRQ_enable = 0;
+ break;
+
+ case 0x6001:
+ state->m_IRQ_enable = 1;
+ break;
+
+ default:
+ LOG_MMC(("Mapper 64 write. addr: %04x value: %02x\n", offset + 0x8000, data));
+ break;
+ }
+}
+
+/*************************************************************
+
+ Tengen 800037 Board
+
+ Games: Alien Syndrome
+
+ iNES: mapper 158
+
+ In MESS: Very preliminary support.
+
+ *************************************************************/
+
+// probably wrong...
+static void tengen_800037_set_mirror( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ UINT8 nt_mode = state->m_mmc_latch1 & 0x80;
+
+ set_nt_page(machine, 0, ROM, state->m_mmc_vrom_bank[nt_mode ? 2 : 0], 0);
+ set_nt_page(machine, 1, ROM, state->m_mmc_vrom_bank[nt_mode ? 3 : 0], 0);
+ set_nt_page(machine, 2, ROM, state->m_mmc_vrom_bank[nt_mode ? 4 : 1], 0);
+ set_nt_page(machine, 3, ROM, state->m_mmc_vrom_bank[nt_mode ? 5 : 1], 0);
+}
+
+static WRITE8_HANDLER( tengen_800037_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 map158_helper, cmd;
+ LOG_MMC(("tengen_800037_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6001)
+ {
+ case 0x0000:
+ map158_helper = state->m_mmc_latch1 ^ data;
+ state->m_mmc_latch1 = data;
+
+ /* Has PRG Mode changed? */
+ if (map158_helper & 0x40)
+ tengen_800032_set_prg(space->machine());
+
+ /* Has CHR Mode changed? */
+ if (map158_helper & 0xa0)
+ {
+ tengen_800032_set_chr(space->machine());
+ tengen_800037_set_mirror(space->machine());
+ }
+ break;
+
+ case 0x0001:
+ cmd = state->m_mmc_latch1 & 0x0f;
+ switch (cmd)
+ {
+ case 0: case 1:
+ case 2: case 3:
+ case 4: case 5:
+ state->m_mmc_vrom_bank[cmd] = data;
+ tengen_800032_set_chr(space->machine());
+ tengen_800037_set_mirror(space->machine());
+ break;
+ case 6: case 7:
+ state->m_mmc_prg_bank[cmd - 6] = data;
+ tengen_800032_set_prg(space->machine());
+ break;
+ case 8: case 9:
+ state->m_mmc_vrom_bank[cmd - 2] = data;
+ tengen_800032_set_chr(space->machine());
+ tengen_800037_set_mirror(space->machine());
+ break;
+ case 0x0f:
+ state->m_mmc_prg_bank[2] = data;
+ tengen_800032_set_prg(space->machine());
+ break;
+ }
+ break;
+
+ case 0x2000:
+ break;
+
+ default:
+ tengen_800032_w(space, offset, data);
+ break;
+ }
+}
+
+/*************************************************************
+
+ 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.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( txc_22211_l_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("txc_22211_l_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset < 4)
+ state->m_txc_reg[offset & 0x03] = data;
+}
+
+static READ8_HANDLER( txc_22211_l_r )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("txc_22211_l_r, offset: %04x\n", offset));
+
+ if (offset == 0x0000)
+ return (state->m_txc_reg[1] ^ state->m_txc_reg[2]) | 0x40;
+ else
+ return 0x00;
+}
+
+static WRITE8_HANDLER( txc_22211_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("txc_22211_w, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(space->machine(), state->m_txc_reg[2] >> 2);
+ chr8(space->machine(), state->m_txc_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.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( txc_22211b_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("txc_22211b_w, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(space->machine(), state->m_txc_reg[2] >> 2);
+ chr8(space->machine(), (((data ^ state->m_txc_reg[2]) >> 3) & 0x02) | (((data ^ state->m_txc_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.
+
+ *************************************************************/
+
+static READ8_HANDLER( txc_22211c_l_r )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("txc_22211c_l_r, offset: %04x\n", offset));
+
+ if (offset == 0x0000)
+ return (state->m_txc_reg[1] ^ state->m_txc_reg[2]) | 0x41;
+ else
+ return 0x00;
+}
+
+/*************************************************************
+
+ Bootleg Board 'Thunder Warrior' by TXC
+
+ Games: Master Fighter II, Master Fighter 3, Thunder Warrior
+
+ MMC3 clone
+
+ iNES: mapper 189
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( txc_tw_l_w )
+{
+ LOG_MMC(("txctw_l_w, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(space->machine(), (data >> 4) | data);
+}
+
+static WRITE8_HANDLER( txc_tw_m_w )
+{
+ LOG_MMC(("txctw_m_w, offset: %04x, data: %04x\n", offset, data));
+
+ txc_tw_l_w(space, offset & 0xff, data); // offset does not really count for this mapper
+}
+
+/* writes to 0x8000-0xffff are like MMC3 but no PRG bankswitch (beacuse it is handled by low writes) */
+static void txc_tw_prg_cb( running_machine &machine, int start, int bank )
+{
+ return;
+}
+
+/*************************************************************
+
+ Bootleg Board 'Strike Wolf' by TXC
+
+ Games: Strike Wolf (also Policeman?? according to Nestopia)
+
+ iNES: mapper 36
+
+ Known Boards: Bootleg Board by TXC
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( txc_strikewolf_w )
+{
+ LOG_MMC(("txc_strikewolf_w, offset: %04x, data: %02x\n", offset, data));
+
+ if ((offset >= 0x400) && (offset < 0x7fff))
+ {
+ prg32(space->machine(), data >> 4);
+ chr8(space->machine(), 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.
+
+ *************************************************************/
+
+static READ8_HANDLER( txc_mxmdhtwo_l_r )
+{
+ return 0x50;
+}
+
+static WRITE8_HANDLER( txc_mxmdhtwo_w )
+{
+ LOG_MMC(("txc_mxmdhtwo_w, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(space->machine(), data);
+}
+
+/*************************************************************
+
+ 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! */
+static void waixing_set_mirror( running_machine &machine, UINT8 nt )
+{
+ switch (nt)
+ {
+ case 0:
+ case 1:
+ set_nt_mirroring(machine, nt ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+ case 2:
+ set_nt_mirroring(machine, PPU_MIRROR_LOW);
+ break;
+ case 3:
+ set_nt_mirroring(machine, PPU_MIRROR_HIGH);
+ break;
+ default:
+ LOG_MMC(("Mapper set NT to invalid value %02x", nt));
+ break;
+ }
+}
+
+/* Luo Ke Ren X only works with this */
+static void waixing_a_chr_cb( running_machine &machine, int start, int bank, int source )
+{
+ int chr_src = (bank <= 9) ? CHRRAM : CHRROM;
+ chr1_x(machine, start, bank, chr_src);
+}
+
+/* Ji Jia Zhan Shi only works with this */
+static void waixing_a1_chr_cb( running_machine &machine, int start, int bank, int source )
+{
+ int chr_src = ((bank == 8) || (bank == 9)) ? CHRRAM : CHRROM;
+ chr1_x(machine, start, bank, chr_src);
+}
+
+static WRITE8_HANDLER( waixing_a_w )
+{
+ LOG_MMC(("waixing_a_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6001)
+ {
+ case 0x2000:
+ waixing_set_mirror(space->machine(), data); //maybe data & 0x03?
+ break;
+
+ case 0x2001:
+ break;
+
+ default:
+ txrom_w(space, offset, data);
+ break;
+ }
+}
+
+/*************************************************************
+
+ 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.
+
+ *************************************************************/
+
+static void waixing_b_chr_cb( running_machine &machine, int start, int bank, int source )
+{
+ int chr_src = BIT(bank, 7) ? CHRRAM : CHRROM;
+ chr1_x(machine, 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.
+
+ *************************************************************/
+
+static void waixing_c_chr_cb( running_machine &machine, int start, int bank, int source )
+{
+ int chr_src = ((bank == 0x08) || (bank == 0x09) || (bank == 0x0a) || (bank == 0x0b)) ? CHRRAM : CHRROM;
+ chr1_x(machine, 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.
+
+ *************************************************************/
+
+static void waixing_d_chr_cb( running_machine &machine, int start, int bank, int source )
+{
+ int chr_src = (bank < 0x02) ? CHRRAM : CHRROM;
+ chr1_x(machine, 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.
+
+ *************************************************************/
+
+static void waixing_e_chr_cb( running_machine &machine, int start, int bank, int source )
+{
+ int chr_src = (bank < 0x04) ? CHRRAM : CHRROM;
+ chr1_x(machine, start, bank, chr_src);
+}
+
+/*************************************************************
+
+ Waixing Board Type F
+
+ Games: Tenchi wo Kurau II (C)
+
+ MMC3 clone.
+
+ iNES: mapper 198
+
+ In MESS: Preliminary support.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( waixing_f_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 cmd;
+ LOG_MMC(("waixing_f_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6001)
+ {
+ case 0x0001:
+ cmd = state->m_mmc_latch1 & 0x07;
+ if (cmd >= 6)
+ {
+ state->m_mmc_prg_bank[cmd - 6] = data & ((data > 0x3f) ? 0x4f : 0x3f);
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ }
+ else
+ waixing_a_w(space, offset, data);
+ break;
+
+ default:
+ waixing_a_w(space, offset, data);
+ break;
+ }
+}
+
+/*************************************************************
+
+ Waixing Board Type G
+
+ Games: San Guo Zhi 2, Dragon Ball Z Gaiden (C), Dragon
+ Ball Z II (C)
+
+ MMC3 clone
+
+ iNES: mapper 199
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static void waixing_g_chr_cb( running_machine &machine, int start, int bank, int source )
+{
+ int chr_src = (bank < 0x08) ? CHRRAM : CHRROM;
+ chr1_x(machine, start, bank, chr_src);
+}
+
+static void waixing_g_set_chr( running_machine &machine, int chr_base, int chr_mask )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ UINT8 chr_page = (state->m_mmc_latch1 & 0x80) >> 5;
+
+ state->m_mmc3_chr_cb(machine, chr_page ^ 0, chr_base | (state->m_mmc_vrom_bank[0] & chr_mask), state->m_mmc_chr_source);
+ state->m_mmc3_chr_cb(machine, chr_page ^ 1, chr_base | (state->m_mmc_vrom_bank[6] & chr_mask), state->m_mmc_chr_source);
+ state->m_mmc3_chr_cb(machine, chr_page ^ 2, chr_base | (state->m_mmc_vrom_bank[1] & chr_mask), state->m_mmc_chr_source);
+ state->m_mmc3_chr_cb(machine, chr_page ^ 3, chr_base | (state->m_mmc_vrom_bank[7] & chr_mask), state->m_mmc_chr_source);
+ state->m_mmc3_chr_cb(machine, chr_page ^ 4, chr_base | (state->m_mmc_vrom_bank[2] & chr_mask), state->m_mmc_chr_source);
+ state->m_mmc3_chr_cb(machine, chr_page ^ 5, chr_base | (state->m_mmc_vrom_bank[3] & chr_mask), state->m_mmc_chr_source);
+ state->m_mmc3_chr_cb(machine, chr_page ^ 6, chr_base | (state->m_mmc_vrom_bank[4] & chr_mask), state->m_mmc_chr_source);
+ state->m_mmc3_chr_cb(machine, chr_page ^ 7, chr_base | (state->m_mmc_vrom_bank[5] & chr_mask), state->m_mmc_chr_source);
+}
+
+static WRITE8_HANDLER( waixing_g_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 MMC3_helper, cmd;
+ LOG_MMC(("waixing_g_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6001)
+ {
+ case 0x0000:
+ MMC3_helper = state->m_mmc_latch1 ^ data;
+ state->m_mmc_latch1 = data;
+
+ /* Has PRG Mode changed? */
+ if (MMC3_helper & 0x40)
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+
+ /* Has CHR Mode changed? */
+ if (MMC3_helper & 0x80)
+ waixing_g_set_chr(space->machine(), state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ break;
+
+ case 0x0001:
+ cmd = state->m_mmc_latch1 & 0x0f;
+ 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:
+ state->m_mmc_vrom_bank[cmd] = data;
+ waixing_g_set_chr(space->machine(), state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ break;
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ state->m_mmc_prg_bank[cmd - 6] = data;
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ break;
+ case 0x0a: case 0x0b:
+ state->m_mmc_vrom_bank[cmd - 4] = data;
+ waixing_g_set_chr(space->machine(), state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ break;
+ }
+ break;
+
+ default:
+ waixing_a_w(space, offset, data);
+ 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.
+
+ iNES: mapper 245
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static void waixing_h_chr_cb( running_machine &machine, int start, int bank, int source )
+{
+ if (source == CHRROM)
+ chr1_x(machine, start, bank, source);
+}
+
+static WRITE8_HANDLER( waixing_h_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 cmd;
+ LOG_MMC(("waixing_h_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6001)
+ {
+ case 0x0001:
+ cmd = state->m_mmc3_latch & 0x07;
+ switch (cmd)
+ {
+ case 0: // in this case we set prg_base in addition to state->m_mmc_vrom_bank!
+ state->m_mmc_prg_base = (data << 5) & 0x40;
+ state->m_mmc_prg_mask = 0x3f;
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ txrom_w(space, offset, data);
+ default:
+ txrom_w(space, offset, data);
+ break;
+ }
+ break;
+
+ case 0x2001:
+ break;
+
+ default:
+ txrom_w(space, offset, data);
+ break;
+ }
+}
+
+/*************************************************************
+
+ Waixing San Guo Zhi Board
+
+ Games: San Guo Zhi
+
+ This board uses Konami IRQ
+
+ iNES: mapper 252
+
+ In MESS: Unsupported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( waixing_sgz_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 mmc_helper, bank;
+ LOG_MMC(("waixing_sgz_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7000)
+ {
+ case 0x0000:
+ prg8_89(space->machine(), data);
+ break;
+ case 0x2000:
+ prg8_ab(space->machine(), data);
+ break;
+ case 0x3000:
+ case 0x4000:
+ case 0x5000:
+ case 0x6000:
+ bank = ((offset & 0x7000) - 0x3000) / 0x0800 + ((offset & 0x0008) >> 3);
+ mmc_helper = offset & 0x04;
+ if (mmc_helper)
+ state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4);
+ else
+ state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f);
+ chr1_x(space->machine(), bank, state->m_mmc_vrom_bank[bank], CHRROM);
+ break;
+ case 0x7000:
+ switch (offset & 0x0c)
+ {
+ case 0x00:
+ state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0xf0) | (data & 0x0f);
+ break;
+ case 0x04:
+ state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0x0f) | ((data & 0x0f) << 4);
+ break;
+ case 0x08:
+ state->m_IRQ_enable = data & 0x02;
+ state->m_IRQ_enable_latch = data & 0x01;
+ if (data & 0x02)
+ state->m_IRQ_count = state->m_IRQ_count_latch;
+ break;
+ case 0x0c:
+ state->m_IRQ_enable = state->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.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( waixing_sgzlz_l_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("waixing_sgzlz_l_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset)
+ {
+ case 0x700:
+ set_nt_mirroring(space->machine(), data ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+ case 0x701:
+ state->m_mmc_latch1 = (state->m_mmc_latch1 & 0x0c) | ((data >> 1) & 0x03);
+ prg32(space->machine(), state->m_mmc_latch1);
+ break;
+ case 0x702:
+ state->m_mmc_latch1 = (state->m_mmc_latch1 & 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.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( waixing_ffv_l_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 mmc_helper;
+ LOG_MMC(("waixing_ffv_l_w, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100; /* the checks work better on addresses */
+
+ if (0x1000 == (offset & 0x1200))
+ {
+ state->m_mmc_reg[BIT(offset, 8)] = data;
+ mmc_helper = BIT(state->m_mmc_reg[1], 0) << 5;
+ switch (state->m_mmc_reg[0] & 0x70)
+ {
+ case 0x00:
+ case 0x20:
+ case 0x40:
+ case 0x60:
+ prg16_89ab(space->machine(), mmc_helper | ((state->m_mmc_reg[0] >> 1) & 0x10) | (state->m_mmc_reg[0] & 0x0f));
+ prg16_cdef(space->machine(), mmc_helper & 0x1f);
+ break;
+ case 0x50:
+ prg32(space->machine(), (mmc_helper >> 1) | (state->m_mmc_reg[0] & 0x0f));
+ break;
+ case 0x70:
+ prg16_89ab(space->machine(), mmc_helper | ((state->m_mmc_reg[0] << 1) & 0x10) | (state->m_mmc_reg[0] & 0x0f));
+ prg16_cdef(space->machine(), mmc_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.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( waixing_zs_w )
+{
+ LOG_MMC(("waixing_zs_w, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(space->machine(), offset >> 3);
+
+ switch (data & 0x03)
+ {
+ case 0: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break;
+ case 1: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break;
+ case 2: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break;
+ case 3: set_nt_mirroring(space->machine(), 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.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( waixing_dq8_w )
+{
+ LOG_MMC(("waixing_dq8_w, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(space->machine(), offset >> 3);
+}
+
+
+/*************************************************************
+
+ Waixing PS2 board
+
+ Games: Bao Xiao Tien Guo, Bio Hazard, Pokemon Gold, Subor (R)
+
+ iNES: mapper 15
+
+ In MESS: Supported
+
+ *************************************************************/
+
+static WRITE8_HANDLER( waixing_ps2_w )
+{
+ UINT8 map15_flip = (data & 0x80) >> 7;
+ UINT8 map15_helper = (data & 0x7f) << 1;
+
+ LOG_MMC(("waixing_ps2_w, offset: %04x, data: %02x\n", offset, data));
+
+ set_nt_mirroring(space->machine(), BIT(data, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+
+ switch (offset & 0x0fff)
+ {
+ case 0x000:
+ prg8_89(space->machine(), (map15_helper + 0) ^ map15_flip);
+ prg8_ab(space->machine(), (map15_helper + 1) ^ map15_flip);
+ prg8_cd(space->machine(), (map15_helper + 2) ^ map15_flip);
+ prg8_ef(space->machine(), (map15_helper + 3) ^ map15_flip);
+ break;
+ case 0x001:
+ map15_helper |= map15_flip;
+ prg8_89(space->machine(), map15_helper);
+ prg8_ab(space->machine(), map15_helper + 1);
+ prg8_cd(space->machine(), map15_helper + 1);
+ prg8_ef(space->machine(), map15_helper + 1);
+ break;
+ case 0x002:
+ map15_helper |= map15_flip;
+ prg8_89(space->machine(), map15_helper);
+ prg8_ab(space->machine(), map15_helper);
+ prg8_cd(space->machine(), map15_helper);
+ prg8_ef(space->machine(), map15_helper);
+ break;
+ case 0x003:
+ map15_helper |= map15_flip;
+ prg8_89(space->machine(), map15_helper);
+ prg8_ab(space->machine(), map15_helper + 1);
+ prg8_cd(space->machine(), map15_helper);
+ prg8_ef(space->machine(), map15_helper + 1);
+ break;
+ }
+}
+
+/*************************************************************
+
+ 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.
+
+ *************************************************************/
+
+static void waixing_sec_prg_cb( running_machine &machine, int start, int bank )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ if (state->m_mmc_reg[0])
+ bank = ((bank & 0x01)) | ((bank >> 3) & 0x02) | ((bank >> 1) & 0x04) | ((bank << 2) & 0x18);
+
+ prg8_x(machine, start, bank);
+}
+
+static void waixing_sec_chr_cb( running_machine &machine, int start, int bank, int source )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ if (state->m_mmc_reg[0])
+ bank = ((bank & 0x03)) | ((bank >> 1) & 0x04) | ((bank >> 4) & 0x08) |
+ ((bank >> 2) & 0x10) | ((bank << 3) & 0x20) | ((bank << 2) & 0xc0);
+
+ chr1_x(machine, start, bank, source);
+}
+
+static WRITE8_HANDLER( waixing_sec_l_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("waixing_sec_l_w, offset: %04x, data: %02x\n", offset, data));
+
+ offset += 0x100;
+
+ if (offset == 0x1000)
+ {
+ state->m_mmc_reg[0] = data & 0x02;
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ }
+}
+
+/*************************************************************
+
+ 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.
+
+ *************************************************************/
+
+static void waixing_sh2_chr_cb( running_machine &machine, int start, int bank, int source )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ chr4_0(machine, state->m_mmc_reg[0], state->m_mmc_reg[0] ? CHRRAM : CHRROM);
+ chr4_4(machine, state->m_mmc_reg[1], state->m_mmc_reg[1] ? CHRRAM : CHRROM);
+}
+
+READ8_HANDLER( waixing_sh2_chr_r )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ int bank = offset >> 10;
+ UINT8 val = state->m_chr_map[bank].access[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;
+ }
+
+ state->m_mmc_reg[offset >> 12] = chr_helper;
+ if (offset & 0x1000)
+ chr4_4(space->machine(), state->m_mmc_reg[1], state->m_mmc_reg[1] ? CHRRAM : CHRROM);
+ else
+ chr4_0(space->machine(), state->m_mmc_reg[0], state->m_mmc_reg[0] ? CHRRAM : CHRROM);
+
+ return val;
+}
+
+/*************************************************************
+
+ Board UNL-8237
+
+ Games: Pocahontas 2
+
+ MMC3 clone
+
+ In MESS: Supported
+
+ *************************************************************/
+
+static void unl_8237_prg_cb( running_machine &machine, int start, int bank )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ if (!(state->m_mmc_reg[0] & 0x80))
+ prg8_x(machine, start, bank);
+}
+
+static void unl_8237_chr_cb( running_machine &machine, int start, int bank, int source )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ bank |= ((state->m_mmc_reg[1] << 6) & 0x100);
+
+ chr1_x(machine, start, bank, source);
+}
+
+static WRITE8_HANDLER( unl_8237_l_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("unl_8237_l_w offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+
+ if (offset == 0x1000)
+ {
+ state->m_mmc_reg[0] = data;
+ if (state->m_mmc_reg[0] & 0x80)
+ {
+ if (state->m_mmc_reg[0] & 0x20)
+ prg32(space->machine(), (state->m_mmc_reg[0] & 0x0f) >> 1);
+ else
+ {
+ prg16_89ab(space->machine(), state->m_mmc_reg[0] & 0x1f);
+ prg16_cdef(space->machine(), state->m_mmc_reg[0] & 0x1f);
+ }
+ }
+ else
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ }
+
+ if (offset == 0x1001)
+ {
+ state->m_mmc_reg[1] = data;
+ mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ }
+}
+
+static WRITE8_HANDLER( unl_8237_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ static const UINT8 conv_table[8] = {0, 2, 6, 1, 7, 3, 4, 5};
+ LOG_MMC(("unl_8237_w offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7000)
+ {
+ case 0x0000:
+ case 0x1000:
+ set_nt_mirroring(space->machine(), (data | (data >> 7)) & 0x01 ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+
+ case 0x2000:
+ case 0x3000:
+ state->m_mmc_reg[2] = 1;
+ data = (data & 0xc0) | conv_table[data & 0x07];
+ txrom_w(space, 0x0000, data);
+ break;
+
+ case 0x4000:
+ case 0x5000:
+ if (state->m_mmc_reg[2])
+ {
+ state->m_mmc_reg[2] = 0;
+ txrom_w(space, 0x0001, data);
+ }
+ break;
+
+ case 0x6000:
+ break;
+
+ case 0x7000:
+ txrom_w(space, 0x6001, data);
+ txrom_w(space, 0x4000, data);
+ txrom_w(space, 0x4001, data);
+ break;
+ }
+}
+
+/*************************************************************
+
+ Board UNL-AX5705
+
+ Games: Super Mario Bros. Pocker Mali (Crayon Shin-chan pirate hack)
+
+ In MESS: Supported
+
+ *************************************************************/
+
+static void unl_ax5705_set_prg( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ prg8_89(machine, state->m_mmc_prg_bank[0]);
+ prg8_ab(machine, state->m_mmc_prg_bank[1]);
+}
+
+static WRITE8_HANDLER( unl_ax5705_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 bank;
+ LOG_MMC(("unl_ax5705_w offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x700f)
+ {
+ case 0x0000:
+ state->m_mmc_prg_bank[0] = (data & 0x05) | ((data & 0x08) >> 2) | ((data & 0x02) << 2);
+ unl_ax5705_set_prg(space->machine());
+ break;
+ case 0x0008:
+ set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+ case 0x2000:
+ state->m_mmc_prg_bank[1] = (data & 0x05) | ((data & 0x08) >> 2) | ((data & 0x02) << 2);
+ unl_ax5705_set_prg(space->machine());
+ break;
+ /* CHR banks 0, 1, 4, 5 */
+ case 0x2008:
+ case 0x200a:
+ case 0x4008:
+ case 0x400a:
+ bank = ((offset & 0x4000) ? 4 : 0) + ((offset & 0x0002) ? 1 : 0);
+ state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f);
+ chr1_x(space->machine(), bank, state->m_mmc_vrom_bank[bank], CHRROM);
+ break;
+ case 0x2009:
+ case 0x200b:
+ case 0x4009:
+ case 0x400b:
+ bank = ((offset & 0x4000) ? 4 : 0) + ((offset & 0x0002) ? 1 : 0);
+ state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x04) << 3) | ((data & 0x02) << 5) | ((data & 0x09) << 4);
+ chr1_x(space->machine(), bank, state->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);
+ state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f);
+ chr1_x(space->machine(), bank, state->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);
+ state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x04) << 3) | ((data & 0x02) << 5) | ((data & 0x09) << 4);
+ chr1_x(space->machine(), bank, state->m_mmc_vrom_bank[bank], CHRROM);
+ break;
+ }
+}
+
+/*************************************************************
+
+ Board UNL-CC-21
+
+ Games: Mi Hun Che
+
+ In MESS: Supported
+
+ *************************************************************/
+
+static WRITE8_HANDLER( unl_cc21_w )
+{
+ LOG_MMC(("unl_cc21_w offset: %04x, data: %02x\n", offset, data));
+
+ set_nt_mirroring(space->machine(), BIT(data, 1) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
+ chr8(space->machine(), (offset & 0x01), CHRROM);
+}
+
+/*************************************************************
+
+ Board UNL-KOF97
+
+ Games: King of Fighters 97 (Rex Soft)
+
+ MMC3 clone
+
+ In MESS: Not working
+
+ *************************************************************/
+
+static UINT8 unl_kof97_unscramble( UINT8 data )
+{
+ return ((data >> 1) & 0x01) | ((data >> 4) & 0x02) | ((data << 2) & 0x04) | ((data >> 0) & 0xd8) | ((data << 3) & 0x20);
+}
+
+static WRITE8_HANDLER( unl_kof97_w )
+{
+ LOG_MMC(("unl_kof97_w offset: %04x, data: %02x\n", offset, data));
+
+ /* Addresses 0x9000, 0xa000, 0xd000 & 0xf000 behaves differently than MMC3 */
+ if (offset == 0x1000)
+ {
+ data = unl_kof97_unscramble(data);
+ txrom_w(space, 0x0001, data);
+ }
+ else if (offset == 0x2000)
+ {
+ data = unl_kof97_unscramble(data);
+ txrom_w(space, 0x0000, data);
+ }
+ else if (offset == 0x5000)
+ {
+ data = unl_kof97_unscramble(data);
+ txrom_w(space, 0x4001, data);
+ }
+ else if (offset == 0x7000)
+ {
+ data = unl_kof97_unscramble(data);
+ txrom_w(space, 0x6001, data);
+ }
+ else /* Other addresses behaves like MMC3, up to unscrambling data */
+ {
+ switch (offset & 0x6001)
+ {
+ case 0x0000:
+ case 0x0001:
+ case 0x4000:
+ case 0x4001:
+ case 0x6000:
+ case 0x6001:
+ case 0x2000: /* are these ever called?!? */
+ case 0x2001:
+ data = unl_kof97_unscramble(data);
+ txrom_w(space, offset, data);
+ break;
+ }
+ }
+}
+
+/*************************************************************
+
+ Board UNL-KS7057
+
+ Games: Street Fighter VI / Fight Street VI
+
+ MMC3 clone (identical, but for switched address lines)
+
+ In MESS: Supported
+
+ *************************************************************/
+
+static WRITE8_HANDLER( ks7057_w )
+{
+ LOG_MMC(("ks7057_w, offset: %04x, data: %02x\n", offset, data));
+ offset = (BIT(offset, 0) << 1) | BIT(offset, 1) | (offset & ~0x03);
+ txrom_w(space, offset, data);
+}
+
+/*************************************************************
+
+ Board UNL-T-230
+
+ Games: Dragon Ball Z IV (Unl)
+
+ In MESS: Supported
+
+ *************************************************************/
+
+static WRITE8_HANDLER( unl_t230_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 bank;
+ LOG_MMC(("unl_t230_w offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x700c)
+ {
+ case 0x0000:
+ break;
+ case 0x2000:
+ prg16_89ab(space->machine(), data);
+ break;
+
+ // the part below works like VRC-2. how was the original board wired up?
+ // was there a VRC2? if so, we can use VRC-2 and add proper pin settings to xml!
+ case 0x1000:
+ case 0x1004:
+ case 0x1008:
+ case 0x100c:
+ switch (data & 0x03)
+ {
+ case 0x00: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break;
+ case 0x01: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break;
+ case 0x02: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break;
+ case 0x03: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break;
+ }
+ break;
+
+ case 0x3000:
+ case 0x3004:
+ case 0x3008:
+ case 0x300c:
+ case 0x4000:
+ case 0x4004:
+ case 0x4008:
+ case 0x400c:
+ case 0x5000:
+ case 0x5004:
+ case 0x5008:
+ case 0x500c:
+ case 0x6000:
+ case 0x6004:
+ case 0x6008:
+ case 0x600c:
+ bank = ((offset & 0x7000) - 0x3000) / 0x0800 + ((offset & 0x0008) >> 2);
+ if (offset & 0x0004)
+ state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & 0x0f) | (data << 4);
+ else
+ state->m_mmc_vrom_bank[bank] = (state->m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f);
+
+ chr1_x(space->machine(), bank, state->m_mmc_vrom_bank[bank], state->m_mmc_chr_source);
+ break;
+ case 0x7000:
+ state->m_IRQ_count_latch &= ~0x0f;
+ state->m_IRQ_count_latch |= data & 0x0f;
+ break;
+ case 0x7004:
+ state->m_IRQ_count_latch &= ~0xf0;
+ state->m_IRQ_count_latch |= (data << 4) & 0xf0;
+ break;
+ case 0x7008:
+ state->m_IRQ_mode = data & 0x04; // currently not implemented: 0 = prescaler mode / 1 = CPU mode
+ state->m_IRQ_enable = data & 0x02;
+ state->m_IRQ_enable_latch = data & 0x01;
+ if (data & 0x02)
+ state->m_IRQ_count = state->m_IRQ_count_latch;
+ break;
+
+ default:
+ logerror("unl_t230_w uncaught offset: %04x value: %02x\n", offset, data);
+ break;
+ }
+}
+
+/*************************************************************
+
+ 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.
+
+ *************************************************************/
+
+static void kof96_prg_cb( running_machine &machine, int start, int bank )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ if (!(state->m_mmc_reg[0] & 0x80))
+ prg8_x(machine, start, bank);
+}
+
+static void kof96_chr_cb( running_machine &machine, int start, int bank, int source )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ UINT8 chr_page = (state->m_mmc_latch1 & 0x80) >> 5;
+
+ if ((start & 0x04) == chr_page)
+ bank |= 0x100;
+
+ chr1_x(machine, start, bank, source);
+}
+
+static WRITE8_HANDLER( kof96_l_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 new_bank;
+ LOG_MMC(("kof96_l_w, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+
+ if (offset == 0x1000)
+ {
+ state->m_mmc_reg[0] = data;
+
+ if (state->m_mmc_reg[0] & 0x80)
+ {
+ new_bank = (state->m_mmc_reg[0] & 0x1f);
+
+ if (state->m_mmc_reg[0] & 0x20)
+ prg32(space->machine(), new_bank >> 2);
+ else
+ {
+ prg16_89ab(space->machine(), new_bank);
+ prg16_cdef(space->machine(), new_bank);
+ }
+ }
+ else
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ }
+
+ if (offset >= 0x1000)
+ {
+ switch (data & 0x03)
+ {
+ case 0x00:
+ case 0x01:
+ state->m_mmc_reg[1] = 0x83;
+ break;
+ case 0x02:
+ state->m_mmc_reg[1] = 0x42;
+ break;
+ case 0x03:
+ state->m_mmc_reg[1] = 0x00;
+ break;
+ }
+
+ }
+
+ if (!state->m_mmc_reg[3] && offset > 0x1000)
+ {
+ state->m_mmc_reg[3] = 1;
+ space->write_byte(0x4017, 0x40);
+ }
+}
+
+static READ8_HANDLER( kof96_l_r )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("kof96_l_r, offset: %04x\n", offset));
+ offset += 0x100;
+
+ if (!(offset < 0x1000))
+ return state->m_mmc_reg[1];
+ else
+ return 0;
+}
+
+static WRITE8_HANDLER( kof96_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("kof96_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6003)
+ {
+ case 0x0000:
+ state->m_mmc_reg[2] = 1;
+ txrom_w(space, 0x0000, data);
+ break;
+
+ case 0x0001:
+ if (state->m_mmc_reg[2])
+ txrom_w(space, 0x0001, data);
+ break;
+
+ case 0x0002:
+ break;
+
+ case 0x0003:
+ state->m_mmc_reg[2] = 0;
+
+ if (data == 0x28)
+ prg8_cd(space->machine(), 0x17);
+ else if (data == 0x2a)
+ prg8_ab(space->machine(), 0x0f);
+ break;
+
+ default:
+ txrom_w(space, 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.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( mk2_m_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("mk2_m_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x1000)
+ {
+ case 0x0000:
+ switch (offset & 0x03)
+ {
+ case 0x00: chr2_0(space->machine(), data, CHRROM); break;
+ case 0x01: chr2_2(space->machine(), data, CHRROM); break;
+ case 0x02: chr2_4(space->machine(), data, CHRROM); break;
+ case 0x03: chr2_6(space->machine(), data, CHRROM); break;
+ }
+ break;
+ case 0x1000:
+ switch (offset & 0x03)
+ {
+ case 0x00: prg8_89(space->machine(), data); break;
+ case 0x01: prg8_ab(space->machine(), data); break;
+ case 0x02: state->m_IRQ_enable = 0; state->m_IRQ_count = 0; break;
+ case 0x03: state->m_IRQ_enable = 1; state->m_IRQ_count = 7; break;
+ }
+ break;
+ default:
+ logerror("mk2_m_w uncaught addr: %04x value: %02x\n", offset + 0x6000, data);
+ break;
+ }
+}
+
+/*************************************************************
+
+ Bootleg Board N625092
+
+ Games: 400 in 1, 700 in 1, 1000 in 1
+
+ iNES: mapper 221
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static void n625092_set_prg( running_machine &machine, UINT8 reg1, UINT8 reg2 )
+{
+ UINT8 map221_helper1, map221_helper2;
+
+ map221_helper1 = !(reg1 & 0x01) ? reg2 :
+ (reg1 & 0x80) ? reg2 : (reg2 & 0x06) | 0x00;
+ map221_helper2 = !(reg1 & 0x01) ? reg2 :
+ (reg1 & 0x80) ? 0x07 : (reg2 & 0x06) | 0x01;
+
+ prg16_89ab(machine, map221_helper1 | ((reg1 & 0x70) >> 1));
+ prg16_cdef(machine, map221_helper2 | ((reg1 & 0x70) >> 1));
+}
+
+static WRITE8_HANDLER( n625092_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("n625092_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset < 0x4000)
+ {
+ set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ offset = (offset >> 1) & 0xff;
+
+ if (state->m_mmc_latch1 != offset)
+ {
+ state->m_mmc_latch1 = offset;
+ n625092_set_prg(space->machine(), state->m_mmc_latch1, state->m_mmc_latch2);
+ }
+ }
+ else
+ {
+ offset &= 0x07;
+
+ if (state->m_mmc_latch2 != offset)
+ {
+ state->m_mmc_latch2 = offset;
+ n625092_set_prg(space->machine(), state->m_mmc_latch1, state->m_mmc_latch2);
+ }
+ }
+}
+
+/*************************************************************
+
+ SC-127 Board
+
+ Games: Wario World II (Kirby Hack)
+
+ iNES: mapper 35
+
+ In MESS: Supported
+
+ *************************************************************/
+
+static void sc127_irq( device_t *device, int scanline, int vblank, int blanked )
+{
+ nes_state *state = device->machine().driver_data<nes_state>();
+
+ if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE && state->m_IRQ_enable)
+ {
+ state->m_IRQ_count--;
+
+ if (!blanked && (state->m_IRQ_count == 0))
+ {
+ LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline,
+ device->machine().primary_screen->vpos(), device->machine().primary_screen->hpos()));
+ device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE);
+ state->m_IRQ_enable = 0;
+ }
+ }
+}
+
+static WRITE8_HANDLER( sc127_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("sc127_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset)
+ {
+ case 0x0000:
+ prg8_89(space->machine(), data);
+ break;
+ case 0x0001:
+ prg8_ab(space->machine(), data);
+ break;
+ case 0x0002:
+ // state->m_mmc_prg_bank[offset & 0x02] = data;
+ prg8_cd(space->machine(), data);
+ break;
+ case 0x1000:
+ case 0x1001:
+ case 0x1002:
+ case 0x1003:
+ case 0x1004:
+ case 0x1005:
+ case 0x1006:
+ case 0x1007:
+ // state->m_mmc_vrom_bank[offset & 0x07] = data;
+ chr1_x(space->machine(), offset & 0x07, data, CHRROM);
+ break;
+ case 0x4002:
+ state->m_IRQ_enable = 0;
+ break;
+ case 0x4003:
+ state->m_IRQ_enable = 1;
+ break;
+ case 0x4005:
+ state->m_IRQ_count = data;
+ break;
+ case 0x5001:
+ set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+ }
+}
+
+/*************************************************************
+
+ Bootleg Board SMB2J
+
+ Games: Super Mario Bros. 2 Pirate (LF36)
+
+ iNES: mapper 43
+
+ In MESS: Supported? The only image I found is not working
+ (not even in NEStopia).
+
+ *************************************************************/
+
+static WRITE8_HANDLER( smb2j_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ int bank = (((offset >> 8) & 0x03) * 0x20) + (offset & 0x1f);
+
+ LOG_MMC(("smb2j_w, offset: %04x, data: %02x\n", offset, data));
+
+ set_nt_mirroring(space->machine(), (offset & 0x2000) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+
+ if (offset & 0x0800)
+ {
+ if (offset & 0x1000)
+ {
+ if (bank * 2 >= state->m_prg_chunks)
+ {
+ state->membank("bank3")->set_base(state->m_wram);
+ state->membank("bank4")->set_base(state->m_wram);
+ }
+ else
+ {
+ LOG_MMC(("smb2j_w, selecting upper 16KB bank of #%02x\n", bank));
+ prg16_cdef(space->machine(), 2 * bank + 1);
+ }
+ }
+ else
+ {
+ if (bank * 2 >= state->m_prg_chunks)
+ {
+ state->membank("bank1")->set_base(state->m_wram);
+ state->membank("bank2")->set_base(state->m_wram);
+ }
+ else
+ {
+ LOG_MMC(("smb2j_w, selecting lower 16KB bank of #%02x\n", bank));
+ prg16_89ab(space->machine(), 2 * bank);
+ }
+ }
+ }
+ else
+ {
+ if (bank * 2 >= state->m_prg_chunks)
+ {
+ state->membank("bank1")->set_base(state->m_wram);
+ state->membank("bank2")->set_base(state->m_wram);
+ state->membank("bank3")->set_base(state->m_wram);
+ state->membank("bank4")->set_base(state->m_wram);
+ }
+ else
+ {
+ LOG_MMC(("smb2j_w, selecting 32KB bank #%02x\n", bank));
+ prg32(space->machine(), bank);
+ }
+ }
+}
+
+/*************************************************************
+
+ 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: Supported.
+
+ *************************************************************/
+
+static void smb2jb_irq( device_t *device, int scanline, int vblank, int blanked )
+{
+ nes_state *state = device->machine().driver_data<nes_state>();
+ if (state->m_IRQ_enable)
+ {
+ if (state->m_IRQ_count < 0x1000)
+ {
+ if ((0x1000 - state->m_IRQ_count) <= 114)
+ device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE);
+ else
+ state->m_IRQ_count += 114;
+ }
+ else
+ state->m_IRQ_count += 114;
+
+ state->m_IRQ_count &= 0xffff; // according to docs is 16bit counter -> it wraps only after 0xffff
+ }
+}
+
+static WRITE8_HANDLER( smb2jb_l_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 prg;
+ LOG_MMC(("smb2jb_l_w, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+
+ switch (offset & 0x160)
+ {
+ case 0x020:
+ prg = (data & 0x08) | ((data & 0x06) >> 1) | ((data & 0x01) << 2);
+ prg8_cd(space->machine(), prg);
+ break;
+ case 0x120:
+ state->m_IRQ_enable = data & 0x01;
+ break;
+ }
+}
+
+/* This goes to 0x4020-0x403f */
+WRITE8_HANDLER( smb2jb_extra_w )
+{
+ UINT8 prg;
+ LOG_MMC(("smb2jb_extra_w, offset: %04x, data: %02x\n", offset, data));
+
+ prg = (data & 0x08) | ((data & 0x06) >> 1) | ((data & 0x01) << 2);
+ prg8_cd(space->machine(), prg);
+}
+
+/*************************************************************
+
+ Bootleg Board for Super Fighter III
+
+ MMC3 clone
+
+ iNES: mapper 197
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static void unl_sf3_set_chr( running_machine &machine, UINT8 chr_source, int chr_base, int chr_mask )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ chr4_0(machine, chr_base | ((state->m_mmc_vrom_bank[0] >> 1) & chr_mask), chr_source);
+ chr2_4(machine, chr_base | (state->m_mmc_vrom_bank[1] & chr_mask), chr_source);
+ chr2_6(machine, chr_base | (state->m_mmc_vrom_bank[2] & chr_mask), chr_source);
+}
+
+static WRITE8_HANDLER( unl_sf3_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 mmc_helper, cmd;
+ LOG_MMC(("unl_sf3_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6001)
+ {
+ case 0x0000:
+ mmc_helper = state->m_mmc3_latch ^ data;
+ state->m_mmc3_latch = data;
+
+ /* Has PRG Mode changed? */
+ if (mmc_helper & 0x40)
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+
+ /* Has CHR Mode changed? */
+ if (mmc_helper & 0x80)
+ unl_sf3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ break;
+
+ case 0x0001:
+ cmd = state->m_mmc3_latch & 0x0f;
+ switch (cmd)
+ {
+ case 0: case 2: case 4:
+ state->m_mmc_vrom_bank[cmd >> 1] = data;
+ unl_sf3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ break;
+ case 6:
+ case 7:
+ state->m_mmc_prg_bank[cmd - 6] = data;
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ break;
+ }
+ break;
+
+ default:
+ txrom_w(space, offset, data);
+ break;
+ }
+}
+
+/*************************************************************
+
+ 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.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( unl_xzy_l_w )
+{
+ LOG_MMC(("unl_xzy_l_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset)
+ {
+ case 0x1ef1: /* 0x5ff1 */
+ prg32(space->machine(), data >> 1);
+ break;
+ case 0x1ef2: /* 0x5ff2 */
+ chr8(space->machine(), data, CHRROM);
+ break;
+ }
+}
+
+/*************************************************************
+
+ Board UNL-RACERMATE
+
+ In MESS: *VERY* preliminary support. Also, it seems that this
+ board saves to battery the CHRRAM!!!
+
+ *************************************************************/
+
+static void racmate_update_banks( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ chr4_4(machine, state->m_mmc_latch1 & 0x0f, state->m_mmc_chr_source);
+ prg16_89ab(machine, state->m_mmc_latch1 >> 1);
+}
+
+static WRITE8_HANDLER( unl_racmate_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("unl_racmate_w offset: %04x, data: %02x\n", offset, data));
+
+ if (offset == 0x3000)
+ {
+ state->m_mmc_latch1 = data;
+ racmate_update_banks(space->machine());
+ }
+}
+
+
+/*************************************************************
+
+ Board UNL-FS304
+
+ Games: A Link to the Past by Waixing
+
+ iNES: mapper 162? (only found in UNIF format)
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( unl_fs304_l_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("unl_fs304_l_w, offset: %04x, data: %02x\n", offset, data));
+ int bank;
+ offset += 0x100;
+
+ if (offset >= 0x1000)
+ {
+ state->m_mmc_reg[(offset >> 8) & 3] = data;
+ bank = ((state->m_mmc_reg[2] & 0x0f) << 4) | BIT(state->m_mmc_reg[1], 1) | (state->m_mmc_reg[0] & 0x0e);
+ prg32(space->machine(), bank);
+ chr8(space->machine(), 0, CHRRAM);
+ }
+}
+
+
+/*************************************************************
+
+ BOOTLEG CART VERSIONS OF FDS GAMES
+
+ *************************************************************/
+
+/*************************************************************
+
+ 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.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( btl_smb11_w )
+{
+ LOG_MMC(("btl_smb11_w, offset: %04x, data: %02x\n", offset, data));
+
+ txrom_w(space, (offset & 0x6000) | ((offset & 0x04) >> 2), data);
+}
+
+/*************************************************************
+
+ BTL-MARIOBABY
+
+ Games: Mario Baby, Ai Senshi Nicol
+
+ iNES: mapper 42
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+// is the code fine for ai senshi nicol?!?
+static WRITE8_HANDLER( btl_mariobaby_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("btl_mariobaby_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset >= 0x7000)
+ {
+ switch (offset & 0x03)
+ {
+ case 0x00:
+ prg8_67(space->machine(), data);
+ break;
+ case 0x01:
+ set_nt_mirroring(space->machine(), BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+ case 0x02:
+ /* Check if IRQ is being enabled */
+ if (!state->m_IRQ_enable && (data & 0x02))
+ {
+ state->m_IRQ_enable = 1;
+ state->m_irq_timer->adjust(downcast<cpu_device *>(state->m_maincpu)->cycles_to_attotime(24576));
+ }
+ if (!(data & 0x02))
+ {
+ state->m_IRQ_enable = 0;
+ state->m_irq_timer->adjust(attotime::never);
+ }
+ break;
+ }
+ }
+}
+
+/*************************************************************
+
+ BTL-SMB2A
+
+ Games: Super Mario Bros. 2 Pirate (Jpn version of SMB2)
+
+ iNES: mapper 40
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static void btl_smb2a_irq( device_t *device, int scanline, int vblank, int blanked )
+{
+ nes_state *state = device->machine().driver_data<nes_state>();
+
+ if (state->m_IRQ_enable)
+ {
+ if ((0xfff - state->m_IRQ_count) <= 114)
+ {
+ state->m_IRQ_count = (state->m_IRQ_count + 1) & 0xfff;
+ state->m_IRQ_enable = 0;
+ device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE);
+ }
+ else
+ state->m_IRQ_count += 114;
+ }
+}
+
+static WRITE8_HANDLER( btl_smb2a_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("btl_smb2a_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6000)
+ {
+ case 0x0000:
+ state->m_IRQ_enable = 0;
+ state->m_IRQ_count = 0;
+ break;
+ case 0x2000:
+ state->m_IRQ_enable = 1;
+ break;
+ case 0x6000:
+ prg8_cd(space->machine(), data);
+ break;
+ }
+}
+
+/*************************************************************
+
+ WHIRLWIND-2706
+
+ Games: Meikyuu Jiin Dababa (FDS conversion)
+
+ iNES: mapper 108
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( whirl2706_w )
+{
+ LOG_MMC(("whirl2706_w, offset: %04x, data: %02x\n", offset, data));
+ prg8_67(space->machine(), data);
+}
+
+/*************************************************************
+
+ Bootleg Board used for FDS conversion
+
+ Games: Tobidase Daisakusen (FDS conversion)
+
+ iNES: mapper 120
+
+ In MESS: Partially Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( btl_tobi_l_w )
+{
+ LOG_MMC(("btl_tobi_l_w, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+
+ if ((offset & 0x43c0) == 0x41c0)
+ prg8_67(space->machine(), data & 0x07);
+}
+
+/*************************************************************
+
+ BTL-SMB3
+
+ Games: Super Mario Bros. 3 Pirate
+
+ iNES: mapper 106
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static void btl_smb3_irq( device_t *device, int scanline, int vblank, int blanked )
+{
+ nes_state *state = device->machine().driver_data<nes_state>();
+
+ if (state->m_IRQ_enable)
+ {
+ if ((0xffff - state->m_IRQ_count) < 114)
+ {
+ device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE);
+ state->m_IRQ_enable = 0;
+ }
+
+ state->m_IRQ_count = (state->m_IRQ_count + 114) & 0xffff;
+ }
+}
+
+static WRITE8_HANDLER( btl_smb3_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("btl_smb3_w, offset: %04x, data: %02x\n", offset, data));
+ switch (offset & 0x0f)
+ {
+ case 0x00:
+ case 0x02:
+ chr1_x(space->machine(), offset & 0x07, data & 0xfe, CHRROM);
+ break;
+ case 0x01:
+ case 0x03:
+ chr1_x(space->machine(), offset & 0x07, data | 0x01, CHRROM);
+ break;
+ case 0x04: case 0x05:
+ case 0x06: case 0x07:
+ chr1_x(space->machine(), offset & 0x07, data, CHRROM);
+ break;
+ case 0x08:
+ prg8_89(space->machine(), data | 0x10);
+ break;
+ case 0x09:
+ prg8_ab(space->machine(), data);
+ break;
+ case 0x0a:
+ prg8_cd(space->machine(), data);
+ break;
+ case 0x0b:
+ prg8_ef(space->machine(), data | 0x10);
+ break;
+ case 0x0c:
+ set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+ case 0x0d:
+ state->m_IRQ_count = 0;
+ state->m_IRQ_enable = 0;
+ break;
+ case 0x0e:
+ state->m_IRQ_count = (state->m_IRQ_count & 0xff00) | data;
+ break;
+ case 0x0f:
+ state->m_IRQ_count = (state->m_IRQ_count & 0x00ff) | (data << 8);
+ state->m_IRQ_enable = 1;
+ break;
+ }
+}
+
+/*************************************************************
+
+ BTL-DRAGONNINJA
+
+ Games: Dragon Ninja (Bootleg), Super Mario Bros. 8
+
+ iNES: mapper 222
+
+ In MESS: Unsupported.
+
+ *************************************************************/
+
+/* Scanline based IRQ ? */
+static void btl_dn_irq( device_t *device, int scanline, int vblank, int blanked )
+{
+ nes_state *state = device->machine().driver_data<nes_state>();
+ if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE)
+ {
+ if (!state->m_IRQ_count || ++state->m_IRQ_count < 240)
+ return;
+
+ state->m_IRQ_count = 0;
+ LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline,
+ device->machine().primary_screen->vpos(), device->machine().primary_screen->hpos()));
+ device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE);
+ }
+}
+
+static WRITE8_HANDLER( btl_dn_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 bank;
+ LOG_MMC(("btl_dn_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7003)
+ {
+ case 0x0000:
+ prg8_89(space->machine(), data);
+ break;
+ case 0x1000:
+ set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+ case 0x2000:
+ prg8_ab(space->machine(), 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) >> 3);
+ chr1_x(space->machine(), bank, data, CHRROM);
+ break;
+ case 0x7000:
+ state->m_IRQ_count = data;
+ break;
+ }
+}
+
+/*************************************************************
+
+ BTL-PIKACHUY2K
+
+ Games: Pikachu Y2k
+
+ iNES: mapper 254
+
+ In MESS:
+
+ *************************************************************/
+
+static WRITE8_HANDLER( btl_pika_y2k_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("btl_pika_y2k_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6001)
+ {
+ case 0x2001:
+ state->m_mmc_latch2 = data;
+ break;
+
+ case 0x2000:
+ state->m_mmc_reg[0] = 0;
+ default:
+ txrom_w(space, offset, data);
+ break;
+ }
+}
+
+// strange WRAM usage: it is protected at start, and gets unprotected after the first write to 0xa000
+static WRITE8_HANDLER( btl_pika_y2k_m_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("btl_pika_y2k_m_w, offset: %04x, data: %02x\n", offset, data));
+
+ state->m_wram[offset] = data;
+}
+
+static READ8_HANDLER( btl_pika_y2k_m_r )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("btl_pika_y2k_m_r, offset: %04x\n", offset));
+
+ return state->m_wram[offset] ^ (state->m_mmc_latch2 & state->m_mmc_reg[0]);
+}
+
+/*************************************************************
+
+ MULTICART
+
+ *************************************************************/
+
+/*************************************************************
+
+ Board BMC-FK23C
+
+ In MESS: partially supported (still to sort initial banking
+ for many games)
+
+ *************************************************************/
+
+#if 0
+static void fk23c_prg_cb( running_machine &machine, int start, int bank )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ if (((state->m_mmc_reg[0] & 0x07) - 3) > 1 && (!(state->m_mmc_reg[3] & 0x02) || start < 2))
+ {
+ if (state->m_mmc_reg[0] & 0x03)
+ bank = (bank & (0x3f >> (state->m_mmc_reg[0] & 0x03))) | (state->m_mmc_reg[1] << 1);
+
+ prg8_x(machine, start, bank);
+ }
+}
+
+static void fk23c_chr_cb( running_machine &machine, int start, int bank, int source )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ if (!(state->m_mmc_reg[0] & 0x40) && (!(state->m_mmc_reg[3] & 0x02) || (start != 1 && start != 3)))
+ chr1_x(machine, start, ((state->m_mmc_reg[2] & 0x7f) << 3) | bank, source);
+}
+
+#endif
+
+static void fk23c_prg_cb( running_machine &machine, int start, int bank )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ UINT8 mask = (0x3f >> (state->m_mmc_reg[0] & 0x03));
+
+ if ((state->m_mmc_reg[0] & 0x07) < 3)
+ {
+ if (!(state->m_mmc_reg[0] & 0x03))
+ bank = (bank & mask) | ((state->m_mmc_reg[1] & (0x7f ^ mask)) << 1);
+
+ prg8_x(machine, start, bank);
+ }
+}
+
+static void fk23c_chr_cb( running_machine &machine, int start, int bank, int source )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ if (!(state->m_mmc_reg[0] & 0x40) && (!(state->m_mmc_reg[3] & 0x02) || (start != 1 && start != 3)))
+ chr1_x(machine, start, ((state->m_mmc_reg[2] & 0x7f) << 3) | bank, source);
+}
+
+static void fk23c_set_prg( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ if ((state->m_mmc_reg[0] & 0x07) == 4)
+ prg32(machine, (state->m_mmc_reg[1] & 0x7f) >> 1);
+ else if ((state->m_mmc_reg[0] & 0x07) == 3)
+ {
+ prg16_89ab(machine, state->m_mmc_reg[1] & 0x7f);
+ prg16_cdef(machine, state->m_mmc_reg[1] & 0x7f);
+ }
+ else
+ {
+ if (state->m_mmc_reg[3] & 0x02)
+ {
+ prg8_cd(machine, state->m_mmc_reg[4]);
+ prg8_ef(machine, state->m_mmc_reg[5]);
+ }
+ else
+ mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ }
+}
+
+static void fk23c_set_chr( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ if (state->m_mmc_reg[0] & 0x40)
+ chr8(machine, state->m_mmc_reg[2] | state->m_mmc_cmd1, state->m_mmc_chr_source);
+ else
+ {
+ if (state->m_mmc_reg[3] & 0x02)
+ {
+ int base = (state->m_mmc_reg[2] & 0x7f) << 3;
+ chr1_x(machine, 1, base | state->m_mmc_reg[6], state->m_mmc_chr_source);
+ chr1_x(machine, 3, base | state->m_mmc_reg[7], state->m_mmc_chr_source);
+ }
+ else
+ mmc3_set_chr(machine, state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ }
+}
+
+static WRITE8_HANDLER( fk23c_l_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("fk23c_l_w, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+
+ if (offset >= 0x1000)
+ {
+ if (offset & (1 << 4)) // here it should be (4 + state->m_mmc_dipsetting)
+ {
+ state->m_mmc_reg[offset & 0x03] = data;
+
+ fk23c_set_prg(space->machine());
+ fk23c_set_chr(space->machine());
+ }
+ }
+}
+
+static WRITE8_HANDLER( fk23c_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("fk23c_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (state->m_mmc_reg[0] & 0x40)
+ {
+ if (state->m_mmc_reg[0] & 0x30)
+ state->m_mmc_cmd1 = 0;
+ else
+ {
+ state->m_mmc_cmd1 = data & 0x03;
+ fk23c_set_chr(space->machine());
+ }
+ }
+ else
+ {
+ switch (offset & 0x6001)
+ {
+ case 0x0001:
+ if ((state->m_mmc_reg[3] & 0x02) && (state->m_mmc3_latch & 0x08))
+ {
+ state->m_mmc_reg[4 | (state->m_mmc3_latch & 0x03)] = data;
+ fk23c_set_prg(space->machine());
+ fk23c_set_chr(space->machine());
+ }
+ else
+ txrom_w(space, offset, data);
+ break;
+
+ case 0x2000:
+ set_nt_mirroring(space->machine(), data ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+
+ default:
+ txrom_w(space, offset, data);
+ break;
+ }
+ }
+}
+
+
+/*************************************************************
+
+ Board BMC-64IN1NOREPEAT
+
+ Games: 64-in-1 Y2K
+
+ In MESS: Supported
+
+ *************************************************************/
+
+static void bmc_64in1nr_set_prg( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ UINT8 helper1 = (state->m_mmc_reg[1] & 0x1f);
+ UINT8 helper2 = (helper1 << 1) | ((state->m_mmc_reg[1] & 0x40) >> 6);
+
+ if (state->m_mmc_reg[0] & 0x80)
+ {
+ if (state->m_mmc_reg[1] & 0x80)
+ prg32(machine, helper1);
+ else
+ {
+ prg16_89ab(machine, helper2);
+ prg16_cdef(machine, helper2);
+ }
+ }
+ else
+ prg16_cdef(machine, helper2);
+}
+
+static WRITE8_HANDLER( bmc_64in1nr_l_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("bmc_64in1nr_l_w offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+
+ switch (offset)
+ {
+ case 0x1000:
+ case 0x1001:
+ case 0x1002:
+ case 0x1003:
+ state->m_mmc_reg[offset & 0x03] = data;
+ bmc_64in1nr_set_prg(space->machine());
+ chr8(space->machine(), ((state->m_mmc_reg[0] >> 1) & 0x03) | (state->m_mmc_reg[2] << 2), CHRROM);
+ break;
+ }
+ if (offset == 0x1000) /* reg[0] also sets mirroring */
+ set_nt_mirroring(space->machine(), BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+}
+
+static WRITE8_HANDLER( bmc_64in1nr_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("bmc_64in1nr_w offset: %04x, data: %02x\n", offset, data));
+
+ state->m_mmc_reg[3] = data; // reg[3] is currently unused?!?
+}
+
+/*************************************************************
+
+ Board BMC-190IN1
+
+ Games: 190-in-1
+
+ In MESS: Supported
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bmc_190in1_w )
+{
+ LOG_MMC(("bmc_190in1_w offset: %04x, data: %02x\n", offset, data));
+
+ set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ offset >>= 2;
+ prg16_89ab(space->machine(), offset);
+ prg16_cdef(space->machine(), offset);
+ chr8(space->machine(), offset, CHRROM);
+}
+
+/*************************************************************
+
+ Board BMC-A65AS
+
+ Games: 3-in-1 (N068)
+
+ In MESS: Supported
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bmc_a65as_w )
+{
+ UINT8 helper = (data & 0x30) >> 1;
+ LOG_MMC(("bmc_a65as_w offset: %04x, data: %02x\n", offset, data));
+
+ if (data & 0x80)
+ set_nt_mirroring(space->machine(), BIT(data, 5) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
+ else
+ set_nt_mirroring(space->machine(), BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+
+ if (data & 0x40)
+ prg32(space->machine(), data >> 1);
+ else
+ {
+ prg16_89ab(space->machine(), helper | (data & 0x07));
+ prg16_cdef(space->machine(), helper | 0x07);
+ }
+}
+
+/*************************************************************
+
+ Board BMC-GS2004
+
+ Games: Tetris Family 6-in-1
+
+ In MESS: Preliminary Support. It also misses WRAM handling
+ (we need reads from 0x6000-0x7fff)
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bmc_gs2004_w )
+{
+ LOG_MMC(("bmc_gs2004_w offset: %04x, data: %02x\n", offset, data));
+
+ prg32(space->machine(), 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)
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bmc_gs2013_w )
+{
+ LOG_MMC(("bmc_gs2013_w offset: %04x, data: %02x\n", offset, data));
+
+ if (data & 0x08)
+ prg32(space->machine(), data & 0x09);
+ else
+ prg32(space->machine(), data & 0x07);
+}
+
+/*************************************************************
+
+ Board BMC-SUPER24IN1SC03
+
+ Games: Super 24-in-1
+
+ In MESS: Partially Supported
+
+ *************************************************************/
+
+static void bmc_s24in1sc03_prg_cb( running_machine &machine, int start, int bank )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ static const UINT8 masks[8] = {0x3f, 0x1f, 0x0f, 0x01, 0x03, 0x00, 0x00, 0x00};
+ int prg_base = state->m_mmc_reg[1] << 1;
+ int prg_mask = masks[state->m_mmc_reg[0] & 0x07];
+
+ bank = prg_base | (bank & prg_mask);
+ prg8_x(machine, start, bank);
+}
+
+static void bmc_s24in1sc03_chr_cb( running_machine &machine, int start, int bank, int source )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ UINT8 chr = BIT(state->m_mmc_reg[0], 5) ? CHRRAM : CHRROM;
+ int chr_base = (state->m_mmc_reg[2] << 3) & 0xf00;
+
+ chr1_x(machine, start, chr_base | bank, chr);
+}
+
+static WRITE8_HANDLER( bmc_s24in1sc03_l_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("bmc_s24in1sc03_l_w offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+
+ if (offset == 0x1ff0)
+ {
+ state->m_mmc_reg[0] = data;
+ mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ }
+
+ if (offset == 0x1ff1)
+ {
+ state->m_mmc_reg[1] = data;
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ }
+
+ if (offset == 0x1ff2)
+ {
+ state->m_mmc_reg[2] = data;
+ mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ }
+}
+
+/*************************************************************
+
+ Board BMC-T-262
+
+ Games: 4-in-1 (D-010), 8-in-1 (A-020)
+
+ In MESS: Supported
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bmc_t262_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 mmc_helper;
+ LOG_MMC(("bmc_t262_w offset: %04x, data: %02x\n", offset, data));
+
+ if (state->m_mmc_latch2 || offset == 0)
+ {
+ state->m_mmc_latch1 = (state->m_mmc_latch1 & 0x38) | (data & 0x07);
+ prg16_89ab(space->machine(), state->m_mmc_latch1);
+ }
+ else
+ {
+ state->m_mmc_latch2 = 1;
+ set_nt_mirroring(space->machine(), BIT(data, 1) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ mmc_helper = ((offset >> 3) & 0x20) | ((offset >> 2) & 0x18);
+ state->m_mmc_latch1 = mmc_helper | (state->m_mmc_latch1 & 0x07);
+ prg16_89ab(space->machine(), state->m_mmc_latch1);
+ prg16_cdef(space->machine(), mmc_helper | 0x07);
+ }
+}
+
+/*************************************************************
+
+ Board BMC-WS
+
+ Games: Super 40-in-1
+
+ In MESS: Partially Supported (some games, like Galaxian, have
+ issues)
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bmc_ws_m_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 mmc_helper;
+ LOG_MMC(("bmc_ws_m_w offset: %04x, data: %02x\n", offset, data));
+
+ if (offset < 0x1000)
+ {
+ switch (offset & 0x01)
+ {
+ case 0:
+ if (!state->m_mmc_latch1)
+ {
+ state->m_mmc_latch1 = data & 0x20;
+ set_nt_mirroring(space->machine(), BIT(data, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ mmc_helper = (~data & 0x08) >> 3;
+ prg16_89ab(space->machine(), data & ~mmc_helper);
+ prg16_cdef(space->machine(), data | mmc_helper);
+ }
+ break;
+ case 1:
+ if (!state->m_mmc_latch1)
+ {
+ chr8(space->machine(), data, CHRROM);
+ }
+ break;
+ }
+ }
+}
+
+/*************************************************************
+
+ 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?
+static WRITE8_HANDLER( novel1_w )
+{
+ LOG_MMC(("novel1_w, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(space->machine(), offset & 0x03);
+ chr8(space->machine(), offset & 0x07, CHRROM);
+}
+
+static WRITE8_HANDLER( novel2_w )
+{
+ LOG_MMC(("novel2_w, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(space->machine(), offset >> 1);
+ chr8(space->machine(), offset >> 3, CHRROM);
+}
+
+/*************************************************************
+
+ Board BMC-GKA
+
+ Unknown Bootleg Multigame Board
+ Games: 6 in 1, 54 in 1, 106 in 1
+
+ iNES: mapper 57
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bmc_gka_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("bmc_gka_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset & 0x0800)
+ state->m_mmc_latch2 = data;
+ else
+ state->m_mmc_latch1 = data;
+
+ if (state->m_mmc_latch2 & 0x80)
+ prg32(space->machine(), 2 | (state->m_mmc_latch2 >> 6));
+ else
+ {
+ prg16_89ab(space->machine(), (state->m_mmc_latch2 >> 5) & 0x03);
+ prg16_cdef(space->machine(), (state->m_mmc_latch2 >> 5) & 0x03);
+ }
+
+ set_nt_mirroring(space->machine(), (state->m_mmc_latch2 & 0x08) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+
+ chr8(space->machine(), (state->m_mmc_latch1 & 0x03) | (state->m_mmc_latch2 & 0x07) | ((state->m_mmc_latch2 & 0x10) >> 1), 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).
+
+ *************************************************************/
+
+static WRITE8_HANDLER( sng32_w )
+{
+ LOG_MMC(("sng32_w, offset: %04x, data: %02x\n", offset, data));
+ prg32(space->machine(), data);
+}
+
+/*************************************************************
+
+ Board BMC-GKB
+
+ Unknown Bootleg Multigame Board
+ Games: 68 in 1, 73 in 1, 98 in 1
+
+ iNES: mapper 58
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bmc_gkb_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 bank = (offset & 0x40) ? 0 : 1;
+ LOG_MMC(("bmc_gkb_w, offset: %04x, data: %02x\n", offset, data));
+
+ prg16_89ab(space->machine(), offset & ~bank);
+ prg16_cdef(space->machine(), offset | bank);
+ chr8(space->machine(), offset >> 3, state->m_mmc_chr_source);
+ set_nt_mirroring(space->machine(), BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+}
+
+/*************************************************************
+
+ BMC-SUPER-700IN1
+
+ Unknown Bootleg Multigame Board
+ Games: Super 700 in 1
+
+ iNES: mapper 62
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bmc_super700in1_w )
+{
+ LOG_MMC(("bmc_super700in1_w, offset :%04x, data: %02x\n", offset, data));
+
+ chr8(space->machine(), ((offset & 0x1f) << 2) | (data & 0x03), CHRROM);
+
+ if (offset & 0x20)
+ {
+ prg16_89ab(space->machine(), (offset & 0x40) | ((offset >> 8) & 0x3f));
+ prg16_cdef(space->machine(), (offset & 0x40) | ((offset >> 8) & 0x3f));
+ }
+ else
+ {
+ prg32(space->machine(), ((offset & 0x40) | ((offset >> 8) & 0x3f)) >> 1);
+ }
+
+ set_nt_mirroring(space->machine(), BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+}
+
+/*************************************************************
+
+ BMC-36IN1
+
+ Unknown Bootleg Multigame Board
+ Games: 36 in 1, 1200 in 1
+
+ iNES: mapper 200
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bmc_36in1_w )
+{
+ LOG_MMC(("bmc_36in1_w, offset: %04x, data: %02x\n", offset, data));
+
+ prg16_89ab(space->machine(), offset & 0x07);
+ prg16_cdef(space->machine(), offset & 0x07);
+ chr8(space->machine(), offset & 0x07, CHRROM);
+
+ set_nt_mirroring(space->machine(), BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+}
+
+/*************************************************************
+
+ BMC-21IN1
+
+ Unknown Bootleg Multigame Board
+ Games: 8 in 1, 21 in 1
+
+ iNES: mapper 201
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bmc_21in1_w )
+{
+ LOG_MMC(("bmc_21in1_w, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(space->machine(), offset & 0x03);
+ chr8(space->machine(), offset & 0x03, CHRROM);
+}
+
+/*************************************************************
+
+ BMC-150IN1
+
+ Unknown Bootleg Multigame Board
+ Games: 150 in 1
+
+ iNES: mapper 202
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bmc_150in1_w )
+{
+ int bank = (offset >> 1) & 0x07;
+
+ LOG_MMC(("bmc_150in1_w, offset: %04x, data: %02x\n", offset, data));
+
+ prg16_89ab(space->machine(), bank);
+ prg16_cdef(space->machine(), bank + (((bank & 0x06) == 0x06) ? 1 : 0));
+ chr8(space->machine(), bank, CHRROM);
+
+ set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ: PPU_MIRROR_VERT);
+}
+
+/*************************************************************
+
+ BMC-35IN1
+
+ Unknown Bootleg Multigame Board
+ Games: 35 in 1
+
+ iNES: mapper 203
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bmc_35in1_w )
+{
+ LOG_MMC(("bmc_35in1_w, offset: %04x, data: %02x\n", offset, data));
+
+ prg16_89ab(space->machine(), (data >> 2) & 0x03);
+ prg16_cdef(space->machine(), (data >> 2) & 0x03);
+ chr8(space->machine(), data & 0x03, CHRROM);
+}
+
+/*************************************************************
+
+ BMC-64IN1
+
+ Unknown Bootleg Multigame Board
+ Games: 64 in 1
+
+ iNES: mapper 204
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bmc_64in1_w )
+{
+ int bank = (offset >> 1) & (offset >> 2) & 0x01;
+
+ LOG_MMC(("bmc_64in1_w, offset: %04x, data: %02x\n", offset, data));
+
+ prg16_89ab(space->machine(), offset & ~bank);
+ prg16_cdef(space->machine(), offset | bank);
+ chr8(space->machine(), offset & ~bank, CHRROM);
+
+ set_nt_mirroring(space->machine(), BIT(data, 4) ? PPU_MIRROR_HORZ: PPU_MIRROR_VERT);
+}
+
+/*************************************************************
+
+ BMC-15IN1
+
+ Unknown Bootleg Multigame Board
+ Games: 3 in 1, 15 in 1
+
+ iNES: mapper 205, MMC3 clone
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bmc_15in1_m_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("bmc_15in1_m_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset & 0x0800)
+ {
+ state->m_mmc_prg_base = (data & 0x03) << 4;
+ state->m_mmc_prg_mask = (data & 0x02) ? 0x0f : 0x1f;
+ state->m_mmc_chr_base = (data & 0x03) << 7;
+ state->m_mmc_chr_mask = (data & 0x02) ? 0x7f : 0xff;
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ }
+}
+
+/*************************************************************
+
+ 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.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bmc_hik300_w )
+{
+ LOG_MMC(("bmc_hik300_w, offset: %04x, data: %02x\n", offset, data));
+
+ set_nt_mirroring(space->machine(), BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ chr8(space->machine(), offset, CHRROM);
+
+ if (offset < 0x4000)
+ {
+ prg16_89ab(space->machine(), offset);
+ prg16_cdef(space->machine(), offset);
+ }
+ else
+ prg32(space->machine(), offset >> 1);
+}
+
+/*************************************************************
+
+ BMC-SUPERGUN-20IN1
+
+ Unknown Bootleg Multigame Board
+ Games: Super Gun 20 in 1
+
+ iNES: mapper 214
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( supergun20in1_w )
+{
+ LOG_MMC(("supergun20in1_w, offset: %04x, data: %02x\n", offset, data));
+
+ prg16_89ab(space->machine(), offset >> 2);
+ prg16_cdef(space->machine(), offset >> 2);
+ chr8(space->machine(), offset, CHRROM);
+}
+
+/*************************************************************
+
+ BMC-72IN1
+
+ Unknown Bootleg Multigame Board
+ Games: 72 in 1, 115 in 1 and other multigame carts
+
+ iNES: mapper 225
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bmc_72in1_w )
+{
+ int hi_bank;
+ int size_16;
+ int bank;
+
+ LOG_MMC(("bmc_72in1_w, offset: %04x, data: %02x\n", offset, data));
+
+ chr8(space->machine(), offset, CHRROM);
+ set_nt_mirroring(space->machine(), (offset & 0x2000) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+
+ hi_bank = offset & 0x40;
+ size_16 = offset & 0x1000;
+ bank = (offset & 0xf80) >> 7;
+ if (size_16)
+ {
+ bank <<= 1;
+ if (hi_bank)
+ bank ++;
+
+ prg16_89ab(space->machine(), bank);
+ prg16_cdef(space->machine(), bank);
+ }
+ else
+ prg32(space->machine(), 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?!?
+static WRITE8_HANDLER( bmc_76in1_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ int hi_bank;
+ int size_16;
+ int bank;
+
+ LOG_MMC(("bmc_76in1_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset & 0x01)
+ state->m_mmc_latch2 = data;
+ else
+ state->m_mmc_latch1 = data;
+
+ set_nt_mirroring(space->machine(), BIT(state->m_mmc_latch1, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+
+ hi_bank = state->m_mmc_latch1 & 0x01;
+ size_16 = state->m_mmc_latch1 & 0x20;
+ bank = ((state->m_mmc_latch1 & 0x1e) >> 1) | ((state->m_mmc_latch1 & 0x80) >> 3) | ((state->m_mmc_latch2 & 0x01) << 5);
+
+ if (size_16)
+ {
+ bank <<= 1;
+ if (hi_bank)
+ bank ++;
+
+ prg16_89ab(space->machine(), bank);
+ prg16_cdef(space->machine(), bank);
+ }
+ else
+ prg32(space->machine(), bank);
+}
+
+/*************************************************************
+
+ BMC-1200IN1
+
+ Unknown Bootleg Multigame Board
+ Games: 1200 in 1, 295 in 1, 76 in 1
+
+ iNES: mapper 227
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bmc_1200in1_w )
+{
+ int hi_bank;
+ int size_32;
+ int bank;
+
+ LOG_MMC(("bmc_1200in1_w, offset: %04x, data: %02x\n", offset, data));
+
+ hi_bank = offset & 0x04;
+ size_32 = offset & 0x01;
+ bank = ((offset & 0x78) >> 3) | ((offset & 0x0100) >> 4);
+ if (!size_32)
+ {
+ bank <<= 1;
+ if (hi_bank)
+ bank ++;
+
+ prg16_89ab(space->machine(), bank);
+ prg16_cdef(space->machine(), bank);
+ }
+ else
+ prg32(space->machine(), bank);
+
+ if (!(offset & 0x80))
+ {
+ if (offset & 0x200)
+ prg16_cdef(space->machine(), ((bank << 1) & 0x38) + 7);
+ else
+ prg16_cdef(space->machine(), ((bank << 1) & 0x38));
+ }
+
+ set_nt_mirroring(space->machine(), BIT(data, 1) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+}
+
+/*************************************************************
+
+ BMC-31IN1
+
+ Unknown Bootleg Multigame Board
+ Games: 31 in 1
+
+ iNES: mapper 229
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bmc_31in1_w )
+{
+ LOG_MMC(("bmc_31in1_w, offset: %04x, data: %02x\n", offset, data));
+
+ set_nt_mirroring(space->machine(), BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ chr8(space->machine(), offset, CHRROM);
+
+ if ((offset & 0x1e) == 0)
+ {
+ prg16_89ab(space->machine(), 0);
+ prg16_89ab(space->machine(), 1);
+ }
+ else
+ {
+ prg16_89ab(space->machine(), offset & 0x1f);
+ prg16_89ab(space->machine(), offset & 0x1f);
+ }
+}
+
+/*************************************************************
+
+ 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)
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bmc_22g_w )
+{
+ LOG_MMC(("bmc_22g_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (1) // this should flip at reset
+ {
+ prg16_89ab(space->machine(), data & 0x07);
+ }
+ else
+ {
+ if (data & 0x20)
+ {
+ prg16_89ab(space->machine(), (data & 0x1f) + 8);
+ prg16_cdef(space->machine(), (data & 0x1f) + 8);
+ }
+ else
+ {
+ prg16_89ab(space->machine(), (data & 0x1f) + 8);
+ prg16_cdef(space->machine(), (data & 0x1f) + 9);
+ }
+ set_nt_mirroring(space->machine(), BIT(data, 6) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ);
+ }
+}
+
+/*************************************************************
+
+ BMC-20IN1
+
+ Unknown Bootleg Multigame Board
+ Games: 20 in 1
+
+ iNES: mapper 231
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bmc_20in1_w )
+{
+ LOG_MMC(("bmc_20in1_w, offset: %04x, data: %02x\n", offset, data));
+
+ set_nt_mirroring(space->machine(), BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+
+ prg16_89ab(space->machine(), (offset & 0x1e));
+ prg16_cdef(space->machine(), (offset & 0x1e) | ((offset & 0x20) ? 1 : 0));
+}
+
+/*************************************************************
+
+ BMC-110IN1
+
+ Known Boards: Unknown Bootleg Board
+ Games: 110 in 1
+
+ iNES: mapper 255
+
+ In MESS: Preliminary support.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bmc_110in1_w )
+{
+ UINT8 map255_helper1 = (offset >> 12) ? 0 : 1;
+ UINT8 map255_helper2 = ((offset >> 8) & 0x40) | ((offset >> 6) & 0x3f);
+
+ LOG_MMC(("bmc_110in1_w, offset: %04x, data: %02x\n", offset, data));
+
+ set_nt_mirroring(space->machine(), (offset & 0x2000) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ prg16_89ab(space->machine(), map255_helper1 & ~map255_helper2);
+ prg16_cdef(space->machine(), map255_helper1 | map255_helper2);
+ chr8(space->machine(), ((offset >> 8) & 0x40) | (offset & 0x3f), CHRROM);
+}
+
+/*************************************************************
+
+ 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.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bmc_sbig7_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 page;
+ LOG_MMC(("bmc_sbig7_w, 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;
+
+ state->m_mmc_prg_base = page << 4;
+ state->m_mmc_prg_mask = (page > 5) ? 0x1f : 0x0f;
+ state->m_mmc_chr_base = page << 7;
+ state->m_mmc_chr_mask = (page > 5) ? 0xff : 0x7f;
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ break;
+
+ default:
+ txrom_w(space, offset, data);
+ 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.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bmc_hik8_m_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("bmc_hik8_m_w, 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 ((state->m_mmc_reg[3] & 0x40) && state->m_wram != NULL)
+ state->m_wram[offset] = data;
+ else
+ {
+ state->m_mmc_reg[state->m_mmc_count] = data;
+ state->m_mmc_count = (state->m_mmc_count + 1) & 0x03;
+
+ if (!state->m_mmc_count)
+ {
+ LOG_MMC(("bmc_hik8_m_w, command completed %02x %02x %02x %02x\n", state->m_mmc_reg[3],
+ state->m_mmc_reg[2], state->m_mmc_reg[1], state->m_mmc_reg[0]));
+
+ state->m_mmc_prg_base = state->m_mmc_reg[1];
+ state->m_mmc_prg_mask = 0x3f ^ (state->m_mmc_reg[3] & 0x3f);
+ state->m_mmc_chr_base = ((state->m_mmc_reg[2] & 0xf0) << 4) | state->m_mmc_reg[0];
+ if (BIT(state->m_mmc_reg[2], 3))
+ state->m_mmc_chr_mask = (1 << ((state->m_mmc_reg[2] & 7) + 1)) - 1;
+ else if (state->m_mmc_reg[2])
+ state->m_mmc_chr_mask = 0;
+ else
+ state->m_mmc_chr_mask = 0xff; // i.e. we use the vrom_bank with no masking
+
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_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.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bmc_hik4in1_m_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("bmc_hik4in1_m_w, offset: %04x, data: %02x\n", offset, data));
+
+ /* mid writes only work when WRAM is enabled. not sure if I should
+ change the condition to state->m_mmc_latch2==0x80 (i.e. what is the effect of
+ the read-only bit?) */
+ if (state->m_mmc3_wram_protect & 0x80)
+ {
+ if (data & 0x01) /* if this is 0, then we have 32k PRG blocks */
+ {
+ state->m_mmc_prg_base = (data & 0xc0) >> 2;
+ state->m_mmc_prg_mask = 0x0f;
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ }
+ else
+ prg32(space->machine(), (data & 0x30) >> 4);
+
+ state->m_mmc_chr_base = (data & 0xc0) << 1;
+ state->m_mmc_chr_mask = 0x7f;
+ mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ }
+}
+
+/*************************************************************
+
+ BMC-BALLGAMES-11IN1
+
+ Known Boards: Unknown Multigame Bootleg Board
+ Games: 11 in 1 Ball Games
+
+ iNES: mapper 51
+
+ In MESS: Partially Supported.
+
+ *************************************************************/
+
+static void bmc_ball11_set_banks( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ set_nt_mirroring(machine, (state->m_mmc_reg[0] == 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+
+ if (state->m_mmc_reg[0] & 0x01)
+ {
+ prg32(machine, state->m_mmc_reg[1]);
+ }
+ else
+ {
+ prg16_89ab(machine, (state->m_mmc_reg[1] << 1) | (state->m_mmc_reg[0] >> 1));
+ prg16_cdef(machine, (state->m_mmc_reg[1] << 1) | 0x07);
+ }
+}
+
+static WRITE8_HANDLER( bmc_ball11_m_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+
+ LOG_MMC(("bmc_ball11_m_w, offset: %04x, data: %02x\n", offset, data));
+
+ state->m_mmc_reg[0] = ((data >> 1) & 0x01) | ((data >> 3) & 0x02);
+ bmc_ball11_set_banks(space->machine());
+}
+
+static WRITE8_HANDLER( bmc_ball11_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+
+ LOG_MMC(("bmc_ball11_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6000)
+ {
+ case 0x4000: // here we also update reg[0] upper bit
+ state->m_mmc_reg[0] = (state->m_mmc_reg[0] & 0x01) | ((data >> 3) & 0x02);
+ case 0x0000:
+ case 0x2000:
+ case 0x6000:
+ state->m_mmc_reg[1] = data & 0x0f;
+ bmc_ball11_set_banks(space->machine());
+ break;
+ }
+}
+
+/*************************************************************
+
+ BMC-MARIOPARTY-7IN1
+
+ Known Boards: Unknown Multigame Bootleg Board
+ Games: Mario 7 in 1
+
+ MMC3 clone
+
+ iNES: mapper 52
+
+ In MESS: Supported.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bmc_mario7in1_m_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 map52_helper1, map52_helper2;
+ LOG_MMC(("bmc_mario7in1_m_w, offset: %04x, data: %02x\n", offset, data));
+
+ /* mid writes only work when WRAM is enabled. not sure if I should
+ change the condition to state->m_map52_reg_written == 0x80 (i.e. what is the effect of
+ the read-only bit?) and it only can happen once! */
+ if ((state->m_mmc3_wram_protect & 0x80) && !state->m_map52_reg_written)
+ {
+ map52_helper1 = (data & 0x08);
+ map52_helper2 = (data & 0x40);
+
+ state->m_mmc_prg_base = map52_helper1 ? ((data & 0x07) << 4) : ((data & 0x06) << 4);
+ state->m_mmc_prg_mask = map52_helper1 ? 0x0f : 0x1f;
+ state->m_mmc_chr_base = ((data & 0x20) << 4) | ((data & 0x04) << 6) | (map52_helper2 ? ((data & 0x10) << 3) : 0);
+ state->m_mmc_chr_mask = map52_helper2 ? 0x7f : 0xff;
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+
+ state->m_map52_reg_written = 1;
+ }
+ else
+ state->m_wram[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.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bmc_gold7in1_m_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 map52_helper1, map52_helper2;
+ LOG_MMC(("bmc_gold7in1_m_w, offset: %04x, data: %02x\n", offset, data));
+
+ if ((state->m_mmc3_wram_protect & 0x80) && !state->m_map52_reg_written)
+ {
+ map52_helper1 = (data & 0x08);
+ map52_helper2 = (data & 0x40);
+
+ state->m_mmc_prg_base = map52_helper1 ? ((data & 0x07) << 4) : ((data & 0x06) << 4);
+ state->m_mmc_prg_mask = map52_helper1 ? 0x0f : 0x1f;
+ state->m_mmc_chr_base = ((data & 0x20) << 3) | ((data & 0x04) << 7) | (map52_helper2 ? ((data & 0x10) << 3) : 0);
+ state->m_mmc_chr_mask = map52_helper2 ? 0x7f : 0xff;
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+
+ state->m_map52_reg_written = BIT(data, 7); // mc_2hikg & mc_s3nt3 write here multiple time
+ }
+ else
+ state->m_wram[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.
+
+ *************************************************************/
+
+// remove mask & base parameters!
+static void bmc_gc6in1_set_prg( running_machine &machine, int prg_base, int prg_mask )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ state->m_mmc_prg_base = (state->m_mmc_reg[1] & 0x08) ? 0 : (state->m_mmc_reg[1] & 0x10);
+ state->m_mmc_prg_mask = (state->m_mmc_reg[1] & 0x08) ? 0x1f : 0x0f;
+
+ state->m_mmc_prg_base |= ((state->m_mmc_reg[1] & 0x03) << 5);
+
+ mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask);
+}
+
+static void bmc_gc6in1_set_chr( running_machine &machine, UINT8 chr )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ UINT8 chr_page = (state->m_mmc_latch1 & 0x80) >> 5;
+ int chr_base = (state->m_mmc_reg[1] & 0x08) ? 0x00 : ((state->m_mmc_reg[1] & 0x10) << 3);
+ int chr_mask = (state->m_mmc_reg[1] & 0x08) ? 0xff : 0x7f;
+
+ chr_base |= ((state->m_mmc_reg[1] & 0x03) << 8);
+
+ chr1_x(machine, chr_page ^ 0, chr_base | ((state->m_mmc_vrom_bank[0] & ~0x01) & chr_mask), chr);
+ chr1_x(machine, chr_page ^ 1, chr_base | ((state->m_mmc_vrom_bank[0] | 0x01) & chr_mask), chr);
+ chr1_x(machine, chr_page ^ 2, chr_base | ((state->m_mmc_vrom_bank[1] & ~0x01) & chr_mask), chr);
+ chr1_x(machine, chr_page ^ 3, chr_base | ((state->m_mmc_vrom_bank[1] | 0x01) & chr_mask), chr);
+ chr1_x(machine, chr_page ^ 4, chr_base | (state->m_mmc_vrom_bank[2] & chr_mask), chr);
+ chr1_x(machine, chr_page ^ 5, chr_base | (state->m_mmc_vrom_bank[3] & chr_mask), chr);
+ chr1_x(machine, chr_page ^ 6, chr_base | (state->m_mmc_vrom_bank[4] & chr_mask), chr);
+ chr1_x(machine, chr_page ^ 7, chr_base | (state->m_mmc_vrom_bank[5] & chr_mask), chr);
+}
+
+static WRITE8_HANDLER( bmc_gc6in1_l_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 bank;
+ LOG_MMC(("bmc_gc6in1_l_w, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+
+ if (offset == 0x1000)
+ {
+ state->m_mmc_reg[0] = data;
+ if (data & 0x80)
+ {
+ bank = (data & 0x0f) | ((state->m_mmc_reg[1] & 0x03) << 4);
+ prg16_89ab(space->machine(), bank);
+ prg16_cdef(space->machine(), bank);
+ }
+ else
+ bmc_gc6in1_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ }
+ else if (offset == 0x1001)
+ {
+ state->m_mmc_reg[1] = data;
+ bmc_gc6in1_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ }
+ else if (offset == 0x1007)
+ {
+ state->m_mmc_reg[2] = data;
+ }
+}
+
+static WRITE8_HANDLER( bmc_gc6in1_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 mmc_helper, cmd;
+ static const UINT8 conv_table[8] = {0, 6, 3, 7, 5, 2, 4, 1};
+ LOG_MMC(("bmc_gc6in1_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (!state->m_mmc_reg[2]) // in this case we act like MMC3, only with alt prg/chr handlers
+ {
+ switch (offset & 0x6001)
+ {
+ case 0x0000:
+ mmc_helper = state->m_mmc3_latch ^ data;
+ state->m_mmc3_latch = data;
+
+ /* Has PRG Mode changed? */
+ if (mmc_helper & 0x40)
+ bmc_gc6in1_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+
+ /* Has CHR Mode changed? */
+ if (mmc_helper & 0x80)
+ bmc_gc6in1_set_chr(space->machine(), state->m_mmc_chr_source);
+ break;
+
+ case 0x0001:
+ cmd = state->m_mmc3_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:
+ state->m_mmc_vrom_bank[cmd] = data;
+ bmc_gc6in1_set_chr(space->machine(), state->m_mmc_chr_source);
+ break;
+ case 6:
+ case 7:
+ state->m_mmc_prg_bank[cmd - 6] = data;
+ bmc_gc6in1_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ break;
+ }
+ break;
+
+ default:
+ txrom_w(space, offset, data);
+ break;
+ }
+ }
+ else
+ {
+ switch (offset & 0x6001)
+ {
+ case 0x0000:
+ txrom_w(space, 0x4000, data);
+ break;
+
+ case 0x0001:
+ data = (data & 0xc0) | conv_table[data & 0x07];
+ mmc_helper = state->m_mmc3_latch ^ data;
+ state->m_mmc3_latch = data;
+
+ /* Has PRG Mode changed? */
+ if (mmc_helper & 0x40)
+ bmc_gc6in1_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+
+ /* Has CHR Mode changed? */
+ if (mmc_helper & 0x80)
+ bmc_gc6in1_set_chr(space->machine(), state->m_mmc_chr_source);
+
+ state->m_mmc_reg[3] = 1;
+ break;
+
+ case 0x2000:
+ cmd = state->m_mmc3_latch & 0x07;
+ if (state->m_mmc_reg[3])
+ {
+ state->m_mmc_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:
+ state->m_mmc_vrom_bank[cmd] = data;
+ bmc_gc6in1_set_chr(space->machine(), state->m_mmc_chr_source);
+ break;
+ case 6:
+ case 7:
+ state->m_mmc_prg_bank[cmd - 6] = data;
+ bmc_gc6in1_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ break;
+ }
+ }
+ break;
+
+
+ case 0x2001:
+ set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+
+ default:
+ txrom_w(space, offset, data);
+ break;
+ }
+ }
+}
+
+/*************************************************************
+
+ 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.
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bmc_family4646_m_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("bmc_family4646_m_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset == 0x01)
+ {
+ state->m_mmc_prg_base = (data & 0x02) << 4;
+ state->m_mmc_prg_mask = 0x1f;
+ state->m_mmc_chr_base = (data & 0x20) << 3;
+ state->m_mmc_chr_mask = 0xff;
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ }
+}
+
+/*************************************************************
+
+ BMC-VT5201
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bmc_vt5201_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("bmc_vt5201_w, offset: %04x, data: %02x\n", offset, data));
+
+ state->m_mmc_latch1 = 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(space->machine(), BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ if (BIT(offset, 7))
+ {
+ prg16_89ab(space->machine(), (offset >> 4) & 0x07);
+ prg16_cdef(space->machine(), (offset >> 4) & 0x07);
+ }
+ else
+ prg32(space->machine(), (offset >> 5) & 0x03);
+ chr8(space->machine(), offset, CHRROM);
+}
+
+static READ8_HANDLER( bmc_vt5201_r )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("bmc_vt5201_r, offset: %04x\n", offset));
+ // state->m_mmc_dipsetting = state->ioport("CARTDIPS")->read();
+
+ if (state->m_mmc_latch1)
+ return state->m_mmc_dipsetting; // cart mode, depending on the Dip Switches (always zero atm, given we have no way to add cart-based DIPs)
+ else
+ return mmc_hi_access_rom(space->machine(), offset);
+}
+
+/*************************************************************
+
+ BMC-BS-5
+
+ Games: a few 4 in 1 multicarts
+
+ *************************************************************/
+
+static void bmc_bs5_update_banks( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ prg8_89(machine, state->m_mmc_prg_bank[0]);
+ prg8_ab(machine, state->m_mmc_prg_bank[1]);
+ prg8_cd(machine, state->m_mmc_prg_bank[2]);
+ prg8_ef(machine, state->m_mmc_prg_bank[3]);
+ chr2_0(machine, state->m_mmc_vrom_bank[0], CHRROM);
+ chr2_2(machine, state->m_mmc_vrom_bank[1], CHRROM);
+ chr2_4(machine, state->m_mmc_vrom_bank[2], CHRROM);
+ chr2_6(machine, state->m_mmc_vrom_bank[3], CHRROM);
+}
+
+static WRITE8_HANDLER( bmc_bs5_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 bs5_helper = (offset & 0xc00) >> 10;
+ LOG_MMC(("bmc_bs5_w, offset: %04x, data: %02x\n", offset, data));
+// state->m_mmc_dipsetting = state->ioport("CARTDIPS")->read();
+
+ switch (offset & 0x7000)
+ {
+ case 0x0000:
+ state->m_mmc_vrom_bank[bs5_helper] = offset & 0x1f;
+ break;
+ case 0x2000:
+ if (BIT(offset, state->m_mmc_dipsetting + 4)) // mmc_dipsetting is always zero atm, given we have no way to add cart-based DIPs
+ state->m_mmc_prg_bank[bs5_helper] = offset & 0x0f;
+ break;
+ }
+ bmc_bs5_update_banks(space->machine());
+}
+
+/*************************************************************
+
+ BMC-810544-C-A1
+
+ Games: 200-in-1 Elfland
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bmc_810544_w )
+{
+ UINT8 bank = (offset >> 7);
+ LOG_MMC(("bmc_810544_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (!BIT(offset, 6))
+ {
+ prg16_89ab(space->machine(), (bank << 1) | BIT(offset, 5));
+ prg16_cdef(space->machine(), (bank << 1) | BIT(offset, 5));
+ }
+ else
+ prg32(space->machine(), bank);
+
+ set_nt_mirroring(space->machine(), BIT(offset, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+
+ chr8(space->machine(), offset & 0x0f, CHRROM);
+}
+
+/*************************************************************
+
+ BMC-NTD-03
+
+ *************************************************************/
+
+static WRITE8_HANDLER( bmc_ntd03_w )
+{
+ UINT8 pbank, cbank;
+ LOG_MMC(("bmc_ntd03_w, offset: %04x, data: %02x\n", offset, data));
+
+ pbank = (offset >> 10) & 0x1e;
+ cbank = ((offset & 0x300) >> 5) | (offset & 0x07);
+
+ if (BIT(offset, 7))
+ {
+ prg16_89ab(space->machine(), pbank | BIT(offset, 6));
+ prg16_cdef(space->machine(), pbank | BIT(offset, 6));
+ }
+ else
+ prg32(space->machine(), pbank >> 1);
+
+ set_nt_mirroring(space->machine(), BIT(offset, 10) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+
+ chr8(space->machine(), cbank, CHRROM);
+}
+
+/*************************************************************
+
+ BMC-GHOSTBUSTERS63IN1
+
+ in MESS: only preliminar support
+
+ *************************************************************/
+
+static void bmc_gb63_update( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ set_nt_mirroring(machine, BIT(state->m_mmc_reg[0], 6) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ);
+
+ if (BIT(state->m_mmc_reg[0], 5))
+ {
+ prg16_89ab(machine, state->m_mmc_reg[0] & 0x1f); // FIXME: here probably we could also have PRGRAM, depending on mmc_latch1!
+ prg16_cdef(machine, state->m_mmc_reg[0] & 0x1f); // FIXME: here probably we could also have PRGRAM, depending on mmc_latch1!
+ }
+ else
+ prg32(machine, (state->m_mmc_reg[0] & 0x1f) >> 1); // FIXME: here probably we could also have PRGRAM, depending on mmc_latch1!
+
+ if (BIT(state->m_mmc_reg[1], 2))
+ chr8(machine, 0, CHRRAM);
+// else
+// chr8(machine, 0, CHRROM);
+}
+
+static WRITE8_HANDLER( bmc_gb63_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("bmc_gb63_w, offset: %04x, data: %02x\n", offset, data));
+
+ state->m_mmc_reg[offset & 1] = data;
+ state->m_mmc_latch1 = BIT(state->m_mmc_reg[0], 7) | (BIT(state->m_mmc_reg[1], 0) << 1);
+
+}
+
+static READ8_HANDLER( bmc_gb63_r )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("bmc_gb63_r, offset: %04x\n", offset));
+ // state->m_mmc_dipsetting = state->ioport("CARTDIPS")->read();
+
+ if (state->m_mmc_latch1 == 1)
+ return 0xff; // open bus
+ else
+ return mmc_hi_access_rom(space->machine(), offset);
+}
+
+/*************************************************************
+
+ UNL-EDU2000
+
+ *************************************************************/
+
+static WRITE8_HANDLER( edu2k_w )
+{
+ LOG_MMC(("edu2k_w, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(space->machine(), data & 0x1f);
+ wram_bank(space->machine(), (data & 0xc0) >> 6, NES_WRAM);
+}
+
+/*************************************************************
+
+ UNL-H2288
+
+ *************************************************************/
+
+static void h2288_prg_cb( running_machine &machine, int start, int bank )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ if (!(state->m_mmc_reg[0] & 0x40))
+ prg8_x(machine, start, bank);
+}
+
+static WRITE8_HANDLER( h2288_l_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("h2288_l_w offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+
+ if (offset >= 0x1800)
+ {
+ state->m_mmc_reg[offset & 1] = data;
+ if (state->m_mmc_reg[0] & 0x40)
+ {
+ UINT8 helper1 = (state->m_mmc_reg[0] & 0x05) | ((state->m_mmc_reg[0] >> 2) & 0x0a);
+ UINT8 helper2 = BIT(state->m_mmc_reg[0], 1);
+ prg16_89ab(space->machine(), helper1 & ~helper2);
+ prg16_cdef(space->machine(), helper1 | helper2);
+ }
+ else
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ }
+}
+
+static READ8_HANDLER( h2288_l_r )
+{
+ LOG_MMC(("h2288_l_r 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;
+}
+
+static WRITE8_HANDLER( h2288_w )
+{
+ static const UINT8 conv_table[8] = {0, 3, 1, 5, 6, 7, 2, 4};
+ LOG_MMC(("h2288_w, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6001)
+ {
+ case 0x0000:
+ txrom_w(space, 0x0000, (data & 0xc0) | conv_table[data & 0x07]);
+ break;
+
+ default:
+ txrom_w(space, offset, data);
+ break;
+ }
+}
+
+/*************************************************************
+
+ UNL-SHJY3
+
+ *************************************************************/
+
+/* I think the IRQ should only get fired if enough CPU cycles have passed, but we don't implement (yet) this part */
+static void shjy3_irq( device_t *device, int scanline, int vblank, int blanked )
+{
+ nes_state *state = device->machine().driver_data<nes_state>();
+ if (state->m_IRQ_enable & 0x02)
+ {
+ if (state->m_IRQ_count == 0xff)
+ {
+ state->m_IRQ_count = state->m_IRQ_count_latch;
+ state->m_IRQ_enable = state->m_IRQ_enable | ((state->m_IRQ_enable & 0x01) << 1);
+ device_set_input_line(state->m_maincpu, M6502_IRQ_LINE, HOLD_LINE);
+ }
+ else
+ state->m_IRQ_count++;
+ }
+}
+
+static void shjy3_update( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ int i;
+
+ prg8_89(machine, state->m_mmc_prg_bank[0]);
+ prg8_ab(machine, state->m_mmc_prg_bank[1]);
+
+ for (i = 0; i < 8; i++)
+ {
+ UINT8 chr_bank = state->m_mmc_vrom_bank[i] | (state->m_mmc_extra_bank[i] << 4);
+ if (state->m_mmc_vrom_bank[i] == 0xc8)
+ {
+ state->m_mmc_latch1 = 0;
+ continue;
+ }
+ else if (state->m_mmc_vrom_bank[i] == 0x88)
+ {
+ state->m_mmc_latch1 = 1;
+ continue;
+ }
+ if ((state->m_mmc_vrom_bank[i] == 4 || state->m_mmc_vrom_bank[i] == 5) && !state->m_mmc_latch1)
+ chr1_x(machine, i, chr_bank & 1, CHRRAM);
+ else
+ chr1_x(machine, i, chr_bank, CHRROM);
+ }
+}
+
+static WRITE8_HANDLER( shjy3_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 mmc_helper, shift;
+ LOG_MMC(("shjy3_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset >= 0x3000 && offset <= 0x600c)
+ {
+ mmc_helper = ((offset & 8) | (offset >> 8)) >> 3;
+ mmc_helper += 2;
+ mmc_helper &= 7;
+ shift = offset & 4;
+
+ state->m_mmc_vrom_bank[mmc_helper] = (state->m_mmc_vrom_bank[mmc_helper] & (0xf0 >> shift)) | ((data & 0x0f) << shift);
+ if (shift)
+ state->m_mmc_extra_bank[mmc_helper] = data >> 4;
+ }
+ else
+ {
+ switch (offset)
+ {
+ case 0x0010:
+ state->m_mmc_prg_bank[0] = data;
+ break;
+ case 0x2010:
+ state->m_mmc_prg_bank[1] = data;
+ break;
+ case 0x1400:
+ switch (data & 0x03)
+ {
+ case 0: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break;
+ case 1: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break;
+ case 2: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break;
+ case 3: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break;
+ }
+ break;
+ case 0x7000:
+ state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0xf0) | (data & 0x0f);
+ break;
+ case 0x7004:
+ state->m_IRQ_count_latch = (state->m_IRQ_count_latch & 0x0f) | ((data & 0x0f) << 4);
+ break;
+ case 0x7008:
+ state->m_IRQ_enable = data & 0x03;
+ if (state->m_IRQ_enable & 0x02)
+ state->m_IRQ_count = state->m_IRQ_count_latch;
+ break;
+ }
+ }
+ shjy3_update(space->machine());
+}
+
+/*************************************************************
+
+ UNL-603-5052
+
+ MMC3 + protection access in 0x4020 - 0x7fff
+
+ in MESS: Partial support
+
+ *************************************************************/
+
+WRITE8_HANDLER( unl_6035052_extra_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("unl_6035052_extra_w, offset: %04x, data: %02x\n", offset, data));
+ state->m_mmc_latch1 = data & 0x03;
+ if (state->m_mmc_latch1 == 1)
+ state->m_mmc_latch1 = 2;
+}
+
+READ8_HANDLER( unl_6035052_extra_r )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("unl_6035052_extra_r, offset: %04x\n", offset));
+ return state->m_mmc_latch1;
+}
+
+
+/*************************************************************
+
+ BMC-POWERJOY
+
+ *************************************************************/
+
+static void pjoy84_prg_cb( running_machine &machine, int start, int bank )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ UINT8 flip = (state->m_mmc3_latch & 0x40) ? 2 : 0;
+
+ if (!(state->m_mmc_reg[3] & 0x03))
+ prg8_x(machine, start, bank);
+ else if (start == flip)
+ {
+ if ((state->m_mmc_reg[3] & 0x03) == 0x03)
+ prg32(machine, bank >> 2);
+ else
+ {
+ prg16_89ab(machine, bank >> 1);
+ prg16_cdef(machine, bank >> 1);
+ }
+ }
+}
+
+static void pjoy84_chr_cb( running_machine &machine, int start, int bank, int source )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ if (!(state->m_mmc_reg[3] & 0x10))
+ chr1_x(machine, start, bank, source);
+}
+
+INLINE void pjoy84_set_base_mask( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ state->m_mmc_prg_base = ((state->m_mmc_reg[0] & (0x06 | BIT(state->m_mmc_reg[0], 6))) << 4) |
+ (BIT(state->m_mmc_reg[0], 4) << 7);
+
+ state->m_mmc_chr_base = ((~state->m_mmc_reg[0] << 0) & 0x080 & state->m_mmc_reg[2]) |
+ ((state->m_mmc_reg[0] << 4) & 0x080 & state->m_mmc_reg[0]) |
+ ((state->m_mmc_reg[0] << 3) & 0x100) |
+ ((state->m_mmc_reg[0] << 5) & 0x200);
+
+ state->m_mmc_prg_mask = BIT(state->m_mmc_reg[0], 6) ? 0x0f : 0x1f;
+ state->m_mmc_chr_mask = BIT(state->m_mmc_reg[0], 7) ? 0x7f : 0xff;
+}
+
+static WRITE8_HANDLER( pjoy84_m_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("pjoy84_m_w offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x03)
+ {
+ case 0x00:
+ case 0x03:
+ if (state->m_mmc_reg[3] & 0x80)
+ return; // else we act as if offset & 3 = 1,2
+ case 0x01:
+ case 0x02:
+ state->m_mmc_reg[offset & 0x03] = data;
+ pjoy84_set_base_mask(space->machine());
+ if (state->m_mmc_reg[3] & 0x10)
+ chr8(space->machine(), (state->m_mmc_chr_base >> 3) | (state->m_mmc_reg[2] & 0x0f), state->m_mmc_chr_source);
+ else
+ mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ break;
+ }
+}
+
+/*************************************************************
+
+ SOMERI TEAM
+
+ iNES: mapper 116
+
+ Emulation note about regs in MESS: currently,
+ - state->m_mmc_cmd1 represent the board mode
+ - state->m_mmc_reg[n] for n=0,1,2,3 represent the MMC1 regs
+ - state->m_mmc_prg_bank[n] for n=0,...,3 represent the MMC3 PRG banks
+ - state->m_mmc_vrom_bank[n] for n=0,...,5 represent the MMC3 CHR banks
+ - state->m_mmc_prg_bank[n] for n=4,5 represent the VRC2 PRG banks
+ - state->m_mmc_vrom_bank[n] for n=6,...,13 represent the VRC2 CHR banks
+
+ In MESS: Preliminary support
+
+ *************************************************************/
+
+// MMC1 Mode emulation
+static void someri_mmc1_set_prg( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ UINT8 prg_mode = state->m_mmc_reg[0] & 0x0c;
+ UINT8 prg_offset = state->m_mmc_reg[1] & 0x10;
+
+ switch (prg_mode)
+ {
+ case 0x00:
+ case 0x04:
+ prg32(machine, (prg_offset + state->m_mmc_reg[3]) >> 1);
+ break;
+ case 0x08:
+ prg16_89ab(machine, prg_offset + 0);
+ prg16_cdef(machine, prg_offset + state->m_mmc_reg[3]);
+ break;
+ case 0x0c:
+ prg16_89ab(machine, prg_offset + state->m_mmc_reg[3]);
+ prg16_cdef(machine, prg_offset + 0x0f);
+ break;
+ }
+}
+
+static void someri_mmc1_set_chr( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ UINT8 chr_mode = BIT(state->m_mmc_reg[0], 4);
+
+ if (chr_mode)
+ {
+ chr4_0(machine, state->m_mmc_reg[1] & 0x1f, state->m_mmc_chr_source);
+ chr4_4(machine, state->m_mmc_reg[2] & 0x1f, state->m_mmc_chr_source);
+ }
+ else
+ chr8(machine, (state->m_mmc_reg[1] & 0x1f) >> 1, state->m_mmc_chr_source);
+}
+
+static WRITE8_HANDLER( someri_mmc1_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+
+ assert(state->m_mmc_cmd1 == 2);
+
+ if (data & 0x80)
+ {
+ state->m_mmc1_count = 0;
+ state->m_mmc1_latch = 0;
+
+ state->m_mmc_reg[0] |= 0x0c;
+ someri_mmc1_set_prg(space->machine());
+ return;
+ }
+
+ if (state->m_mmc1_count < 5)
+ {
+ if (state->m_mmc1_count == 0) state->m_mmc1_latch = 0;
+ state->m_mmc1_latch >>= 1;
+ state->m_mmc1_latch |= (data & 0x01) ? 0x10 : 0x00;
+ state->m_mmc1_count++;
+ }
+
+ if (state->m_mmc1_count == 5)
+ {
+ switch (offset & 0x6000)
+ {
+ case 0x0000:
+ state->m_mmc_reg[0] = state->m_mmc1_latch;
+ switch (state->m_mmc_reg[0] & 0x03)
+ {
+ case 0: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break;
+ case 1: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break;
+ case 2: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break;
+ case 3: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break;
+ }
+ someri_mmc1_set_chr(space->machine());
+ someri_mmc1_set_prg(space->machine());
+ break;
+ case 0x2000:
+ state->m_mmc_reg[1] = state->m_mmc1_latch;
+ someri_mmc1_set_chr(space->machine());
+ someri_mmc1_set_prg(space->machine());
+ break;
+ case 0x4000:
+ state->m_mmc_reg[2] = state->m_mmc1_latch;
+ someri_mmc1_set_chr(space->machine());
+ break;
+ case 0x6000:
+ state->m_mmc_reg[3] = state->m_mmc1_latch;
+ someri_mmc1_set_prg(space->machine());
+ break;
+ }
+
+ state->m_mmc1_count = 0;
+ }
+}
+
+// MMC3 Mode emulation
+static WRITE8_HANDLER( someri_mmc3_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 mmc_helper, cmd;
+
+ assert(state->m_mmc_cmd1 == 1);
+ switch (offset & 0x6001)
+ {
+ case 0x0000:
+ mmc_helper = state->m_mmc3_latch ^ data;
+ state->m_mmc3_latch = data;
+
+ if (mmc_helper & 0x40)
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+
+ if (mmc_helper & 0x80)
+ mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ break;
+
+ case 0x0001:
+ cmd = state->m_mmc3_latch & 0x07;
+ switch (cmd)
+ {
+ case 0: case 1:
+ case 2: case 3: case 4: case 5:
+ state->m_mmc_vrom_bank[cmd] = data;
+ mmc3_set_chr(space->machine(), state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ break;
+ case 6:
+ case 7:
+ state->m_mmc_prg_bank[cmd - 6] = data;
+ mmc3_set_prg(space->machine(), state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ break;
+ }
+ break;
+
+ case 0x2000:
+ set_nt_mirroring(space->machine(), BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+ case 0x2001: break;
+ case 0x4000: state->m_IRQ_count_latch = data; break;
+ case 0x4001: state->m_IRQ_count = 0; break;
+ case 0x6000: state->m_IRQ_enable = 0; break;
+ case 0x6001: state->m_IRQ_enable = 1; break;
+ }
+}
+
+// VRC2 Mode emulation
+static WRITE8_HANDLER( someri_vrc2_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ UINT8 bank, shift;
+
+ assert(state->m_mmc_cmd1 == 0);
+
+ if (offset < 0x1000)
+ {
+ state->m_mmc_prg_bank[4] = data;
+ prg8_89(space->machine(), state->m_mmc_prg_bank[4]);
+ }
+ else if (offset < 0x2000)
+ {
+ switch (data & 0x03)
+ {
+ case 0x00: set_nt_mirroring(space->machine(), PPU_MIRROR_VERT); break;
+ case 0x01: set_nt_mirroring(space->machine(), PPU_MIRROR_HORZ); break;
+ case 0x02: set_nt_mirroring(space->machine(), PPU_MIRROR_LOW); break;
+ case 0x03: set_nt_mirroring(space->machine(), PPU_MIRROR_HIGH); break;
+ }
+ }
+ else if (offset < 0x3000)
+ {
+ state->m_mmc_prg_bank[5] = data;
+ prg8_ab(space->machine(), state->m_mmc_prg_bank[5]);
+ }
+ else if (offset < 0x7000)
+ {
+ bank = ((offset & 0x7000) - 0x3000) / 0x0800 + BIT(offset, 1);
+ shift = BIT(offset, 2) * 4;
+ data = (data & 0x0f) << shift;
+ state->m_mmc_vrom_bank[6 + bank] = data | state->m_mmc_chr_base;
+ chr1_x(space->machine(), bank, state->m_mmc_vrom_bank[6 + bank], CHRROM);
+ }
+}
+
+static WRITE8_HANDLER( someri_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("someri_w mode %d, offset: %04x, data: %02x\n", state->m_mmc_cmd1, offset, data));
+
+ switch (state->m_mmc_cmd1)
+ {
+ case 0x00: someri_vrc2_w(space, offset, data); break;
+ case 0x01: someri_mmc3_w(space, offset, data); break;
+ case 0x02: someri_mmc1_w(space, offset, data); break;
+ }
+}
+
+static void someri_mode_update( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ int i;
+
+ switch (state->m_mmc_cmd1)
+ {
+ case 0x00:
+ prg8_89(machine, state->m_mmc_prg_bank[4]);
+ prg8_ab(machine, state->m_mmc_prg_bank[5]);
+ for (i = 0; i < 8; i++)
+ chr1_x(machine, i, state->m_mmc_vrom_bank[6 + i], CHRROM);
+ break;
+ case 0x01:
+ mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ mmc3_set_chr(machine, state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ break;
+ case 0x02:
+ someri_mmc1_set_prg(machine);
+ someri_mmc1_set_chr(machine);
+ break;
+ }
+}
+
+static WRITE8_HANDLER( someri_l_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("someri_l_w, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+
+ if (offset & 0x100)
+ {
+ state->m_mmc_cmd1 = data & 0x03;
+ state->m_mmc_chr_base = ((state->m_mmc_cmd1 & 0x04) << 6);
+ if (state->m_mmc_cmd1 != 1)
+ state->m_IRQ_enable = 0;
+ someri_mode_update(space->machine());
+ }
+}
+
+#ifdef UNUSED_FUNCTION
+/*************************************************************
+
+ FUJIYA Board - mapper 170 according to NEStopia
+
+ Which games are supposed to use this?
+
+ *************************************************************/
+
+static WRITE8_HANDLER( fujiya_m_w )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("fujiya_m_w, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x6000;
+
+ if (offset == 0x6502 || offset == 0x7000)
+ state->m_mmc_latch1 = (data & 0x40) << 1;
+}
+
+static READ8_HANDLER( fujiya_m_r )
+{
+ nes_state *state = space->machine().driver_data<nes_state>();
+ LOG_MMC(("fujiya_m_r, offset: %04x\n", offset));
+ offset += 0x6000;
+
+ if (offset == 0x7001 || offset == 0x7777)
+ return state->m_mmc_latch1 | ((offset >> 8) & 0x7f);
+
+ return 0;
+}
+#endif
+
+
+
+
+typedef void (*nes_ppu_latch)(device_t *device, offs_t offset);
+
+struct nes_memory_accessor
+{
+ write8_space_func write;
+ const char *write_name;
+ read8_space_func read;
+ const char *read_name;
+};
+
+typedef struct _nes_pcb_intf nes_pcb_intf;
+struct _nes_pcb_intf
+{
+ int mmc_pcb;
+ nes_memory_accessor mmc_l; /* $4100-$5fff read/write routines */
+ nes_memory_accessor mmc_m; /* $6000-$7fff read/write routines */
+ nes_memory_accessor mmc_h; /* $8000-$ffff read/write routines */
+ nes_ppu_latch mmc_ppu_latch;
+ ppu2c0x_scanline_cb mmc_scanline;
+ ppu2c0x_hblank_cb mmc_hblank;
+};
+
+#define NES_NOACCESS \
+{FUNC_NULL, FUNC_NULL}
+
+#define NES_READONLY(a) \
+{FUNC_NULL, FUNC(a)}
+
+#define NES_WRITEONLY(a) \
+{FUNC(a), FUNC_NULL}
+
+static WRITE8_HANDLER( dummy_l_w )
+{
+ logerror("write access, offset: %04x, data: %02x\n", offset + 0x4100, data);
+}
+
+static WRITE8_HANDLER( dummy_m_w )
+{
+ logerror("write access, offset: %04x, data: %02x\n", offset + 0x6000, data);
+}
+
+static WRITE8_HANDLER( dummy_w )
+{
+ logerror("write access, offset: %04x, data: %02x\n", offset + 0x8000, data);
+}
+
+static READ8_HANDLER( dummy_l_r )
+{
+ logerror("read access, offset: %04x\n", offset + 0x4100);
+ return 0x00;
+}
+
+static READ8_HANDLER( dummy_m_r )
+{
+ logerror("read access, offset: %04x\n", offset + 0x6000);
+ return 0x00;
+}
+
+static READ8_HANDLER( dummy_r )
+{
+ logerror("read access, offset: %04x\n", offset + 0x8000);
+ return 0x00;
+}
+
+static const nes_pcb_intf nes_intf_list[] =
+{
+ { STD_NROM, NES_NOACCESS, NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL },
+ { HVC_FAMBASIC, NES_NOACCESS, NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL },
+ { GG_NROM, NES_NOACCESS, NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL },
+ { STD_UXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(uxrom_w), NULL, NULL, NULL },
+ { STD_UN1ROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(un1rom_w), NULL, NULL, NULL },
+ { STD_CPROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(cprom_w), NULL, NULL, NULL },
+ { STD_CNROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(cnrom_w), NULL, NULL, NULL },
+ { BANDAI_PT554, NES_NOACCESS, NES_WRITEONLY(bandai_pt554_m_w), NES_WRITEONLY(cnrom_w), NULL, NULL, NULL },
+ { STD_AXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(axrom_w), NULL, NULL, NULL },
+ { STD_PXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(pxrom_w), mmc2_latch, NULL, NULL },
+ { STD_FXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(fxrom_w), mmc2_latch, NULL, NULL },
+ { STD_BXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bxrom_w), NULL, NULL, NULL },
+ { STD_GXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(gxrom_w), NULL, NULL, NULL },
+ { STD_MXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(gxrom_w), NULL, NULL, NULL },
+ { STD_NXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(ntbrom_w), NULL, NULL, NULL },
+ { SUNSOFT_DCS, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(ntbrom_w), NULL, NULL, NULL },
+ { STD_JXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(jxrom_w), NULL, NULL, jxrom_irq },
+ { STD_SXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(sxrom_w), NULL, NULL, NULL },
+ { STD_SOROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(sxrom_w), NULL, NULL, NULL },
+ { STD_SXROM_A, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(sxrom_w), NULL, NULL, NULL },
+ { STD_SOROM_A, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(sxrom_w), NULL, NULL, NULL },
+ { STD_TXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq },
+ { STD_TVROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq },
+ { STD_TKROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq },
+ { STD_HKROM, NES_NOACCESS, {FUNC(hkrom_m_w), FUNC(hkrom_m_r)}, NES_WRITEONLY(hkrom_w), NULL, NULL, mmc3_irq },
+ { STD_TQROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(tqrom_w), NULL, NULL, mmc3_irq },
+ { STD_TXSROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(txsrom_w), NULL, NULL, mmc3_irq },
+ { STD_DXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(dxrom_w), NULL, NULL, NULL },
+ { STD_DRROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(dxrom_w), NULL, NULL, NULL },
+ { NAMCOT_34X3, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(dxrom_w), NULL, NULL, NULL },
+ { NAMCOT_3425, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(namcot3425_w), NULL, NULL, NULL },
+ { NAMCOT_3446, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(namcot3446_w), NULL, NULL, NULL },
+ { NAMCOT_3453, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(namcot3453_w), NULL, NULL, NULL },
+ { STD_EXROM, {FUNC(exrom_l_w), FUNC(exrom_l_r)}, NES_NOACCESS, NES_NOACCESS, NULL, NULL, mmc5_irq },
+ { NES_QJ, NES_NOACCESS, NES_WRITEONLY(qj_m_w), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq },
+ { PAL_ZZ, NES_NOACCESS, NES_WRITEONLY(zz_m_w), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq },
+ { UXROM_CC, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(uxrom_cc_w), NULL, NULL, NULL },
+ //
+ { DIS_74X139X74, NES_NOACCESS, NES_WRITEONLY(dis_74x139x74_m_w), NES_NOACCESS, NULL, NULL, NULL },
+ { DIS_74X377, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(dis_74x377_w), NULL, NULL, NULL },
+ { DIS_74X161X161X32, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(dis_74x161x161x32_w), NULL, NULL, NULL },
+ { DIS_74X161X138, NES_NOACCESS, NES_WRITEONLY(dis_74x161x138_m_w), NES_NOACCESS, NULL, NULL, NULL },
+ { BANDAI_LZ93, NES_NOACCESS, NES_WRITEONLY(lz93d50_m_w), NES_WRITEONLY(lz93d50_w), NULL, NULL, bandai_lz_irq },
+ { BANDAI_LZ93EX, NES_NOACCESS, NES_WRITEONLY(lz93d50_m_w), NES_WRITEONLY(lz93d50_w), NULL, NULL, bandai_lz_irq },
+ { BANDAI_FCG, NES_NOACCESS, NES_WRITEONLY(lz93d50_m_w), NES_WRITEONLY(lz93d50_w), NULL, NULL, bandai_lz_irq },
+ { BANDAI_DATACH, NES_NOACCESS, NES_WRITEONLY(lz93d50_m_w), NES_WRITEONLY(lz93d50_w), NULL, NULL, bandai_lz_irq },
+ { BANDAI_JUMP2, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(fjump2_w), NULL, NULL, bandai_lz_irq },
+ { BANDAI_KARAOKE, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bandai_ks_w), NULL, NULL, NULL },
+ { BANDAI_OEKAKIDS, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bandai_ok_w), NULL, NULL, NULL },
+ { IREM_G101, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(g101_w), NULL, NULL, NULL },
+ { IREM_LROG017, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(lrog017_w), NULL, NULL, NULL },
+ { IREM_H3001, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(h3001_w), NULL, NULL, h3001_irq },
+ { IREM_TAM_S1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(tam_s1_w), NULL, NULL, NULL },
+ { IREM_HOLYDIV, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(irem_hd_w), NULL, NULL, NULL },
+ { JALECO_SS88006, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(ss88006_w), NULL, NULL, ss88006_irq },
+ { JALECO_JF11, NES_NOACCESS, NES_WRITEONLY(jf11_m_w), NES_NOACCESS, NULL, NULL, NULL },
+ { JALECO_JF13, NES_NOACCESS, NES_WRITEONLY(jf13_m_w), NES_NOACCESS, NULL, NULL, NULL },
+ { JALECO_JF16, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(jf16_w), NULL, NULL, NULL },
+ { JALECO_JF17, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(jf17_w), NULL, NULL, NULL },
+ { JALECO_JF19, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(jf19_w), NULL, NULL, NULL },
+ { KONAMI_VRC1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(konami_vrc1_w), NULL, NULL, NULL },
+ { KONAMI_VRC2, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(konami_vrc2_w), NULL, NULL, NULL },
+ { KONAMI_VRC3, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(konami_vrc3_w), NULL, NULL, konami_irq },
+ { KONAMI_VRC4, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(konami_vrc4_w), NULL, NULL, konami_irq },
+ { KONAMI_VRC6, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(konami_vrc6_w), NULL, NULL, konami_irq },
+ { KONAMI_VRC7, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(konami_vrc7_w), NULL, NULL, konami_irq },
+ { NAMCOT_163, {FUNC(namcot163_l_w), FUNC(namcot163_l_r) }, NES_NOACCESS, NES_WRITEONLY(namcot163_w), NULL, NULL, namcot_irq },
+ { SUNSOFT_1, NES_NOACCESS, NES_WRITEONLY(sunsoft1_m_w), NES_NOACCESS, NULL, NULL, NULL },
+ { SUNSOFT_2, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(sunsoft2_w), NULL, NULL, NULL },
+ { SUNSOFT_3, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(sunsoft3_w), NULL, NULL, sunsoft3_irq },
+ { TAITO_TC0190FMC, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(tc0190fmc_w), NULL, NULL, NULL },
+ { TAITO_TC0190FMCP, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(tc0190fmc_p16_w), NULL, NULL, mmc3_irq },
+ { TAITO_X1_005, NES_NOACCESS, {FUNC(x1005_m_w), FUNC(x1005_m_r)}, NES_NOACCESS, NULL, NULL, NULL },
+ { TAITO_X1_005_A, NES_NOACCESS, {FUNC(x1005a_m_w), FUNC(x1005_m_r)}, NES_NOACCESS, NULL, NULL, NULL },
+ { TAITO_X1_017, NES_NOACCESS, {FUNC(x1017_m_w), FUNC(x1017_m_r)}, NES_NOACCESS, NULL, NULL, NULL },
+ //
+ { AGCI_50282, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(agci_50282_w), NULL, NULL, NULL },
+ { ACTENT_ACT52, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(ae_act52_w), NULL, NULL, NULL },
+ { AVE_NINA01, NES_NOACCESS, NES_WRITEONLY(nina01_m_w), NES_NOACCESS, NULL, NULL, NULL },
+ { AVE_NINA06, NES_WRITEONLY(nina06_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL },
+ { CNE_DECATHLON, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(cne_decathl_w), NULL, NULL, NULL },
+ { CNE_FSB, NES_NOACCESS, NES_WRITEONLY(cne_fsb_m_w), NES_NOACCESS, NULL, NULL, NULL },
+ { CNE_SHLZ, NES_WRITEONLY(cne_shlz_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL },
+ { CALTRON_6IN1, NES_NOACCESS, NES_WRITEONLY(caltron6in1_m_w), NES_WRITEONLY(caltron6in1_w), NULL, NULL, NULL },
+ { CAMERICA_BF9093, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bf9093_w), NULL, NULL, NULL },
+ { CAMERICA_BF9097, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bf9093_w), NULL, NULL, NULL },
+ { CAMERICA_BF9096, NES_NOACCESS, NES_WRITEONLY(bf9096_w), NES_WRITEONLY(bf9096_w), NULL, NULL, NULL },
+ { CAMERICA_GOLDENFIVE, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(golden5_w), NULL, NULL, NULL },
+ { CONY_BOARD, {FUNC(cony_l_w), FUNC(cony_l_r)}, NES_NOACCESS, NES_WRITEONLY(cony_w), NULL, NULL, sunsoft3_irq },
+ { YOKO_BOARD, {FUNC(yoko_l_w), FUNC(yoko_l_r)}, NES_NOACCESS, NES_WRITEONLY(yoko_w), NULL, NULL, sunsoft3_irq },
+ { DREAMTECH_BOARD, NES_WRITEONLY(dreamtech_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL },
+ { FUTUREMEDIA_BOARD, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(futuremedia_w), NULL, NULL, futuremedia_irq },
+ { FUKUTAKE_BOARD, {FUNC(fukutake_l_w), FUNC(fukutake_l_r)}, NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL },
+ { GOUDER_37017, {FUNC(gouder_sf4_l_w), FUNC(gouder_sf4_l_r)}, NES_NOACCESS, NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq },
+ { HENGEDIANZI_BOARD, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(henggedianzi_w), NULL, NULL, NULL },
+ { HENGEDIANZI_XJZB, NES_WRITEONLY(heng_xjzb_l_w), NES_NOACCESS, NES_WRITEONLY(heng_xjzb_w), NULL, NULL, NULL },
+ { HES6IN1_BOARD, NES_WRITEONLY(hes6in1_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL },
+ { HES_BOARD, NES_WRITEONLY(hes_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL },
+ { HOSENKAN_BOARD, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(hosenkan_w), NULL, NULL, mmc3_irq },
+ { KAISER_KS7058, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(ks7058_w), NULL, NULL, NULL },
+ { KAISER_KS7022, NES_NOACCESS, NES_NOACCESS, {FUNC(ks7022_w), FUNC(ks7022_r)}, NULL, NULL, NULL },
+ { KAISER_KS7032, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(ks7032_w), NULL, NULL, ks7032_irq },
+ { KAISER_KS202, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(ks202_w), NULL, NULL, ks7032_irq },
+ { KAISER_KS7017, NES_WRITEONLY(ks7017_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, mmc_fds_irq },
+ { KAY_PANDAPRINCE, {FUNC(kay_pp_l_w), FUNC(kay_pp_l_r)}, NES_NOACCESS, NES_WRITEONLY(kay_pp_w), NULL, NULL, mmc3_irq },
+ { KASING_BOARD, NES_NOACCESS, NES_WRITEONLY(kasing_m_w), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq },
+ { SACHEN_74LS374, {FUNC(sachen_74x374_l_w), FUNC(sachen_74x374_l_r)}, NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL },
+ { SACHEN_74LS374_A, NES_WRITEONLY(sachen_74x374a_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL },
+ { SACHEN_8259A, NES_WRITEONLY(s8259_l_w), NES_WRITEONLY(s8259_m_w), NES_NOACCESS, NULL, NULL, NULL },
+ { SACHEN_8259B, NES_WRITEONLY(s8259_l_w), NES_WRITEONLY(s8259_m_w), NES_NOACCESS, NULL, NULL, NULL },
+ { SACHEN_8259C, NES_WRITEONLY(s8259_l_w), NES_WRITEONLY(s8259_m_w), NES_NOACCESS, NULL, NULL, NULL },
+ { SACHEN_8259D, NES_WRITEONLY(s8259_l_w), NES_WRITEONLY(s8259_m_w), NES_NOACCESS, NULL, NULL, NULL },
+ { SACHEN_SA009, NES_WRITEONLY(sa009_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL },
+ { SACHEN_SA0036, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(sa0036_w), NULL, NULL, NULL },
+ { SACHEN_SA0037, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(sa0037_w), NULL, NULL, NULL },
+ { SACHEN_SA72007, NES_WRITEONLY(sa72007_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL },
+ { SACHEN_SA72008, NES_WRITEONLY(sa72008_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL },
+ { SACHEN_TCA01, NES_READONLY(tca01_l_r), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL },
+ { SACHEN_TCU01, NES_WRITEONLY(tcu01_l_w), NES_WRITEONLY(tcu01_m_w), NES_WRITEONLY(tcu01_w), NULL, NULL, NULL },
+ { SACHEN_TCU02, {FUNC(tcu02_l_w), FUNC(tcu02_l_r)}, NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL },
+ { SUBOR_TYPE0, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(subor0_w), NULL, NULL, NULL },
+ { SUBOR_TYPE1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(subor1_w), NULL, NULL, NULL },
+ { MAGICSERIES_MD, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(magics_md_w), NULL, NULL, NULL },
+ { NANJING_BOARD, {FUNC(nanjing_l_w), FUNC(nanjing_l_r)}, NES_NOACCESS, NES_NOACCESS, NULL, NULL, nanjing_irq },
+ { NITRA_TDA, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nitra_w), NULL, NULL, mmc3_irq },
+ { NTDEC_ASDER, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(ntdec_asder_w), NULL, NULL, NULL },
+ { NTDEC_FIGHTINGHERO, NES_NOACCESS, NES_WRITEONLY(ntdec_fh_m_w), NES_NOACCESS, NULL, NULL, NULL },
+ { OPENCORP_DAOU306, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(daou306_w), NULL, NULL, NULL },
+ { RCM_GS2015, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(gs2015_w), NULL, NULL, NULL },
+ { RCM_TETRISFAMILY, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(rcm_tf_w), NULL, NULL, NULL },
+ { REXSOFT_DBZ5, {FUNC(rex_dbz_l_w), FUNC(rex_dbz_l_r)}, NES_READONLY(rex_dbz_l_r), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq },
+ { REXSOFT_SL1632, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(rex_sl1632_w), NULL, NULL, mmc3_irq },
+ { RUMBLESTATION_BOARD, NES_NOACCESS, NES_WRITEONLY(rumblestation_m_w), NES_WRITEONLY(rumblestation_w), NULL, NULL, NULL },
+ { SOMERI_SL12, NES_WRITEONLY(someri_l_w), NES_NOACCESS, NES_WRITEONLY(someri_w), NULL, NULL, mmc3_irq },
+ { SUPERGAME_BOOGERMAN, NES_WRITEONLY(sgame_boog_l_w), NES_WRITEONLY(sgame_boog_m_w), NES_WRITEONLY(sgame_boog_w), NULL, NULL, mmc3_irq },
+ { SUPERGAME_LIONKING, NES_NOACCESS, NES_WRITEONLY(sgame_lion_m_w), NES_WRITEONLY(sgame_lion_w), NULL, NULL, mmc3_irq },
+ { TENGEN_800008, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(tengen_800008_w), NULL, NULL, NULL },
+ { TENGEN_800032, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(tengen_800032_w), NULL, NULL, tengen_800032_irq },
+ { TENGEN_800037, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(tengen_800037_w), NULL, NULL, tengen_800032_irq },
+ { TXC_22211A, {FUNC(txc_22211_l_w), FUNC(txc_22211_l_r)}, NES_NOACCESS, NES_WRITEONLY(txc_22211_w), NULL, NULL, NULL },
+ { TXC_22211B, {FUNC(txc_22211_l_w), FUNC(txc_22211_l_r)}, NES_NOACCESS, NES_WRITEONLY(txc_22211b_w), NULL, NULL, NULL },
+ { TXC_22211C, {FUNC(txc_22211_l_w), FUNC(txc_22211c_l_r)}, NES_NOACCESS, NES_WRITEONLY(txc_22211_w), NULL, NULL, NULL },
+ { TXC_TW, NES_WRITEONLY(txc_tw_l_w), NES_WRITEONLY(txc_tw_m_w), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq },
+ { TXC_STRIKEWOLF, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(txc_strikewolf_w), NULL, NULL, NULL },
+ { TXC_MXMDHTWO, NES_READONLY(txc_mxmdhtwo_l_r), NES_NOACCESS, NES_WRITEONLY(txc_mxmdhtwo_w), NULL, NULL, NULL },
+ { WAIXING_TYPE_A, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_a_w), NULL, NULL, mmc3_irq },
+ { WAIXING_TYPE_A_1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_a_w), NULL, NULL, mmc3_irq },
+ { WAIXING_TYPE_B, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_a_w), NULL, NULL, mmc3_irq },
+ { WAIXING_TYPE_C, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_a_w), NULL, NULL, mmc3_irq },
+ { WAIXING_TYPE_D, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_a_w), NULL, NULL, mmc3_irq },
+ { WAIXING_TYPE_E, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_a_w), NULL, NULL, mmc3_irq },
+ { WAIXING_TYPE_F, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_f_w), NULL, NULL, mmc3_irq },
+ { WAIXING_TYPE_G, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_g_w), NULL, NULL, mmc3_irq },
+ { WAIXING_TYPE_H, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_h_w), NULL, NULL, mmc3_irq },
+ { WAIXING_TYPE_I, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, // this is MMC3 + possibly additional WRAM added in 0x5000-0x5fff
+ { WAIXING_TYPE_J, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, // this is MMC3 + possibly additional WRAM added in 0x5000-0x5fff
+ { WAIXING_SGZ, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_sgz_w), NULL, NULL, konami_irq },
+ { WAIXING_SGZLZ, NES_WRITEONLY(waixing_sgzlz_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL },
+ { WAIXING_FFV, NES_WRITEONLY(waixing_ffv_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL },
+ { WAIXING_ZS, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_zs_w), NULL, NULL, NULL },
+ { WAIXING_DQ8, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_dq8_w), NULL, NULL, NULL },
+ { WAIXING_SECURITY, NES_WRITEONLY(waixing_sec_l_w), NES_NOACCESS, NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq },
+ { WAIXING_SH2, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq }, // this is MMC3 + possibly additional WRAM added in 0x5000-0x5fff
+ { WAIXING_PS2, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(waixing_ps2_w), NULL, NULL, NULL },
+ { UNL_8237, NES_WRITEONLY(unl_8237_l_w), NES_NOACCESS, NES_WRITEONLY(unl_8237_w), NULL, NULL, mmc3_irq },
+ { UNL_AX5705, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(unl_ax5705_w), NULL, NULL, NULL },
+ { UNL_CC21, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(unl_cc21_w), NULL, NULL, NULL },
+ { UNL_KOF97, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(unl_kof97_w), NULL, NULL, mmc3_irq },
+ { UNL_KS7057, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(ks7057_w), NULL, NULL, mmc3_irq },
+ { UNL_T230, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(unl_t230_w), NULL, NULL, konami_irq },
+ { UNL_KOF96, {FUNC(kof96_l_w), FUNC(kof96_l_r)}, NES_NOACCESS, NES_WRITEONLY(kof96_w), NULL, NULL, mmc3_irq },
+ { UNL_MK2, NES_NOACCESS, NES_WRITEONLY(mk2_m_w), NES_NOACCESS, NULL, NULL, mmc3_irq },
+ { UNL_N625092, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(n625092_w), NULL, NULL, NULL },
+ { UNL_SC127, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(sc127_w), NULL, NULL, sc127_irq },
+ { UNL_SMB2J, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(smb2j_w), NULL, NULL, NULL },
+ { UNL_SUPERFIGHTER3, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(unl_sf3_w), NULL, NULL, mmc3_irq },
+ { UNL_XZY, NES_WRITEONLY(unl_xzy_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL },
+ { UNL_RACERMATE, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(unl_racmate_w), NULL, NULL, NULL },
+ { UNL_STUDYNGAME, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(sng32_w), NULL, NULL, NULL },
+ { UNL_603_5052, {FUNC(unl_6035052_extra_w), FUNC(unl_6035052_extra_r)}, {FUNC(unl_6035052_extra_w), FUNC(unl_6035052_extra_r)}, NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq },
+ { UNL_EDU2K, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(edu2k_w), NULL, NULL, NULL },
+ { UNL_SHJY3, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(shjy3_w), NULL, NULL, shjy3_irq },
+ { UNL_H2288, {FUNC(h2288_l_w), FUNC(h2288_l_r)}, NES_NOACCESS, NES_WRITEONLY(h2288_w), NULL, NULL, mmc3_irq },
+ { UNL_FS304, NES_WRITEONLY(unl_fs304_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL },
+ //
+ { BTL_AISENSHINICOL, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(btl_mariobaby_w), NULL, NULL, NULL },
+ { BTL_DRAGONNINJA, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(btl_dn_w), NULL, NULL, btl_dn_irq },
+ { BTL_MARIOBABY, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(btl_mariobaby_w), NULL, NULL, NULL },
+ { BTL_SMB2A, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(btl_smb2a_w), NULL, NULL, btl_smb2a_irq },
+ { BTL_SMB2B, NES_WRITEONLY(smb2jb_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, smb2jb_irq },
+ { BTL_SMB3, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(btl_smb3_w), NULL, NULL, btl_smb3_irq },
+ { BTL_SUPERBROS11, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(btl_smb11_w), NULL, NULL, mmc3_irq },
+ { BTL_TOBIDASE, NES_WRITEONLY(btl_tobi_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL },
+ { BTL_PIKACHUY2K, NES_NOACCESS, {FUNC(btl_pika_y2k_m_w), FUNC(btl_pika_y2k_m_r)}, NES_WRITEONLY(btl_pika_y2k_w), NULL, NULL, mmc3_irq },
+ { WHIRLWIND_2706, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(whirl2706_w), NULL, NULL, NULL },
+ //
+ { BMC_190IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_190in1_w), NULL, NULL, NULL },
+ { BMC_A65AS, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_a65as_w), NULL, NULL, NULL },
+ { BMC_GS2004, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_gs2004_w), NULL, NULL, NULL },
+ { BMC_GS2013, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_gs2013_w), NULL, NULL, NULL },
+ { BMC_NOVELDIAMOND, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(novel1_w), NULL, NULL, NULL },
+ { BMC_9999999IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(novel2_w), NULL, NULL, NULL },
+ { BMC_T262, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_t262_w), NULL, NULL, NULL },
+ { BMC_WS, NES_NOACCESS, NES_WRITEONLY(bmc_ws_m_w), NES_NOACCESS, NULL, NULL, NULL },
+ { BMC_GKA, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_gka_w), NULL, NULL, NULL },
+ { BMC_GKB, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_gkb_w), NULL, NULL, NULL },
+ { BMC_SUPER_700IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_super700in1_w), NULL, NULL, NULL },
+ { BMC_36IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_36in1_w), NULL, NULL, NULL },
+ { BMC_21IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_21in1_w), NULL, NULL, NULL },
+ { BMC_150IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_150in1_w), NULL, NULL, NULL },
+ { BMC_35IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_35in1_w), NULL, NULL, NULL },
+ { BMC_64IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_64in1_w), NULL, NULL, NULL },
+ { BMC_SUPERHIK_300IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_hik300_w), NULL, NULL, NULL },
+ { BMC_SUPERGUN_20IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(supergun20in1_w), NULL, NULL, NULL },
+ { BMC_72IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_72in1_w), NULL, NULL, NULL },
+ { BMC_76IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_76in1_w), NULL, NULL, NULL },
+ { BMC_SUPER_42IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_76in1_w), NULL, NULL, NULL },
+ { BMC_1200IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_1200in1_w), NULL, NULL, NULL },
+ { BMC_31IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_31in1_w), NULL, NULL, NULL },
+ { BMC_22GAMES, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_22g_w), NULL, NULL, NULL },
+ { BMC_20IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_20in1_w), NULL, NULL, NULL },
+ { BMC_110IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_110in1_w), NULL, NULL, NULL },
+ { BMC_64IN1NR, NES_WRITEONLY(bmc_64in1nr_l_w), NES_NOACCESS, NES_WRITEONLY(bmc_64in1nr_w), NULL, NULL, NULL },
+ { BMC_S24IN1SC03, NES_WRITEONLY(bmc_s24in1sc03_l_w), NES_NOACCESS, NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq },
+ { BMC_HIK8IN1, NES_NOACCESS, NES_WRITEONLY(bmc_hik8_m_w), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq },
+ { BMC_SUPERHIK_4IN1, NES_NOACCESS, NES_WRITEONLY(bmc_hik4in1_m_w), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq },
+ { BMC_SUPERBIG_7IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_sbig7_w), NULL, NULL, mmc3_irq },
+ { BMC_MARIOPARTY_7IN1, NES_NOACCESS, NES_WRITEONLY(bmc_mario7in1_m_w), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq },
+ { BMC_GOLD_7IN1, NES_NOACCESS, NES_WRITEONLY(bmc_gold7in1_m_w), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq },
+ { BMC_FAMILY_4646B, NES_NOACCESS, NES_WRITEONLY(bmc_family4646_m_w), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq },
+ { BMC_15IN1, NES_NOACCESS, NES_WRITEONLY(bmc_15in1_m_w), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq },
+ { BMC_BALLGAMES_11IN1, NES_NOACCESS, NES_WRITEONLY(bmc_ball11_m_w), NES_WRITEONLY(bmc_ball11_w), NULL, NULL, NULL },
+ { BMC_GOLDENCARD_6IN1, NES_WRITEONLY(bmc_gc6in1_l_w), NES_NOACCESS, NES_WRITEONLY(bmc_gc6in1_w), NULL, NULL, mmc3_irq },
+ { BMC_VT5201, NES_NOACCESS, NES_NOACCESS, {FUNC(bmc_vt5201_w), FUNC(bmc_vt5201_r)}, NULL, NULL, NULL },
+ { BMC_BENSHENG_BS5, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_bs5_w), NULL, NULL, NULL },
+ { BMC_810544, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_810544_w), NULL, NULL, NULL },
+ { BMC_NTD_03, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(bmc_ntd03_w), NULL, NULL, NULL },
+ { BMC_G63IN1, NES_NOACCESS, NES_NOACCESS, {FUNC(bmc_gb63_w), FUNC(bmc_gb63_r)}, NULL, NULL, NULL },
+ { BMC_FK23C, NES_WRITEONLY(fk23c_l_w), NES_NOACCESS, NES_WRITEONLY(fk23c_w), NULL, NULL, mmc3_irq },
+ { BMC_FK23CA, NES_WRITEONLY(fk23c_l_w), NES_NOACCESS, NES_WRITEONLY(fk23c_w), NULL, NULL, mmc3_irq },
+ { BMC_PJOY84, NES_NOACCESS, NES_WRITEONLY(pjoy84_m_w), NES_WRITEONLY(txrom_w), NULL, NULL, mmc3_irq },
+ //
+ { FFE_MAPPER6, NES_WRITEONLY(mapper6_l_w), NES_NOACCESS, NES_WRITEONLY(mapper6_w), NULL, NULL, ffe_irq },
+ { FFE_MAPPER8, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(mapper8_w), NULL, NULL, NULL },
+ { FFE_MAPPER17, NES_WRITEONLY(mapper17_l_w), NES_NOACCESS, NES_NOACCESS, NULL, NULL, ffe_irq },
+ // for debug and development
+ { UNKNOWN_BOARD, {FUNC(dummy_l_w), FUNC(dummy_l_r)}, {FUNC(dummy_m_w), FUNC(dummy_m_r)}, {FUNC(dummy_w), FUNC(dummy_r)}, NULL, NULL, NULL },
+ //
+ { UNSUPPORTED_BOARD, NES_NOACCESS, NES_NOACCESS, NES_NOACCESS, NULL, NULL, NULL },
+ //
+};
+
+const nes_pcb_intf *nes_pcb_intf_lookup( int pcb_id )
+{
+ int i;
+ for (i = 0; i < ARRAY_LENGTH(nes_intf_list); i++)
+ {
+ if (nes_intf_list[i].mmc_pcb == pcb_id)
+ return &nes_intf_list[i];
+ }
+ return NULL;
+}
+
+void pcb_handlers_setup( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ const nes_pcb_intf *intf = nes_pcb_intf_lookup(state->m_pcb_id);
+
+ if (intf == NULL)
+ fatalerror("Missing PCB interface\n");
+
+ if (intf)
+ {
+ state->m_mmc_write_low = intf->mmc_l.write;
+ state->m_mmc_write_low_name = intf->mmc_l.write_name;
+ state->m_mmc_write_mid = intf->mmc_m.write;
+ state->m_mmc_write_mid_name = intf->mmc_m.write_name;
+ state->m_mmc_write = intf->mmc_h.write;
+ state->m_mmc_write_name = intf->mmc_h.write_name;
+ state->m_mmc_read_low = intf->mmc_l.read;
+ state->m_mmc_read_low_name = intf->mmc_l.read_name;
+ state->m_mmc_read_mid = intf->mmc_m.read; // in progress
+ state->m_mmc_read_mid_name = intf->mmc_m.read_name;
+ state->m_mmc_read = intf->mmc_h.read; // in progress
+ state->m_mmc_read_name = intf->mmc_h.read_name;
+ state->m_ppu->set_latch(intf->mmc_ppu_latch);
+ }
+ else
+ {
+ logerror("PCB %d is not yet supported, defaulting to no mapper.\n", state->m_pcb_id);
+ state->m_mmc_write_low = NULL;
+ state->m_mmc_write_mid = NULL;
+ state->m_mmc_write = NULL;
+ state->m_mmc_read_low = NULL;
+ state->m_mmc_read_mid = NULL; // in progress
+ state->m_mmc_read = NULL; // in progress
+ state->m_ppu->set_latch(NULL);
+ }
+
+ state->m_mmc3_prg_cb = prg8_x;
+ state->m_mmc3_chr_cb = chr1_x;
+
+ switch (state->m_pcb_id)
+ {
+ case STD_TXSROM:
+ state->m_mmc3_chr_cb = txsrom_chr_cb;
+ break;
+ case GOUDER_37017:
+ state->m_mmc3_prg_cb = gouder_sf4_prg_cb;
+ break;
+ case KASING_BOARD:
+ state->m_mmc3_prg_cb = kasing_prg_cb;
+ break;
+ case REXSOFT_DBZ5:
+ state->m_mmc3_chr_cb = rex_dbz_chr_cb;
+ break;
+ case TXC_TW:
+ state->m_mmc3_prg_cb = txc_tw_prg_cb;
+ break;
+ case WAIXING_TYPE_A:
+ state->m_mmc3_chr_cb = waixing_a_chr_cb;
+ break;
+ case WAIXING_TYPE_A_1:
+ state->m_mmc3_chr_cb = waixing_a1_chr_cb;
+ break;
+ case WAIXING_TYPE_B:
+ state->m_mmc3_chr_cb = waixing_b_chr_cb;
+ break;
+ case WAIXING_TYPE_C:
+ state->m_mmc3_chr_cb = waixing_c_chr_cb;
+ break;
+ case WAIXING_TYPE_D:
+ state->m_mmc3_chr_cb = waixing_d_chr_cb;
+ break;
+ case WAIXING_TYPE_E:
+ state->m_mmc3_chr_cb = waixing_e_chr_cb;
+ break;
+ case WAIXING_TYPE_G:
+ state->m_mmc3_chr_cb = waixing_g_chr_cb;
+ break;
+ case WAIXING_TYPE_H:
+ state->m_mmc3_chr_cb = waixing_h_chr_cb;
+ break;
+ case WAIXING_SECURITY:
+ state->m_mmc3_prg_cb = waixing_sec_prg_cb;
+ state->m_mmc3_chr_cb = waixing_sec_chr_cb;
+ break;
+ case WAIXING_SH2:
+ state->m_mmc3_chr_cb = waixing_sh2_chr_cb;
+ break;
+ case UNL_8237:
+ state->m_mmc3_prg_cb = unl_8237_prg_cb;
+ state->m_mmc3_chr_cb = unl_8237_chr_cb;
+ break;
+ case UNL_H2288:
+ state->m_mmc3_prg_cb = h2288_prg_cb;
+ break;
+ case SUPERGAME_BOOGERMAN:
+ state->m_mmc3_prg_cb = sgame_boog_prg_cb;
+ state->m_mmc3_chr_cb = sgame_boog_chr_cb;
+ break;
+ case UNL_KOF96:
+ state->m_mmc3_prg_cb = kof96_prg_cb;
+ state->m_mmc3_chr_cb = kof96_chr_cb;
+ break;
+ case KAY_PANDAPRINCE:
+ state->m_mmc3_prg_cb = kay_pp_prg_cb;
+ state->m_mmc3_chr_cb = kay_pp_chr_cb;
+ break;
+ case BMC_FK23C:
+ case BMC_FK23CA:
+ state->m_mmc3_prg_cb = fk23c_prg_cb;
+ state->m_mmc3_chr_cb = fk23c_chr_cb;
+ break;
+ case BMC_S24IN1SC03:
+ state->m_mmc3_prg_cb = bmc_s24in1sc03_prg_cb;
+ state->m_mmc3_chr_cb = bmc_s24in1sc03_chr_cb;
+ break;
+ case BMC_PJOY84:
+ state->m_mmc3_prg_cb = pjoy84_prg_cb;
+ state->m_mmc3_chr_cb = pjoy84_chr_cb;
+ break;
+ }
+}
+
+/*************************************************************
+
+ pcb_initialize
+
+ Initialize all the necessary registers and quantities for
+ emulation of each board
+
+ *************************************************************/
+
+/* this is used by many boards (MMC3, MMC6 + most MMC3 pirate clone boards) */
+static void mmc3_common_initialize( running_machine &machine, int prg_mask, int chr_mask, int IRQ_type )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+
+ state->m_mmc3_alt_irq = IRQ_type; // later MMC3 boards seem to use MMC6-type IRQ... more investigations are in progress at NESDev...
+ state->m_mmc_prg_bank[0] = state->m_mmc_prg_bank[2] = 0xfe; // prg_bank[2] & prg_bank[3] remain always the same in most MMC3 variants
+ state->m_mmc_prg_bank[1] = state->m_mmc_prg_bank[3] = 0xff; // but some pirate clone mappers change them after writing certain registers
+ state->m_mmc3_latch = 0;
+ state->m_mmc3_wram_protect = 0x80;
+ state->m_mmc_prg_base = state->m_mmc_chr_base = 0;
+ state->m_mmc_prg_mask = prg_mask;
+ state->m_mmc_chr_mask = chr_mask;
+ mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ mmc3_set_chr(machine, state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+}
+
+// WIP code
+static int pcb_initialize( running_machine &machine, int idx )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ int err = 0, i;
+
+ /* basic PRG config */
+ prg32(machine, 0);
+
+ /* some boards will not use this, but directly CHRROM (resp. CHRRAM) if the board only has VROM (resp. VRAM) */
+ state->m_mmc_chr_source = state->m_chr_chunks ? CHRROM : CHRRAM;
+ chr8(machine, 0, state->m_mmc_chr_source);
+
+ /* Here, we init a few helpers: 4 prg banks and 16 chr banks - some mappers use them */
+ for (i = 0; i < 4; i++)
+ state->m_mmc_prg_bank[i] = 0;
+ for (i = 0; i < 16; i++)
+ state->m_mmc_vrom_bank[i] = 0;
+ for (i = 0; i < 16; i++)
+ state->m_mmc_extra_bank[i] = 0;
+
+ state->m_mmc_latch1 = 0;
+ state->m_mmc_latch2 = 0;
+
+ /* Finally, we init IRQ-related quantities. */
+ state->m_IRQ_enable = state->m_IRQ_enable_latch = 0;
+ state->m_IRQ_count = state->m_IRQ_count_latch = 0;
+ state->m_IRQ_toggle = 0;
+
+ switch (idx)
+ {
+ /* many boards only needs PRG to point at first 32k and CHR at first 8k */
+ case STD_NROM: // mapper 0
+ case HVC_FAMBASIC:
+ case GG_NROM:
+ case UXROM_CC: // mapper 180
+ case STD_CNROM: // mapper 3, 185
+ case BANDAI_PT554:
+ case TENGEN_800008:
+ case STD_BXROM: // mapper 34
+ case STD_GXROM: // mapper 66
+ case STD_MXROM:
+ case BANDAI_OEKAKIDS: // mapper 96
+ case JALECO_JF11: // mapper 140
+ case JALECO_JF13: // mapper 86
+ case JALECO_JF19: // mapper 92
+ case DIS_74X377: // mapper 11
+ case DIS_74X161X138: // mapper 38
+ case CALTRON_6IN1: // mapper 41
+ case TXC_STRIKEWOLF: // mapper 36
+ case UNL_STUDYNGAME: // mapper 39
+ case RUMBLESTATION_BOARD: // mapper 46
+ case BMC_GKB: // mapper 58
+ case RCM_TETRISFAMILY: // mapper 61
+ case BMC_SUPER_700IN1: // mapper 62
+ case MAGICSERIES_MD: // mapper 107
+ case HES_BOARD: // mapper 113
+ case HES6IN1_BOARD: // mapper 113
+ case SACHEN_SA72008: // mapper 133
+ case SACHEN_TCU02: // mapper 136
+ case SACHEN_SA72007: // mapper 145
+ case SACHEN_TCU01: // mapper 147
+ case SACHEN_SA009: // mapper 160
+ case SACHEN_SA0037: // mapper 148
+ case SACHEN_SA0036: // mapper 149
+ case AGCI_50282: // mapper 144
+ case KAISER_KS7058: // mapper 171
+ case HENGEDIANZI_BOARD: // mapper 177
+ case WAIXING_SGZLZ: // mapper 178
+ case HENGEDIANZI_XJZB: // mapper 179
+ case BMC_21IN1: // mapper 201
+ case BMC_9999999IN1: // mapper 213
+ case RCM_GS2015: // mapper 216
+ case BMC_72IN1: // mapper 225
+ case BMC_76IN1: // mapper 226
+ case BMC_SUPER_42IN1: // mapper 226
+ case ACTENT_ACT52: // mapper 228
+ case CNE_SHLZ: // mapper 240
+ case TXC_MXMDHTWO: // mapper 241
+ case WAIXING_ZS: // mapper 242
+ case WAIXING_DQ8: // mapper 242
+ case CNE_DECATHLON: // mapper 244
+ case UNL_CC21:
+ case BMC_VT5201:
+ case BMC_WS:
+ case UNL_EDU2K:
+ break;
+
+ /* other boards need additional initialization */
+ case STD_UXROM: // mapper 2
+ case STD_UN1ROM: // mapper 94
+ case STD_JXROM: // mapper 69
+ case SUNSOFT_5B:
+ case SUNSOFT_FME7:
+ case NAMCOT_3425: // mapper 95
+ case DIS_74X139X74: // mapper 87
+ case DIS_74X161X161X32: // mapper 152 & 70
+ case BANDAI_LZ93: // mapper 16, 157
+ case BANDAI_LZ93EX: // same + EEPROM
+ case BANDAI_DATACH:
+ case BANDAI_FCG:
+ case IREM_HOLYDIV: // mapper 78
+ case IREM_G101: // mapper 32
+ case IREM_H3001: // mapper 65
+ case JALECO_SS88006: // mapper 18
+ case JALECO_JF16: // mapper 78
+ case JALECO_JF17: // mapper 72
+ case KONAMI_VRC1: // mapper 75
+ case KONAMI_VRC2:
+ case KONAMI_VRC3: // mapper 73
+ case KONAMI_VRC4:
+ case KONAMI_VRC6:
+ case SUNSOFT_3: // mapper 67
+ case TAITO_TC0190FMC: // mapper 33
+ case TAITO_TC0190FMCP: // mapper 48
+ case TAITO_X1_005: // mapper 80
+ case TAITO_X1_005_A: // mapper 207
+ case TAITO_X1_017: // mapper 82
+ case NTDEC_ASDER: // mapper 112
+ case FUTUREMEDIA_BOARD: // mapper 117
+ case BTL_DRAGONNINJA: // mapper 222
+ case WAIXING_SGZ: // mapper 252
+ case UNL_T230:
+ case BMC_NTD_03:
+ case KAISER_KS7022:
+ case UNL_SHJY3:
+ case KAISER_KS7017:
+ case KAISER_KS7032:
+ case KAISER_KS202:
+ prg16_89ab(machine, 0);
+ prg16_cdef(machine, state->m_prg_chunks - 1);
+ break;
+
+ case STD_CPROM: // mapper 13
+ chr4_0(machine, 0, CHRRAM);
+ chr4_4(machine, 0, CHRRAM);
+ break;
+ case STD_AXROM: // mapper 7
+ set_nt_mirroring(machine, PPU_MIRROR_LOW);
+ break;
+ case STD_SXROM: // mapper 1, 155
+ case STD_SOROM:
+ case STD_SXROM_A:
+ case STD_SOROM_A:
+ state->m_mmc1_latch = 0;
+ state->m_mmc1_count = 0;
+ state->m_mmc_reg[0] = 0x0f;
+ state->m_mmc_reg[1] = state->m_mmc_reg[2] = state->m_mmc_reg[3] = 0;
+ state->m_mmc1_reg_write_enable = 1;
+ set_nt_mirroring(machine, PPU_MIRROR_HORZ);
+ mmc1_set_chr(machine);
+ mmc1_set_prg(machine);
+ if (state->m_battery || state->m_wram)
+ wram_bank(machine, 0, (idx == STD_SOROM) ? NES_WRAM : NES_BATTERY);
+ break;
+ case STD_PXROM: // mapper 9
+ state->m_mmc_reg[0] = state->m_mmc_reg[2] = 0;
+ state->m_mmc_reg[1] = state->m_mmc_reg[3] = 0;
+ state->m_mmc_latch1 = state->m_mmc_latch2 = 0xfe;
+ prg8_89(machine, 0);
+ prg8_ab(machine, (state->m_prg_chunks << 1) - 3);
+ prg8_cd(machine, (state->m_prg_chunks << 1) - 2);
+ prg8_ef(machine, (state->m_prg_chunks << 1) - 1);
+ break;
+ case STD_FXROM: // mapper 10
+ state->m_mmc_reg[0] = state->m_mmc_reg[2] = 0;
+ state->m_mmc_reg[1] = state->m_mmc_reg[3] = 0;
+ state->m_mmc_latch1 = state->m_mmc_latch2 = 0xfe;
+ prg16_89ab(machine, 0);
+ prg16_cdef(machine, state->m_prg_chunks - 1);
+ break;
+ case STD_TXROM: // mapper 4
+ case STD_TVROM:
+ case STD_TKROM:
+ case REXSOFT_DBZ5: // mapper 12
+ case WAIXING_TYPE_A: // mapper 74
+ case WAIXING_TYPE_A_1:
+ case STD_TXSROM: // mapper 118
+ case STD_TQROM: // mapper 119
+ case WAIXING_SH2: // mapper 165
+ case WAIXING_TYPE_B: // mapper 191
+ case WAIXING_TYPE_C: // mapper 192
+ case WAIXING_TYPE_D: // mapper 194
+ case WAIXING_TYPE_E: // mapper 195
+ case WAIXING_TYPE_H: // mapper 245
+ case BTL_SUPERBROS11: // mapper 196
+ case UNL_KS7057: // mapper 196 alt (for Street Fighter VI / Fight Street VI)
+ case UNL_H2288: // mapper 123
+ case UNL_KOF97:
+ case UNL_603_5052:
+ case NITRA_TDA: // mapper 250
+ if (state->m_four_screen_vram) // only TXROM and DXROM have 4-screen mirroring
+ {
+ set_nt_page(machine, 0, CART_NTRAM, 0, 1);
+ set_nt_page(machine, 1, CART_NTRAM, 1, 1);
+ set_nt_page(machine, 2, CART_NTRAM, 2, 1);
+ set_nt_page(machine, 3, CART_NTRAM, 3, 1);
+ }
+ mmc3_common_initialize(machine, 0xff, 0xff, 0);
+ break;
+ case STD_HKROM: // MMC6 (basically the same as TxROM, but alt IRQ behaviour)
+ mmc3_common_initialize(machine, 0xff, 0xff, 1);
+ state->m_mmc6_reg = 0xf0;
+ state->m_mmc_latch2 = 0; // this is used differently here compared to MMC3
+ break;
+ case PAL_ZZ: // mapper 37
+ mmc3_common_initialize(machine, 0x07, 0x7f, 0);
+ break;
+ case NES_QJ: // mapper 47
+ mmc3_common_initialize(machine, 0x0f, 0x7f, 0);
+ break;
+ case STD_EXROM: // mapper 5
+ state->m_MMC5_rom_bank_mode = 3;
+ state->m_MMC5_vrom_bank_mode = 0;
+ state->m_MMC5_vram_protect = 0;
+ state->m_mmc5_high_chr = 0;
+ state->m_mmc5_vram_control = 0;
+ state->m_mmc5_split_scr = 0;
+ memset(state->m_MMC5_vrom_bank, 0, ARRAY_LENGTH(state->m_MMC5_vrom_bank));
+ state->m_mmc5_prg_mode = 3;
+ state->m_mmc5_last_chr_a = 1;
+ state->m_mmc5_prg_regs[0] = 0xfc;
+ state->m_mmc5_prg_regs[1] = 0xfd;
+ state->m_mmc5_prg_regs[2] = 0xfe;
+ state->m_mmc5_prg_regs[3] = 0xff;
+ memset(state->m_mmc5_vrom_regA, ~0, ARRAY_LENGTH(state->m_mmc5_vrom_regA));
+ memset(state->m_mmc5_vrom_regB, ~0, ARRAY_LENGTH(state->m_mmc5_vrom_regB));
+ prg16_89ab(machine, state->m_prg_chunks - 2);
+ prg16_cdef(machine, state->m_prg_chunks - 1);
+ break;
+ case STD_NXROM: // mapper 68
+ case SUNSOFT_DCS: // mapper 68
+ state->m_mmc_reg[0] = 0;
+ prg16_89ab(machine, 0);
+ prg16_cdef(machine, state->m_prg_chunks - 1);
+ break;
+ case NAMCOT_34X3: // mapper 88
+ case STD_DXROM: // mapper 206
+ case STD_DRROM:
+ if (state->m_four_screen_vram) // only TXROM and DXROM have 4-screen mirroring
+ {
+ set_nt_page(machine, 0, CART_NTRAM, 0, 1);
+ set_nt_page(machine, 1, CART_NTRAM, 1, 1);
+ set_nt_page(machine, 2, CART_NTRAM, 2, 1);
+ set_nt_page(machine, 3, CART_NTRAM, 3, 1);
+ }
+ case NAMCOT_3453: // mapper 154
+ prg16_89ab(machine, state->m_prg_chunks - 2);
+ prg16_cdef(machine, state->m_prg_chunks - 1);
+ break;
+ case NAMCOT_3446: // mapper 76
+ prg8_89(machine, 0);
+ prg8_ab(machine, 1);
+ prg16_cdef(machine, state->m_prg_chunks - 1);
+ chr2_0(machine, 0, CHRROM);
+ chr2_2(machine, 1, CHRROM);
+ chr2_4(machine, 2, CHRROM);
+ chr2_6(machine, 3, CHRROM);
+ break;
+ case BANDAI_JUMP2: // mapper 153
+ for (i = 0; i < 8; i++)
+ state->m_mmc_reg[i] = 0;
+ prg16_89ab(machine, 0);
+ prg16_cdef(machine, state->m_prg_chunks - 1);
+ fjump2_set_prg(machine);
+ break;
+ case BANDAI_KARAOKE: // mapper 188
+ prg16_89ab(machine, 0);
+ prg16_cdef(machine, (state->m_prg_chunks - 1) ^ 0x08);
+ break;
+ case IREM_LROG017: // mapper 77
+ chr2_2(machine, 0, CHRROM);
+ chr2_4(machine, 1, CHRROM);
+ chr2_6(machine, 2, CHRROM);
+ break;
+ case IREM_TAM_S1: // mapper 97
+ prg16_89ab(machine, state->m_prg_chunks - 1);
+ prg16_cdef(machine, 0);
+ break;
+ case KONAMI_VRC7: // mapper 85
+ prg8_89(machine, 0);
+ prg8_ab(machine, 0);
+ prg8_cd(machine, 0);
+ prg8_ef(machine, 0xff);
+ break;
+ case NAMCOT_163: // mapper 19
+ prg16_89ab(machine, 0);
+ prg16_cdef(machine, state->m_prg_chunks - 1);
+ set_nt_mirroring(machine, PPU_MIRROR_VERT);
+ break;
+ case SUNSOFT_1: // mapper 184
+ case SUNSOFT_2: // mapper 89 & 93
+ prg16_89ab(machine, 0);
+ prg16_cdef(machine, state->m_prg_chunks - 1);
+ if (!state->m_hard_mirroring)
+ set_nt_mirroring(machine, PPU_MIRROR_LOW);
+ break;
+
+ // mapper 14
+ case REXSOFT_SL1632:
+ state->m_mmc_extra_bank[2] = 0xfe;
+ state->m_mmc_extra_bank[3] = 0xff;
+ state->m_mmc_extra_bank[0] = state->m_mmc_extra_bank[1] = state->m_mmc_extra_bank[4] = state->m_mmc_extra_bank[5] = state->m_mmc_extra_bank[6] = 0;
+ state->m_mmc_extra_bank[7] = state->m_mmc_extra_bank[8] = state->m_mmc_extra_bank[9] = state->m_mmc_extra_bank[0xa] = state->m_mmc_extra_bank[0xb] = 0;
+ state->m_mmc_reg[0] = state->m_mmc_reg[1] = 0;
+ mmc3_common_initialize(machine, 0xff, 0xff, 0);
+ break;
+ // mapper 15
+ case WAIXING_PS2:
+ set_nt_mirroring(machine, PPU_MIRROR_VERT);
+ break;
+
+ // mapper 35
+ case UNL_SC127:
+ // mapper 42
+ case BTL_MARIOBABY:
+ case BTL_AISENSHINICOL:
+ prg32(machine, 0xff);
+ break;
+
+ // mapper 40
+ case BTL_SMB2A:
+ prg8_67(machine, 0xfe);
+ prg8_89(machine, 0xfc);
+ prg8_ab(machine, 0xfd);
+ prg8_cd(machine, 0xfe);
+ prg8_ef(machine, 0xff);
+ break;
+
+ // mapper 43
+ case UNL_SMB2J:
+ if (state->m_battery)
+ memset(state->m_battery_ram, 0x2000, 0xff);
+ else if (state->m_prg_ram)
+ memset(state->m_wram, 0x2000, 0xff);
+ break;
+ // mapper 44
+ case BMC_SUPERBIG_7IN1:
+ // mapper 49
+ case BMC_SUPERHIK_4IN1:
+ mmc3_common_initialize(machine, 0x0f, 0x7f, 0);
+ break;
+ // mapper 45
+ case BMC_HIK8IN1:
+ state->m_mmc_reg[0] = state->m_mmc_reg[1] = state->m_mmc_reg[2] = state->m_mmc_reg[3] = 0;
+ mmc3_common_initialize(machine, 0x3f, 0xff, 0);
+ break;
+
+ // mapper 50
+ case BTL_SMB2B:
+ prg8_67(machine, 0x0f);
+ prg8_89(machine, 0x08);
+ prg8_ab(machine, 0x09);
+ prg8_cd(machine, 0);
+ prg8_ef(machine, 0x0b);
+ break;
+ // mapper 51
+ case BMC_BALLGAMES_11IN1:
+ state->m_mmc_reg[0] = 0x01;
+ state->m_mmc_reg[1] = 0x00;
+ bmc_ball11_set_banks(machine);
+ break;
+ // mapper 52
+ case BMC_MARIOPARTY_7IN1:
+ case BMC_GOLD_7IN1:
+ state->m_map52_reg_written = 0;
+ mmc3_common_initialize(machine, 0x1f, 0xff, 0);
+ break;
+ // mapper 54
+ case BMC_NOVELDIAMOND:
+ set_nt_mirroring(machine, PPU_MIRROR_VERT);
+ break;
+ // mapper 57
+ case BMC_GKA:
+ prg16_89ab(machine, 0);
+ prg16_cdef(machine, 0);
+ break;
+
+ // mapper 64
+ case TENGEN_800032:
+ // mapper 158
+ case TENGEN_800037:
+ prg16_89ab(machine, state->m_prg_chunks - 1);
+ prg16_cdef(machine, state->m_prg_chunks - 1);
+ break;
+ // mapper 71
+ case CAMERICA_BF9097:
+ set_nt_mirroring(machine, PPU_MIRROR_HORZ);
+ case CAMERICA_BF9093:
+ prg32(machine, 0xff);
+ break;
+
+ // mapper 79 (& 146)
+ case AVE_NINA06:
+ set_nt_mirroring(machine, PPU_MIRROR_HORZ);
+ break;
+
+ // mapper 83
+ case CONY_BOARD:
+ case YOKO_BOARD:
+ state->m_mapper83_reg[9] = 0x0f;
+ prg8_cd(machine, 0x1e);
+ prg8_ef(machine, 0x1f);
+ break;
+
+ // mapper 91
+ case UNL_MK2:
+ set_nt_mirroring(machine, PPU_MIRROR_VERT);
+ prg16_89ab(machine, state->m_prg_chunks - 1);
+ prg16_cdef(machine, state->m_prg_chunks - 1);
+ break;
+
+ // mapper 104
+ case CAMERICA_GOLDENFIVE:
+ prg16_89ab(machine, 0x00);
+ prg16_cdef(machine, 0x0f);
+ break;
+ // mapper 106
+ case BTL_SMB3:
+ prg8_89(machine, (state->m_prg_chunks << 1) - 1);
+ prg8_ab(machine, 0);
+ prg8_cd(machine, 0);
+ prg8_ef(machine, (state->m_prg_chunks << 1) - 1);
+ break;
+
+ // mapper 108
+ case WHIRLWIND_2706:
+ prg32(machine, 0xff);
+ break;
+
+ // mapper 114
+ case SUPERGAME_LIONKING:
+ state->m_map114_reg = state->m_map114_reg_enabled = 0;
+ mmc3_common_initialize(machine, 0xff, 0xff, 0);
+ break;
+ // mapper 115
+ case KASING_BOARD:
+ state->m_mmc_reg[0] = 0;
+ mmc3_common_initialize(machine, 0xff, 0xff, 0);
+ break;
+ // mapper 116
+ case SOMERI_SL12:
+ state->m_mmc_prg_base = state->m_mmc_chr_base = 0;
+ state->m_mmc_prg_mask = 0xff;
+ state->m_mmc_chr_mask = 0xff;
+ state->m_mmc_cmd1 = 2; // mode
+ state->m_mmc3_latch = 0;
+ state->m_mmc3_wram_protect = 0;
+ // MMC1 regs
+ state->m_mmc1_count = 0;
+ state->m_mmc_reg[0] = 0x0c;
+ state->m_mmc_reg[1] = 0x00;
+ state->m_mmc_reg[2] = 0x00;
+ state->m_mmc_reg[3] = 0x00;
+ // MMC3 regs
+ state->m_mmc_prg_bank[0] = 0x3c;
+ state->m_mmc_prg_bank[1] = 0x3d;
+ state->m_mmc_prg_bank[2] = 0xfe;
+ state->m_mmc_prg_bank[3] = 0xff;
+ state->m_mmc_vrom_bank[0] = 0x00;
+ state->m_mmc_vrom_bank[1] = 0x01;
+ state->m_mmc_vrom_bank[2] = 0x04;
+ state->m_mmc_vrom_bank[3] = 0x05;
+ state->m_mmc_vrom_bank[4] = 0x06;
+ state->m_mmc_vrom_bank[5] = 0x07;
+ // VRC2 regs
+ state->m_mmc_prg_bank[4] = 0x00;
+ state->m_mmc_prg_bank[5] = 0x01;
+ for (i = 0; i < 8; ++i)
+ state->m_mmc_vrom_bank[6 + i] = i;
+ someri_mode_update(machine);
+ break;
+
+ // mapper 120
+ case BTL_TOBIDASE:
+ prg32(machine, 2);
+ break;
+
+ // mapper 121
+ case KAY_PANDAPRINCE:
+ state->m_mmc_reg[5] = state->m_mmc_reg[6] = state->m_mmc_reg[7] = 0;
+ mmc3_common_initialize(machine, 0xff, 0xff, 0);
+ break;
+
+ // mapper 126
+ case BMC_PJOY84:
+ mmc3_common_initialize(machine, 0xff, 0xff, 0);
+ state->m_mmc_reg[0] = state->m_mmc_reg[1] = state->m_mmc_reg[2] = state->m_mmc_reg[3] = 0;
+ pjoy84_set_base_mask(machine);
+ mmc3_set_chr(machine, state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ break;
+
+ // mapper 132
+ case TXC_22211A:
+ // mapper 172
+ case TXC_22211B:
+ // mapper 173
+ case TXC_22211C:
+ state->m_txc_reg[0] = state->m_txc_reg[1] = state->m_txc_reg[2] = state->m_txc_reg[3] = 0;
+ break;
+
+ // mapper 134
+ case BMC_FAMILY_4646B:
+ mmc3_common_initialize(machine, 0x1f, 0xff, 0);
+ break;
+
+ // mapper 137
+ case SACHEN_8259D:
+ chr8(machine, state->m_chr_chunks - 1, CHRROM);
+ set_nt_mirroring(machine, PPU_MIRROR_VERT);
+ break;
+ // mapper 138
+ case SACHEN_8259B:
+ // mapper 139
+ case SACHEN_8259C:
+ // mapper 141
+ case SACHEN_8259A:
+ // mapper 150
+ case SACHEN_74LS374:
+ set_nt_mirroring(machine, PPU_MIRROR_VERT);
+ break;
+ // mapper 143
+ case SACHEN_TCA01:
+ prg16_89ab(machine, 0);
+ prg16_cdef(machine, 1);
+ break;
+
+ // mapper 156
+ case OPENCORP_DAOU306:
+ prg16_89ab(machine, state->m_prg_chunks - 2);
+ prg16_cdef(machine, state->m_prg_chunks - 1);
+ set_nt_mirroring(machine, PPU_MIRROR_LOW);
+ break;
+ // mapper 163
+ case NANJING_BOARD:
+ state->m_mmc_count = 0xff;
+ state->m_mmc_reg[0] = 0xff;
+ state->m_mmc_reg[1] = 0;
+ prg16_89ab(machine, state->m_prg_chunks - 2);
+ prg16_cdef(machine, state->m_prg_chunks - 1);
+ break;
+ // mapper 164
+ case WAIXING_FFV:
+ prg16_89ab(machine, 0);
+ prg16_cdef(machine, 0x1f);
+ break;
+ // mapper 166
+ case SUBOR_TYPE1:
+ state->m_subor_reg[0] = state->m_subor_reg[1] = state->m_subor_reg[2] = state->m_subor_reg[3] = 0;
+ prg16_89ab(machine, 0);
+ prg16_cdef(machine, 0x07);
+ break;
+ // mapper 167
+ case SUBOR_TYPE0:
+ state->m_subor_reg[0] = state->m_subor_reg[1] = state->m_subor_reg[2] = state->m_subor_reg[3] = 0;
+ prg16_89ab(machine, 0);
+ prg16_cdef(machine, 0x20);
+ break;
+
+ // mapper 176
+ case UNL_XZY:
+ // mapper 182
+ case HOSENKAN_BOARD:
+ prg32(machine, (state->m_prg_chunks - 1) >> 1);
+ break;
+
+ case FUKUTAKE_BOARD: // mapper 186
+ prg16_89ab(machine, 0);
+ prg16_cdef(machine, 0);
+ break;
+
+ // mapper 187
+ case UNL_KOF96:
+ state->m_mmc_reg[0] = state->m_mmc_reg[1] = state->m_mmc_reg[2] = state->m_mmc_reg[3] = 0;
+ mmc3_common_initialize(machine, 0xff, 0xff, 0);
+ break;
+ // mapper 189
+ case TXC_TW:
+ state->m_mmc_latch1 = 0;
+ state->m_mmc_latch2 = 0x80;
+ state->m_mmc_chr_base = 0;
+ state->m_mmc_chr_mask = 0xff;
+ mmc3_set_chr(machine, state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ break;
+ // mapper 193
+ case NTDEC_FIGHTINGHERO:
+ prg32(machine, (state->m_prg_chunks - 1) >> 1);
+ set_nt_mirroring(machine, PPU_MIRROR_VERT);
+ break;
+ // mapper 197
+ case UNL_SUPERFIGHTER3:
+ mmc3_common_initialize(machine, 0xff, 0xff, 0);
+ unl_sf3_set_chr(machine, state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ break;
+ // mapper 198
+ case WAIXING_TYPE_F:
+ mmc3_common_initialize(machine, 0xff, 0xff, 0);
+ state->m_mmc_prg_bank[0] = 0x00;
+ state->m_mmc_prg_bank[1] = 0x01;
+ state->m_mmc_prg_bank[2] = 0x4e;
+ state->m_mmc_prg_bank[3] = 0x4f;
+ mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ break;
+ // mapper 199
+ case WAIXING_TYPE_G:
+ mmc3_common_initialize(machine, 0xff, 0xff, 0);
+ state->m_mmc_prg_bank[0] = 0x00;
+ state->m_mmc_prg_bank[1] = 0x01;
+ state->m_mmc_prg_bank[2] = 0x3e;
+ state->m_mmc_prg_bank[3] = 0x3f;
+ mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ state->m_mmc_vrom_bank[0] = 0x00;
+ state->m_mmc_vrom_bank[1] = 0x02;
+ state->m_mmc_vrom_bank[2] = 0x04;
+ state->m_mmc_vrom_bank[3] = 0x05;
+ state->m_mmc_vrom_bank[4] = 0x06;
+ state->m_mmc_vrom_bank[5] = 0x07;
+ state->m_mmc_vrom_bank[6] = 0x01;
+ state->m_mmc_vrom_bank[7] = 0x03;
+ waixing_g_set_chr(machine, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ break;
+
+ // mapper 200
+ case BMC_36IN1:
+ prg16_89ab(machine, state->m_prg_chunks - 1);
+ prg16_cdef(machine, state->m_prg_chunks - 1);
+ break;
+
+ // mapper 202
+ case BMC_150IN1:
+ // mapper 203
+ case BMC_35IN1:
+ // mapper 204
+ case BMC_64IN1:
+ // mapper 214
+ case BMC_SUPERGUN_20IN1:
+ prg16_89ab(machine, 0);
+ prg16_cdef(machine, 0);
+ break;
+ // mapper 205
+ case BMC_15IN1:
+ mmc3_common_initialize(machine, 0x1f, 0xff, 0);
+ state->m_mmc_prg_base = 0x10; // this board has a diff prg_base
+ mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ break;
+
+ // mapper 208
+ case GOUDER_37017:
+ state->m_mmc_reg[0] = state->m_mmc_reg[1] = state->m_mmc_reg[2] = state->m_mmc_reg[3] = state->m_mmc_reg[4] = 0;
+ mmc3_common_initialize(machine, 0xff, 0xff, 0);
+ break;
+ // mapper 212
+ case BMC_SUPERHIK_300IN1:
+ chr8(machine, 0xff, CHRROM);
+ prg32(machine, 0xff);
+ break;
+
+ // mapper 215
+ case SUPERGAME_BOOGERMAN:
+ state->m_mmc_reg[0] = 0x00;
+ state->m_mmc_reg[1] = 0xff;
+ state->m_mmc_reg[2] = 0x04;
+ state->m_mmc_reg[3] = 0;
+ mmc3_common_initialize(machine, 0x1f, 0xff, 0);
+ sgame_boog_set_prg(machine);
+ mmc3_set_chr(machine, state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
+ break;
+
+ // mapper 217
+ case BMC_GOLDENCARD_6IN1:
+ mmc3_common_initialize(machine, 0xff, 0xff, 0);
+ state->m_mmc_reg[0] = 0x00;
+ state->m_mmc_reg[1] = 0xff;
+ state->m_mmc_reg[2] = 0x03;
+ state->m_mmc_reg[3] = 0;
+ bmc_gc6in1_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ bmc_gc6in1_set_chr(machine, state->m_mmc_chr_source);
+ break;
+ // mapper 221
+ case UNL_N625092:
+ prg16_89ab(machine, 0);
+ prg16_cdef(machine, 0);
+ break;
+
+ // mapper 223?
+ case WAIXING_TYPE_I:
+ mmc3_common_initialize(machine, 0xff, 0xff, 0);
+ state->m_mmc3_wram_protect = 0;
+ break;
+
+ // mapper 224?
+ case WAIXING_TYPE_J:
+ mmc3_common_initialize(machine, 0xff, 0xff, 0);
+ state->m_mmc_prg_bank[0] = 0x01;
+ state->m_mmc_prg_bank[1] = 0x02;
+ state->m_mmc_prg_bank[2] = 0x7e;
+ state->m_mmc_prg_bank[3] = 0x7f;
+ mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask);
+ break;
+
+ // mapper 227
+ case BMC_1200IN1:
+ prg16_89ab(machine, 0);
+ prg16_cdef(machine, 0);
+ break;
+
+ // mapper 229
+ case BMC_31IN1:
+ prg16_89ab(machine, 0);
+ prg16_cdef(machine, 1);
+ set_nt_mirroring(machine, PPU_MIRROR_VERT);
+ break;
+ // mapper 230
+ case BMC_22GAMES:
+ prg16_89ab(machine, 0);
+ prg16_cdef(machine, 7);
+ break;
+ // mapper 231
+ case BMC_20IN1:
+ prg16_89ab(machine, 0);
+ prg16_cdef(machine, state->m_prg_chunks - 1);
+ set_nt_mirroring(machine, PPU_MIRROR_VERT);
+ break;
+ // mapper 232
+ case CAMERICA_BF9096:
+ state->m_mmc_latch1 = 0x18;
+ state->m_mmc_latch2 = 0x00;
+ bf9096_set_prg(machine);
+ break;
+
+ // mapper 243
+ case SACHEN_74LS374_A:
+ state->m_mmc_vrom_bank[0] = 3;
+ chr8(machine, 3, CHRROM);
+ set_nt_mirroring(machine, PPU_MIRROR_VERT);
+ break;
+
+ // mapper 246
+ case CNE_FSB:
+ prg32(machine, 0xff);
+ break;
+ // mapper 249
+ case WAIXING_SECURITY:
+ state->m_mmc_reg[0] = 0;
+ mmc3_common_initialize(machine, 0xff, 0xff, 0);
+ break;
+
+ // mapper 254
+ case BTL_PIKACHUY2K:
+ state->m_mmc_reg[0] = 0xff;
+ mmc3_common_initialize(machine, 0xff, 0xff, 0);
+ break;
+
+ // mapper 255
+ case BMC_110IN1:
+ prg16_89ab(machine, 0);
+ prg16_cdef(machine, 1);
+ set_nt_mirroring(machine, PPU_MIRROR_VERT);
+ break;
+
+ // UNIF only
+ case BMC_64IN1NR:
+ state->m_mmc_reg[0] = 0x80;
+ state->m_mmc_reg[1] = 0x43;
+ state->m_mmc_reg[2] = state->m_mmc_reg[3] = 0;
+ bmc_64in1nr_set_prg(machine);
+ set_nt_mirroring(machine, PPU_MIRROR_VERT);
+ break;
+ case BMC_190IN1:
+ prg16_89ab(machine, 0);
+ prg16_cdef(machine, 0);
+ break;
+ case BMC_A65AS:
+ prg16_89ab(machine, 0);
+ prg16_cdef(machine, 7);
+ set_nt_mirroring(machine, PPU_MIRROR_VERT);
+ break;
+ case BMC_GS2004:
+ case BMC_GS2013:
+ prg32(machine, 0xff);
+ break;
+ case BMC_S24IN1SC03:
+ state->m_mmc_reg[0] = 0x24;
+ state->m_mmc_reg[1] = 0x9f;
+ state->m_mmc_reg[2] = 0;
+ mmc3_common_initialize(machine, 0xff, 0xff, 0);
+ break;
+ case BMC_T262:
+ state->m_mmc_latch1 = 0;
+ state->m_mmc_latch2 = 0;
+ prg16_89ab(machine, 0);
+ prg16_cdef(machine, 7);
+ break;
+ case DREAMTECH_BOARD:
+ prg16_89ab(machine, 0);
+ prg16_cdef(machine, 8);
+ break;
+ case UNL_8237:
+ state->m_mmc_reg[0] = state->m_mmc_reg[1] = state->m_mmc_reg[2] = 0;
+ mmc3_common_initialize(machine, 0xff, 0xff, 0);
+ break;
+ case UNL_AX5705:
+ state->m_mmc_prg_bank[0] = 0;
+ state->m_mmc_prg_bank[1] = 1;
+ prg8_89(machine, state->m_mmc_prg_bank[0]);
+ prg8_ab(machine, state->m_mmc_prg_bank[1]);
+ prg8_cd(machine, 0xfe);
+ prg8_ef(machine, 0xff);
+ break;
+ case UNL_RACERMATE:
+ chr4_0(machine, 0, state->m_mmc_chr_source);
+ chr4_4(machine, 0, state->m_mmc_chr_source);
+ prg16_89ab(machine, 0);
+ prg16_cdef(machine, state->m_prg_chunks - 1);
+ break;
+
+ case BMC_BENSHENG_BS5:
+ state->m_mmc_prg_bank[0] = 0xff;
+ state->m_mmc_prg_bank[1] = 0xff;
+ state->m_mmc_prg_bank[2] = 0xff;
+ state->m_mmc_prg_bank[3] = 0xff;
+ bmc_bs5_update_banks(machine);
+ break;
+
+ case BMC_810544:
+ prg16_89ab(machine, 0);
+ prg16_cdef(machine, 0);
+ set_nt_mirroring(machine, PPU_MIRROR_VERT);
+ break;
+
+ case BMC_G63IN1:
+ bmc_gb63_update(machine);
+ break;
+
+ case BMC_FK23C:
+ state->m_mmc_reg[0] = 4;
+ state->m_mmc_reg[1] = 0xff;
+ state->m_mmc_reg[2] = state->m_mmc_reg[3] = 0;
+ state->m_mmc_reg[4] = state->m_mmc_reg[5] = state->m_mmc_reg[6] = state->m_mmc_reg[7] = 0xff;
+ mmc3_common_initialize(machine, 0xff, 0xff, 0);
+ fk23c_set_prg(machine);
+ fk23c_set_chr(machine);
+ break;
+
+ case BMC_FK23CA:
+ state->m_mmc_reg[0] = state->m_mmc_reg[1] = state->m_mmc_reg[2] = state->m_mmc_reg[3] = 0;
+ state->m_mmc_reg[4] = state->m_mmc_reg[5] = state->m_mmc_reg[6] = state->m_mmc_reg[7] = 0xff;
+ mmc3_common_initialize(machine, 0xff, 0xff, 0);
+ fk23c_set_prg(machine);
+ fk23c_set_chr(machine);
+ break;
+
+
+ case FFE_MAPPER6:
+ prg16_89ab(machine, 0);
+ prg16_cdef(machine, 7);
+ break;
+ case FFE_MAPPER8:
+ prg32(machine, 0);
+ break;
+ case FFE_MAPPER17:
+ prg16_89ab(machine, 0);
+ prg16_cdef(machine, state->m_prg_chunks - 1);
+ break;
+
+ case UNSUPPORTED_BOARD:
+ default:
+ /* Mapper not supported */
+ err = 2;
+ break;
+ }
+
+ return err;
+}
+
+/*************************************************************
+
+ 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
+
+ *************************************************************/
+
+int nes_pcb_reset( running_machine &machine )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ int err = 0;
+ const nes_pcb_intf *intf = nes_pcb_intf_lookup(state->m_pcb_id);
+
+ if (intf == NULL)
+ fatalerror("Missing PCB interface\n");
+
+ /* Set the mapper irq callback */
+ state->m_ppu->set_scanline_callback(intf ? intf->mmc_scanline : NULL);
+ state->m_ppu->set_hblank_callback(intf ? intf->mmc_hblank : NULL);
+
+ err = pcb_initialize(machine, state->m_pcb_id);
+
+ return err;
+}
diff --git a/src/mess/machine/nes_unif.c b/src/mess/machine/nes_unif.c
new file mode 100644
index 00000000000..f7ff44d90ca
--- /dev/null
+++ b/src/mess/machine/nes_unif.c
@@ -0,0 +1,176 @@
+/*****************************************************************************************
+
+ NES MMC Emulation - UNIF boards
+
+ Very preliminary support for UNIF boards
+
+ TODO:
+ - properly support WRAM, etc.
+
+****************************************************************************************/
+
+typedef struct __unif
+{
+ const char *board; /* UNIF board */
+
+ int nvwram;
+ int wram;
+ int chrram;
+ int board_idx;
+} unif;
+
+
+/*************************************************************
+
+ Constants
+
+*************************************************************/
+
+/* CHRRAM sizes */
+enum
+{
+ CHRRAM_0 = 0,
+ CHRRAM_1,
+ CHRRAM_2,
+ CHRRAM_4,
+ CHRRAM_6,
+ CHRRAM_8,
+ CHRRAM_16,
+ CHRRAM_32
+};
+
+/*************************************************************
+
+ unif_list
+
+ Supported UNIF boards and corresponding handlers
+
+*************************************************************/
+
+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, STD_NXROM},
+ { "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_22211A},
+ // 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, UNSUPPORTED_BOARD},
+ { "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, BMC_GS2004}, //UNIF only!
+ { "BMC-GS-2013", 0, 0, CHRRAM_8, BMC_GS2013}, //UNIF only!
+ { "BMC-NOVELDIAMOND9999999IN1", 0, 0, CHRRAM_0, BMC_NOVELDIAMOND},
+ { "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, UNSUPPORTED_BOARD}, // related to JY Company? (i.e. mappers 90, 209, 211?)
+ { "UNL-KS7017", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD},
+ { "UNL-KS7032", 0, 0, CHRRAM_0, KAISER_KS7032}, // mapper 142
+ { "UNL-DANCE", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD},
+ { "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, UNSUPPORTED_BOARD /*SACHEN_SHERO*/},
+ { "UNL-TF1201", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD /*UNL_TF1201*/},
+ { "UNL-DRIPGAME", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // [by Quietust - we need more info]}
+ { "UNL-OneBus", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD},
+ { "UNL-YOKO", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // similar to mapper 83, but not the same
+ { "UNL-FS304", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // used in Zelda 3 by Waixing (support missing atm)
+ { "UNL-43272", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // used in Gaau Hok Gwong Cheung (support missing atm)
+ { "BTL-MARIO1-MALEE2", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // 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_BENSHENG_BS5},
+ { "BMC-810544-C-A1", 0, 0, CHRRAM_0, BMC_810544},
+ { "BMC-411120-C", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD},
+ { "BMC-8157", 0, 0, CHRRAM_8, UNSUPPORTED_BOARD /*BMC_8157*/},
+ { "BMC-42IN1RESETSWITCH", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // mapper 60?
+ { "BMC-830118C", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD},
+ { "BMC-D1038", 0, 0, CHRRAM_0, BMC_VT5201}, // mapper 60?
+ { "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-SUPERVISION16IN1", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // mapper 53
+ { "BMC-NTD-03", 0, 0, CHRRAM_0, BMC_NTD_03}
+};
+
+const unif *nes_unif_lookup( const char *board )
+{
+ int i;
+ for (i = 0; i < ARRAY_LENGTH(unif_list); i++)
+ {
+ if (!mame_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( running_machine &machine, const char *board )
+{
+ nes_state *state = machine.driver_data<nes_state>();
+ const unif *unif_board = nes_unif_lookup(board);
+
+ logerror("%s\n", board);
+
+ if (unif_board == NULL)
+ fatalerror("Unknown UNIF board %s.", board);
+
+ state->m_pcb_id = unif_board->board_idx;
+ state->m_battery = unif_board->nvwram; // we should implement battery banks based on the size of this...
+ state->m_battery_size = NES_BATTERY_SIZE; // FIXME: we should allow for smaller battery!
+ state->m_prg_ram = unif_board->wram; // we should implement WRAM banks based on the size of this...
+
+ if (unif_board->chrram <= CHRRAM_8)
+ state->m_vram_chunks = 1;
+ else if (unif_board->chrram == CHRRAM_16)
+ state->m_vram_chunks = 2;
+ else if (unif_board->chrram == CHRRAM_32)
+ state->m_vram_chunks = 4;
+}
diff --git a/src/mess/machine/nextkbd.c b/src/mess/machine/nextkbd.c
new file mode 100644
index 00000000000..019fd7bc223
--- /dev/null
+++ b/src/mess/machine/nextkbd.c
@@ -0,0 +1,298 @@
+
+#include "nextkbd.h"
+
+const device_type NEXTKBD = &device_creator<nextkbd_device>;
+
+DEVICE_ADDRESS_MAP_START(amap, 32, nextkbd_device)
+ AM_RANGE(0x0, 0x3) AM_READWRITE(ctrl_r, ctrl_w)
+ AM_RANGE(0x4, 0x7) AM_READWRITE(ctrl2_r, ctrl2_w)
+ AM_RANGE(0x8, 0xb) AM_READWRITE(data_r, data_w)
+ADDRESS_MAP_END
+
+nextkbd_device::nextkbd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : device_t(mconfig, NEXTKBD, "NEXTKBD", tag, owner, clock)
+{
+}
+
+void nextkbd_device::setup(line_cb_t _int_change_cb, line_cb_t _int_power_cb, line_cb_t _int_nmi_cb)
+{
+ int_change_cb = _int_change_cb;
+ int_power_cb = _int_power_cb;
+ int_nmi_cb = _int_nmi_cb;
+}
+
+void nextkbd_device::device_start()
+{
+ kbd_timer = timer_alloc(0);
+
+ save_item(NAME(control));
+ save_item(NAME(control2));
+ save_item(NAME(data));
+ save_item(NAME(fifo_ir));
+ save_item(NAME(fifo_iw));
+ save_item(NAME(fifo_size));
+ save_item(NAME(fifo));
+ save_item(NAME(modifiers_state));
+ save_item(NAME(nmi_active));
+}
+
+void nextkbd_device::device_reset()
+{
+ control = 0;
+ control2 = 0;
+ data = 0;
+ fifo_ir = 0;
+ fifo_iw = 0;
+ fifo_size = 0;
+ memset(fifo, 0, sizeof(fifo));
+ modifiers_state = 0;
+ nmi_active = false;
+}
+
+void nextkbd_device::send()
+{
+ if(control & FLAG_DATA)
+ return;
+
+ data = fifo_pop();
+ control |= FLAG_DATA;
+ if(!(control & FLAG_INT)) {
+ control |= FLAG_INT;
+ int_change_cb(true);
+ }
+}
+
+void nextkbd_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ if(fifo_empty())
+ return;
+
+ send();
+}
+
+void nextkbd_device::fifo_push(UINT32 val)
+{
+ if(fifo_size == FIFO_SIZE)
+ return;
+
+ fifo_size++;
+ fifo[fifo_iw++] = val;
+ if(fifo_iw == FIFO_SIZE)
+ fifo_iw = 0;
+ if(fifo_size == 1)
+ kbd_timer->adjust(attotime::from_hz(1000));
+}
+
+UINT32 nextkbd_device::fifo_pop()
+{
+ if(fifo_size == 0)
+ return 0;
+
+ fifo_size--;
+ UINT32 res = fifo[fifo_ir++];
+ if(fifo_ir == FIFO_SIZE)
+ fifo_ir = 0;
+ if(fifo_size == 0)
+ kbd_timer->adjust(attotime::never);
+
+ return res;
+}
+
+bool nextkbd_device::fifo_empty() const
+{
+ return !fifo_size;
+}
+
+READ32_MEMBER( nextkbd_device::ctrl_r )
+{
+ // logerror("nextkbd: ctrl_r %08x @ %08x\n", control, mem_mask);
+ return control;
+}
+
+READ32_MEMBER( nextkbd_device::ctrl2_r )
+{
+ return control2;
+}
+
+READ32_MEMBER( nextkbd_device::data_r )
+{
+ UINT32 old = control;
+ control &= ~(FLAG_DATA|FLAG_INT);
+ if(old & FLAG_INT)
+ int_change_cb(false);
+ return data;
+}
+
+WRITE32_MEMBER( nextkbd_device::ctrl_w )
+{
+ UINT32 diff;
+ if(data & FLAG_RESET) {
+ diff = control;
+ device_reset();
+ } else {
+ diff = control ^ data;
+ control = data;
+ }
+ if(diff & FLAG_INT)
+ int_change_cb(control & FLAG_INT);
+ // logerror("nextkbd: ctrl_w %08x @ %08x\n", data, mem_mask);
+}
+
+WRITE32_MEMBER( nextkbd_device::ctrl2_w )
+{
+ // logerror("nextkbd: ctrl2_w %08x @ %08x\n", data, mem_mask);
+}
+
+WRITE32_MEMBER( nextkbd_device::data_w )
+{
+}
+
+INPUT_CHANGED_MEMBER( nextkbd_device::update )
+{
+ int bank = (int)(FPTR)param;
+ switch(bank) {
+ case 0: case 1: case 2: {
+ int index;
+ for(index=0; index < 32; index++)
+ if(field.mask() & (1 << index))
+ break;
+ assert(index != 32);
+ index += bank*32;
+ UINT16 val = index | modifiers_state | KEYVALID;
+ if(!newval)
+ val |= KEYDOWN;
+ if(val == 0x8826 || val == 0x884a) {
+ nmi_active = true;
+ int_nmi_cb(true);
+ } else if(nmi_active) {
+ nmi_active = false;
+ int_nmi_cb(false);
+ }
+ fifo_push(val | (1<<28));
+ send();
+ break;
+ }
+
+ case 3:
+ if(newval)
+ modifiers_state |= field.mask();
+ else
+ modifiers_state &= ~field.mask();
+ fifo_push(modifiers_state | (1<<28));
+ send();
+ break;
+
+ case 4:
+ if(field.mask() & 1)
+ int_power_cb(newval & 1);
+ break;
+ }
+}
+
+static INPUT_PORTS_START(nextkbd_keymap)
+ PORT_START("0")
+ PORT_BIT(0x00000001, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 0)
+ PORT_BIT(0x00000002, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 0)
+ PORT_BIT(0x00000004, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 0)
+ PORT_BIT(0x00000008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 0) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|')
+ PORT_BIT(0x00000010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 0) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{')
+ PORT_BIT(0x00000020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 0) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}')
+ PORT_BIT(0x00000040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 0) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I')
+ PORT_BIT(0x00000080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 0) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O')
+ PORT_BIT(0x00000100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 0) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P')
+ PORT_BIT(0x00000200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 0) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
+ PORT_BIT(0x00000400, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 0)
+ PORT_BIT(0x00000800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 0) PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD))
+ PORT_BIT(0x00001000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 0) PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD))
+ PORT_BIT(0x00002000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 0) PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD))
+ PORT_BIT(0x00004000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 0)
+ PORT_BIT(0x00008000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 0) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN))
+ PORT_BIT(0x00010000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 0) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT))
+ PORT_BIT(0x00020000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 0) PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD))
+ PORT_BIT(0x00040000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 0) PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD))
+ PORT_BIT(0x00080000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 0) PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD))
+ PORT_BIT(0x00100000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 0) PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD))
+ PORT_BIT(0x00200000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 0) PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(PLUS_PAD))
+ PORT_BIT(0x00400000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 0) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP))
+ PORT_BIT(0x00800000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 0) PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD))
+ PORT_BIT(0x01000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 0) PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD))
+ PORT_BIT(0x02000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 0)
+ PORT_BIT(0x04000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 0)
+ PORT_BIT(0x08000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 0) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8)
+ PORT_BIT(0x10000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 0) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+')
+ PORT_BIT(0x20000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 0) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_')
+ PORT_BIT(0x40000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 0) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*')
+ PORT_BIT(0x80000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 0) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(')
+
+ PORT_START("1")
+ PORT_BIT(0x00000001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 1) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')')
+ PORT_BIT(0x00000002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 1) PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD))
+ PORT_BIT(0x00000004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 1) PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD))
+ PORT_BIT(0x00000008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 1) PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD))
+ PORT_BIT(0x00000010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 1) PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD))
+ PORT_BIT(0x00000020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 1) PORT_CODE(KEYCODE_ASTERISK) PORT_CHAR(UCHAR_MAMEKEY(ASTERISK))
+ PORT_BIT(0x00000040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 1) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') PORT_CHAR('~')
+ PORT_BIT(0x00000080, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 1) // Keypad = ?
+ PORT_BIT(0x00000100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 1) PORT_CODE(KEYCODE_SLASH_PAD) PORT_CHAR(UCHAR_MAMEKEY(SLASH_PAD))
+ PORT_BIT(0x00000200, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 1)
+ PORT_BIT(0x00000400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 1) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13)
+ PORT_BIT(0x00000800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 1) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('"')
+ PORT_BIT(0x00001000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 1) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':')
+ PORT_BIT(0x00002000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 1) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L')
+ PORT_BIT(0x00004000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 1) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')
+ PORT_BIT(0x00008000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 1) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
+ PORT_BIT(0x00010000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 1) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?')
+ PORT_BIT(0x00020000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 1) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z')
+ PORT_BIT(0x00040000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 1) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X')
+ PORT_BIT(0x00080000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 1) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C')
+ PORT_BIT(0x00100000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 1) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V')
+ PORT_BIT(0x00200000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 1) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B')
+ PORT_BIT(0x00400000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 1) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M')
+ PORT_BIT(0x00800000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 1) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N')
+ PORT_BIT(0x01000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 1) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
+ PORT_BIT(0x02000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 1) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A')
+ PORT_BIT(0x04000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 1) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S')
+ PORT_BIT(0x08000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 1) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D')
+ PORT_BIT(0x10000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 1) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F')
+ PORT_BIT(0x20000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 1) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G')
+ PORT_BIT(0x40000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 1) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K')
+ PORT_BIT(0x80000000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 1) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J')
+
+ PORT_START("2")
+ PORT_BIT(0x00000001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 2) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H')
+ PORT_BIT(0x00000002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 2) PORT_CODE(KEYCODE_TAB) PORT_CHAR('\t')
+ PORT_BIT(0x00000004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 2) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q')
+ PORT_BIT(0x00000008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 2) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W')
+ PORT_BIT(0x00000010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 2) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E')
+ PORT_BIT(0x00000020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 2) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R')
+ PORT_BIT(0x00000040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 2) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U')
+ PORT_BIT(0x00000080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 2) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y')
+ PORT_BIT(0x00000100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 2) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T')
+ PORT_BIT(0x00000200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 2) PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC))
+ PORT_BIT(0x00000400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 2) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')
+ PORT_BIT(0x00000800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 2) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@')
+ PORT_BIT(0x00001000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 2) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')
+ PORT_BIT(0x00002000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 2) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
+ PORT_BIT(0x00004000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 2) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&')
+ PORT_BIT(0x00008000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 2) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^')
+ PORT_BIT(0x00010000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 2) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')
+ PORT_BIT(0xfffe0000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 2)
+
+ PORT_START("modifiers")
+ PORT_BIT(0x00000100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 3) PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) PORT_NAME("Control")
+ PORT_BIT(0x00000200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 3) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) PORT_NAME("Shift (Left)")
+ PORT_BIT(0x00000400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 3) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) PORT_NAME("Shift (Right)")
+ PORT_BIT(0x00000800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 3) PORT_CODE(KEYCODE_LWIN) PORT_NAME("Command (Left)")
+ PORT_BIT(0x00001000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 3) PORT_CODE(KEYCODE_RWIN) PORT_NAME("Command (Right)")
+ PORT_BIT(0x00002000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 3) PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_MAMEKEY(LALT)) PORT_NAME("Alt (Left)")
+ PORT_BIT(0x00004000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 3) PORT_CODE(KEYCODE_RALT) PORT_CHAR(UCHAR_MAMEKEY(RALT)) PORT_NAME("Alt (Right)")
+ PORT_BIT(0xffff80ff, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 3)
+
+ PORT_START("special")
+ PORT_BIT(0x00000001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 4) PORT_CODE(KEYCODE_HOME) PORT_NAME("Power")
+ PORT_BIT(0xfffffffe, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_CHANGED_MEMBER(DEVICE_SELF, nextkbd_device, update, 4)
+INPUT_PORTS_END
+
+ioport_constructor nextkbd_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME(nextkbd_keymap);
+}
diff --git a/src/mess/machine/nextkbd.h b/src/mess/machine/nextkbd.h
new file mode 100644
index 00000000000..b9ec06db77e
--- /dev/null
+++ b/src/mess/machine/nextkbd.h
@@ -0,0 +1,57 @@
+#ifndef __NEXTKBD_H__
+#define __NEXTKBD_H__
+
+#include "emu.h"
+
+#define MCFG_NEXTKBD_ADD(_tag, _int_change_cb, _int_power_cb, _int_nmi_cb) \
+ MCFG_DEVICE_ADD(_tag, NEXTKBD, 0) \
+ downcast<nextkbd_device *>(device)->setup(_int_change_cb, _int_power_cb, _int_nmi_cb);
+
+class nextkbd_device : public device_t {
+public:
+ nextkbd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ void setup(line_cb_t int_change_cb, line_cb_t _int_power_cb, line_cb_t _int_nmi_cb);
+
+ DECLARE_ADDRESS_MAP(amap, 32);
+ ioport_constructor device_input_ports() const;
+
+ DECLARE_READ32_MEMBER(ctrl_r);
+ DECLARE_READ32_MEMBER(ctrl2_r);
+ DECLARE_READ32_MEMBER(data_r);
+
+ DECLARE_WRITE32_MEMBER(ctrl_w);
+ DECLARE_WRITE32_MEMBER(ctrl2_w);
+ DECLARE_WRITE32_MEMBER(data_w);
+
+ bool int_level_get();
+
+ DECLARE_INPUT_CHANGED_MEMBER(update);
+
+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 { FLAG_INT = 0x800000, FLAG_DATA = 0x400000, FLAG_RESET = 0x000200 };
+ enum { FIFO_SIZE = 32 };
+ enum { KEYDOWN = 0x0080, KEYVALID = 0x8000 };
+
+ line_cb_t int_change_cb, int_power_cb, int_nmi_cb;
+ emu_timer *kbd_timer;
+ bool nmi_active;
+
+ UINT32 control, control2, data, fifo_ir, fifo_iw, fifo_size;
+ UINT32 fifo[FIFO_SIZE];
+ UINT16 modifiers_state;
+
+ void fifo_push(UINT32 val);
+ UINT32 fifo_pop();
+ bool fifo_empty() const;
+
+ void send();
+};
+
+extern const device_type NEXTKBD;
+
+#endif
diff --git a/src/mess/machine/nextmo.c b/src/mess/machine/nextmo.c
new file mode 100644
index 00000000000..a79fc9cfbf4
--- /dev/null
+++ b/src/mess/machine/nextmo.c
@@ -0,0 +1,197 @@
+
+#include "emu.h"
+#include "nextmo.h"
+
+const device_type NEXTMO = &device_creator<nextmo_device>;
+
+DEVICE_ADDRESS_MAP_START(map, 8, nextmo_device)
+ AM_RANGE(0x04, 0x04) AM_READWRITE(r4_r, r4_w)
+ AM_RANGE(0x05, 0x05) AM_READWRITE(r5_r, r5_w)
+ AM_RANGE(0x06, 0x06) AM_READWRITE(r6_r, r6_w)
+ AM_RANGE(0x07, 0x07) AM_READWRITE(r7_r, r7_w)
+ AM_RANGE(0x08, 0x08) AM_READWRITE(r8_r, r8_w)
+ AM_RANGE(0x09, 0x09) AM_READWRITE(r9_r, r9_w)
+ AM_RANGE(0x0a, 0x0a) AM_READWRITE(ra_r, ra_w)
+ AM_RANGE(0x0b, 0x0b) AM_READWRITE(rb_r, rb_w)
+ AM_RANGE(0x10, 0x17) AM_READWRITE(r10_r, r10_w)
+ADDRESS_MAP_END
+
+nextmo_device::nextmo_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, NEXTMO, "NeXT Magneto-optical drive", tag, owner, clock)
+{
+}
+
+void nextmo_device::set_cb(line_cb_t _irq_cb, line_cb_t _drq_cb)
+{
+ irq_cb = _irq_cb;
+ drq_cb = _drq_cb;
+}
+
+void nextmo_device::device_start()
+{
+}
+
+void nextmo_device::device_reset()
+{
+}
+
+READ8_MEMBER(nextmo_device::r4_r)
+{
+ logerror("nextmo: r4_r %02x (%08x)\n", r4, cpu_get_pc(&space.device()));
+ return r4;
+}
+
+WRITE8_MEMBER(nextmo_device::r4_w)
+{
+ if(r4 & 1)
+ device_reset();
+ r4 = (r4 & (~data & 0xfc)) | (data & 3);
+ logerror("nextmo: r4_w %02x (%08x)\n", r4, cpu_get_pc(&space.device()));
+}
+
+READ8_MEMBER(nextmo_device::r5_r)
+{
+ logerror("nextmo: r5_r %02x (%08x)\n", r5, cpu_get_pc(&space.device()));
+ return r5;
+}
+
+WRITE8_MEMBER(nextmo_device::r5_w)
+{
+ r5 = data;
+ logerror("nextmo: r5_w %02x (%08x)\n", r5, cpu_get_pc(&space.device()));
+}
+
+READ8_MEMBER(nextmo_device::r6_r)
+{
+ logerror("nextmo: r6_r %02x (%08x)\n", r6, cpu_get_pc(&space.device()));
+ return r6;
+}
+
+WRITE8_MEMBER(nextmo_device::r6_w)
+{
+ r6 = data;
+ logerror("nextmo: r6_w %02x (%08x)\n", r6, cpu_get_pc(&space.device()));
+}
+
+READ8_MEMBER(nextmo_device::r7_r)
+{
+ logerror("nextmo: r7_r %02x (%08x)\n", r7, cpu_get_pc(&space.device()));
+ return r7;
+}
+
+WRITE8_MEMBER(nextmo_device::r7_w)
+{
+ r7 = data;
+ logerror("nextmo: r7_w %02x (%08x)\n", r7, cpu_get_pc(&space.device()));
+ if(r7 & 0xc0) {
+ logerror("nextmo: start dma %02x %02x\n", r6, r7);
+ sector_pos = 0;
+ if(!drq_cb.isnull())
+ drq_cb(true);
+ }
+}
+
+UINT8 nextmo_device::dma_r()
+{
+ UINT8 r = 0;
+ if(r7 & 0x80)
+ r = sector[sector_pos++];
+ check_dma_end();
+ return r;
+}
+
+void nextmo_device::dma_w(UINT8 data)
+{
+ if(r7 & 0x40)
+ sector[sector_pos++] = data;
+ check_dma_end();
+}
+
+void nextmo_device::check_dma_end()
+{
+ int limit;
+ if(r7 & 0x40)
+ limit = r6 & 0x20 ? 0x510 : 0x400;
+ else
+ limit = r6 & 0x20 ? 0x400 : 0x510;
+ if(sector_pos == limit) {
+ if(!drq_cb.isnull())
+ drq_cb(false);
+ if(r7 & 0x40) {
+ if(r6 & 0x20)
+ check_ecc();
+ else
+ compute_ecc();
+ }
+ r7 &= 0x3f;
+ r4 |= 0x08;
+ }
+}
+
+READ8_MEMBER(nextmo_device::r8_r)
+{
+ logerror("nextmo: r8_r (%08x)\n", cpu_get_pc(&space.device()));
+ return 0x00;
+}
+
+WRITE8_MEMBER(nextmo_device::r8_w)
+{
+ logerror("nextmo: r8_w %02x (%08x)\n", data, cpu_get_pc(&space.device()));
+}
+
+READ8_MEMBER(nextmo_device::r9_r)
+{
+ logerror("nextmo: r9_r (%08x)\n", cpu_get_pc(&space.device()));
+ return 0x00;
+}
+
+WRITE8_MEMBER(nextmo_device::r9_w)
+{
+ logerror("nextmo: r9_w %02x (%08x)\n", data, cpu_get_pc(&space.device()));
+}
+
+READ8_MEMBER(nextmo_device::ra_r)
+{
+ logerror("nextmo: ra_r (%08x)\n", cpu_get_pc(&space.device()));
+ return 0x00;
+}
+
+WRITE8_MEMBER(nextmo_device::ra_w)
+{
+ logerror("nextmo: ra_w %02x (%08x)\n", data, cpu_get_pc(&space.device()));
+}
+
+READ8_MEMBER(nextmo_device::rb_r)
+{
+ logerror("nextmo: rb_r (%08x)\n", cpu_get_pc(&space.device()));
+ return 0x24;
+}
+
+WRITE8_MEMBER(nextmo_device::rb_w)
+{
+ logerror("nextmo: rb_w %02x (%08x)\n", data, cpu_get_pc(&space.device()));
+}
+
+READ8_MEMBER(nextmo_device::r10_r)
+{
+ logerror("nextmo: r10_r %d (%08x)\n", offset, cpu_get_pc(&space.device()));
+ return 0x00;
+}
+
+WRITE8_MEMBER(nextmo_device::r10_w)
+{
+ logerror("nextmo: r10_w %d, %02x (%08x)\n", offset, data, cpu_get_pc(&space.device()));
+}
+
+void nextmo_device::check_ecc()
+{
+ logerror("nextmo: check_ecc\n");
+ for(int i=0; i<0x400; i++)
+ sector[i] = i;
+}
+
+void nextmo_device::compute_ecc()
+{
+ logerror("nextmo: compute_ecc\n");
+ memset(sector+0x400, 0, 0x110);
+}
diff --git a/src/mess/machine/nextmo.h b/src/mess/machine/nextmo.h
new file mode 100644
index 00000000000..e105464377a
--- /dev/null
+++ b/src/mess/machine/nextmo.h
@@ -0,0 +1,56 @@
+#ifndef NEXTMO_H
+#define NEXTMO_H
+
+#define MCFG_NEXTMO_ADD(_tag, _irq, _drq) \
+ MCFG_DEVICE_ADD(_tag, NEXTMO, 0) \
+ downcast<nextmo_device *>(device)->set_cb(_irq, _drq);
+
+class nextmo_device : public device_t
+{
+public:
+ nextmo_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ void set_cb(line_cb_t irq_cb, line_cb_t drq_cb);
+
+ DECLARE_ADDRESS_MAP(map, 32);
+
+ DECLARE_READ8_MEMBER(r4_r);
+ DECLARE_WRITE8_MEMBER(r4_w);
+ DECLARE_READ8_MEMBER(r5_r);
+ DECLARE_WRITE8_MEMBER(r5_w);
+ DECLARE_READ8_MEMBER(r6_r);
+ DECLARE_WRITE8_MEMBER(r6_w);
+ DECLARE_READ8_MEMBER(r7_r);
+ DECLARE_WRITE8_MEMBER(r7_w);
+ DECLARE_READ8_MEMBER(r8_r);
+ DECLARE_WRITE8_MEMBER(r8_w);
+ DECLARE_READ8_MEMBER(r9_r);
+ DECLARE_WRITE8_MEMBER(r9_w);
+ DECLARE_READ8_MEMBER(ra_r);
+ DECLARE_WRITE8_MEMBER(ra_w);
+ DECLARE_READ8_MEMBER(rb_r);
+ DECLARE_WRITE8_MEMBER(rb_w);
+ DECLARE_READ8_MEMBER(r10_r);
+ DECLARE_WRITE8_MEMBER(r10_w);
+
+ UINT8 dma_r();
+ void dma_w(UINT8 data);
+
+protected:
+ virtual void device_start();
+ virtual void device_reset();
+
+private:
+ UINT8 sector[0x510];
+ UINT8 r4, r5, r6, r7;
+ line_cb_t irq_cb, drq_cb;
+ int sector_pos;
+
+ void check_dma_end();
+ void check_ecc();
+ void compute_ecc();
+};
+
+extern const device_type NEXTMO;
+
+#endif
diff --git a/src/mess/machine/northbridge.c b/src/mess/machine/northbridge.c
new file mode 100644
index 00000000000..15bcd161d7b
--- /dev/null
+++ b/src/mess/machine/northbridge.c
@@ -0,0 +1,46 @@
+/***************************************************************************
+
+ Northbridge implementation
+
+***************************************************************************/
+
+#include "emu.h"
+#include "machine/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)
+ : device_t(mconfig, type, name, tag, owner, clock),
+ 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/mess/machine/northbridge.h b/src/mess/machine/northbridge.h
new file mode 100644
index 00000000000..75282b09314
--- /dev/null
+++ b/src/mess/machine/northbridge.h
@@ -0,0 +1,32 @@
+#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);
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+public:
+ required_device<cpu_device> m_maincpu;
+ required_device<ram_device> m_ram;
+
+};
+
+#endif /* __NORTHBRIDGE_H__ */
diff --git a/src/mess/machine/nubus.c b/src/mess/machine/nubus.c
new file mode 100644
index 00000000000..f8bfde9ec1e
--- /dev/null
+++ b/src/mess/machine/nubus.c
@@ -0,0 +1,479 @@
+/***************************************************************************
+
+ 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 "machine/nubus.h"
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type NUBUS_SLOT = &device_creator<nubus_slot_device>;
+
+//**************************************************************************
+// 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),
+ 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) :
+ device_t(mconfig, type, name, tag, owner, clock),
+ 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<nubus_slot_device &>(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<device_nubus_card_interface *>(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<nubus_device>;
+
+void nubus_device::static_set_cputag(device_t &device, const char *tag)
+{
+ nubus_device &nubus = downcast<nubus_device &>(device);
+ nubus.m_cputag = tag;
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void nubus_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const nbbus_interface *intf = reinterpret_cast<const nbbus_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<nbbus_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_irq9_cb, 0, sizeof(m_out_irq9_cb));
+ memset(&m_out_irqa_cb, 0, sizeof(m_out_irqa_cb));
+ memset(&m_out_irqb_cb, 0, sizeof(m_out_irqb_cb));
+ memset(&m_out_irqc_cb, 0, sizeof(m_out_irqc_cb));
+ memset(&m_out_irqd_cb, 0, sizeof(m_out_irqd_cb));
+ memset(&m_out_irqe_cb, 0, sizeof(m_out_irqe_cb));
+ }
+}
+
+//**************************************************************************
+// 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_device::nubus_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)
+{
+}
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void nubus_device::device_start()
+{
+ m_maincpu = machine().device(m_cputag);
+ // resolve callbacks
+ m_out_irq9_func.resolve(m_out_irq9_cb, *this);
+ m_out_irqa_func.resolve(m_out_irqa_cb, *this);
+ m_out_irqb_func.resolve(m_out_irqb_cb, *this);
+ m_out_irqc_func.resolve(m_out_irqc_cb, *this);
+ m_out_irqd_func.resolve(m_out_irqd_cb, *this);
+ m_out_irqe_func.resolve(m_out_irqe_cb, *this);
+}
+
+//-------------------------------------------------
+// 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->memory().space_config(AS_PROGRAM)->m_databus_width;
+ switch(buswidth)
+ {
+ case 32:
+ m_maincpu->memory().space(AS_PROGRAM)->install_readwrite_handler(start, end, rhandler, whandler, mask);
+ break;
+ case 64:
+ m_maincpu->memory().space(AS_PROGRAM)->install_readwrite_handler(start, end, rhandler, whandler, ((UINT64)mask<<32)|mask);
+ break;
+ default:
+ fatalerror("NUBUS: Bus width %d not supported", buswidth);
+ break;
+ }
+}
+
+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->memory().space_config(AS_PROGRAM)->m_databus_width;
+ switch(buswidth)
+ {
+ case 32:
+ m_maincpu->memory().space(AS_PROGRAM)->install_readwrite_handler(start, end, rhandler, whandler, mask);
+ break;
+ case 64:
+ m_maincpu->memory().space(AS_PROGRAM)->install_readwrite_handler(start, end, rhandler, whandler, ((UINT64)mask<<32)|mask);
+ break;
+ default:
+ fatalerror("NUBUS: Bus width %d not supported", buswidth);
+ break;
+ }
+}
+
+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->memory().space_config(AS_PROGRAM)->m_databus_width;
+ switch(buswidth)
+ {
+ case 32:
+ m_maincpu->memory().space(AS_PROGRAM)->install_readwrite_handler(start, end, rhandler, whandler, mask);
+ break;
+ case 64:
+ m_maincpu->memory().space(AS_PROGRAM)->install_readwrite_handler(start, end, rhandler, whandler, ((UINT64)mask<<32)|mask);
+ break;
+ default:
+ fatalerror("NUBUS: Bus width %d not supported", buswidth);
+ break;
+ }
+}
+
+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->memory().space_config(AS_PROGRAM)->m_databus_width;
+ switch(buswidth)
+ {
+ case 32:
+ m_maincpu->memory().space(AS_PROGRAM)->install_read_handler(start, end, rhandler, mask);
+ break;
+ case 64:
+ m_maincpu->memory().space(AS_PROGRAM)->install_read_handler(start, end, rhandler, ((UINT64)mask<<32)|mask);
+ break;
+ default:
+ fatalerror("NUBUS: Bus width %d not supported", buswidth);
+ break;
+ }
+}
+
+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->memory().space_config(AS_PROGRAM)->m_databus_width;
+ switch(buswidth)
+ {
+ case 32:
+ m_maincpu->memory().space(AS_PROGRAM)->install_write_handler(start, end, whandler, mask);
+ break;
+ case 64:
+ m_maincpu->memory().space(AS_PROGRAM)->install_write_handler(start, end, whandler, ((UINT64)mask<<32)|mask);
+ break;
+ default:
+ fatalerror("NUBUS: Bus width %d not supported", buswidth);
+ break;
+ }
+}
+
+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->memory().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_func(state); }
+WRITE_LINE_MEMBER( nubus_device::irqa_w ) { m_out_irqa_func(state); }
+WRITE_LINE_MEMBER( nubus_device::irqb_w ) { m_out_irqb_func(state); }
+WRITE_LINE_MEMBER( nubus_device::irqc_w ) { m_out_irqc_func(state); }
+WRITE_LINE_MEMBER( nubus_device::irqd_w ) { m_out_irqd_func(state); }
+WRITE_LINE_MEMBER( nubus_device::irqe_w ) { m_out_irqe_func(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_interface &>(device);
+ nubus_card.m_nubus_tag = tag;
+ nubus_card.m_nubus_slottag = slottag;
+}
+
+void device_nubus_card_interface::set_nubus_device()
+{
+ // 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<nubus_device *>(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 *newrom = NULL;
+
+ astring tempstring;
+ UINT8 *rom = device().machine().root_device().memregion(dev->subtag(tempstring, romregion))->base();
+ UINT32 romlen = device().machine().root_device().memregion(dev->subtag(tempstring, romregion))->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)
+ newrom = auto_alloc_array_clear(device().machine(), UINT8, romlen);
+ for (int i = 0; i < romlen; i++)
+ {
+ newrom[BYTE4_XOR_BE(i)] = rom[i];
+ }
+ break;
+
+ case 0xe1: // lane 0 only
+ newrom = auto_alloc_array_clear(device().machine(), UINT8, romlen*4);
+ for (int i = 0; i < romlen; i++)
+ {
+ newrom[BYTE4_XOR_BE(i*4)] = rom[i];
+ }
+ romlen *= 4;
+ break;
+
+ case 0xd2: // lane 1 only
+ newrom = auto_alloc_array_clear(device().machine(), UINT8, romlen*4);
+ for (int i = 0; i < romlen; i++)
+ {
+ newrom[BYTE4_XOR_BE((i*4)+1)] = rom[i];
+ }
+ romlen *= 4;
+ break;
+
+ case 0xb4: // lane 2 only
+ newrom = auto_alloc_array_clear(device().machine(), UINT8, romlen*4);
+ for (int i = 0; i < romlen; i++)
+ {
+ newrom[BYTE4_XOR_BE((i*4)+2)] = rom[i];
+ }
+ romlen *= 4;
+ break;
+
+ case 0x78: // lane 3 only
+ newrom = auto_alloc_array_clear(device().machine(), UINT8, romlen*4);
+ for (int i = 0; i < romlen; i++)
+ {
+ newrom[BYTE4_XOR_BE((i*4)+3)] = rom[i];
+ }
+ romlen *= 4;
+ break;
+
+ case 0xc3: // lanes 0, 1
+ newrom = auto_alloc_array_clear(device().machine(), UINT8, romlen*2);
+ for (int i = 0; i < romlen/2; i++)
+ {
+ newrom[BYTE4_XOR_BE((i*4)+0)] = rom[(i*2)];
+ newrom[BYTE4_XOR_BE((i*4)+1)] = rom[(i*2)+1];
+ }
+ romlen *= 2;
+ break;
+
+ case 0xa5: // lanes 0, 2
+ newrom = auto_alloc_array_clear(device().machine(), UINT8, romlen*2);
+ for (int i = 0; i < romlen/2; i++)
+ {
+ newrom[BYTE4_XOR_BE((i*4)+0)] = rom[(i*2)];
+ newrom[BYTE4_XOR_BE((i*4)+2)] = rom[(i*2)+1];
+ }
+ romlen *= 2;
+ break;
+
+ case 0x3c: // lanes 2,3
+ newrom = auto_alloc_array_clear(device().machine(), UINT8, romlen*2);
+ for (int i = 0; i < romlen/2; i++)
+ {
+ newrom[BYTE4_XOR_BE((i*4)+2)] = rom[(i*2)];
+ newrom[BYTE4_XOR_BE((i*4)+3)] = rom[(i*2)+1];
+ }
+ romlen *= 2;
+ break;
+
+ default:
+ fatalerror("NuBus: unhandled byteLanes value %02x\n", byteLanes);
+ break;
+ }
+
+ // 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++)
+ {
+ newrom[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, newrom);
+ }
+ else
+ {
+ m_nubus->install_bank(addr, addr+romlen-1, 0, 0, bankname, newrom);
+ }
+}
+
diff --git a/src/mess/machine/nubus.h b/src/mess/machine/nubus.h
new file mode 100644
index 00000000000..532532d35ad
--- /dev/null
+++ b/src/mess/machine/nubus.h
@@ -0,0 +1,167 @@
+/***************************************************************************
+
+ 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_BUS_ADD(_tag, _cputag, _config) \
+ MCFG_DEVICE_ADD(_tag, NUBUS, 0) \
+ MCFG_DEVICE_CONFIG(_config) \
+ nubus_device::static_set_cputag(*device, _cputag); \
+
+#define MCFG_NUBUS_SLOT_ADD(_nbtag, _tag, _slot_intf, _def_slot, _def_inp) \
+ MCFG_DEVICE_ADD(_tag, NUBUS_SLOT, 0) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, 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);
+
+#define MCFG_NUBUS_BUS_REMOVE(_tag) \
+ MCFG_DEVICE_REMOVE(_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);
+
+ // 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;
+
+// ======================> nbbus_interface
+
+struct nbbus_interface
+{
+ 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;
+};
+
+class device_nubus_card_interface;
+// ======================> nubus_device
+class nubus_device : public device_t,
+ public nbbus_interface
+{
+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);
+ // inline configuration
+ static void static_set_cputag(device_t &device, const char *tag);
+
+ 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();
+ virtual void device_config_complete();
+
+ // internal state
+ device_t *m_maincpu;
+
+ devcb_resolved_write_line m_out_irq9_func;
+ devcb_resolved_write_line m_out_irqa_func;
+ devcb_resolved_write_line m_out_irqb_func;
+ devcb_resolved_write_line m_out_irqc_func;
+ devcb_resolved_write_line m_out_irqd_func;
+ devcb_resolved_write_line m_out_irqe_func;
+
+ simple_list<device_nubus_card_interface> 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;
+};
+
+#endif /* __NUBUS_H__ */
diff --git a/src/mess/machine/nubus_asntmc3b.c b/src/mess/machine/nubus_asntmc3b.c
new file mode 100644
index 00000000000..7bb6977b394
--- /dev/null
+++ b/src/mess/machine/nubus_asntmc3b.c
@@ -0,0 +1,214 @@
+/***************************************************************************
+
+ 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 "machine/nubus_asntmc3b.h"
+
+#define MAC8390_ROM_REGION "asntm3b_rom"
+#define MAC8390_839X "dp83902"
+
+static const dp8390_interface dp8390_interface =
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, nubus_mac8390_device, dp_irq_w),
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, nubus_mac8390_device, dp_mem_read),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, nubus_mac8390_device, dp_mem_write)
+};
+
+MACHINE_CONFIG_FRAGMENT( asntm3b )
+ MCFG_DP8390D_ADD(MAC8390_839X, dp8390_interface)
+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<nubus_asntmc3nb_device>;
+const device_type NUBUS_APPLEENET = &device_creator<nubus_appleenet_device>;
+
+
+//-------------------------------------------------
+// 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) :
+ device_t(mconfig, NUBUS_ASNTMC3NB, name, tag, owner, clock),
+ 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)
+{
+ m_shortname = "nb_amc3b";
+}
+
+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)
+{
+ m_shortname = "nb_aenet";
+}
+
+//-------------------------------------------------
+// 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, cpu_get_pc(&space.device()));
+ }
+}
+
+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, cpu_get_pc(&space.device()));
+ }
+
+ 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/mess/machine/nubus_asntmc3b.h b/src/mess/machine/nubus_asntmc3b.h
new file mode 100644
index 00000000000..f44244de3db
--- /dev/null
+++ b/src/mess/machine/nubus_asntmc3b.h
@@ -0,0 +1,66 @@
+#pragma once
+
+#ifndef __NUBUS_ASNTMC3B_H__
+#define __NUBUS_ASNTMC3B_H__
+
+#include "emu.h"
+#include "machine/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);
+
+ // 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<dp8390_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/mess/machine/null_modem.c b/src/mess/machine/null_modem.c
new file mode 100644
index 00000000000..4e2d7a6d0fe
--- /dev/null
+++ b/src/mess/machine/null_modem.c
@@ -0,0 +1,27 @@
+#include "machine/null_modem.h"
+
+const device_type NULL_MODEM = &device_creator<null_modem_device>;
+
+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),
+ device_serial_port_interface(mconfig, *this),
+ m_bitbanger(*this, "bitbanger")
+{
+}
+
+static struct _bitbanger_config null_modem_image_config =
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, null_modem_device, read),
+ BITBANGER_MODEM,
+ BITBANGER_9600,
+ BITBANGER_0PERCENT
+};
+
+static MACHINE_CONFIG_FRAGMENT(null_modem_config)
+ MCFG_BITBANGER_ADD("bitbanger", null_modem_image_config);
+MACHINE_CONFIG_END
+
+machine_config_constructor null_modem_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME(null_modem_config);
+}
diff --git a/src/mess/machine/null_modem.h b/src/mess/machine/null_modem.h
new file mode 100644
index 00000000000..fa6bd00e3b3
--- /dev/null
+++ b/src/mess/machine/null_modem.h
@@ -0,0 +1,27 @@
+#ifndef NULL_MODEM_H_
+#define NULL_MODEM_H_
+
+#include "emu.h"
+#include "machine/serial.h"
+#include "imagedev/bitbngr.h"
+
+class null_modem_device :
+ public device_t,
+ public device_serial_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;
+ DECLARE_WRITE_LINE_MEMBER( read ) { m_rbit = state; m_owner->out_rx(state); }
+ virtual void tx(UINT8 state) { m_tbit = state; m_bitbanger->output(state); }
+protected:
+ virtual void device_start() { m_owner = dynamic_cast<serial_port_device *>(owner()); }
+ virtual void device_reset() { m_owner->out_rx(1); m_rbit = 1; }
+ virtual void device_config_complete() { m_shortname = "null_modem"; }
+private:
+ serial_port_device *m_owner;
+ required_device<bitbanger_device> m_bitbanger;
+};
+
+extern const device_type NULL_MODEM;
+#endif
diff --git a/src/mess/machine/odyssey2.c b/src/mess/machine/odyssey2.c
new file mode 100644
index 00000000000..9d25d2d4913
--- /dev/null
+++ b/src/mess/machine/odyssey2.c
@@ -0,0 +1,241 @@
+/***************************************************************************
+
+ odyssey2.c
+
+ Machine file to handle emulation of the Odyssey 2.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/odyssey2.h"
+#include "imagedev/cartslot.h"
+#include "sound/sp0256.h"
+
+
+
+static void odyssey2_switch_banks(running_machine &machine)
+{
+ odyssey2_state *state = machine.driver_data<odyssey2_state>();
+ switch ( state->m_cart_size ) {
+ case 12288:
+ /* 12KB cart support (for instance, KTAA as released) */
+ state->membank( "bank1" )->set_base( machine.root_device().memregion("user1")->base() + (state->m_p1 & 0x03) * 0xC00 );
+ state->membank( "bank2" )->set_base( machine.root_device().memregion("user1")->base() + (state->m_p1 & 0x03) * 0xC00 + 0x800 );
+ break;
+ case 16384:
+ /* 16KB cart support (for instance, full sized version KTAA) */
+ state->membank( "bank1" )->set_base( machine.root_device().memregion("user1")->base() + (state->m_p1 & 0x03) * 0x1000 + 0x400 );
+ state->membank( "bank2" )->set_base( machine.root_device().memregion("user1")->base() + (state->m_p1 & 0x03) * 0x1000 + 0xC00 );
+ break;
+ default:
+ state->membank("bank1")->set_base(machine.root_device().memregion("user1")->base() + (state->m_p1 & 0x03) * 0x800);
+ state->membank("bank2")->set_base(state->memregion("user1")->base() + (state->m_p1 & 0x03) * 0x800 );
+ break;
+ }
+}
+
+void odyssey2_the_voice_lrq_callback(device_t *device, int state) {
+ odyssey2_state *drvstate = device->machine().driver_data<odyssey2_state>();
+ drvstate->m_the_voice_lrq_state = state;
+}
+
+READ8_MEMBER(odyssey2_state::odyssey2_t0_r){
+ return ( m_the_voice_lrq_state == ASSERT_LINE ) ? 0 : 1;
+}
+
+DRIVER_INIT_MEMBER(odyssey2_state,odyssey2)
+{
+ int i;
+ int size = 0;
+ UINT8 *gfx = memregion("gfx1")->base();
+ device_image_interface *image = dynamic_cast<device_image_interface *>(machine().device("cart"));
+
+ m_ram = auto_alloc_array(machine(), UINT8, 256);
+
+ for (i = 0; i < 256; i++)
+ {
+ gfx[i] = i; /* TODO: Why i and not 0? */
+ m_ram[i] = 0;
+ }
+
+ if (image->exists())
+ {
+ if (image->software_entry() == NULL)
+ {
+ size = image->length();
+ }
+ else
+ {
+ size = image->get_software_region_length("rom");
+ }
+ }
+ m_cart_size = size;
+}
+
+MACHINE_RESET( odyssey2 )
+{
+ odyssey2_state *state = machine.driver_data<odyssey2_state>();
+ /* jump to "last" bank, will work for all sizes due to being mirrored */
+ state->m_p1 = 0xFF;
+ state->m_p2 = 0xFF;
+ odyssey2_switch_banks(machine);
+}
+
+/****** External RAM ******************************/
+
+READ8_MEMBER(odyssey2_state::odyssey2_bus_r)
+{
+ if ((m_p1 & (P1_VDC_COPY_MODE_ENABLE | P1_VDC_ENABLE)) == 0)
+ return odyssey2_video_r(space, offset); /* seems to have higher priority than ram??? */
+
+ else if (!(m_p1 & P1_EXT_RAM_ENABLE))
+ return m_ram[offset];
+
+ return 0;
+}
+
+WRITE8_MEMBER(odyssey2_state::odyssey2_bus_w)
+{
+ if ((m_p1 & (P1_EXT_RAM_ENABLE | P1_VDC_COPY_MODE_ENABLE)) == 0x00) {
+ m_ram[offset] = data;
+ if ( offset & 0x80 ) {
+ if ( data & 0x20 ) {
+ logerror("voice write %02X, data = %02X (p1 = %02X)\n", offset, data, m_p1 );
+ sp0256_ALD_w( machine().device("sp0256_speech"), 0, offset & 0x7F );
+ } else {
+ /* TODO: Reset sp0256 in this case */
+ }
+ }
+ }
+
+ else if (!(m_p1 & P1_VDC_ENABLE))
+ odyssey2_video_w(space, offset, data);
+}
+
+READ8_MEMBER(odyssey2_state::g7400_bus_r)
+{
+ if ((m_p1 & (P1_VDC_COPY_MODE_ENABLE | P1_VDC_ENABLE)) == 0) {
+ return odyssey2_video_r(space, offset); /* seems to have higher priority than ram??? */
+ }
+ else if (!(m_p1 & P1_EXT_RAM_ENABLE)) {
+ return m_ram[offset];
+ } else {
+// return ef9341_r( offset & 0x02, offset & 0x01 );
+ }
+
+ return 0;
+}
+
+WRITE8_MEMBER(odyssey2_state::g7400_bus_w)
+{
+ if ((m_p1 & (P1_EXT_RAM_ENABLE | P1_VDC_COPY_MODE_ENABLE)) == 0x00) {
+ m_ram[offset] = data;
+ }
+ else if (!(m_p1 & P1_VDC_ENABLE)) {
+ odyssey2_video_w(space, offset, data);
+ } else {
+// ef9341_w( offset & 0x02, offset & 0x01, data );
+ }
+}
+
+/***** 8048 Ports ************************/
+
+READ8_MEMBER(odyssey2_state::odyssey2_getp1)
+{
+ UINT8 data = m_p1;
+
+ logerror("%.9f p1 read %.2x\n", machine().time().as_double(), data);
+ return data;
+}
+
+WRITE8_MEMBER(odyssey2_state::odyssey2_putp1)
+{
+ m_p1 = data;
+
+ odyssey2_switch_banks(machine());
+
+ odyssey2_lum_w ( space, 0, m_p1 >> 7 );
+
+ logerror("%.6f p1 written %.2x\n", machine().time().as_double(), data);
+}
+
+READ8_MEMBER(odyssey2_state::odyssey2_getp2)
+{
+ UINT8 h = 0xFF;
+ int i, j;
+ static const char *const keynames[] = { "KEY0", "KEY1", "KEY2", "KEY3", "KEY4", "KEY5" };
+
+ if (!(m_p1 & P1_KEYBOARD_SCAN_ENABLE))
+ {
+ if ((m_p2 & P2_KEYBOARD_SELECT_MASK) <= 5) /* read keyboard */
+ {
+ h &= ioport(keynames[m_p2 & P2_KEYBOARD_SELECT_MASK])->read();
+ }
+
+ for (i= 0x80, j = 0; i > 0; i >>= 1, j++)
+ {
+ if (!(h & i))
+ {
+ m_p2 &= ~0x10; /* set key was pressed indicator */
+ m_p2 = (m_p2 & ~0xE0) | (j << 5); /* column that was pressed */
+
+ break;
+ }
+ }
+
+ if (h == 0xFF) /* active low inputs, so no keypresses */
+ m_p2 = m_p2 | 0xF0;
+ }
+
+ else
+ m_p2 = m_p2 | 0xF0;
+
+ logerror("%.6f p2 read %.2x\n", machine().time().as_double(), m_p2);
+ return m_p2;
+}
+
+WRITE8_MEMBER(odyssey2_state::odyssey2_putp2)
+{
+ m_p2 = data;
+
+ logerror("%.6f p2 written %.2x\n", machine().time().as_double(), data);
+}
+
+READ8_MEMBER(odyssey2_state::odyssey2_getbus)
+{
+ UINT8 data = 0xff;
+
+ if ((m_p2 & P2_KEYBOARD_SELECT_MASK) == 1)
+ data &= ioport("JOY0")->read(); /* read joystick 1 */
+
+ if ((m_p2 & P2_KEYBOARD_SELECT_MASK) == 0)
+ data &= ioport("JOY1")->read(); /* read joystick 2 */
+
+ logerror("%.6f bus read %.2x\n", machine().time().as_double(), data);
+ return data;
+}
+
+WRITE8_MEMBER(odyssey2_state::odyssey2_putbus)
+{
+ logerror("%.6f bus written %.2x\n", machine().time().as_double(), data);
+}
+
+///////////////////////////////////
+
+#ifdef UNUSED_FUNCTION
+int odyssey2_cart_verify(const UINT8 *cartdata, size_t size)
+{
+ odyssey2_state *state = machine.driver_data<odyssey2_state>();
+ state->m_cart_size = size;
+ if ( (size == 2048)
+ || (size == 4096)
+ || (size == 8192)
+ || (size == 12288)
+ || (size == 16384))
+ {
+ return IMAGE_VERIFY_PASS;
+ }
+
+ return IMAGE_VERIFY_FAIL;
+}
+#endif
diff --git a/src/mess/machine/omti8621.c b/src/mess/machine/omti8621.c
new file mode 100644
index 00000000000..107481ecdab
--- /dev/null
+++ b/src/mess/machine/omti8621.c
@@ -0,0 +1,1363 @@
+/*
+ * omti8621.c - SMS OMTI 8621 disk controller (for Apollo DN3x00)
+ *
+ * Created on: August 30, 2010
+ * Author: Hans Ostermeyer
+ *
+ * Released for general non-commercial use under the MAME license
+ * Visit http://mamedev.org for licensing and usage restrictions.
+ *
+ * see also:
+ * * http://www.bitsavers.org/pdf/sms/pc/OMTI_AT_Controller_Series_Jan87.pdf
+ */
+
+#define VERBOSE 0
+
+static int verbose = VERBOSE;
+
+#include "machine/omti8621.h"
+#include "image.h"
+
+#define LOG(x) { logerror ("%s: ", cpu_context(state->device)); 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 DLOG(x) { logerror ("%s: ", cpu_context(disk->device)); logerror x; logerror ("\n"); }
+#define DLOG1(x) { if (verbose > 0) DLOG(x)}
+#define DLOG2(x) { if (verbose > 1) DLOG(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_MAX_LUN 1
+#define OMTI_DISK0_TAG "omti_disk0"
+#define OMTI_DISK1_TAG "omti_disk1"
+
+#define CDB_SIZE 10
+
+/*
+ * 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
+
+typedef struct _disk_data disk_data;
+struct _disk_data
+{
+ device_t *device;
+ UINT16 type;
+ UINT16 cylinders;
+ UINT16 heads;
+ UINT16 sectors;
+ UINT32 sectorbytes;
+ UINT32 sector_count;
+
+ device_image_interface *image;
+
+ // configuration data
+ UINT8 config_data[10];
+
+ // ESDI defect list data
+ UINT8 esdi_defect_list[256];
+};
+
+typedef struct _omti8621_state omti8621_state;
+struct _omti8621_state {
+ device_t *device;
+ omti8621_set_irq irq_handler;
+
+ disk_data *disk[OMTI_MAX_LUN+1];
+
+ UINT16 jumper;
+
+ /* stored tc state - state present at pins */
+ int tc_state;
+
+ /* stored int state */
+ int int_state;
+
+ 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
+ UINT8 *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];
+};
+
+/***************************************************************************
+ get_safe_token - makes sure that the passed
+ in device is, in fact, a 8621 controller
+ ***************************************************************************/
+
+INLINE omti8621_state *get_safe_token(device_t *device) {
+ assert(device != NULL);
+ assert(device->type() == OMTI8621);
+ return (omti8621_state *) downcast<legacy_device_base *>(device)->token();
+}
+
+/***************************************************************************
+ 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_get_previouspc(cpu), device->tag());
+ } else {
+ strcpy(statebuf, "(no context)");
+ }
+ return statebuf;
+}
+
+/*-------------------------------------------------
+ set_interrupt - update the IRQ state
+ -------------------------------------------------*/
+
+static void set_interrupt(const omti8621_state *state, enum line_state line_state) {
+ if (state->irq_handler != NULL) {
+ LOG2(("set_interrupt: status_port=%x", state->status_port));
+ (*state->irq_handler)(&state->device->machine(), line_state);
+ }
+}
+
+static TIMER_CALLBACK(set_interrupt_caba ) {
+ const omti8621_state *state =(omti8621_state *)ptr;
+ set_interrupt(state, ASSERT_LINE);
+}
+
+/***************************************************************************
+ clear_sense_data - clear the sense data
+ ***************************************************************************/
+
+static void clear_sense_data(omti8621_state *state) {
+ LOG2(("clear_sense_data"));
+ memset(state->sense_data, 0, sizeof(state->sense_data));
+}
+
+/***************************************************************************
+ set_sense_data - set the sense data from code and command descriptor block
+ ***************************************************************************/
+
+static void set_sense_data(omti8621_state *state, UINT8 code, const UINT8 * cdb) {
+ LOG2(("set_sense_data code=%x", code));
+ state->sense_data[0]=code;
+ state->sense_data[1]=cdb[1];
+ state->sense_data[2]=cdb[2];
+ state->sense_data[3]=cdb[3];
+}
+
+/***************************************************************************
+ set_configuration_data - set the configuration data for drive lun
+ ***************************************************************************/
+
+static void set_configuration_data(omti8621_state *state, UINT8 lun) {
+ LOG2(("set_configuration_data lun=%x", lun));
+
+ // initialize the configuration data
+ disk_data *disk = state->disk[lun];
+
+ disk->config_data[0] = (disk->cylinders - 1) >> 8; // Number of Cylinders (MSB)
+ disk->config_data[1] = (disk->cylinders - 1) & 0xff; // Number of Cylinders (LSB) (-1)
+ disk->config_data[2] = disk->heads - 1; // Number of Heads (-1)
+ disk->config_data[3] = disk->sectors - 1; // Number of Sectors (-1)
+ disk->config_data[4] = 0x02; // Drive Configuration Word (MSB)
+ disk->config_data[5] = 0x44; // Drive Configuration Word (LSB)
+ disk->config_data[6] = 0x00; // ISG AFTER INDEX
+ disk->config_data[7] = 0x00; // PLO SYN Field (ID)
+ disk->config_data[8] = 0x00; // PLO SYN Field (DATA)
+ disk->config_data[9] = 0x00; // ISG AFTER SECTOR
+}
+
+/***************************************************************************
+ omti_reset - reset the OMTI controller
+ ***************************************************************************/
+
+static void omti_reset(omti8621_state *state) {
+ LOG2(("omti_reset"));
+
+ // should go from reset to idle after 100 us
+ // state->omti_state = OMTI_STATE_RESET;
+ state->omti_state = OMTI_STATE_IDLE;
+
+ state->status_port = OMTI_STATUS_NU6 | OMTI_STATUS_NU7;
+ state->config_port = ~state->jumper;
+ state->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(state->sector_buffer, 0, OMTI_DISK_SECTOR_SIZE);
+ memcpy(state->sector_buffer, "8621VB.4060487xx", 0x10);
+ state->sector_buffer[0x10] = 0; // ROM Checksum error
+ state->sector_buffer[0x11] = 0; // Processor Register error
+ state->sector_buffer[0x12] = 0; // Buffer RAM error
+ state->sector_buffer[0x13] = 0; // Sequencer Register File error
+ state->sector_buffer[0x14] = 0xc0; // 32K buffer size
+ // TODO: add missing Default values for LUN 0, 1 and 3
+
+ state->command_length = 0;
+ state->command_index = 0;
+ state->command_status = 0;
+
+ state->data_index = 0;
+ state->data_length = 0;
+
+ clear_sense_data(state) ;
+
+ state->diskaddr_ecc_error = 0;
+ state->diskaddr_format_bad_track = 0;
+ state->alternate_track_address[0] = 0;
+ state->alternate_track_address[1] = 0;
+}
+
+/***************************************************************************
+ get_lun - get logical unit number from a command descriptor block (in bit 5)
+ ***************************************************************************/
+
+static UINT8 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
+ ***************************************************************************/
+
+static UINT8 check_disk_address(omti8621_state *state, 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];
+ disk_data *disk = state->disk[lun];
+
+ UINT32 disk_track = cylinder * disk->heads + head;
+ UINT32 disk_addr = (disk_track * disk->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->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->heads) {
+ sense_code = OMTI_SENSE_CODE_ILLEGAL_ADDRESS | OMTI_SENSE_CODE_ADDRESS_VALID;
+ } else if (cylinder >= disk->cylinders) {
+ sense_code = OMTI_SENSE_CODE_ILLEGAL_ADDRESS | OMTI_SENSE_CODE_ADDRESS_VALID;
+ } else if ( disk_track == state->diskaddr_format_bad_track && disk_track != 0) {
+ sense_code = OMTI_SENSE_CODE_BAD_TRACK;
+ } else if (disk_addr == state->diskaddr_ecc_error && disk_addr != 0) {
+ sense_code = OMTI_SENSE_CODE_ECC_ERROR;
+ } else if (disk_track == state->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(state);
+ } else {
+ state->command_status |= OMTI_COMMAND_STATUS_ERROR;
+ set_sense_data(state, sense_code, cdb);
+ }
+ return sense_code == OMTI_SENSE_CODE_NO_ERROR;
+}
+
+/***************************************************************************
+ get_disk_track - get disk track from a command descriptor block
+ ***************************************************************************/
+
+static UINT32 get_disk_track(const omti8621_state *state, 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 * state->disk[lun]->heads + head;
+}
+
+/***************************************************************************
+ get_disk_address - get disk address from a command descriptor block
+ ***************************************************************************/
+
+static UINT32 get_disk_address(const omti8621_state *state, const UINT8 * cdb) {
+ UINT8 lun = get_lun(cdb);
+ UINT16 sector = cdb[2] & 0x3f;
+ return get_disk_track(state, cdb) * state->disk[lun]->sectors + sector;
+}
+
+/***************************************************************************
+ set_data_transfer - setup for data transfer from/to data
+ ***************************************************************************/
+
+static void set_data_transfer(omti8621_state *state, UINT8 *data, UINT16 length) {
+ // set controller for read data transfer
+ state->omti_state = OMTI_STATE_DATA;
+ state->status_port |= OMTI_STATUS_REQ | OMTI_STATUS_IO | OMTI_STATUS_BUSY;
+ state->status_port &= ~OMTI_STATUS_CD;
+
+ state->data_buffer = data;
+ state->data_length = length;
+ state->data_index = 0;
+}
+
+/***************************************************************************
+ read_sectors_from_disk - read sectors starting at diskaddr into sector_buffer
+ ***************************************************************************/
+
+static void read_sectors_from_disk(omti8621_state *state, INT32 diskaddr,
+ UINT8 count, UINT8 lun) {
+
+ UINT8 *data_buffer = state->sector_buffer;
+ device_image_interface *image = state->disk[lun]->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
+ ***************************************************************************/
+
+static void write_sectors_to_disk(omti8621_state *state, INT32 diskaddr,
+ UINT8 count, UINT8 lun) {
+
+ UINT8 *data_buffer = state->sector_buffer;
+ device_image_interface *image = state->disk[lun]->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 == state->diskaddr_ecc_error) {
+ // reset previous ECC error
+ state->diskaddr_ecc_error = 0;
+ }
+
+ diskaddr++;
+ data_buffer += OMTI_DISK_SECTOR_SIZE;
+ }
+}
+
+/***************************************************************************
+ copy_sectors - copy sectors
+ ***************************************************************************/
+
+static void copy_sectors(omti8621_state *state, INT32 dst_addr, INT32 src_addr,
+ UINT8 count, UINT8 lun) {
+ device_image_interface *image = state->disk[lun]->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( state->sector_buffer, OMTI_DISK_SECTOR_SIZE);
+
+ image->fseek( dst_addr * OMTI_DISK_SECTOR_SIZE, SEEK_SET);
+ image->fwrite( state->sector_buffer, OMTI_DISK_SECTOR_SIZE);
+
+ if (dst_addr == state->diskaddr_ecc_error) {
+ // reset previous ECC error
+ state->diskaddr_ecc_error = 0;
+ }
+
+ src_addr++;
+ dst_addr++;
+ }
+}
+
+/***************************************************************************
+ format track - format a track
+ ***************************************************************************/
+
+static void format_track(omti8621_state *state, const UINT8 * cdb) {
+ UINT8 lun = get_lun(cdb);
+ UINT32 disk_addr = get_disk_address(state, cdb);
+ UINT32 disk_track = get_disk_track(state, cdb);
+
+ if (state->diskaddr_ecc_error == disk_addr) {
+ // reset previous ECC error
+ state->diskaddr_ecc_error = 0;
+ }
+
+ if (state->diskaddr_format_bad_track == disk_track) {
+ // reset previous bad track formatting
+ state->diskaddr_format_bad_track = 0;
+ }
+
+ if (state->alternate_track_address[0] == disk_track) {
+ // reset source of alternate track address
+ state->alternate_track_address[0] = 0;
+ }
+
+ if (state->alternate_track_address[1] == disk_track) {
+ // reset alternate track address
+ state->alternate_track_address[1] = 0;
+ }
+
+ if (check_disk_address(state, cdb) ) {
+ if ((cdb[5] & 0x40) == 0) {
+ memset(state->sector_buffer, 0x6C, OMTI_DISK_SECTOR_SIZE * state->disk[lun]->sectors);
+ }
+ write_sectors_to_disk(state, disk_addr, state->disk[lun]->sectors, lun);
+ }
+
+}
+
+/***************************************************************************
+ set_esdi_defect_list - setup the (emty) ESDI defect list
+ ***************************************************************************/
+
+static void set_esdi_defect_list(omti8621_state *state, UINT8 lun, UINT8 head)
+{
+ disk_data *disk = state->disk[lun];
+
+ memset(disk->esdi_defect_list, 0, sizeof(disk->esdi_defect_list));
+ disk->esdi_defect_list[0] = 1; // month
+ disk->esdi_defect_list[1] = 1; // day
+ disk->esdi_defect_list[2] = 90; // year
+ disk->esdi_defect_list[3] = head;
+ memset(disk->esdi_defect_list+6, 0xff, 5); // end of defect list
+}
+
+/***************************************************************************
+ log_command - log command from a command descriptor block
+ ***************************************************************************/
+
+static void log_command(const omti8621_state *state,
+ const UINT8 cdb[], const UINT16 cdb_length) {
+ if (verbose > 0) {
+ int i;
+ logerror("%s: OMTI command ", cpu_context(state->device));
+ 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(state, cdb), cdb[4]);
+ break;
+ }
+ logerror("\n");
+ }
+}
+
+/***************************************************************************
+ log_data - log data in the common data buffer
+ ***************************************************************************/
+
+static void log_data(const omti8621_state *state) {
+ if (verbose > 0) {
+ int i;
+ logerror("%s: OMTI data (length=%02x)", cpu_context(state->device),
+ state->data_length);
+ for (i = 0; i < state->data_length && i < OMTI_DISK_SECTOR_SIZE; i++) {
+ logerror(" %02x", state->data_buffer[i]);
+ }
+
+ if (i < state->data_length) {
+ logerror(" ...");
+ }
+ logerror("\n");
+ }
+}
+
+/***************************************************************************
+ do_command
+ ***************************************************************************/
+
+static void do_command(omti8621_state *state,
+ const UINT8 cdb[], const UINT16 cdb_length) {
+
+ UINT8 lun = get_lun(cdb);
+ disk_data *disk = state->disk[lun];
+ int command_duration = 0; // ms
+
+ log_command( state, cdb, cdb_length);
+
+ // default to read status and status is successful completion
+ state->omti_state = OMTI_STATE_STATUS;
+ state->status_port |= OMTI_STATUS_IO | OMTI_STATUS_CD;
+ state->command_status = lun ? OMTI_COMMAND_STATUS_LUN : 0;
+
+ if (state->mask_port & OMTI_MASK_INTE) {
+ set_interrupt(state, CLEAR_LINE);
+ }
+
+ if (!disk->image->exists()) {
+ state->command_status |= OMTI_COMMAND_STATUS_ERROR; // no such drive
+ }
+
+ switch (cdb[0]) {
+ case OMTI_CMD_TEST_DRIVE_READY: // 0x00
+ if (!disk->image->exists())
+ {
+ set_sense_data(state, OMTI_SENSE_CODE_DRIVE_NOT_READY, cdb);
+ }
+ break;
+
+ case OMTI_CMD_RECALIBRATE: // 0x01
+ break;
+
+ case OMTI_CMD_REQUEST_SENSE: // 0x03
+ set_data_transfer(state, state->sense_data, sizeof(state->sense_data));
+ break;
+
+ case OMTI_CMD_READ_VERIFY: // 0x05
+ check_disk_address(state, cdb);
+ break;
+
+ case OMTI_CMD_FORMAT_TRACK: // 0x06
+ format_track(state, cdb);
+ break;
+
+ case OMTI_CMD_FORMAT_BAD_TRACK: // 0x07
+ state->diskaddr_format_bad_track = get_disk_address(state, cdb);
+ break;
+
+ case OMTI_CMD_READ: // 0x08
+ if (check_disk_address(state, cdb)) {
+ // read data from controller
+ read_sectors_from_disk(state, get_disk_address(state, cdb), cdb[4], lun);
+ set_data_transfer(state, state->sector_buffer, OMTI_DISK_SECTOR_SIZE*cdb[4]);
+ }
+ break;
+
+ case OMTI_CMD_WRITE: // 0x0A
+ log_data(state);
+ if (check_disk_address(state, cdb)) {
+ write_sectors_to_disk(state, get_disk_address(state, cdb), cdb[4], lun);
+ }
+ break;
+
+ case OMTI_CMD_SEEK: // 0x0B
+ check_disk_address(state, cdb);
+ break;
+
+ case OMTI_CMD_READ_SECTOR_BUFFER: // 0x0E
+ set_data_transfer(state, state->sector_buffer, OMTI_DISK_SECTOR_SIZE*cdb[4]);
+ break;
+
+ case OMTI_CMD_WRITE_SECTOR_BUFFER: // 0x0F
+ log_data(state);
+ break;
+
+ case OMTI_CMD_COPY: // 0x20
+ if (check_disk_address(state, cdb) && check_disk_address(state, cdb+4)) {
+ // copy sectors
+ copy_sectors (state, get_disk_address(state, cdb+4), get_disk_address(state, cdb), cdb[4], lun);
+ }
+ break;
+
+ case OMTI_CMD_READ_ESDI_DEFECT_LIST: // 0x37
+ set_esdi_defect_list(state, get_lun(cdb), cdb[1] & 0x1f);
+ set_data_transfer(state, disk->esdi_defect_list, sizeof(disk->esdi_defect_list));
+ break;
+
+ case OMTI_CMD_ASSIGN_ALTERNATE_TRACK: // 0x11
+ log_data(state);
+ state->alternate_track_address[0] = get_disk_track(state, cdb);
+ state->alternate_track_address[1] = get_disk_track(state, state->alternate_track_buffer-1);;
+ break;
+
+ case OMTI_CMD_READ_DATA_TO_BUFFER: // 0x1E
+ if (check_disk_address(state, cdb)) {
+ // read data from controller
+ read_sectors_from_disk (state, get_disk_address(state, 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(state);
+ if (check_disk_address(state, cdb)) {
+ write_sectors_to_disk(state, get_disk_address(state, 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(state, cdb)) {
+ // read data from controller
+ read_sectors_from_disk(state, get_disk_address(state, cdb), cdb[4], lun);
+ set_data_transfer(state, state->sector_buffer, OMTI_DISK_SECTOR_SIZE+6);
+ }
+ break;
+
+ case OMTI_CMD_WRITE_LONG: // 0xE6
+ log_data(state);
+ if (check_disk_address(state, cdb)) {
+ UINT32 diskaddr = get_disk_address(state, cdb);
+ write_sectors_to_disk(state, diskaddr, cdb[4], lun);
+ // this will spoil the ECC code
+ state->diskaddr_ecc_error = diskaddr;
+ }
+ break;
+
+ case OMTI_CMD_READ_CONFIGURATION: // 0xEC
+ set_configuration_data(state, get_lun(cdb));
+ set_data_transfer(state, disk->config_data, sizeof(disk->config_data));
+ break;
+
+ case OMTI_CMD_INVALID_COMMAND: // 0xFF
+ set_sense_data(state, OMTI_SENSE_CODE_INVALID_COMMAND, cdb);
+ state->command_status |= OMTI_COMMAND_STATUS_ERROR;
+ break;
+
+ default:
+ LOG(("do_command: UNEXPECTED command %02x",cdb[0]));
+ set_sense_data(state, OMTI_SENSE_CODE_INVALID_COMMAND, cdb);
+ state->command_status |= OMTI_COMMAND_STATUS_ERROR;
+ break;
+ }
+
+ if (state->mask_port & OMTI_MASK_INTE) {
+// if (state->omti_state != OMTI_STATE_STATUS) {
+// LOG(("do_command: UNEXPECTED omti_state %02x",state->omti_state));
+// }
+ state->status_port |= OMTI_STATUS_IREQ;
+ if (command_duration == 0) {
+ set_interrupt(state, ASSERT_LINE);
+ } else {
+ // FIXME: should delay state->omti_state and state->status_port as well
+ state->device->machine().scheduler().timer_set(attotime::from_msec(command_duration), FUNC(set_interrupt_caba), 0, state);
+ }
+ }
+}
+
+/***************************************************************************
+ get_command_length
+ ***************************************************************************/
+
+static UINT8 get_command_length(UINT8 command_byte) {
+ return command_byte == OMTI_CMD_COPY ? 10 : 6;
+}
+
+/***************************************************************************
+ get_data
+ ***************************************************************************/
+
+static UINT16 get_data(omti8621_state *state) {
+ UINT16 data = 0xff;
+ if (state->data_index < state->data_length) {
+ data = state->data_buffer[state->data_index++] << 8;
+ data |= state->data_buffer[state->data_index++];
+ if (state->data_index >= state->data_length) {
+ state->omti_state = OMTI_STATE_STATUS;
+ state->status_port |= OMTI_STATUS_IO | OMTI_STATUS_CD;
+ log_data(state);
+ }
+ } else {
+ LOG(("UNEXPECTED reading OMTI 8621 data (buffer length exceeded)"));
+ }
+ return data;
+}
+
+/***************************************************************************
+ set_data
+ ***************************************************************************/
+
+static void set_data(omti8621_state *state, UINT16 data) {
+ if (state->data_index < state->data_length) {
+ state->data_buffer[state->data_index++] = data >> 8;
+ state->data_buffer[state->data_index++] = data & 0xff;
+ if (state->data_index >= state->data_length) {
+ do_command(state, state->command_buffer, state->command_index);
+ }
+ } else {
+ LOG(("UNEXPECTED writing OMTI 8621 data (buffer length exceeded)"));
+ }
+}
+
+/***************************************************************************
+ DN3500 Disk Controller-AT Register at 0x4D000
+ ***************************************************************************/
+
+static WRITE8_DEVICE_HANDLER( omti8621_w8 ) {
+ omti8621_state *state = get_safe_token(device);
+
+ switch (offset) {
+ case OMTI_PORT_DATA_OUT: // 0x00
+ switch (state->omti_state) {
+ case OMTI_STATE_COMMAND:
+ LOG2(("writing OMTI 8621 Command Register at offset %02x = %02x", offset, data));
+ if (state->command_index == 0) {
+ state->command_length = get_command_length(data);
+ }
+
+ if (state->command_index < state->command_length) {
+ state->command_buffer[state->command_index++] = data;
+ } else {
+ LOG(("UNEXPECTED writing OMTI 8621 Data Register at offset %02x = %02x (command length exceeded)", offset, data));
+ }
+
+ if (state->command_index == state->command_length) {
+ switch (state->command_buffer[0]) {
+ case OMTI_CMD_WRITE: // 0x0A
+ // TODO: check diskaddr
+ // Fall through
+ case OMTI_CMD_WRITE_SECTOR_BUFFER: // 0x0F
+ set_data_transfer(state, state->sector_buffer,
+ OMTI_DISK_SECTOR_SIZE * state->command_buffer[4]);
+ state->status_port &= ~OMTI_STATUS_IO;
+ break;
+
+ case OMTI_CMD_ASSIGN_ALTERNATE_TRACK: // 0x11
+ set_data_transfer(state, state->alternate_track_buffer, sizeof(state->alternate_track_buffer));
+ state->status_port &= ~OMTI_STATUS_IO;
+ break;
+
+ case OMTI_CMD_WRITE_LONG: // 0xE6
+ // TODO: check diskaddr
+ set_data_transfer(state, state->sector_buffer,
+ (OMTI_DISK_SECTOR_SIZE +6) * state->command_buffer[4]);
+ state->status_port &= ~OMTI_STATUS_IO;
+ break;
+
+ default:
+ do_command(state, state->command_buffer, state->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, state->omti_state));
+ break;
+ }
+ break;
+
+ case OMTI_PORT_RESET: // 0x01
+ LOG2(("writing OMTI 8621 Reset Register at offset %02x = %02x", offset, data));
+ omti_reset(state);
+ break;
+
+ case OMTI_PORT_SELECT: // 0x02
+ LOG2(("writing OMTI 8621 Select Register at offset %02x = %02x (omti state = %02x)", offset, data, state->omti_state));
+ state->omti_state = OMTI_STATE_COMMAND;
+
+ state->status_port |= OMTI_STATUS_BUSY | OMTI_STATUS_REQ | OMTI_STATUS_CD;
+ state->status_port &= ~OMTI_STATUS_IO;
+
+ state->command_status = 0;
+ state->command_index = 0;
+ break;
+
+ case OMTI_PORT_MASK: // 0x03
+ LOG2(("writing OMTI 8621 Mask Register at offset %02x = %02x", offset, data));
+ state->mask_port = data;
+
+ if ((data & OMTI_MASK_INTE) == 0) {
+ state->status_port &= ~OMTI_STATUS_IREQ;
+ set_interrupt(state, CLEAR_LINE);
+ }
+
+ if ((data & OMTI_MASK_DMAE) == 0) {
+ state->status_port &= ~OMTI_STATUS_DREQ;
+ }
+ break;
+
+ default:
+ LOG(("UNEXPECTED writing OMTI 8621 Register at offset %02x = %02x", offset, data));
+ break;
+ }
+}
+
+static READ8_DEVICE_HANDLER( omti8621_r8 ) {
+ omti8621_state *state = get_safe_token(device);
+ UINT8 data = 0xff;
+
+ static UINT8 last_data = 0xff;
+
+ switch (offset) {
+ case OMTI_PORT_DATA_IN: // 0x00
+ if (state->status_port & OMTI_STATUS_CD) {
+ data = state->command_status;
+ switch (state->omti_state) {
+ case OMTI_STATE_COMMAND:
+ LOG2(("reading OMTI 8621 Data Status Register at offset %02x = %02x (omti state = %02x)", offset, data, state->omti_state));
+ break;
+ case OMTI_STATE_STATUS:
+ state->omti_state = OMTI_STATE_IDLE;
+ state->status_port &= ~(OMTI_STATUS_BUSY | OMTI_STATUS_CD | OMTI_STATUS_IO | OMTI_STATUS_REQ);
+ LOG2(("reading OMTI 8621 Data Status Register at offset %02x = %02x", offset, data));
+ break;
+ default:
+ LOG(("UNEXPECTED reading OMTI 8621 Data Status Register at offset %02x = %02x (omti state = %02x)", offset, data, state->omti_state));
+ break;
+ }
+ } else {
+ LOG(("UNEXPECTED reading OMTI 8621 Data Register at offset %02x = %02x (status bit C/D = 0)", offset, data));
+ }
+ break;
+
+ case OMTI_PORT_STATUS: // 0x01
+ data = state->status_port;
+ // omit excessive logging
+ if (data != last_data) {
+ LOG2(("reading OMTI 8621 Status Register at offset %02x = %02x", offset, data));
+// last_data = data;
+ }
+ break;
+
+ case OMTI_PORT_CONFIG: // 0x02
+ data = state->config_port;
+ LOG2(("reading OMTI 8621 Configuration Register at offset %02x = %02x", offset, data));
+ break;
+
+ case OMTI_PORT_MASK: // 0x03
+ data = state->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;
+}
+
+WRITE16_DEVICE_HANDLER(omti8621_w ) {
+ omti8621_state *state = get_safe_token(device);
+
+ switch (mem_mask) {
+ case 0x00ff:
+ omti8621_w8(device, offset*2+1, data);
+ break;
+ case 0xff00:
+ omti8621_w8(device, offset*2, data>>8);
+ break;
+ default:
+ LOG3(("writing OMTI 8621 Data Word Register to %0x = %04x & %04x", offset, data, mem_mask));
+ set_data(state, data);
+ break;
+ }
+}
+
+READ16_DEVICE_HANDLER( omti8621_r ) {
+ omti8621_state *state = get_safe_token(device);
+ UINT16 data;
+ switch (mem_mask) {
+ case 0x00ff:
+ data = omti8621_r8(device, offset*2+1);
+ break;
+ case 0xff00:
+ data = omti8621_r8(device, offset*2) << 8;
+ break;
+ default:
+ data = get_data(state);
+ LOG3(("reading OMTI 8621 Data Word Register from %0x = %04x & %04x", offset, data, mem_mask));
+ break;
+ }
+ return data;
+}
+
+void omti8621_set_verbose(int on_off)
+{
+ verbose = on_off == 0 ? 0 : VERBOSE > 1 ? VERBOSE : 1;
+}
+
+/***************************************************************************
+ omti8621_get_sector - get sector diskaddr of logical unit lun into data_buffer
+ ***************************************************************************/
+
+UINT32 omti8621_get_sector(device_t *device, INT32 diskaddr, UINT8 *data_buffer, UINT32 length, UINT8 lun)
+{
+ omti8621_state *state = get_safe_token(device);
+ disk_data *disk = state->disk[lun];
+
+ if (disk->image == NULL || !disk->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->image->fseek(diskaddr * OMTI_DISK_SECTOR_SIZE, SEEK_SET);
+ disk->image->fread(data_buffer, length);
+
+ return length;
+ }
+}
+
+
+/***************************************************************************
+ omti_set_jumper - set OMI jumpers
+ ***************************************************************************/
+
+static void omti_set_jumper(omti8621_state *state, UINT16 disk_type)
+{
+ LOG1(("omti_set_jumper: disk type=%x", disk_type));
+
+ switch (disk_type)
+ {
+ case OMTI_DISK_TYPE_348_MB: // Maxtor 380 MB (348-MB FA formatted)
+ state->jumper = OMTI_CONFIG_W22 | OMTI_CONFIG_W23;
+ break;
+
+ case OMTI_DISK_TYPE_155_MB: // Micropolis 170 MB (155-MB formatted)
+ default:
+ state->jumper = OMTI_CONFIG_W20;
+ break;
+ }
+}
+
+
+//##########################################################################
+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);
+
+ disk_data *token() { return &m_token; }
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+ virtual void device_start();
+ virtual void device_reset();
+
+ disk_data m_token;
+};
+
+// device type definition
+extern const device_type OMTI_DISK;
+
+const device_type OMTI_DISK = &device_creator<omti_disk_image_device>;
+
+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, "Winchester", tag, owner, clock),
+ device_image_interface(mconfig, *this)
+{
+}
+
+void omti_disk_image_device::device_config_complete()
+{
+ update_names(OMTI_DISK, "disk", "disk");
+};
+
+
+/***************************************************************************
+ get_safe_disk_token - makes sure that the passed in device is a OMTI disk
+ ***************************************************************************/
+
+INLINE disk_data *get_safe_disk_token(device_t *device) {
+ assert(device != NULL);
+ assert(device->type() == OMTI_DISK);
+ return (disk_data *) downcast<omti_disk_image_device *>(device)->token();
+}
+
+/***************************************************************************
+ omti_disk_config - configure disk parameters
+ ***************************************************************************/
+
+static void omti_disk_config(disk_data *disk, UINT16 disk_type)
+{
+ DLOG1(("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)
+ disk->cylinders = 1223;
+ disk->heads = 15;
+ disk->sectors = 18;
+ break;
+
+ case OMTI_DISK_TYPE_155_MB: // Micropolis 170 MB (155-MB formatted)
+ default:
+ disk->cylinders = 1023;
+ disk->heads = 8;
+ disk->sectors = 18;
+ break;
+ }
+
+ disk->type = disk_type;
+ disk->sectorbytes = OMTI_DISK_SECTOR_SIZE;
+ disk->sector_count = disk->cylinders * disk->heads * disk->sectors;
+}
+
+/*-------------------------------------------------
+ device start callback
+-------------------------------------------------*/
+
+void omti_disk_image_device::device_start()
+{
+ disk_data *disk = get_safe_disk_token(this);
+
+ disk->device = this;
+ // note: we must have disk->device before we can log
+
+ disk->image = this;
+
+ if (disk->image->image_core_file() == NULL)
+ {
+ DLOG1(("device_start_omti_disk: no disk"));
+ }
+ else
+ {
+ DLOG1(("device_start_omti_disk: with disk image %s",disk->image->basename() ));
+ }
+
+ // default disk type
+ omti_disk_config(disk, OMTI_DISK_TYPE_DEFAULT);
+}
+
+/*-------------------------------------------------
+ device reset callback
+-------------------------------------------------*/
+
+void omti_disk_image_device::device_reset()
+{
+ disk_data *disk = get_safe_disk_token(this);
+ DLOG1(("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 != disk->type) {
+ DLOG1(("device_reset_omti_disk: disk size=%d blocks, disk type=%x", disk_size, disk_type ));
+ omti_disk_config(disk, disk_type);
+ }
+ }
+}
+
+/*-------------------------------------------------
+ disk image create callback
+-------------------------------------------------*/
+
+bool omti_disk_image_device::call_create(int format_type, option_resolution *format_options)
+{
+ disk_data *disk = get_safe_disk_token(this);
+ DLOG(("device_create_omti_disk: creating OMTI Disk with %d blocks", disk->sector_count));
+
+ int x;
+ unsigned char sectordata[OMTI_DISK_SECTOR_SIZE]; // empty block data
+
+
+ memset(sectordata, 0x55, sizeof(sectordata));
+ for (x = 0; x < disk->sector_count; x++)
+ {
+ if (fwrite(sectordata, OMTI_DISK_SECTOR_SIZE)
+ < OMTI_DISK_SECTOR_SIZE)
+ {
+ return IMAGE_INIT_FAIL;
+ }
+ }
+ return IMAGE_INIT_PASS;
+}
+
+MACHINE_CONFIG_FRAGMENT( omti_disk )
+ MCFG_DEVICE_ADD(OMTI_DISK0_TAG, OMTI_DISK, 0)
+ MCFG_DEVICE_ADD(OMTI_DISK1_TAG, OMTI_DISK, 0)
+MACHINE_CONFIG_END
+
+/*-------------------------------------------------
+ device start callback
+-------------------------------------------------*/
+
+static DEVICE_START( omti8621 ) {
+ omti8621_state *state = get_safe_token(device);
+
+ const omti8621_config *config =
+ (const omti8621_config *) device->static_config();
+
+ /* validate basic stuff */
+ assert(device != NULL);
+ assert(device->type() == OMTI8621);
+
+ /* store a pointer back to the device */
+ state->device = device;
+
+ // note: we must have state->device before we can log
+ LOG2(("device_start_omti8621"));
+
+ state->irq_handler = config->set_irq;
+
+ state->sector_buffer = auto_alloc_array(device->machine(), UINT8,
+ OMTI_DISK_SECTOR_SIZE*OMTI_MAX_BLOCK_COUNT);
+ assert(state->sector_buffer != NULL);
+
+ device_t *device0 = device->machine().device(OMTI_DISK0_TAG);
+ state->disk[0] = (disk_data *) downcast<omti_disk_image_device *>(device0)->token();
+
+ device_t *device1 = device->machine().device(OMTI_DISK1_TAG);
+ state->disk[1] = (disk_data *) downcast<omti_disk_image_device *>(device1)->token();
+}
+
+/*-------------------------------------------------
+ device reset callback
+-------------------------------------------------*/
+
+static DEVICE_RESET( omti8621 )
+{
+ omti8621_state *state = get_safe_token(device);
+ LOG2(("device_reset_omti8621"));
+
+ omti_set_jumper(state, state->disk[0]->type);
+ omti_reset(state);
+}
+
+/*-------------------------------------------------
+ device get info callback
+-------------------------------------------------*/
+
+DEVICE_GET_INFO( omti8621 )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(omti8621_state); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = sizeof(omti8621_config); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(omti8621); break;
+ case DEVINFO_FCT_STOP: /* Nothing */ break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(omti8621); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "OMTI 8621"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "Winchester Disk Controller");break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(OMTI8621, omti8621);
diff --git a/src/mess/machine/omti8621.h b/src/mess/machine/omti8621.h
new file mode 100644
index 00000000000..7d85a8c2cb8
--- /dev/null
+++ b/src/mess/machine/omti8621.h
@@ -0,0 +1,58 @@
+/*
+ * omti8621.h - SMS OMTI 8621 disk controller
+ *
+ * Created on: August 30, 2010
+ * Author: Hans Ostermeyer
+ *
+ * Released for general non-commercial use under the MAME license
+ * Visit http://mamedev.org for licensing and usage restrictions.
+ *
+ */
+
+#pragma once
+
+#ifndef OMTI8621_H_
+#define OMTI8621_H_
+
+#include "emu.h"
+
+/***************************************************************************
+ TYPE DEFINITIONS
+ ***************************************************************************/
+
+typedef void (*omti8621_set_irq)(const running_machine*, int);
+
+typedef struct _omti8621_config omti8621_config;
+struct _omti8621_config {
+ omti8621_set_irq set_irq;
+};
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+ ***************************************************************************/
+
+#define MCFG_OMTI8621_ADD(_tag, _config) \
+ MCFG_FRAGMENT_ADD( omti_disk ) \
+ MCFG_DEVICE_ADD(_tag, OMTI8621, 0) \
+ MCFG_DEVICE_CONFIG(_config)
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+ ***************************************************************************/
+
+READ16_DEVICE_HANDLER( omti8621_r );
+WRITE16_DEVICE_HANDLER( omti8621_w );
+
+void omti8621_set_verbose(int on_off);
+
+// get sector diskaddr of logical unit lun into data_buffer
+UINT32 omti8621_get_sector(device_t *device, INT32 diskaddr, UINT8 *data_buffer, UINT32 length, UINT8 lun);
+
+/* ----- device interface ----- */
+
+DECLARE_LEGACY_DEVICE(OMTI8621, omti8621);
+MACHINE_CONFIG_EXTERN( omti_disk );
+
+//###############################################################NEWNEW
+
+#endif /* OMTI8621_H_ */
diff --git a/src/mess/machine/ondra.c b/src/mess/machine/ondra.c
new file mode 100644
index 00000000000..c7b1b9a7fea
--- /dev/null
+++ b/src/mess/machine/ondra.c
@@ -0,0 +1,97 @@
+/***************************************************************************
+
+ Ondra driver by Miodrag Milanovic
+
+ 08/09/2008 Preliminary driver.
+
+****************************************************************************/
+
+
+#include "emu.h"
+#include "cpu/z80/z80.h"
+#include "imagedev/cassette.h"
+#include "includes/ondra.h"
+#include "machine/ram.h"
+
+
+static cassette_image_device *cassette_device_image(running_machine &machine)
+{
+ return machine.device<cassette_image_device>(CASSETTE_TAG);
+}
+
+
+READ8_MEMBER(ondra_state::ondra_keyboard_r)
+{
+ UINT8 retVal = 0x00;
+ UINT8 ondra_keyboard_line = offset & 0x000f;
+ static const char *const keynames[] = { "LINE0", "LINE1", "LINE2", "LINE3", "LINE4", "LINE5", "LINE6", "LINE7", "LINE8", "LINE9" };
+ double valcas = (cassette_device_image(machine())->input());
+ if ( valcas < 0.00) {
+ retVal = 0x80;
+ }
+ if (ondra_keyboard_line > 9) {
+ retVal |= 0x1f;
+ } else {
+ retVal |= ioport(keynames[ondra_keyboard_line])->read();
+ }
+ return retVal;
+}
+
+static void ondra_update_banks(running_machine &machine)
+{
+ ondra_state *state = machine.driver_data<ondra_state>();
+ UINT8 *mem = state->memregion("maincpu")->base();
+ if (state->m_bank1_status==0) {
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0x0000, 0x3fff);
+ state->membank("bank1")->set_base(mem + 0x010000);
+ } else {
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_write_bank(0x0000, 0x3fff, "bank1");
+ state->membank("bank1")->set_base(machine.device<ram_device>(RAM_TAG)->pointer() + 0x0000);
+ }
+ state->membank("bank2")->set_base(machine.device<ram_device>(RAM_TAG)->pointer() + 0x4000);
+ if (state->m_bank2_status==0) {
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(0xe000, 0xffff, "bank3");
+ state->membank("bank3")->set_base(machine.device<ram_device>(RAM_TAG)->pointer() + 0xe000);
+ } else {
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->unmap_write(0xe000, 0xffff);
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_read_handler (0xe000, 0xffff, read8_delegate(FUNC(ondra_state::ondra_keyboard_r),state));
+ }
+}
+
+WRITE8_MEMBER(ondra_state::ondra_port_03_w)
+{
+ m_video_enable = data & 1;
+ m_bank1_status = (data >> 1) & 1;
+ m_bank2_status = (data >> 2) & 1;
+ ondra_update_banks(machine());
+ cassette_device_image(machine())->output(((data >> 3) & 1) ? -1.0 : +1.0);
+}
+
+WRITE8_MEMBER(ondra_state::ondra_port_09_w)
+{
+}
+
+WRITE8_MEMBER(ondra_state::ondra_port_0a_w)
+{
+}
+
+static TIMER_CALLBACK(nmi_check_callback)
+{
+ if ((machine.root_device().ioport("NMI")->read() & 1) == 1)
+ {
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_NMI, PULSE_LINE);
+ }
+}
+
+MACHINE_RESET( ondra )
+{
+ ondra_state *state = machine.driver_data<ondra_state>();
+ state->m_bank1_status = 0;
+ state->m_bank2_status = 0;
+ ondra_update_banks(machine);
+}
+
+MACHINE_START(ondra)
+{
+ machine.scheduler().timer_pulse(attotime::from_hz(10), FUNC(nmi_check_callback));
+}
diff --git a/src/mess/machine/orao.c b/src/mess/machine/orao.c
new file mode 100644
index 00000000000..cec13613da3
--- /dev/null
+++ b/src/mess/machine/orao.c
@@ -0,0 +1,78 @@
+/***************************************************************************
+
+ Orao machine driver by Miodrag Milanovic
+
+ 23/02/2008 Sound support added.
+ 22/02/2008 Preliminary driver.
+
+****************************************************************************/
+
+#include "emu.h"
+#include "sound/dac.h"
+#include "imagedev/cassette.h"
+#include "includes/orao.h"
+
+
+/* Driver initialization */
+DRIVER_INIT_MEMBER(orao_state,orao)
+{
+ memset(m_memory,0xff,0x6000);
+}
+
+DRIVER_INIT_MEMBER(orao_state,orao103)
+{
+ memset(m_memory,0xff,0x6000);
+}
+
+MACHINE_RESET( orao )
+{
+}
+
+READ8_MEMBER(orao_state::orao_io_r)
+{
+ double level;
+
+ switch(offset) {
+ /* Keyboard*/
+ case 0x07FC : return ioport("LINE0")->read();
+ case 0x07FD : return ioport("LINE1")->read();
+ case 0x07FA : return ioport("LINE2")->read();
+ case 0x07FB : return ioport("LINE3")->read();
+ case 0x07F6 : return ioport("LINE4")->read();
+ case 0x07F7 : return ioport("LINE5")->read();
+ case 0x07EE : return ioport("LINE6")->read();
+ case 0x07EF : return ioport("LINE7")->read();
+ case 0x07DE : return ioport("LINE8")->read();
+ case 0x07DF : return ioport("LINE9")->read();
+ case 0x07BE : return ioport("LINE10")->read();
+ case 0x07BF : return ioport("LINE11")->read();
+ case 0x077E : return ioport("LINE12")->read();
+ case 0x077F : return ioport("LINE13")->read();
+ case 0x06FE : return ioport("LINE14")->read();
+ case 0x06FF : return ioport("LINE15")->read();
+ case 0x05FE : return ioport("LINE16")->read();
+ case 0x05FF : return ioport("LINE17")->read();
+ case 0x03FE : return ioport("LINE18")->read();
+ case 0x03FF : return ioport("LINE19")->read();
+ /* Tape */
+ case 0x07FF :
+ level = (machine().device<cassette_image_device>(CASSETTE_TAG)->input());
+ if (level < 0) {
+ return 0x00;
+ }
+ return 0xff;
+ }
+
+
+ return 0xff;
+}
+
+
+WRITE8_MEMBER(orao_state::orao_io_w)
+{
+ if (offset == 0x0800)
+ {
+ dac_device *dac = machine().device<dac_device>("dac");
+ dac->write_unsigned8(data); //beeper
+ }
+}
diff --git a/src/mess/machine/oric.c b/src/mess/machine/oric.c
new file mode 100644
index 00000000000..490cbeb1e1d
--- /dev/null
+++ b/src/mess/machine/oric.c
@@ -0,0 +1,1430 @@
+/*********************************************************************
+
+ machine/oric.c
+
+ Paul Cook
+ Kev Thacker
+
+ Thankyou to Fabrice Frances for his ORIC documentation which helped with this driver
+ http://oric.ifrance.com/oric/
+
+ TODO:
+ - there are problems loading some .wav's. Try to fix these.
+ - fix more graphics display problems
+ - check the printer works
+ - fix more disc drive/wd179x problems so more software will run
+
+*********************************************************************/
+
+
+#include "includes/oric.h"
+
+
+
+
+/* ==0 if oric1 or oric atmos, !=0 if telestrat */
+
+/* This does not exist in the real hardware. I have used it to
+know which sources are interrupting */
+/* bit 2 = telestrat 2nd via interrupt,
+1 = microdisc interface,
+0 = oric 1st via interrupt */
+
+enum
+{
+ ORIC_FLOPPY_NONE,
+ ORIC_FLOPPY_MFM_DISK,
+ ORIC_FLOPPY_BASIC_DISK
+};
+
+/* type of disc interface connected to oric/oric atmos */
+/* telestrat always has a microdisc interface */
+enum
+{
+ ORIC_FLOPPY_INTERFACE_NONE = 0,
+ ORIC_FLOPPY_INTERFACE_MICRODISC = 1,
+ ORIC_FLOPPY_INTERFACE_JASMIN = 2,
+ ORIC_FLOPPY_INTERFACE_APPLE2 = 3,
+ ORIC_FLOPPY_INTERFACE_APPLE2_V2 = 4
+};
+
+/* called when ints are changed - cleared/set */
+static void oric_refresh_ints(running_machine &machine)
+{
+ oric_state *state = machine.driver_data<oric_state>();
+ /* telestrat has floppy hardware built-in! */
+ if (state->m_is_telestrat==0)
+ {
+ /* oric 1 or oric atmos */
+
+ /* if floppy disc hardware is disabled, do not allow interrupts from it */
+ if ((machine.root_device().ioport("FLOPPY")->read() & 0x07) == ORIC_FLOPPY_INTERFACE_NONE)
+ state->m_irqs &=~(1<<1);
+ }
+
+ /* any irq set? */
+ if (state->m_irqs & 0x0f)
+ cputag_set_input_line(machine, "maincpu", 0, HOLD_LINE);
+ else
+ cputag_set_input_line(machine, "maincpu", 0, CLEAR_LINE);
+}
+
+
+
+/* index of keyboard line to scan */
+/* sense result */
+/* mask to read keys */
+
+
+
+
+
+/* refresh keyboard sense */
+static void oric_keyboard_sense_refresh(running_machine &machine)
+{
+ oric_state *state = machine.driver_data<oric_state>();
+ /* The following assumes that if a 0 is written, it can be used to detect if any key has been pressed.. */
+ /* for each bit that is 0, it combines it's pressed state with the pressed state so far */
+
+ int i;
+ unsigned char key_bit = 0;
+
+ /* what if data is 0, can it sense if any of the keys on a line are pressed? */
+ int input_port_data;
+ static const char *const keynames[] = { "ROW0", "ROW1", "ROW2", "ROW3", "ROW4", "ROW5", "ROW6", "ROW7" };
+
+ input_port_data = machine.root_device().ioport(keynames[state->m_keyboard_line])->read();
+
+ /* go through all bits in line */
+ for (i=0; i<8; i++)
+ {
+ /* sense this bit? */
+ if (((~state->m_keyboard_mask) & (1<<i)) != 0)
+ {
+ /* is key pressed? */
+ if (input_port_data & (1<<i))
+ {
+ /* yes */
+ key_bit |= 1;
+ }
+ }
+ }
+
+ /* clear sense result */
+ state->m_key_sense_bit = 0;
+
+ /* any keys pressed on this line? */
+ if (key_bit!=0)
+ {
+ /* set sense result */
+ state->m_key_sense_bit = (1<<3);
+ }
+}
+
+
+/* this is executed when a write to psg port a is done */
+WRITE8_MEMBER(oric_state::oric_psg_porta_write)
+{
+ m_keyboard_mask = data;
+}
+
+
+/* PSG control pins */
+/* bit 1 = BDIR state */
+/* bit 0 = BC1 state */
+
+/* this port is also used to read printer data */
+static READ8_DEVICE_HANDLER ( oric_via_in_a_func )
+{
+ oric_state *state = device->machine().driver_data<oric_state>();
+ address_space *space = device->machine().device( "maincpu")->memory().space( AS_PROGRAM );
+
+ /*logerror("port a read\r\n"); */
+
+ /* access psg? */
+ if (state->m_psg_control!=0)
+ {
+ /* if psg is in read register state return reg data */
+ if (state->m_psg_control==0x01)
+ return ay8910_r(space->machine().device("ay8912"), 0);
+
+ /* return high-impedance */
+ return 0x0ff;
+ }
+
+ /* correct?? */
+ return state->m_via_port_a_data;
+}
+
+static READ8_DEVICE_HANDLER ( oric_via_in_b_func )
+{
+ oric_state *state = device->machine().driver_data<oric_state>();
+ int data;
+
+ oric_keyboard_sense_refresh(device->machine());
+
+ data = state->m_key_sense_bit;
+ data |= state->m_keyboard_line & 0x07;
+
+ return data;
+}
+
+
+/* read/write data depending on state of bdir, bc1 pins and data output to psg */
+static void oric_psg_connection_refresh(running_machine &machine)
+{
+ oric_state *state = machine.driver_data<oric_state>();
+ if (state->m_psg_control!=0)
+ {
+ switch (state->m_psg_control)
+ {
+ /* PSG inactive */
+ case 0:
+ break;
+ /* read register data */
+ case 1:
+ {
+ //state->m_via_port_a_data = ay8910_read_port_0_r(space, 0);
+ }
+ break;
+ /* write register data */
+ case 2:
+ {
+ device_t *ay8912 = machine.device("ay8912");
+ ay8910_data_w(ay8912, 0, state->m_via_port_a_data);
+ }
+ break;
+ /* write register index */
+ case 3:
+ {
+ device_t *ay8912 = machine.device("ay8912");
+ ay8910_address_w(ay8912, 0, state->m_via_port_a_data);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return;
+ }
+}
+
+static WRITE8_DEVICE_HANDLER ( oric_via_out_a_func )
+{
+ oric_state *state = device->machine().driver_data<oric_state>();
+ state->m_via_port_a_data = data;
+
+ oric_psg_connection_refresh(device->machine());
+
+
+ if (state->m_psg_control==0)
+ {
+ /* if psg not selected, write to printer */
+ centronics_device *centronics = device->machine().device<centronics_device>("centronics");
+ centronics->write(*device->machine().memory().first_space(), 0, data);
+ }
+}
+
+/*
+PB0..PB2
+ keyboard lines-demultiplexer line 7
+
+PB3
+ keyboard sense line 0
+
+PB4
+ printer strobe line 1
+
+PB5
+ (not connected) ?? 1
+
+PB6
+ tape connector motor control 0
+
+PB7
+ tape connector output high 1
+
+ */
+
+
+static cassette_image_device *cassette_device_image(running_machine &machine)
+{
+ return machine.device<cassette_image_device>(CASSETTE_TAG);
+}
+
+/* not called yet - this will update the via with the state of the tape data.
+This allows the via to trigger on bit changes and issue interrupts */
+static TIMER_CALLBACK(oric_refresh_tape)
+{
+ int data;
+ int input_port_9;
+ via6522_device *via_0 = machine.device<via6522_device>("via6522_0");
+
+ data = 0;
+
+ if ((cassette_device_image(machine))->input() > 0.0038)
+ data |= 1;
+
+ /* "A simple cable to catch the vertical retrace signal !
+ This cable connects the video output for the television/monitor
+ to the via cb1 input. Interrupts can be generated from the vertical
+ sync, and flicker free games can be produced */
+
+ input_port_9 = machine.root_device().ioport("FLOPPY")->read();
+ /* cable is enabled? */
+ if ((input_port_9 & 0x08)!=0)
+ {
+ /* return state of vsync */
+ data = input_port_9>>4;
+ }
+
+ via_0->write_cb1(data);
+}
+
+static WRITE8_DEVICE_HANDLER ( oric_via_out_b_func )
+{
+ oric_state *state = device->machine().driver_data<oric_state>();
+ centronics_device *centronics = device->machine().device<centronics_device>("centronics");
+
+ /* KEYBOARD */
+ state->m_keyboard_line = data & 0x07;
+
+ /* CASSETTE */
+ /* cassette motor control */
+ cassette_device_image(device->machine())->change_state(
+ (data & 0x40) ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED,
+ CASSETTE_MOTOR_DISABLED);
+
+ /* cassette data out */
+ cassette_device_image(device->machine())->output((data & (1<<7)) ? -1.0 : +1.0);
+
+ /* centronics STROBE is connected to PB4 */
+ centronics->strobe_w(BIT(data, 4));
+
+ oric_psg_connection_refresh(device->machine());
+ state->m_previous_portb_data = data;
+}
+
+
+static READ8_DEVICE_HANDLER ( oric_via_in_ca2_func )
+{
+ oric_state *state = device->machine().driver_data<oric_state>();
+ return state->m_psg_control & 1;
+}
+
+static READ8_DEVICE_HANDLER ( oric_via_in_cb2_func )
+{
+ oric_state *state = device->machine().driver_data<oric_state>();
+ return (state->m_psg_control>>1) & 1;
+}
+
+static WRITE8_DEVICE_HANDLER ( oric_via_out_ca2_func )
+{
+ oric_state *state = device->machine().driver_data<oric_state>();
+ state->m_psg_control &=~1;
+
+ if (data)
+ state->m_psg_control |=1;
+
+ oric_psg_connection_refresh(device->machine());
+}
+
+static WRITE8_DEVICE_HANDLER ( oric_via_out_cb2_func )
+{
+ oric_state *state = device->machine().driver_data<oric_state>();
+ state->m_psg_control &=~2;
+
+ if (data)
+ state->m_psg_control |=2;
+
+ oric_psg_connection_refresh(device->machine());
+}
+
+
+static void oric_via_irq_func(device_t *device, int state)
+{
+ oric_state *drvstate = device->machine().driver_data<oric_state>();
+ drvstate->m_irqs &= ~(1<<0);
+
+ if (state)
+ drvstate->m_irqs |=(1<<0);
+
+ oric_refresh_ints(device->machine());
+}
+
+
+/*
+VIA Lines
+ Oric usage
+
+PA0..PA7
+ PSG data bus, printer data lines
+
+CA1
+ printer acknowledge line
+
+CA2
+ PSG BC1 line
+
+PB0..PB2
+ keyboard lines-demultiplexer
+
+PB3
+ keyboard sense line
+
+PB4
+ printer strobe line
+
+PB5
+ (not connected)
+
+PB6
+ tape connector motor control
+
+PB7
+ tape connector output
+
+CB1
+ tape connector input
+
+CB2
+ PSG BDIR line
+
+*/
+
+const via6522_interface oric_6522_interface=
+{
+ DEVCB_HANDLER(oric_via_in_a_func),
+ DEVCB_HANDLER(oric_via_in_b_func),
+ DEVCB_NULL, /* printer acknowledge - handled by callback*/
+ DEVCB_NULL, /* tape input - handled by timer */
+ DEVCB_HANDLER(oric_via_in_ca2_func),
+ DEVCB_HANDLER(oric_via_in_cb2_func),
+ DEVCB_HANDLER(oric_via_out_a_func),
+ DEVCB_HANDLER(oric_via_out_b_func),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(oric_via_out_ca2_func),
+ DEVCB_HANDLER(oric_via_out_cb2_func),
+ DEVCB_LINE(oric_via_irq_func),
+};
+
+
+
+
+/*********************/
+/* APPLE 2 INTERFACE */
+
+/*
+apple2 disc drive accessed through 0x0310-0x031f (read/write)
+oric via accessed through 0x0300-0x030f. (read/write)
+disk interface rom accessed through 0x0320-0x03ff (read only)
+
+CALL &320 to start, or use BOBY rom.
+*/
+
+static void oric_install_apple2_interface(running_machine &machine)
+{
+ oric_state *state = machine.driver_data<oric_state>();
+ device_t *fdc = machine.device("fdc");
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ if (state->m_is_telestrat)
+ return;
+
+ space->install_read_handler(0x0300, 0x030f, read8_delegate(FUNC(oric_state::oric_IO_r),state));
+ space->install_legacy_read_handler(*fdc, 0x0310, 0x031f, FUNC(applefdc_r));
+ space->install_read_bank(0x0320, 0x03ff, "bank4");
+
+ space->install_write_handler(0x0300, 0x030f, write8_delegate(FUNC(oric_state::oric_IO_w),state));
+ space->install_legacy_write_handler(*fdc, 0x0310, 0x031f, FUNC(applefdc_w));
+ state->membank("bank4")->set_base( state->memregion("maincpu")->base() + 0x014000 + 0x020);
+}
+
+
+static void oric_enable_memory(running_machine &machine, int low, int high, int rd, int wr)
+{
+ oric_state *state = machine.driver_data<oric_state>();
+ int i;
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ if (state->m_is_telestrat)
+ return;
+ for (i = low; i <= high; i++)
+ {
+ switch(i) {
+ case 1:
+ if (rd) {
+ space->install_read_bank(0xc000, 0xdfff, "bank1");
+ } else {
+ space->nop_read(0xc000, 0xdfff);
+ }
+ if (wr) {
+ space->install_write_bank(0xc000, 0xdfff, "bank5");
+ } else {
+ space->unmap_write(0xc000, 0xdfff);
+ }
+ break;
+ case 2:
+ if (rd) {
+ space->install_read_bank(0xe000, 0xf7ff, "bank2");
+ } else {
+ space->nop_read(0xe000, 0xf7ff);
+ }
+ if (wr) {
+ space->install_write_bank(0xe000, 0xf7ff, "bank6");
+ } else {
+ space->unmap_write(0xe000, 0xf7ff);
+ }
+ break;
+ case 3:
+ if (rd) {
+ space->install_read_bank(0xf800, 0xffff, "bank3");
+ } else {
+ space->nop_read(0xf800, 0xffff);
+ }
+ break;
+ }
+ }
+}
+
+
+
+/************************/
+/* APPLE 2 INTERFACE V2 */
+
+/*
+apple2 disc drive accessed through 0x0310-0x031f (read/write)
+oric via accessed through 0x0300-0x030f. (read/write)
+disk interface rom accessed through 0x0320-0x03ff (read only)
+v2 registers accessed through 0x0380-0x0383 (write only)
+
+CALL &320 to start, or use BOBY rom.
+*/
+
+WRITE8_MEMBER(oric_state::apple2_v2_interface_w)
+{
+ /* data is ignored, address is used to decode operation */
+ if (m_is_telestrat)
+ return;
+
+/* logerror("apple 2 interface v2 rom page: %01x\n",(offset & 0x02)>>1); */
+
+ /* bit 0 is 0 for page 0, 1 for page 1 */
+ membank("bank4")->set_base(machine().root_device().memregion("maincpu")->base() + 0x014000 + 0x0100 + (((offset & 0x02)>>1)<<8));
+
+ oric_enable_memory(machine(), 1, 3, TRUE, TRUE);
+
+ /* bit 1 is 0, rom enabled, bit 1 is 1 ram enabled */
+ if ((offset & 0x01)==0)
+ {
+ unsigned char *rom_ptr;
+
+ /* logerror("apple 2 interface v2: rom enabled\n"); */
+
+ /* enable rom */
+ rom_ptr = memregion("maincpu")->base() + 0x010000;
+ membank("bank1")->set_base(rom_ptr);
+ membank("bank2")->set_base(rom_ptr+0x02000);
+ membank("bank3")->set_base(rom_ptr+0x03800);
+ membank("bank5")->set_base(m_ram_0x0c000);
+ membank("bank6")->set_base(m_ram_0x0c000+0x02000);
+ membank("bank7")->set_base(m_ram_0x0c000+0x03800);
+ }
+ else
+ {
+ /*logerror("apple 2 interface v2: ram enabled\n"); */
+
+ /* enable ram */
+ membank("bank1")->set_base(m_ram_0x0c000);
+ membank("bank2")->set_base(m_ram_0x0c000+0x02000);
+ membank("bank3")->set_base(m_ram_0x0c000+0x03800);
+ membank("bank5")->set_base(m_ram_0x0c000);
+ membank("bank6")->set_base(m_ram_0x0c000+0x02000);
+ membank("bank7")->set_base(m_ram_0x0c000+0x03800);
+ }
+}
+
+
+/* APPLE 2 INTERFACE V2 */
+static void oric_install_apple2_v2_interface(running_machine &machine)
+{
+ oric_state *state = machine.driver_data<oric_state>();
+ device_t *fdc = machine.device("fdc");
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ space->install_read_handler(0x0300, 0x030f, read8_delegate(FUNC(oric_state::oric_IO_r),state));
+ space->install_legacy_read_handler(*fdc, 0x0310, 0x031f, FUNC(applefdc_r));
+ space->install_read_bank(0x0320, 0x03ff, "bank4");
+
+ space->install_write_handler(0x0300, 0x030f, write8_delegate(FUNC(oric_state::oric_IO_w),state));
+ space->install_legacy_write_handler(*fdc, 0x0310, 0x031f, FUNC(applefdc_w));
+ space->install_write_handler(0x0380, 0x0383, write8_delegate(FUNC(oric_state::apple2_v2_interface_w),state));
+
+ state->apple2_v2_interface_w(*space, 0, 0);
+}
+
+/********************/
+/* JASMIN INTERFACE */
+
+
+/* bit 0: overlay ram access (1 means overlay ram enabled) */
+
+/* bit 0: ROMDIS (1 means internal Basic rom disabled) */
+
+
+static void oric_jasmin_set_mem_0x0c000(running_machine &machine)
+{
+ oric_state *state = machine.driver_data<oric_state>();
+ /* assumption:
+ 1. It is possible to access all 16k overlay ram.
+ 2. If os is enabled, and overlay ram is enabled, all 16k can be accessed.
+ 3. if os is disabled, and overlay ram is enabled, jasmin rom takes priority.
+ */
+ if (state->m_is_telestrat)
+ return;
+
+ /* the ram is disabled in the jasmin rom which indicates that jasmin takes
+ priority over the ram */
+
+ /* basic rom disabled? */
+ if ((state->m_port_3fb_w & 0x01)==0)
+ {
+ /* no, it is enabled! */
+
+ /* overlay ram enabled? */
+ if ((state->m_port_3fa_w & 0x01)==0)
+ {
+ unsigned char *rom_ptr;
+
+ /* no it is disabled */
+ /*logerror("&c000-&ffff is os rom\n"); */
+
+ oric_enable_memory(machine, 1, 3, TRUE, FALSE);
+
+ rom_ptr = state->memregion("maincpu")->base() + 0x010000;
+ state->membank("bank1")->set_base(rom_ptr);
+ state->membank("bank2")->set_base(rom_ptr+0x02000);
+ state->membank("bank3")->set_base(rom_ptr+0x03800);
+ }
+ else
+ {
+ /*logerror("&c000-&ffff is ram\n"); */
+
+ oric_enable_memory(machine, 1, 3, TRUE, TRUE);
+
+ state->membank("bank1")->set_base(state->m_ram_0x0c000);
+ state->membank("bank2")->set_base(state->m_ram_0x0c000+0x02000);
+ state->membank("bank3")->set_base(state->m_ram_0x0c000+0x03800);
+ state->membank("bank5")->set_base(state->m_ram_0x0c000);
+ state->membank("bank6")->set_base(state->m_ram_0x0c000+0x02000);
+ state->membank("bank7")->set_base(state->m_ram_0x0c000+0x03800);
+ }
+ }
+ else
+ {
+ /* yes, basic rom is disabled */
+
+ if ((state->m_port_3fa_w & 0x01)==0)
+ {
+ /* overlay ram disabled */
+
+ /*logerror("&c000-&f8ff is nothing!\n"); */
+ oric_enable_memory(machine, 1, 2, FALSE, FALSE);
+ }
+ else
+ {
+ /*logerror("&c000-&f8ff is ram!\n"); */
+ oric_enable_memory(machine, 1, 2, TRUE, TRUE);
+
+ state->membank("bank1")->set_base(state->m_ram_0x0c000);
+ state->membank("bank2")->set_base(state->m_ram_0x0c000+0x02000);
+ state->membank("bank5")->set_base(state->m_ram_0x0c000);
+ state->membank("bank6")->set_base(state->m_ram_0x0c000+0x02000);
+ }
+
+ {
+ /* basic rom disabled */
+ unsigned char *rom_ptr;
+
+ /*logerror("&f800-&ffff is jasmin rom\n"); */
+ /* jasmin rom enabled */
+ oric_enable_memory(machine, 3, 3, TRUE, TRUE);
+ rom_ptr = machine.root_device().memregion("maincpu")->base() + 0x010000+0x04000+0x02000;
+ state->membank("bank3")->set_base(rom_ptr);
+ state->membank("bank7")->set_base(rom_ptr);
+ }
+ }
+}
+
+/* DRQ is connected to interrupt */
+static WRITE_LINE_DEVICE_HANDLER( oric_jasmin_wd179x_drq_w )
+{
+ oric_state *drvstate = device->machine().driver_data<oric_state>();
+ if (state)
+ drvstate->m_irqs |= (1<<1);
+ else
+ drvstate->m_irqs &=~(1<<1);
+
+ oric_refresh_ints(device->machine());
+}
+
+READ8_MEMBER(oric_state::oric_jasmin_r)
+{
+ via6522_device *via_0 = machine().device<via6522_device>("via6522_0");
+ device_t *fdc = machine().device("wd179x");
+ unsigned char data = 0x0ff;
+
+ switch (offset & 0x0f)
+ {
+ /* jasmin floppy disc interface */
+ case 0x04:
+ data = wd17xx_status_r(fdc, 0);
+ break;
+ case 0x05:
+ data =wd17xx_track_r(fdc, 0);
+ break;
+ case 0x06:
+ data = wd17xx_sector_r(fdc, 0);
+ break;
+ case 0x07:
+ data = wd17xx_data_r(fdc, 0);
+ break;
+ default:
+ data = via_0->read(space,offset & 0x0f);
+ //logerror("unhandled io read: %04x %02x\n", offset, data);
+ break;
+
+ }
+
+ return data;
+}
+
+WRITE8_MEMBER(oric_state::oric_jasmin_w)
+{
+ via6522_device *via_0 = machine().device<via6522_device>("via6522_0");
+ device_t *fdc = machine().device("wd179x");
+ switch (offset & 0x0f)
+ {
+ /* microdisc floppy disc interface */
+ case 0x04:
+ wd17xx_command_w(fdc, 0, data);
+ break;
+ case 0x05:
+ wd17xx_track_w(fdc, 0, data);
+ break;
+ case 0x06:
+ wd17xx_sector_w(fdc, 0, data);
+ break;
+ case 0x07:
+ wd17xx_data_w(fdc, 0, data);
+ break;
+ /* bit 0 = side */
+ case 0x08:
+ wd17xx_set_side(fdc,data & 0x01);
+ break;
+ /* any write will cause wd179x to reset */
+ case 0x09:
+ wd17xx_reset(fdc);
+ break;
+ case 0x0a:
+ //logerror("jasmin overlay ram w: %02x PC: %04x\n", data, cpu_get_pc(machine().device("maincpu")));
+ m_port_3fa_w = data;
+ oric_jasmin_set_mem_0x0c000(machine());
+ break;
+ case 0x0b:
+ //logerror("jasmin romdis w: %02x PC: %04x\n", data, cpu_get_pc(machine().device("maincpu")));
+ m_port_3fb_w = data;
+ oric_jasmin_set_mem_0x0c000(machine());
+ break;
+ /* bit 0,1 of addr is the drive */
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f:
+ wd17xx_set_drive(fdc,offset & 0x03);
+ break;
+
+ default:
+ via_0->write(space,offset & 0x0f, data);
+ break;
+ }
+}
+
+
+static void oric_install_jasmin_interface(running_machine &machine)
+{
+ oric_state *state = machine.driver_data<oric_state>();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ /* romdis */
+ state->m_port_3fb_w = 1;
+ oric_jasmin_set_mem_0x0c000(machine);
+
+ space->install_read_handler(0x0300, 0x03ef, read8_delegate(FUNC(oric_state::oric_IO_r),state));
+ space->install_read_handler(0x03f0, 0x03ff, read8_delegate(FUNC(oric_state::oric_jasmin_r),state));
+
+ space->install_write_handler(0x0300, 0x03ef, write8_delegate(FUNC(oric_state::oric_IO_w),state));
+ space->install_write_handler(0x03f0, 0x03ff, write8_delegate(FUNC(oric_state::oric_jasmin_w),state));
+}
+
+/*********************************/
+/* MICRODISC INTERFACE variables */
+
+/* used by Microdisc interfaces */
+
+/* bit 7 is intrq state */
+/* bit 7 is drq state (active low) */
+/* bit 6,5: drive */
+/* bit 4: side */
+/* bit 3: double density enable */
+/* bit 0: enable FDC IRQ to trigger IRQ on CPU */
+
+
+static void oric_microdisc_refresh_wd179x_ints(running_machine &machine)
+{
+ oric_state *state = machine.driver_data<oric_state>();
+ state->m_irqs &=~(1<<1);
+
+ if ((state->m_wd179x_int_state) && (state->m_port_314_w & (1<<0)))
+ {
+ /*logerror("oric microdisc interrupt\n"); */
+
+ state->m_irqs |=(1<<1);
+ }
+
+ oric_refresh_ints(machine);
+}
+
+static WRITE_LINE_DEVICE_HANDLER( oric_microdisc_wd179x_intrq_w )
+{
+ oric_state *drvstate = device->machine().driver_data<oric_state>();
+ drvstate->m_wd179x_int_state = state;
+
+ if (state)
+ drvstate->m_port_314_r &= ~(1<<7);
+ else
+ drvstate->m_port_314_r |=(1<<7);
+
+ oric_microdisc_refresh_wd179x_ints(device->machine());
+}
+
+static WRITE_LINE_DEVICE_HANDLER( oric_microdisc_wd179x_drq_w )
+{
+ oric_state *drvstate = device->machine().driver_data<oric_state>();
+ if (state)
+ drvstate->m_port_318_r &=~(1<<7);
+ else
+ drvstate->m_port_318_r |= (1<<7);
+}
+
+static void oric_microdisc_set_mem_0x0c000(running_machine &machine)
+{
+ oric_state *state = machine.driver_data<oric_state>();
+ if (state->m_is_telestrat)
+ return;
+
+ /* for 0x0c000-0x0dfff: */
+ /* if os disabled, ram takes priority */
+ /* /ROMDIS */
+ if ((state->m_port_314_w & (1<<1))==0)
+ {
+ /*logerror("&c000-&dfff is ram\n"); */
+ /* rom disabled enable ram */
+ oric_enable_memory(machine, 1, 1, TRUE, TRUE);
+ state->membank("bank1")->set_base(state->m_ram_0x0c000);
+ state->membank("bank5")->set_base(state->m_ram_0x0c000);
+ }
+ else
+ {
+ unsigned char *rom_ptr;
+ /*logerror("&c000-&dfff is os rom\n"); */
+ /* basic rom */
+ oric_enable_memory(machine, 1, 1, TRUE, FALSE);
+ rom_ptr = machine.root_device().memregion("maincpu")->base() + 0x010000;
+ state->membank("bank1")->set_base(rom_ptr);
+ state->membank("bank5")->set_base(rom_ptr);
+ }
+
+ /* for 0x0e000-0x0ffff */
+ /* if not disabled, os takes priority */
+ if ((state->m_port_314_w & (1<<1))!=0)
+ {
+ unsigned char *rom_ptr;
+ /*logerror("&e000-&ffff is os rom\n"); */
+ /* basic rom */
+ oric_enable_memory(machine, 2, 3, TRUE, FALSE);
+ rom_ptr = machine.root_device().memregion("maincpu")->base() + 0x010000;
+ state->membank("bank2")->set_base(rom_ptr+0x02000);
+ state->membank("bank3")->set_base(rom_ptr+0x03800);
+ state->membank("bank6")->set_base(rom_ptr+0x02000);
+ state->membank("bank7")->set_base(rom_ptr+0x03800);
+
+ }
+ else
+ {
+ /* if eprom is enabled, it takes priority over ram */
+ if ((state->m_port_314_w & (1<<7))==0)
+ {
+ unsigned char *rom_ptr;
+ /*logerror("&e000-&ffff is disk rom\n"); */
+ oric_enable_memory(machine, 2, 3, TRUE, FALSE);
+ /* enable rom of microdisc interface */
+ rom_ptr = machine.root_device().memregion("maincpu")->base() + 0x014000;
+ state->membank("bank2")->set_base(rom_ptr);
+ state->membank("bank3")->set_base(rom_ptr+0x01800);
+ }
+ else
+ {
+ /*logerror("&e000-&ffff is ram\n"); */
+ /* rom disabled enable ram */
+ oric_enable_memory(machine, 2, 3, TRUE, TRUE);
+ state->membank("bank2")->set_base(state->m_ram_0x0c000+0x02000);
+ state->membank("bank3")->set_base(state->m_ram_0x0c000+0x03800);
+ state->membank("bank6")->set_base(state->m_ram_0x0c000+0x02000);
+ state->membank("bank7")->set_base(state->m_ram_0x0c000+0x03800);
+ }
+ }
+}
+
+
+
+READ8_MEMBER(oric_state::oric_microdisc_r)
+{
+ unsigned char data = 0x0ff;
+ device_t *fdc = machine().device("wd179x");
+
+ switch (offset & 0x0ff)
+ {
+ /* microdisc floppy disc interface */
+ case 0x00:
+ data = wd17xx_status_r(fdc, 0);
+ break;
+ case 0x01:
+ data =wd17xx_track_r(fdc, 0);
+ break;
+ case 0x02:
+ data = wd17xx_sector_r(fdc, 0);
+ break;
+ case 0x03:
+ data = wd17xx_data_r(fdc, 0);
+ break;
+ case 0x04:
+ data = m_port_314_r | 0x07f;
+/* logerror("port_314_r: %02x\n",data); */
+ break;
+ case 0x08:
+ data = m_port_318_r | 0x07f;
+/* logerror("port_318_r: %02x\n",data); */
+ break;
+
+ default:
+ {
+ via6522_device *via_0 = machine().device<via6522_device>("via6522_0");
+ data = via_0->read(space, offset & 0x0f);
+ }
+ break;
+
+ }
+
+ return data;
+}
+
+WRITE8_MEMBER(oric_state::oric_microdisc_w)
+{
+ device_t *fdc = machine().device("wd179x");
+ switch (offset & 0x0ff)
+ {
+ /* microdisc floppy disc interface */
+ case 0x00:
+ wd17xx_command_w(fdc, 0, data);
+ break;
+ case 0x01:
+ wd17xx_track_w(fdc, 0, data);
+ break;
+ case 0x02:
+ wd17xx_sector_w(fdc, 0, data);
+ break;
+ case 0x03:
+ wd17xx_data_w(fdc, 0, data);
+ break;
+ case 0x04:
+ {
+ m_port_314_w = data;
+
+ //logerror("port_314_w: %02x\n",data);
+
+ /* bit 6,5: drive */
+ /* bit 4: side */
+ /* bit 3: double density enable */
+ /* bit 0: enable FDC IRQ to trigger IRQ on CPU */
+ wd17xx_set_drive(fdc,(data>>5) & 0x03);
+ wd17xx_set_side(fdc,(data>>4) & 0x01);
+ wd17xx_dden_w(fdc, !BIT(data, 3));
+
+ oric_microdisc_set_mem_0x0c000(machine());
+ oric_microdisc_refresh_wd179x_ints(machine());
+ }
+ break;
+
+ default:
+ {
+ via6522_device *via_0 = machine().device<via6522_device>("via6522_0");
+ via_0->write(space, offset & 0x0f, data);
+ }
+ break;
+ }
+}
+
+static void oric_install_microdisc_interface(running_machine &machine)
+{
+ oric_state *state = machine.driver_data<oric_state>();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ space->install_read_handler(0x0300, 0x030f, read8_delegate(FUNC(oric_state::oric_IO_r),state));
+ space->install_read_handler(0x0310, 0x031f, read8_delegate(FUNC(oric_state::oric_microdisc_r),state));
+ space->install_read_handler(0x0320, 0x03ff, read8_delegate(FUNC(oric_state::oric_IO_r),state));
+
+ space->install_write_handler(0x0300, 0x030f, write8_delegate(FUNC(oric_state::oric_IO_w),state));
+ space->install_write_handler(0x0310, 0x031f, write8_delegate(FUNC(oric_state::oric_microdisc_w),state));
+ space->install_write_handler(0x0320, 0x03ff, write8_delegate(FUNC(oric_state::oric_IO_w),state));
+
+ /* disable os rom, enable microdisc rom */
+ /* 0x0c000-0x0dfff will be ram, 0x0e000-0x0ffff will be microdisc rom */
+ state->m_port_314_w = 0x0ff^((1<<7) | (1<<1));
+
+ oric_microdisc_set_mem_0x0c000(machine);
+}
+
+
+
+/*********************************************************/
+
+static WRITE_LINE_DEVICE_HANDLER( oric_wd179x_intrq_w )
+{
+ if ((device->machine().root_device().ioport("FLOPPY")->read() & 0x07) == ORIC_FLOPPY_INTERFACE_MICRODISC)
+ oric_microdisc_wd179x_intrq_w(device, state);
+}
+
+static WRITE_LINE_DEVICE_HANDLER( oric_wd179x_drq_w )
+{
+ switch (device->machine().root_device().ioport("FLOPPY")->read() & 0x07)
+ {
+ default:
+ case ORIC_FLOPPY_INTERFACE_NONE:
+ case ORIC_FLOPPY_INTERFACE_APPLE2:
+ return;
+ case ORIC_FLOPPY_INTERFACE_MICRODISC:
+ oric_microdisc_wd179x_drq_w(device, state);
+ return;
+ case ORIC_FLOPPY_INTERFACE_JASMIN:
+ oric_jasmin_wd179x_drq_w(device, state);
+ return;
+ }
+}
+
+const wd17xx_interface oric_wd17xx_interface =
+{
+ DEVCB_NULL,
+ DEVCB_LINE(oric_wd179x_intrq_w),
+ DEVCB_LINE(oric_wd179x_drq_w),
+ {FLOPPY_0, FLOPPY_1, FLOPPY_2, FLOPPY_3}
+};
+
+static void oric_common_init_machine(running_machine &machine)
+{
+ oric_state *state = machine.driver_data<oric_state>();
+ /* clear all irqs */
+ state->m_irqs = 0;
+ state->m_ram_0x0c000 = NULL;
+ state->m_keyboard_line = 0;
+ state->m_key_sense_bit = 0;
+ state->m_keyboard_mask = 0;
+ state->m_via_port_a_data = 0;
+ state->m_psg_control = 0;
+ state->m_previous_portb_data = 0;
+ state->m_port_3fa_w = 0;
+ state->m_port_3fb_w = 0;
+ state->m_wd179x_int_state = 0;
+ state->m_port_314_r = 0;
+ state->m_port_318_r = 0;
+ state->m_port_314_w = 0;
+ machine.scheduler().timer_pulse(attotime::from_hz(4800), FUNC(oric_refresh_tape));
+}
+
+MACHINE_START( oric )
+{
+ oric_state *state = machine.driver_data<oric_state>();
+ oric_common_init_machine(machine);
+
+ state->m_is_telestrat = 0;
+
+ state->m_ram_0x0c000 = auto_alloc_array(machine, UINT8, 16384);
+}
+
+
+MACHINE_RESET( oric )
+{
+ oric_state *state = machine.driver_data<oric_state>();
+ int disc_interface_id = machine.root_device().ioport("FLOPPY")->read() & 0x07;
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ if (state->m_is_telestrat)
+ return;
+
+ switch (disc_interface_id)
+ {
+ default:
+
+ case ORIC_FLOPPY_INTERFACE_APPLE2:
+ case ORIC_FLOPPY_INTERFACE_NONE:
+ {
+ /* setup memory when there is no disc interface */
+ unsigned char *rom_ptr;
+
+ /* os rom */
+ oric_enable_memory(machine, 1, 3, TRUE, FALSE);
+ rom_ptr = state->memregion("maincpu")->base() + 0x010000;
+ state->membank("bank1")->set_base(rom_ptr);
+ state->membank("bank2")->set_base(rom_ptr+0x02000);
+ state->membank("bank3")->set_base(rom_ptr+0x03800);
+ state->membank("bank5")->set_base(rom_ptr);
+ state->membank("bank6")->set_base(rom_ptr+0x02000);
+ state->membank("bank7")->set_base(rom_ptr+0x03800);
+
+
+ if (disc_interface_id==ORIC_FLOPPY_INTERFACE_APPLE2)
+ {
+ oric_install_apple2_interface(machine);
+ }
+ else
+ {
+ space->install_read_handler(0x0300, 0x03ff, read8_delegate(FUNC(oric_state::oric_IO_r),state));
+ space->install_write_handler(0x0300, 0x03ff, write8_delegate(FUNC(oric_state::oric_IO_w),state));
+ }
+ }
+ break;
+
+ case ORIC_FLOPPY_INTERFACE_APPLE2_V2:
+ {
+ oric_install_apple2_v2_interface(machine);
+ }
+ break;
+
+
+ case ORIC_FLOPPY_INTERFACE_MICRODISC:
+ {
+ oric_install_microdisc_interface(machine);
+ }
+ break;
+
+ case ORIC_FLOPPY_INTERFACE_JASMIN:
+ {
+ oric_install_jasmin_interface(machine);
+ }
+ break;
+ }
+ machine.device("maincpu")->reset();
+}
+
+
+READ8_MEMBER(oric_state::oric_IO_r)
+{
+ via6522_device *via_0 = machine().device<via6522_device>("via6522_0");
+ switch (ioport("FLOPPY")->read() & 0x07)
+ {
+ default:
+ case ORIC_FLOPPY_INTERFACE_NONE:
+ break;
+
+ case ORIC_FLOPPY_INTERFACE_MICRODISC:
+ {
+ if ((offset>=0x010) && (offset<=0x01f))
+ {
+ return oric_microdisc_r(space, offset);
+ }
+ }
+ break;
+
+ case ORIC_FLOPPY_INTERFACE_JASMIN:
+ {
+ if ((offset>=0x0f4) && (offset<=0x0ff))
+ {
+ return oric_jasmin_r(space, offset);
+ }
+ }
+ break;
+ }
+
+ /* it is repeated */
+ return via_0->read(space, offset & 0x0f);
+}
+
+WRITE8_MEMBER(oric_state::oric_IO_w)
+{
+ via6522_device *via_0 = machine().device<via6522_device>("via6522_0");
+ switch (ioport("FLOPPY")->read() & 0x07)
+ {
+ default:
+ case ORIC_FLOPPY_INTERFACE_NONE:
+ break;
+
+ case ORIC_FLOPPY_INTERFACE_MICRODISC:
+ {
+ if ((offset >= 0x010) && (offset <= 0x01f))
+ {
+ oric_microdisc_w(space, offset, data);
+ return;
+ }
+ }
+ break;
+
+ case ORIC_FLOPPY_INTERFACE_JASMIN:
+ {
+ if ((offset >= 0x0f4) && (offset <= 0x0ff))
+ {
+ oric_jasmin_w(space, offset, data);
+ return;
+ }
+
+ }
+ break;
+ }
+
+ via_0->write(space, offset & 0x0f, data);
+}
+
+
+
+/**** TELESTRAT ****/
+
+/*
+VIA lines
+ Telestrat usage
+
+PA0..PA2
+ Memory bank selection
+
+PA3
+ "Midi" port pin 3
+
+PA4
+ RS232/Minitel selection
+
+PA5
+ Third mouse button (right joystick port pin 5)
+
+PA6
+ "Midi" port pin 5
+
+PA7
+ Second mouse button (right joystick port pin 9)
+
+CA1
+ "Midi" port pin 1
+
+CA2
+ not used ?
+
+PB0..PB4
+ Joystick ports
+
+PB5
+ Joystick doubler switch
+
+PB6
+ Select Left Joystick port
+
+PB7
+ Select Right Joystick port
+
+CB1
+ Phone Ring detection
+
+CB2
+ "Midi" port pin 4
+
+*/
+
+
+static void telestrat_refresh_mem(running_machine &machine)
+{
+ oric_state *state = machine.driver_data<oric_state>();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ telestrat_mem_block *mem_block = &state->m_telestrat_blocks[state->m_telestrat_bank_selection];
+
+ switch (mem_block->MemType)
+ {
+ case TELESTRAT_MEM_BLOCK_RAM:
+ {
+ state->membank("bank1")->set_base(mem_block->ptr);
+ state->membank("bank2")->set_base(mem_block->ptr);
+ space->install_read_bank(0xc000, 0xffff, "bank1");
+ space->install_write_bank(0xc000, 0xffff, "bank2");
+ }
+ break;
+
+ case TELESTRAT_MEM_BLOCK_ROM:
+ {
+ state->membank("bank1")->set_base(mem_block->ptr);
+ space->install_read_bank(0xc000, 0xffff, "bank1");
+ space->nop_write(0xc000, 0xffff);
+ }
+ break;
+
+ default:
+ case TELESTRAT_MEM_BLOCK_UNDEFINED:
+ {
+ space->nop_readwrite(0xc000, 0xffff);
+ }
+ break;
+ }
+}
+
+static READ8_DEVICE_HANDLER(telestrat_via2_in_a_func)
+{
+ oric_state *state = device->machine().driver_data<oric_state>();
+ //logerror("via 2 - port a %02x\n",state->m_telestrat_via2_port_a_data);
+ return state->m_telestrat_via2_port_a_data;
+}
+
+
+static WRITE8_DEVICE_HANDLER(telestrat_via2_out_a_func)
+{
+ oric_state *state = device->machine().driver_data<oric_state>();
+ //logerror("via 2 - port a w: %02x\n",data);
+
+ state->m_telestrat_via2_port_a_data = data;
+
+ if (((data^state->m_telestrat_bank_selection) & 0x07)!=0)
+ {
+ state->m_telestrat_bank_selection = data & 0x07;
+
+ telestrat_refresh_mem(device->machine());
+ }
+}
+
+static READ8_DEVICE_HANDLER(telestrat_via2_in_b_func)
+{
+ oric_state *state = device->machine().driver_data<oric_state>();
+ unsigned char data = 0x01f;
+
+ /* left joystick selected? */
+ if (state->m_telestrat_via2_port_b_data & (1<<6))
+ {
+ data &= state->ioport("JOY0")->read();
+ }
+
+ /* right joystick selected? */
+ if (state->m_telestrat_via2_port_b_data & (1<<7))
+ {
+ data &= device->machine().root_device().ioport("JOY1")->read();
+ }
+
+ data |= state->m_telestrat_via2_port_b_data & ((1<<7) | (1<<6) | (1<<5));
+
+ return data;
+}
+
+static WRITE8_DEVICE_HANDLER(telestrat_via2_out_b_func)
+{
+ oric_state *state = device->machine().driver_data<oric_state>();
+ state->m_telestrat_via2_port_b_data = data;
+}
+
+
+static void telestrat_via2_irq_func(device_t *device, int state)
+{
+ oric_state *drvstate = device->machine().driver_data<oric_state>();
+ drvstate->m_irqs &=~(1<<2);
+
+ if (state)
+ {
+ //logerror("telestrat via2 interrupt\n");
+
+ drvstate->m_irqs |=(1<<2);
+ }
+
+ oric_refresh_ints(device->machine());
+}
+
+const via6522_interface telestrat_via2_interface=
+{
+ DEVCB_HANDLER(telestrat_via2_in_a_func),
+ DEVCB_HANDLER(telestrat_via2_in_b_func),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(telestrat_via2_out_a_func),
+ DEVCB_HANDLER(telestrat_via2_out_b_func),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_LINE(telestrat_via2_irq_func),
+};
+
+#if 0
+/* interrupt state from acia6551 */
+static void telestrat_acia_callback(running_machine &machine, int irq_state)
+{
+ oric_state *state = machine.driver_data<oric_state>();
+ state->m_irqs&=~(1<<3);
+
+ if (irq_state)
+ {
+ state->m_irqs |= (1<<3);
+ }
+
+ oric_refresh_ints(machine);
+}
+#endif
+
+MACHINE_START( telestrat )
+{
+ oric_state *state = machine.driver_data<oric_state>();
+ UINT8 *mem = state->memregion("maincpu")->base();
+
+ oric_common_init_machine(machine);
+
+ state->m_telestrat_via2_port_a_data = 0;
+ state->m_telestrat_via2_port_b_data = 0;
+ state->m_is_telestrat = 1;
+
+ /* initialise overlay ram */
+ state->m_telestrat_blocks[0].MemType = TELESTRAT_MEM_BLOCK_RAM;
+ state->m_telestrat_blocks[0].ptr = mem+0x020000; //auto_alloc_array(machine, UINT8, 16384);
+
+ state->m_telestrat_blocks[1].MemType = TELESTRAT_MEM_BLOCK_RAM;
+ state->m_telestrat_blocks[1].ptr = mem+0x024000; //auto_alloc_array(machine, UINT8, 16384);
+
+ state->m_telestrat_blocks[2].MemType = TELESTRAT_MEM_BLOCK_RAM;
+ state->m_telestrat_blocks[2].ptr = mem+0x028000; //auto_alloc_array(machine, UINT8, 16384);
+
+ /* initialise default cartridge */
+ state->m_telestrat_blocks[3].MemType = TELESTRAT_MEM_BLOCK_ROM;
+ state->m_telestrat_blocks[3].ptr = mem+0x010000; // telmatic.rom
+
+ state->m_telestrat_blocks[4].MemType = TELESTRAT_MEM_BLOCK_RAM;
+ state->m_telestrat_blocks[4].ptr = mem+0x02c000; //auto_alloc_array(machine, UINT8, 16384);
+
+ /* initialise default cartridge */
+ state->m_telestrat_blocks[5].MemType = TELESTRAT_MEM_BLOCK_ROM;
+ state->m_telestrat_blocks[5].ptr = mem+0x014000; // teleass.rom
+
+ /* initialise default cartridge */
+ state->m_telestrat_blocks[6].MemType = TELESTRAT_MEM_BLOCK_ROM;
+ state->m_telestrat_blocks[6].ptr = mem+0x018000; // hyperbas.rom
+
+ /* initialise default cartridge */
+ state->m_telestrat_blocks[7].MemType = TELESTRAT_MEM_BLOCK_ROM;
+ state->m_telestrat_blocks[7].ptr = mem+0x01c000; // telmon24.rom
+
+ state->m_telestrat_bank_selection = 7;
+ telestrat_refresh_mem(machine);
+
+ /* disable os rom, enable microdisc rom */
+ /* 0x0c000-0x0dfff will be ram, 0x0e000-0x0ffff will be microdisc rom */
+ state->m_port_314_w = 0x0ff^((1<<7) | (1<<1));
+}
diff --git a/src/mess/machine/orion.c b/src/mess/machine/orion.c
new file mode 100644
index 00000000000..e860fc50f26
--- /dev/null
+++ b/src/mess/machine/orion.c
@@ -0,0 +1,626 @@
+/***************************************************************************
+
+ Orion machine driver by Miodrag Milanovic
+
+ 22/04/2008 Orion Pro added
+ 02/04/2008 Preliminary driver.
+
+****************************************************************************/
+
+
+#include "emu.h"
+#include "cpu/i8085/i8085.h"
+#include "imagedev/cassette.h"
+#include "machine/mc146818.h"
+#include "machine/wd17xx.h"
+#include "sound/speaker.h"
+#include "sound/ay8910.h"
+#include "includes/orion.h"
+#include "includes/radio86.h"
+#include "machine/ram.h"
+
+#define SCREEN_WIDTH_384 48
+#define SCREEN_WIDTH_480 60
+#define SCREEN_WIDTH_512 64
+
+
+
+
+
+static READ8_DEVICE_HANDLER (orion_romdisk_porta_r )
+{
+ orion_state *state = device->machine().driver_data<orion_state>();
+ UINT8 *romdisk = state->memregion("maincpu")->base() + 0x10000;
+ return romdisk[state->m_romdisk_msb*256+state->m_romdisk_lsb];
+}
+
+static WRITE8_DEVICE_HANDLER (orion_romdisk_portb_w )
+{
+ orion_state *state = device->machine().driver_data<orion_state>();
+ state->m_romdisk_lsb = data;
+}
+
+static WRITE8_DEVICE_HANDLER (orion_romdisk_portc_w )
+{
+ orion_state *state = device->machine().driver_data<orion_state>();
+ state->m_romdisk_msb = data;
+}
+
+I8255A_INTERFACE( orion128_ppi8255_interface_1)
+{
+ DEVCB_HANDLER(orion_romdisk_porta_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(orion_romdisk_portb_w),
+ DEVCB_NULL,
+ DEVCB_HANDLER(orion_romdisk_portc_w)
+};
+
+
+MACHINE_START( orion128 )
+{
+ orion_state *state = machine.driver_data<orion_state>();
+ state->m_video_mode_mask = 7;
+}
+
+READ8_MEMBER(orion_state::orion128_system_r)
+{
+ return machine().device<i8255_device>("ppi8255_2")->read(space, offset & 3);
+}
+
+WRITE8_MEMBER(orion_state::orion128_system_w)
+{
+ machine().device<i8255_device>("ppi8255_2")->write(space, offset & 3, data);
+}
+
+READ8_MEMBER(orion_state::orion128_romdisk_r)
+{
+ return machine().device<i8255_device>("ppi8255_1")->read(space, offset & 3);
+}
+
+WRITE8_MEMBER(orion_state::orion128_romdisk_w)
+{
+ machine().device<i8255_device>("ppi8255_1")->write(space, offset & 3, data);
+}
+
+static void orion_set_video_mode(running_machine &machine, int width)
+{
+ rectangle visarea(0, width-1, 0, 255);
+ machine.primary_screen->configure(width, 256, visarea, machine.primary_screen->frame_period().attoseconds);
+}
+
+WRITE8_MEMBER(orion_state::orion128_video_mode_w)
+{
+ if ((data & 0x80)!=(m_orion128_video_mode & 0x80))
+ {
+ if ((data & 0x80)==0x80)
+ {
+ if (m_video_mode_mask == 31)
+ {
+ m_orion128_video_width = SCREEN_WIDTH_512;
+ orion_set_video_mode(machine(),512);
+ }
+ else
+ {
+ m_orion128_video_width = SCREEN_WIDTH_480;
+ orion_set_video_mode(machine(),480);
+ }
+ }
+ else
+ {
+ m_orion128_video_width = SCREEN_WIDTH_384;
+ orion_set_video_mode(machine(),384);
+ }
+ }
+
+ m_orion128_video_mode = data;
+}
+
+WRITE8_MEMBER(orion_state::orion128_video_page_w)
+{
+ if (m_orion128_video_page != data)
+ {
+ if ((data & 0x80)!=(m_orion128_video_page & 0x80))
+ {
+ if ((data & 0x80)==0x80)
+ {
+ if (m_video_mode_mask == 31)
+ {
+ m_orion128_video_width = SCREEN_WIDTH_512;
+ orion_set_video_mode(machine(),512);
+ }
+ else
+ {
+ m_orion128_video_width = SCREEN_WIDTH_480;
+ orion_set_video_mode(machine(),480);
+ }
+ }
+ else
+ {
+ m_orion128_video_width = SCREEN_WIDTH_384;
+ orion_set_video_mode(machine(),384);
+ }
+ }
+ }
+ m_orion128_video_page = data;
+}
+
+
+WRITE8_MEMBER(orion_state::orion128_memory_page_w)
+{
+ if (data!=m_orion128_memory_page )
+ {
+ membank("bank1")->set_base(machine().device<ram_device>(RAM_TAG)->pointer() + (data & 3) * 0x10000);
+ m_orion128_memory_page = (data & 3);
+ }
+}
+
+MACHINE_RESET ( orion128 )
+{
+ orion_state *state = machine.driver_data<orion_state>();
+ state->m_orion128_video_page = 0;
+ state->m_orion128_video_mode = 0;
+ state->m_orion128_memory_page = -1;
+ state->membank("bank1")->set_base(state->memregion("maincpu")->base() + 0xf800);
+ state->membank("bank2")->set_base(machine.device<ram_device>(RAM_TAG)->pointer() + 0xf000);
+ state->m_orion128_video_width = SCREEN_WIDTH_384;
+ orion_set_video_mode(machine,384);
+ radio86_init_keyboard(machine);
+}
+
+WRITE8_MEMBER(orion_state::orion_disk_control_w)
+{
+ device_t *fdc = machine().device("wd1793");
+
+ wd17xx_set_side(fdc,((data & 0x10) >> 4) ^ 1);
+ wd17xx_set_drive(fdc,data & 3);
+}
+
+READ8_MEMBER(orion_state::orion128_floppy_r)
+{
+ device_t *fdc = machine().device("wd1793");
+
+ switch(offset)
+ {
+ case 0x0 :
+ case 0x10 : return wd17xx_status_r(fdc,0);
+ case 0x1 :
+ case 0x11 : return wd17xx_track_r(fdc,0);
+ case 0x2 :
+ case 0x12 : return wd17xx_sector_r(fdc,0);
+ case 0x3 :
+ case 0x13 : return wd17xx_data_r(fdc,0);
+ }
+ return 0xff;
+}
+
+WRITE8_MEMBER(orion_state::orion128_floppy_w)
+{
+ device_t *fdc = machine().device("wd1793");
+
+ switch(offset)
+ {
+ case 0x0 :
+ case 0x10 : wd17xx_command_w(fdc,0,data); break;
+ case 0x1 :
+ case 0x11 : wd17xx_track_w(fdc,0,data);break;
+ case 0x2 :
+ case 0x12 : wd17xx_sector_w(fdc,0,data);break;
+ case 0x3 :
+ case 0x13 : wd17xx_data_w(fdc,0,data);break;
+ case 0x4 :
+ case 0x14 :
+ case 0x20 : orion_disk_control_w(space, offset, data);break;
+ }
+}
+READ8_MEMBER(orion_state::orionz80_floppy_rtc_r)
+{
+ if ((offset >= 0x60) && (offset <= 0x6f))
+ {
+ return machine().device<mc146818_device>("rtc")->read(space,offset-0x60);
+ }
+ else
+ {
+ return orion128_floppy_r(space,offset);
+ }
+}
+
+WRITE8_MEMBER(orion_state::orionz80_floppy_rtc_w)
+{
+ if ((offset >= 0x60) && (offset <= 0x6f))
+ {
+ machine().device<mc146818_device>("rtc")->write(space,offset-0x60,data);
+ }
+ else
+ {
+ orion128_floppy_w(space,offset,data);
+ }
+}
+
+
+MACHINE_START( orionz80 )
+{
+ orion_state *state = machine.driver_data<orion_state>();
+ state->m_video_mode_mask = 7;
+}
+
+WRITE8_MEMBER(orion_state::orionz80_sound_w)
+{
+ device_t *speaker = machine().device(SPEAKER_TAG);
+ if (m_speaker == 0)
+ {
+ m_speaker = data;
+ }
+ else
+ {
+ m_speaker = 0 ;
+ }
+ speaker_level_w(speaker,m_speaker);
+
+}
+
+WRITE8_MEMBER(orion_state::orionz80_sound_fe_w)
+{
+ device_t *speaker = machine().device(SPEAKER_TAG);
+ speaker_level_w(speaker,(data>>4) & 0x01);
+}
+
+
+static void orionz80_switch_bank(running_machine &machine)
+{
+ orion_state *state = machine.driver_data<orion_state>();
+ UINT8 bank_select;
+ UINT8 segment_select;
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ bank_select = (state->m_orionz80_dispatcher & 0x0c) >> 2;
+ segment_select = state->m_orionz80_dispatcher & 0x03;
+
+ space->install_write_bank(0x0000, 0x3fff, "bank1");
+ if ((state->m_orionz80_dispatcher & 0x80)==0)
+ { // dispatcher on
+ state->membank("bank1")->set_base(machine.device<ram_device>(RAM_TAG)->pointer() + 0x10000 * bank_select + segment_select * 0x4000 );
+ }
+ else
+ { // dispatcher off
+ state->membank("bank1")->set_base(machine.device<ram_device>(RAM_TAG)->pointer() + 0x10000 * state->m_orionz80_memory_page);
+ }
+
+ state->membank("bank2")->set_base(machine.device<ram_device>(RAM_TAG)->pointer() + 0x4000 + 0x10000 * state->m_orionz80_memory_page);
+
+ if ((state->m_orionz80_dispatcher & 0x20) == 0)
+ {
+ space->install_write_handler(0xf400, 0xf4ff, write8_delegate(FUNC(orion_state::orion128_system_w),state));
+ space->install_write_handler(0xf500, 0xf5ff, write8_delegate(FUNC(orion_state::orion128_romdisk_w),state));
+ space->install_write_handler(0xf700, 0xf7ff, write8_delegate(FUNC(orion_state::orionz80_floppy_rtc_w),state));
+ space->install_read_handler(0xf400, 0xf4ff, read8_delegate(FUNC(orion_state::orion128_system_r),state));
+ space->install_read_handler(0xf500, 0xf5ff, read8_delegate(FUNC(orion_state::orion128_romdisk_r),state));
+ space->install_read_handler(0xf700, 0xf7ff, read8_delegate(FUNC(orion_state::orionz80_floppy_rtc_r),state));
+
+ space->install_write_handler(0xf800, 0xf8ff, write8_delegate(FUNC(orion_state::orion128_video_mode_w),state));
+ space->install_write_handler(0xf900, 0xf9ff, write8_delegate(FUNC(orion_state::orionz80_memory_page_w),state));
+ space->install_write_handler(0xfa00, 0xfaff, write8_delegate(FUNC(orion_state::orion128_video_page_w),state));
+ space->install_write_handler(0xfb00, 0xfbff, write8_delegate(FUNC(orion_state::orionz80_dispatcher_w),state));
+ space->unmap_write(0xfc00, 0xfeff);
+ space->install_write_handler(0xff00, 0xffff, write8_delegate(FUNC(orion_state::orionz80_sound_w),state));
+
+ state->membank("bank3")->set_base(machine.device<ram_device>(RAM_TAG)->pointer() + 0xf000);
+ state->membank("bank5")->set_base(machine.root_device().memregion("maincpu")->base() + 0xf800);
+
+ }
+ else
+ {
+ /* if it is full memory access */
+ state->membank("bank3")->set_base(machine.device<ram_device>(RAM_TAG)->pointer() + 0xf000 + 0x10000 * state->m_orionz80_memory_page);
+ state->membank("bank4")->set_base(machine.device<ram_device>(RAM_TAG)->pointer() + 0xf400 + 0x10000 * state->m_orionz80_memory_page);
+ state->membank("bank5")->set_base(machine.device<ram_device>(RAM_TAG)->pointer() + 0xf800 + 0x10000 * state->m_orionz80_memory_page);
+ }
+}
+
+WRITE8_MEMBER(orion_state::orionz80_memory_page_w)
+{
+ m_orionz80_memory_page = data & 7;
+ orionz80_switch_bank(machine());
+}
+
+WRITE8_MEMBER(orion_state::orionz80_dispatcher_w)
+{
+ m_orionz80_dispatcher = data;
+ orionz80_switch_bank(machine());
+}
+
+MACHINE_RESET ( orionz80 )
+{
+ orion_state *state = machine.driver_data<orion_state>();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ space->unmap_write(0x0000, 0x3fff);
+ space->install_write_bank(0x4000, 0xefff, "bank2");
+ space->install_write_bank(0xf000, 0xf3ff, "bank3");
+
+ space->install_write_handler(0xf400, 0xf4ff, write8_delegate(FUNC(orion_state::orion128_system_w),state));
+ space->install_write_handler(0xf500, 0xf5ff, write8_delegate(FUNC(orion_state::orion128_romdisk_w),state));
+ space->install_write_handler(0xf700, 0xf7ff, write8_delegate(FUNC(orion_state::orionz80_floppy_rtc_w),state));
+ space->install_read_handler(0xf400, 0xf4ff, read8_delegate(FUNC(orion_state::orion128_system_r),state));
+ space->install_read_handler(0xf500, 0xf5ff, read8_delegate(FUNC(orion_state::orion128_romdisk_r),state));
+ space->install_read_handler(0xf700, 0xf7ff, read8_delegate(FUNC(orion_state::orionz80_floppy_rtc_r),state));
+
+ space->install_write_handler(0xf800, 0xf8ff, write8_delegate(FUNC(orion_state::orion128_video_mode_w),state));
+ space->install_write_handler(0xf900, 0xf9ff, write8_delegate(FUNC(orion_state::orionz80_memory_page_w),state));
+ space->install_write_handler(0xfa00, 0xfaff, write8_delegate(FUNC(orion_state::orion128_video_page_w),state));
+ space->install_write_handler(0xfb00, 0xfbff, write8_delegate(FUNC(orion_state::orionz80_dispatcher_w),state));
+ space->unmap_write(0xfc00, 0xfeff);
+ space->install_write_handler(0xff00, 0xffff, write8_delegate(FUNC(orion_state::orionz80_sound_w),state));
+
+
+ state->membank("bank1")->set_base(machine.root_device().memregion("maincpu")->base() + 0xf800);
+ state->membank("bank2")->set_base(machine.device<ram_device>(RAM_TAG)->pointer() + 0x4000);
+ state->membank("bank3")->set_base(machine.device<ram_device>(RAM_TAG)->pointer() + 0xf000);
+ state->membank("bank5")->set_base(state->memregion("maincpu")->base() + 0xf800);
+
+
+ state->m_orion128_video_page = 0;
+ state->m_orion128_video_mode = 0;
+ state->m_orionz80_memory_page = 0;
+ state->m_orionz80_dispatcher = 0;
+ state->m_speaker = 0;
+ state->m_orion128_video_width = SCREEN_WIDTH_384;
+ orion_set_video_mode(machine,384);
+ radio86_init_keyboard(machine);
+}
+
+INTERRUPT_GEN( orionz80_interrupt )
+{
+ orion_state *state = device->machine().driver_data<orion_state>();
+ if ((state->m_orionz80_dispatcher & 0x40)==0x40)
+ {
+ device_set_input_line(device, 0, HOLD_LINE);
+ }
+}
+
+READ8_MEMBER(orion_state::orionz80_io_r)
+{
+ if (offset == 0xFFFD)
+ {
+ return ay8910_r (machine().device("ay8912"), 0);
+ }
+ return 0xff;
+}
+
+WRITE8_MEMBER(orion_state::orionz80_io_w)
+{
+ switch (offset & 0xff)
+ {
+ case 0xf8 : orion128_video_mode_w(space,0,data);break;
+ case 0xf9 : orionz80_memory_page_w(space,0,data);break;
+ case 0xfa : orion128_video_page_w(space,0,data);break;
+ case 0xfb : orionz80_dispatcher_w(space,0,data);break;
+ case 0xfe : orionz80_sound_fe_w(space,0,data);break;
+ case 0xff : orionz80_sound_w(space,0,data);break;
+ }
+ switch(offset)
+ {
+ case 0xfffd : ay8910_address_w(machine().device("ay8912"), 0, data);
+ break;
+ case 0xbffd :
+ case 0xbefd : ay8910_data_w(machine().device("ay8912"), 0, data);
+ break;
+ }
+}
+
+
+
+
+
+
+
+static void orionpro_bank_switch(running_machine &machine)
+{
+ orion_state *state = machine.driver_data<orion_state>();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ int page = state->m_orionpro_page & 7; // we have only 8 pages
+ int is128 = (state->m_orionpro_dispatcher & 0x80) ? 1 : 0;
+ UINT8 *ram = machine.device<ram_device>(RAM_TAG)->pointer();
+
+ if (is128==1)
+ {
+ page = state->m_orionpro_128_page & 7;
+ }
+ space->install_write_bank(0x0000, 0x1fff, "bank1");
+ space->install_write_bank(0x2000, 0x3fff, "bank2");
+ space->install_write_bank(0x4000, 0x7fff, "bank3");
+ space->install_write_bank(0x8000, 0xbfff, "bank4");
+ space->install_write_bank(0xc000, 0xefff, "bank5");
+ space->install_write_bank(0xf000, 0xf3ff, "bank6");
+ space->install_write_bank(0xf400, 0xf7ff, "bank7");
+ space->install_write_bank(0xf800, 0xffff, "bank8");
+
+
+ if ((state->m_orionpro_dispatcher & 0x01)==0x00)
+ { // RAM0 segment disabled
+ state->membank("bank1")->set_base(ram + 0x10000 * page);
+ state->membank("bank2")->set_base(ram + 0x10000 * page + 0x2000);
+ }
+ else
+ {
+ state->membank("bank1")->set_base(ram + (state->m_orionpro_ram0_segment & 31) * 0x4000);
+ state->membank("bank2")->set_base(ram + (state->m_orionpro_ram0_segment & 31) * 0x4000 + 0x2000);
+ }
+ if ((state->m_orionpro_dispatcher & 0x10)==0x10)
+ { // ROM1 enabled
+ space->unmap_write(0x0000, 0x1fff);
+ state->membank("bank1")->set_base(machine.root_device().memregion("maincpu")->base() + 0x20000);
+ }
+ if ((state->m_orionpro_dispatcher & 0x08)==0x08)
+ { // ROM2 enabled
+ space->unmap_write(0x2000, 0x3fff);
+ state->membank("bank2")->set_base(machine.root_device().memregion("maincpu")->base() + 0x22000 + (state->m_orionpro_rom2_segment & 7) * 0x2000);
+ }
+
+ if ((state->m_orionpro_dispatcher & 0x02)==0x00)
+ { // RAM1 segment disabled
+ state->membank("bank3")->set_base(ram + 0x10000 * page + 0x4000);
+ }
+ else
+ {
+ state->membank("bank3")->set_base(ram + (state->m_orionpro_ram1_segment & 31) * 0x4000);
+ }
+
+ if ((state->m_orionpro_dispatcher & 0x04)==0x00)
+ { // RAM2 segment disabled
+ state->membank("bank4")->set_base(ram + 0x10000 * page + 0x8000);
+ }
+ else
+ {
+ state->membank("bank4")->set_base(ram + (state->m_orionpro_ram2_segment & 31) * 0x4000);
+ }
+
+ state->membank("bank5")->set_base(ram + 0x10000 * page + 0xc000);
+
+ if (is128)
+ {
+ state->membank("bank6")->set_base(ram + 0x10000 * 0 + 0xf000);
+
+ space->install_write_handler(0xf400, 0xf4ff, write8_delegate(FUNC(orion_state::orion128_system_w),state));
+ space->install_write_handler(0xf500, 0xf5ff, write8_delegate(FUNC(orion_state::orion128_romdisk_w),state));
+ space->unmap_write(0xf600, 0xf6ff);
+ space->install_write_handler(0xf700, 0xf7ff, write8_delegate(FUNC(orion_state::orion128_floppy_w),state));
+ space->install_read_handler(0xf400, 0xf4ff, read8_delegate(FUNC(orion_state::orion128_system_r),state));
+ space->install_read_handler(0xf500, 0xf5ff, read8_delegate(FUNC(orion_state::orion128_romdisk_r),state));
+ space->unmap_read(0xf600, 0xf6ff);
+ space->install_read_handler(0xf700, 0xf7ff, read8_delegate(FUNC(orion_state::orion128_floppy_r),state));
+
+ space->install_write_handler(0xf800, 0xf8ff, write8_delegate(FUNC(orion_state::orion128_video_mode_w),state));
+ space->install_write_handler(0xf900, 0xf9ff, write8_delegate(FUNC(orion_state::orionpro_memory_page_w),state));
+ space->install_write_handler(0xfa00, 0xfaff, write8_delegate(FUNC(orion_state::orion128_video_page_w),state));
+ space->unmap_write(0xfb00, 0xfeff);
+ space->install_write_handler(0xff00, 0xffff, write8_delegate(FUNC(orion_state::orionz80_sound_w),state));
+
+
+ state->membank("bank8")->set_base(ram + 0x10000 * 0 + 0xf800);
+ }
+ else
+ {
+ if ((state->m_orionpro_dispatcher & 0x40)==0x40)
+ { // FIX F000 enabled
+ state->membank("bank6")->set_base(ram + 0x10000 * 0 + 0xf000);
+ state->membank("bank7")->set_base(ram + 0x10000 * 0 + 0xf400);
+ state->membank("bank8")->set_base(ram + 0x10000 * 0 + 0xf800);
+ }
+ else
+ {
+ state->membank("bank6")->set_base(ram + 0x10000 * page + 0xf000);
+ state->membank("bank7")->set_base(ram + 0x10000 * page + 0xf400);
+ state->membank("bank8")->set_base(ram + 0x10000 * page + 0xf800);
+ }
+ }
+}
+
+WRITE8_MEMBER(orion_state::orionpro_memory_page_w)
+{
+ m_orionpro_128_page = data;
+ orionpro_bank_switch(machine());
+}
+
+MACHINE_RESET ( orionpro )
+{
+ orion_state *state = machine.driver_data<orion_state>();
+ radio86_init_keyboard(machine);
+
+ state->m_orion128_video_page = 0;
+ state->m_orion128_video_mode = 0;
+ state->m_orionpro_ram0_segment = 0;
+ state->m_orionpro_ram1_segment = 0;
+ state->m_orionpro_ram2_segment = 0;
+
+ state->m_orionpro_page = 0;
+ state->m_orionpro_128_page = 0;
+ state->m_orionpro_rom2_segment = 0;
+
+ state->m_orionpro_dispatcher = 0x50;
+ orionpro_bank_switch(machine);
+
+ state->m_speaker = 0;
+ state->m_orion128_video_width = SCREEN_WIDTH_384;
+ orion_set_video_mode(machine,384);
+
+ state->m_video_mode_mask = 31;
+ state->m_orionpro_pseudo_color = 0;
+}
+
+READ8_MEMBER(orion_state::orionpro_io_r)
+{
+ device_t *fdc = machine().device("wd1793");
+
+ switch (offset & 0xff)
+ {
+ case 0x00 : return 0x56;
+ case 0x04 : return m_orionpro_ram0_segment;
+ case 0x05 : return m_orionpro_ram1_segment;
+ case 0x06 : return m_orionpro_ram2_segment;
+ case 0x08 : return m_orionpro_page;
+ case 0x09 : return m_orionpro_rom2_segment;
+ case 0x0a : return m_orionpro_dispatcher;
+ case 0x10 : return wd17xx_status_r(fdc,0);
+ case 0x11 : return wd17xx_track_r(fdc,0);
+ case 0x12 : return wd17xx_sector_r(fdc,0);
+ case 0x13 : return wd17xx_data_r(fdc,0);
+ case 0x18 :
+ case 0x19 :
+ case 0x1a :
+ case 0x1b :
+ return orion128_system_r(space,(offset & 0xff)-0x18);
+ case 0x28 : return orion128_romdisk_r(space,0);
+ case 0x29 : return orion128_romdisk_r(space,1);
+ case 0x2a : return orion128_romdisk_r(space,2);
+ case 0x2b : return orion128_romdisk_r(space,3);
+ }
+ if (offset == 0xFFFD)
+ {
+ return ay8910_r (machine().device("ay8912"), 0);
+ }
+ return 0xff;
+}
+
+WRITE8_MEMBER(orion_state::orionpro_io_w)
+{
+ device_t *fdc = machine().device("wd1793");
+
+ switch (offset & 0xff)
+ {
+ case 0x04 : m_orionpro_ram0_segment = data; orionpro_bank_switch(machine()); break;
+ case 0x05 : m_orionpro_ram1_segment = data; orionpro_bank_switch(machine()); break;
+ case 0x06 : m_orionpro_ram2_segment = data; orionpro_bank_switch(machine()); break;
+ case 0x08 : m_orionpro_page = data; orionpro_bank_switch(machine()); break;
+ case 0x09 : m_orionpro_rom2_segment = data; orionpro_bank_switch(machine()); break;
+ case 0x0a : m_orionpro_dispatcher = data; orionpro_bank_switch(machine()); break;
+ case 0x10 : wd17xx_command_w(fdc,0,data); break;
+ case 0x11 : wd17xx_track_w(fdc,0,data);break;
+ case 0x12 : wd17xx_sector_w(fdc,0,data);break;
+ case 0x13 : wd17xx_data_w(fdc,0,data);break;
+ case 0x14 : orion_disk_control_w(space, 9, data);break;
+ case 0x18 :
+ case 0x19 :
+ case 0x1a :
+ case 0x1b :
+ orion128_system_w(space,(offset & 0xff)-0x18,data); break;
+ case 0x28 : orion128_romdisk_w(space,0,data); break;
+ case 0x29 : orion128_romdisk_w(space,1,data); break;
+ case 0x2a : orion128_romdisk_w(space,2,data); break;
+ case 0x2b : orion128_romdisk_w(space,3,data); break;
+ case 0xf8 : orion128_video_mode_w(space,0,data);break;
+ case 0xf9 : m_orionpro_128_page = data; orionpro_bank_switch(machine()); break;
+ case 0xfa : orion128_video_page_w(space,0,data);break;
+ case 0xfc : m_orionpro_pseudo_color = data;break;
+ case 0xfe : orionz80_sound_fe_w(space,0,data);break;
+ case 0xff : orionz80_sound_w(space,0,data);break;
+ }
+ switch(offset)
+ {
+ case 0xfffd : ay8910_address_w(machine().device("ay8912"), 0, data);
+ break;
+ case 0xbffd :
+ case 0xbefd : ay8910_data_w(machine().device("ay8912"), 0, data);
+ break;
+ }
+}
diff --git a/src/mess/machine/osborne1.c b/src/mess/machine/osborne1.c
new file mode 100644
index 00000000000..b8fa04c81a8
--- /dev/null
+++ b/src/mess/machine/osborne1.c
@@ -0,0 +1,543 @@
+/***************************************************************************
+
+There are three IRQ sources:
+- IRQ0
+- IRQ1 = IRQA from the video PIA
+- IRQ2 = IRQA from the IEEE488 PIA
+
+Interrupt handling on the Osborne-1 is a bit awkward. When an interrupt is
+taken by the Z80 the ROMMODE is enabled on each fetch of an instruction
+byte. During execution of an instruction the previous ROMMODE setting seems
+to be used. Side effect of this is that when an interrupt is taken and the
+stack pointer is pointing to 0000-3FFF then the return address will still
+be written to RAM if RAM was switched in.
+
+***************************************************************************/
+
+#include "includes/osborne1.h"
+
+#define RAMMODE (0x01)
+
+
+WRITE8_MEMBER( osborne1_state::osborne1_0000_w )
+{
+ /* Check whether regular RAM is enabled */
+ if ( ! m_bank2_enabled || ( m_in_irq_handler && m_bankswitch == RAMMODE ) )
+ machine().device<ram_device>(RAM_TAG)->pointer()[ offset ] = data;
+}
+
+
+WRITE8_MEMBER( osborne1_state::osborne1_1000_w )
+{
+ /* Check whether regular RAM is enabled */
+ if ( ! m_bank2_enabled || ( m_in_irq_handler && m_bankswitch == RAMMODE ) )
+ machine().device<ram_device>(RAM_TAG)->pointer()[ 0x1000 + offset ] = data;
+}
+
+
+READ8_MEMBER( osborne1_state::osborne1_2000_r )
+{
+ UINT8 data = 0xFF;
+
+ /* Check whether regular RAM is enabled */
+ if ( ! m_bank2_enabled )
+ data = machine().device<ram_device>(RAM_TAG)->pointer()[ 0x2000 + offset ];
+ else
+ {
+ switch( offset & 0x0F00 )
+ {
+ case 0x100: /* Floppy */
+ data = wd17xx_r( m_fdc, offset );
+ break;
+ case 0x200: /* Keyboard */
+ /* Row 0 */
+ if ( offset & 0x01 ) data &= ioport("ROW0")->read();
+ /* Row 1 */
+ if ( offset & 0x02 ) data &= ioport("ROW1")->read();
+ /* Row 2 */
+ if ( offset & 0x04 ) data &= ioport("ROW3")->read();
+ /* Row 3 */
+ if ( offset & 0x08 ) data &= ioport("ROW4")->read();
+ /* Row 4 */
+ if ( offset & 0x10 ) data &= ioport("ROW5")->read();
+ /* Row 5 */
+ if ( offset & 0x20 ) data &= ioport("ROW2")->read();
+ /* Row 6 */
+ if ( offset & 0x40 ) data &= ioport("ROW6")->read();
+ /* Row 7 */
+ if ( offset & 0x80 ) data &= ioport("ROW7")->read();
+ break;
+ case 0x900: /* IEEE488 PIA */
+ data = m_pia0->read(space, offset & 0x03 );
+ break;
+ case 0xA00: /* Serial */
+ break;
+ case 0xC00: /* Video PIA */
+ data = m_pia1->read(space, offset & 0x03 );
+ break;
+ }
+ }
+ return data;
+}
+
+
+WRITE8_MEMBER( osborne1_state::osborne1_2000_w )
+{
+ /* Check whether regular RAM is enabled */
+ if ( ! m_bank2_enabled )
+ machine().device<ram_device>(RAM_TAG)->pointer()[ 0x2000 + offset ] = data;
+ else
+ {
+ if ( m_in_irq_handler && m_bankswitch == RAMMODE )
+ {
+ machine().device<ram_device>(RAM_TAG)->pointer()[ 0x2000 + offset ] = data;
+ }
+ /* Handle writes to the I/O area */
+ switch( offset & 0x0F00 )
+ {
+ case 0x100: /* Floppy */
+ wd17xx_w( m_fdc, offset, data );
+ break;
+ case 0x900: /* IEEE488 PIA */
+ m_pia0->write(space, offset & 0x03, data );
+ break;
+ case 0xA00: /* Serial */
+ break;
+ case 0xC00: /* Video PIA */
+ m_pia1->write(space, offset & 0x03, data );
+ break;
+ }
+ }
+}
+
+
+WRITE8_MEMBER( osborne1_state::osborne1_3000_w )
+{
+ /* Check whether regular RAM is enabled */
+ if ( ! m_bank2_enabled || ( m_in_irq_handler && m_bankswitch == RAMMODE ) )
+ machine().device<ram_device>(RAM_TAG)->pointer()[ 0x3000 + offset ] = data;
+}
+
+
+WRITE8_MEMBER( osborne1_state::osborne1_videoram_w )
+{
+ /* Check whether the video attribute section is enabled */
+ if ( m_bank3_enabled )
+ data |= 0x7F;
+
+ m_bank4_ptr[offset] = data;
+}
+
+
+WRITE8_MEMBER( osborne1_state::osborne1_bankswitch_w )
+{
+ switch( offset )
+ {
+ case 0x00:
+ m_bank2_enabled = 1;
+ m_bank3_enabled = 0;
+ break;
+ case 0x01:
+ m_bank2_enabled = 0;
+ m_bank3_enabled = 0;
+ break;
+ case 0x02:
+ m_bank2_enabled = 1;
+ m_bank3_enabled = 1;
+ break;
+ case 0x03:
+ m_bank2_enabled = 1;
+ m_bank3_enabled = 0;
+ break;
+ }
+ if ( m_bank2_enabled )
+ {
+ membank("bank1")->set_base(machine().root_device().memregion("maincpu")->base() );
+ membank("bank2")->set_base(m_empty_4K );
+ membank("bank3")->set_base(m_empty_4K );
+ }
+ else
+ {
+ membank("bank1")->set_base(machine().device<ram_device>(RAM_TAG)->pointer() );
+ membank("bank2")->set_base(machine().device<ram_device>(RAM_TAG)->pointer() + 0x1000 );
+ membank("bank3")->set_base(machine().device<ram_device>(RAM_TAG)->pointer() + 0x3000 );
+ }
+ m_bank4_ptr = machine().device<ram_device>(RAM_TAG)->pointer() + ( ( m_bank3_enabled ) ? 0x10000 : 0xF000 );
+ membank("bank4")->set_base(m_bank4_ptr );
+ m_bankswitch = offset;
+ m_in_irq_handler = 0;
+}
+
+
+DIRECT_UPDATE_MEMBER(osborne1_state::osborne1_opbase)
+{
+ if ( ( address & 0xF000 ) == 0x2000 )
+ {
+ if ( ! m_bank2_enabled )
+ {
+ direct.explicit_configure(0x2000, 0x2fff, 0x0fff, machine().device<ram_device>(RAM_TAG)->pointer() + 0x2000);
+ return ~0;
+ }
+ }
+ return address;
+}
+
+
+WRITE_LINE_MEMBER( osborne1_state::ieee_pia_irq_a_func )
+{
+ m_pia_0_irq_state = state;
+ cputag_set_input_line(machine(), "maincpu", 0, ( m_pia_1_irq_state ) ? ASSERT_LINE : CLEAR_LINE);
+}
+
+
+READ8_MEMBER( osborne1_state::ieee_pia_pb_r )
+{
+ /*
+
+ bit description
+
+ 0
+ 1
+ 2
+ 3 EOI
+ 4
+ 5 DAV
+ 6 NDAC
+ 7 NRFD
+
+ */
+
+ UINT8 data = 0;
+
+ data |= m_ieee->eoi_r() << 3;
+ data |= m_ieee->dav_r() << 5;
+ data |= m_ieee->ndac_r() << 6;
+ data |= m_ieee->nrfd_r() << 7;
+
+ return data;
+}
+
+
+WRITE8_MEMBER( osborne1_state::ieee_pia_pb_w )
+{
+ /*
+
+ bit description
+
+ 0
+ 1
+ 2
+ 3 EOI
+ 4 ATN
+ 5 DAV
+ 6 NDAC
+ 7 NRFD
+
+ */
+
+ m_ieee->eoi_w(BIT(data, 3));
+ m_ieee->atn_w(BIT(data, 4));
+ m_ieee->dav_w(BIT(data, 5));
+ m_ieee->ndac_w(BIT(data, 6));
+ m_ieee->nrfd_w(BIT(data, 7));
+}
+
+
+const pia6821_interface osborne1_ieee_pia_config =
+{
+ DEVCB_DEVICE_MEMBER(IEEE488_TAG, ieee488_device, dio_r), /* in_a_func */
+ DEVCB_DRIVER_MEMBER(osborne1_state, ieee_pia_pb_r), /* in_b_func */
+ DEVCB_NULL, /* in_ca1_func */
+ DEVCB_NULL, /* in_cb1_func */
+ DEVCB_NULL, /* in_ca2_func */
+ DEVCB_NULL, /* in_cb2_func */
+ DEVCB_DEVICE_MEMBER(IEEE488_TAG, ieee488_device, dio_w), /* out_a_func */
+ DEVCB_DRIVER_MEMBER(osborne1_state, ieee_pia_pb_w), /* out_b_func */
+ DEVCB_DEVICE_LINE_MEMBER(IEEE488_TAG, ieee488_device, ifc_w), /* out_ca2_func */
+ DEVCB_DEVICE_LINE_MEMBER(IEEE488_TAG, ieee488_device, ren_w), /* out_cb2_func */
+ DEVCB_DRIVER_LINE_MEMBER(osborne1_state, ieee_pia_irq_a_func), /* irq_a_func */
+ DEVCB_NULL /* irq_b_func */
+};
+
+
+WRITE8_MEMBER( osborne1_state::video_pia_out_cb2_dummy )
+{
+}
+
+
+WRITE8_MEMBER( osborne1_state::video_pia_port_a_w )
+{
+ wd17xx_dden_w(m_fdc, BIT(data, 0));
+
+ data -= 0xea; // remove bias
+
+ m_new_start_x = (data >> 1);
+ if (m_new_start_x)
+ m_new_start_x--;
+
+ //logerror("Video pia port a write: %02X, density set to %s\n", data, data & 1 ? "FM" : "MFM" );
+}
+
+
+WRITE8_MEMBER( osborne1_state::video_pia_port_b_w )
+{
+ m_new_start_y = data & 0x1F;
+ m_beep_state = BIT(data, 5);
+
+ if (BIT(data, 6))
+ wd17xx_set_drive( m_fdc, 0 );
+ else
+ if (BIT(data, 7))
+ wd17xx_set_drive( m_fdc, 1 );
+
+ //logerror("Video pia port b write: %02X\n", data );
+}
+
+
+WRITE_LINE_MEMBER( osborne1_state::video_pia_irq_a_func )
+{
+ m_pia_1_irq_state = state;
+ cputag_set_input_line(machine(), "maincpu", 0, ( m_pia_1_irq_state ) ? ASSERT_LINE : CLEAR_LINE);
+}
+
+
+const pia6821_interface osborne1_video_pia_config =
+{
+ DEVCB_NULL, /* in_a_func */
+ DEVCB_NULL, /* in_b_func */
+ DEVCB_NULL, /* in_ca1_func */
+ DEVCB_NULL, /* in_cb1_func */
+ DEVCB_NULL, /* in_ca2_func */
+ DEVCB_NULL, /* in_cb2_func */
+ DEVCB_DRIVER_MEMBER(osborne1_state, video_pia_port_a_w), /* out_a_func */
+ DEVCB_DRIVER_MEMBER(osborne1_state, video_pia_port_b_w), /* out_b_func */
+ DEVCB_NULL, /* out_ca2_func */
+ DEVCB_DRIVER_MEMBER(osborne1_state, video_pia_out_cb2_dummy), /* out_cb2_func */
+ DEVCB_DRIVER_LINE_MEMBER(osborne1_state, video_pia_irq_a_func), /* irq_a_func */
+ DEVCB_NULL /* irq_b_func */
+};
+
+
+//static const struct aica6850_interface osborne1_6850_config =
+//{
+// 10, /* tx_clock */
+// 10, /* rx_clock */
+// NULL, /* rx_pin */
+// NULL, /* tx_pin */
+// NULL, /* cts_pin */
+// NULL, /* rts_pin */
+// NULL, /* dcd_pin */
+// NULL /* int_callback */
+//};
+
+
+static TIMER_CALLBACK(osborne1_video_callback)
+{
+ osborne1_state *state = machine.driver_data<osborne1_state>();
+ int y = machine.primary_screen->vpos();
+ UINT8 ra=0,chr,gfx,dim;
+ UINT16 x,ma;
+
+ /* Check for start of frame */
+ if ( y == 0 )
+ {
+ /* Clear CA1 on video PIA */
+ state->m_pia1->ca1_w(0);
+ }
+ if ( y == 240 )
+ {
+ /* Set CA1 on video PIA */
+ state->m_pia1->ca1_w(1);
+ }
+ if ( y < 240 )
+ {
+ ra = y % 10;
+ /* Draw a line of the display */
+ ma = (state->m_new_start_y + (y/10)) * 128 + state->m_new_start_x;
+ UINT16 *p = &state->m_bitmap.pix16(y);
+
+ for ( x = 0; x < 52; x++ )
+ {
+ chr = machine.device<ram_device>(RAM_TAG)->pointer()[ 0xF000 + ( (ma+x) & 0xFFF ) ];
+ dim = machine.device<ram_device>(RAM_TAG)->pointer()[ 0x10000 + ( (ma+x) & 0xFFF ) ] & 0x80;
+
+ if ( (chr & 0x80) && (ra == 9) )
+ gfx = 0xFF;
+ else
+ gfx = state->m_p_chargen[ (ra << 7) | ( chr & 0x7F ) ];
+
+ /* Display a scanline of a character */
+ *p++ = BIT(gfx, 7) ? ( dim ? 1 : 2 ) : 0;
+ *p++ = BIT(gfx, 6) ? ( dim ? 1 : 2 ) : 0;
+ *p++ = BIT(gfx, 5) ? ( dim ? 1 : 2 ) : 0;
+ *p++ = BIT(gfx, 4) ? ( dim ? 1 : 2 ) : 0;
+ *p++ = BIT(gfx, 3) ? ( dim ? 1 : 2 ) : 0;
+ *p++ = BIT(gfx, 2) ? ( dim ? 1 : 2 ) : 0;
+ *p++ = BIT(gfx, 1) ? ( dim ? 1 : 2 ) : 0;
+ *p++ = BIT(gfx, 0) ? ( dim ? 1 : 2 ) : 0;
+ }
+ }
+
+ if ( (ra==2) || (ra== 6) )
+ {
+ beep_set_state( state->m_beep, state->m_beep_state );
+ }
+ else
+ {
+ beep_set_state( state->m_beep, 0 );
+ }
+
+ state->m_video_timer->adjust(machine.primary_screen->time_until_pos(y + 1, 0 ));
+}
+
+static TIMER_CALLBACK( setup_osborne1 )
+{
+ osborne1_state *state = machine.driver_data<osborne1_state>();
+ beep_set_state( state->m_beep, 0 );
+ beep_set_frequency( state->m_beep, 300 /* 60 * 240 / 2 */ );
+ state->m_pia1->ca1_w(0);
+}
+
+static void osborne1_load_proc(device_image_interface &image)
+{
+ int size = image.length();
+ osborne1_state *state = image.device().machine().driver_data<osborne1_state>();
+
+ switch( size )
+ {
+ case 40 * 10 * 256:
+ wd17xx_dden_w(state->m_fdc, ASSERT_LINE);
+ break;
+ case 40 * 5 * 1024:
+ wd17xx_dden_w(state->m_fdc, CLEAR_LINE);
+ break;
+ case 40 * 8 * 512:
+ wd17xx_dden_w(state->m_fdc, ASSERT_LINE);
+ break;
+ case 40 * 18 * 128:
+ wd17xx_dden_w(state->m_fdc, ASSERT_LINE);
+ break;
+ case 40 * 9 * 512:
+ wd17xx_dden_w(state->m_fdc, CLEAR_LINE);
+ break;
+ }
+}
+
+MACHINE_RESET( osborne1 )
+{
+ osborne1_state *state = machine.driver_data<osborne1_state>();
+ int drive;
+ address_space* space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ /* Initialize memory configuration */
+ state->osborne1_bankswitch_w( *space, 0x00, 0 );
+
+ state->m_pia_0_irq_state = FALSE;
+ state->m_pia_1_irq_state = FALSE;
+ state->m_in_irq_handler = 0;
+
+ state->m_p_chargen = state->memregion( "chargen" )->base();
+
+ memset( machine.device<ram_device>(RAM_TAG)->pointer() + 0x10000, 0xFF, 0x1000 );
+
+ for(drive=0;drive<2;drive++)
+ floppy_install_load_proc(floppy_get_device(machine, drive), osborne1_load_proc);
+
+ space->set_direct_update_handler(direct_update_delegate(FUNC(osborne1_state::osborne1_opbase), state));
+}
+
+
+DRIVER_INIT_MEMBER(osborne1_state,osborne1)
+{
+
+ m_empty_4K = auto_alloc_array(machine(), UINT8, 0x1000 );
+ memset( m_empty_4K, 0xFF, 0x1000 );
+
+ /* Configure the 6850 ACIA */
+// acia6850_config( 0, &osborne1_6850_config );
+ m_video_timer = machine().scheduler().timer_alloc(FUNC(osborne1_video_callback));
+ m_video_timer->adjust(machine().primary_screen->time_until_pos(1, 0 ));
+
+ machine().scheduler().timer_set(attotime::zero, FUNC(setup_osborne1));
+}
+
+
+void osborne1_state::video_start()
+{
+ machine().primary_screen->register_screen_bitmap(m_bitmap);
+}
+
+UINT32 osborne1_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect);
+ return 0;
+}
+
+/****************************************************************
+ Osborne1 specific daisy chain code
+****************************************************************/
+
+const device_type OSBORNE1_DAISY = &device_creator<osborne1_daisy_device>;
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// z80ctc_device - constructor
+//-------------------------------------------------
+osborne1_daisy_device::osborne1_daisy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, OSBORNE1_DAISY, "Osborne 1 daisy", tag, owner, clock),
+ device_z80daisy_interface(mconfig, *this)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void osborne1_daisy_device::device_start()
+{
+}
+
+//**************************************************************************
+// DAISY CHAIN INTERFACE
+//**************************************************************************
+
+//-------------------------------------------------
+// z80daisy_irq_state - return the overall IRQ
+// state for this device
+//-------------------------------------------------
+
+int osborne1_daisy_device::z80daisy_irq_state()
+{
+ osborne1_state *state = machine().driver_data<osborne1_state>();
+ return ( state->m_pia_1_irq_state ? Z80_DAISY_INT : 0 );
+}
+
+
+//-------------------------------------------------
+// z80daisy_irq_ack - acknowledge an IRQ and
+// return the appropriate vector
+//-------------------------------------------------
+
+int osborne1_daisy_device::z80daisy_irq_ack()
+{
+ osborne1_state *state = machine().driver_data<osborne1_state>();
+ /* Enable ROM and I/O when IRQ is acknowledged */
+ UINT8 old_bankswitch = state->m_bankswitch;
+ address_space* space = device().machine().device("maincpu")->memory().space(AS_PROGRAM);
+
+ state->osborne1_bankswitch_w( *space, 0, 0 );
+ state->m_bankswitch = old_bankswitch;
+ state->m_in_irq_handler = 1;
+ return 0xF8;
+}
+
+//-------------------------------------------------
+// z80daisy_irq_reti - clear the interrupt
+// pending state to allow other interrupts through
+//-------------------------------------------------
+
+void osborne1_daisy_device::z80daisy_irq_reti()
+{
+}
diff --git a/src/mess/machine/p2000t.c b/src/mess/machine/p2000t.c
new file mode 100644
index 00000000000..ea09cf5b6ff
--- /dev/null
+++ b/src/mess/machine/p2000t.c
@@ -0,0 +1,160 @@
+/**********************************************************************
+
+ machine.c
+
+ Functions to emulate general aspects of the machine (RAM, ROM, interrups,
+ I/O ports)
+
+**********************************************************************/
+
+#include "includes/p2000t.h"
+
+#define P2000M_101F_CASDAT 0x01
+#define P2000M_101F_CASCMD 0x02
+#define P2000M_101F_CASREW 0x04
+#define P2000M_101F_CASFOR 0x08
+#define P2000M_101F_KEYINT 0x40
+#define P2000M_101F_PRNOUT 0x80
+
+#define P2000M_202F_PINPUT 0x01
+#define P2000M_202F_PREADY 0x02
+#define P2000M_202F_STRAPN 0x04
+#define P2000M_202F_CASENB 0x08
+#define P2000M_202F_CASPOS 0x10
+#define P2000M_202F_CASEND 0x20
+#define P2000M_202F_CASCLK 0x40
+#define P2000M_202F_CASDAT 0x80
+
+#define P2000M_303F_VIDEO 0x01
+
+#define P2000M_707F_DISA 0x01
+
+/*
+ Keyboard port 0x0x
+
+ If the keyboard interrupt is enabled, all keyboard matrix rows are
+ connected and reading from either of these ports will give the
+ keyboard status (FF=no key pressed)
+
+ If the keyboard interrupt is disabled, reading one of these ports
+ will read the corresponding keyboard matrix row
+*/
+READ8_MEMBER( p2000t_state::p2000t_port_000f_r )
+{
+ static const char *const keynames[] = {
+ "KEY0", "KEY1", "KEY2", "KEY3", "KEY4",
+ "KEY5", "KEY6", "KEY7", "KEY8", "KEY9"
+ };
+
+ if (m_port_101f & P2000M_101F_KEYINT)
+ {
+ return (
+ ioport("KEY0")->read() & ioport("KEY1")->read() &
+ ioport("KEY2")->read() & ioport("KEY3")->read() &
+ ioport("KEY4")->read() & ioport("KEY5")->read() &
+ ioport("KEY6")->read() & ioport("KEY7")->read() &
+ ioport("KEY8")->read() & ioport("KEY9")->read());
+ }
+ else
+ if (offset < 10)
+ {
+ return (ioport(keynames[offset])->read());
+ }
+ else
+ return 0xff;
+}
+
+
+/*
+ Input port 0x2x
+
+ bit 0 - Printer input
+ bit 1 - Printer ready
+ bit 2 - Strap N (daisy/matrix)
+ bit 3 - Cassette write enabled
+ bit 4 - Cassette in position
+ bit 5 - Begin/end of tape
+ bit 6 - Cassette read clock
+ bit 7 - Cassette read data
+*/
+READ8_MEMBER( p2000t_state::p2000t_port_202f_r )
+{
+ return (0xff);
+}
+
+
+/*
+ Output Port 0x1x
+
+ bit 0 - Cassette write data
+ bit 1 - Cassette write command
+ bit 2 - Cassette rewind
+ bit 3 - Cassette forward
+ bit 4 - Unused
+ bit 5 - Unused
+ bit 6 - Keyboard interrupt enable
+ bit 7 - Printer output
+*/
+WRITE8_MEMBER( p2000t_state::p2000t_port_101f_w )
+{
+ m_port_101f = data;
+}
+
+/*
+ Scroll Register 0x3x (P2000T only)
+
+ bit 0 - /
+ bit 1 - |
+ bit 2 - | Index of the first character
+ bit 3 - | to be displayed
+ bit 4 - |
+ bit 5 - |
+ bit 6 - \
+ bit 7 - Video disable (0 = enabled)
+*/
+WRITE8_MEMBER( p2000t_state::p2000t_port_303f_w )
+{
+ m_port_303f = data;
+}
+
+/*
+ Beeper 0x5x
+
+ bit 0 - Beeper
+ bit 1 - Unused
+ bit 2 - Unused
+ bit 3 - Unused
+ bit 4 - Unused
+ bit 5 - Unused
+ bit 6 - Unused
+ bit 7 - Unused
+*/
+WRITE8_MEMBER( p2000t_state::p2000t_port_505f_w )
+{
+ speaker_level_w(m_speaker, BIT(data,0));
+}
+
+/*
+ DISAS 0x7x (P2000M only)
+
+ bit 0 - Unused
+ bit 1 - DISAS enable
+ bit 2 - Unused
+ bit 3 - Unused
+ bit 4 - Unused
+ bit 5 - Unused
+ bit 6 - Unused
+ bit 7 - Unused
+
+ When the DISAS is active, the CPU has the highest priority and
+ video refresh is disabled when the CPU accesses video memory
+
+*/
+WRITE8_MEMBER( p2000t_state::p2000t_port_707f_w )
+{
+ m_port_707f = data;
+}
+
+WRITE8_MEMBER( p2000t_state::p2000t_port_888b_w ) {}
+WRITE8_MEMBER( p2000t_state::p2000t_port_8c90_w ) {}
+WRITE8_MEMBER( p2000t_state::p2000t_port_9494_w ) {}
diff --git a/src/mess/machine/partner.c b/src/mess/machine/partner.c
new file mode 100644
index 00000000000..aa719268530
--- /dev/null
+++ b/src/mess/machine/partner.c
@@ -0,0 +1,390 @@
+/***************************************************************************
+
+ Partner driver by Miodrag Milanovic
+
+ 09/06/2008 Preliminary driver.
+
+****************************************************************************/
+
+
+#include "emu.h"
+#include "cpu/i8085/i8085.h"
+#include "imagedev/cassette.h"
+#include "machine/i8255.h"
+#include "machine/8257dma.h"
+#include "machine/wd17xx.h"
+#include "video/i8275.h"
+#include "includes/radio86.h"
+#include "includes/partner.h"
+#include "imagedev/flopdrv.h"
+#include "machine/ram.h"
+
+
+/* Driver initialization */
+DRIVER_INIT_MEMBER(partner_state,partner)
+{
+ m_tape_value = 0x80;
+}
+
+static WRITE_LINE_DEVICE_HANDLER( partner_wd17xx_drq_w )
+{
+ if (state)
+ i8257_drq0_w(device, 1);
+}
+
+const wd17xx_interface partner_wd17xx_interface =
+{
+ DEVCB_LINE_GND,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE("dma8257", partner_wd17xx_drq_w),
+ {FLOPPY_0, FLOPPY_1, NULL, NULL}
+};
+
+MACHINE_START( partner )
+{
+ device_t *fdc = machine.device("wd1793");
+ wd17xx_set_pause_time(fdc, 10);
+}
+
+static void partner_window_1(running_machine &machine, UINT8 bank_num, UINT16 offset,UINT8 *rom)
+{
+ partner_state *state = machine.driver_data<partner_state>();
+ char bank[10];
+ sprintf(bank,"bank%d",bank_num);
+ switch(state->m_win_mem_page) {
+ case 2 : // FDD BIOS
+ state->membank(bank)->set_base(rom + 0x16000 + offset);
+ break;
+ case 4 : // MCPG BIOS
+ state->membank(bank)->set_base(rom + 0x14000 + offset);
+ break;
+ default : // BIOS
+ state->membank(bank)->set_base(rom + 0x10000 + offset);
+ break;
+ }
+}
+
+static void partner_window_2(running_machine &machine, UINT8 bank_num, UINT16 offset,UINT8 *rom)
+{
+ partner_state *state = machine.driver_data<partner_state>();
+ char bank[10];
+ sprintf(bank,"bank%d",bank_num);
+ switch(state->m_win_mem_page) {
+ case 4 : // MCPG FONT
+ state->membank(bank)->set_base(rom + 0x18000 + offset);
+ break;
+ default : // BIOS
+ state->membank(bank)->set_base(rom + 0x10000 + offset);
+ break;
+ }
+}
+
+READ8_MEMBER(partner_state::partner_floppy_r){
+ device_t *fdc = machine().device("wd1793");
+
+ if (offset<0x100) {
+ switch(offset & 3) {
+ case 0x00 : return wd17xx_status_r(fdc,0);
+ case 0x01 : return wd17xx_track_r(fdc,0);
+ case 0x02 : return wd17xx_sector_r(fdc,0);
+ default :
+ return wd17xx_data_r(fdc,0);
+ }
+ } else {
+ return 0;
+ }
+}
+
+WRITE8_MEMBER(partner_state::partner_floppy_w){
+ device_t *fdc = machine().device("wd1793");
+
+ if (offset<0x100) {
+ switch(offset & 3) {
+ case 0x00 : wd17xx_command_w(fdc,0,data); break;
+ case 0x01 : wd17xx_track_w(fdc,0,data);break;
+ case 0x02 : wd17xx_sector_w(fdc,0,data);break;
+ default : wd17xx_data_w(fdc,0,data);break;
+ }
+ } else {
+ floppy_mon_w(floppy_get_device(machine(), 0), 1);
+ floppy_mon_w(floppy_get_device(machine(), 1), 1);
+ if (((data >> 6) & 1)==1) {
+ wd17xx_set_drive(fdc,0);
+ floppy_mon_w(floppy_get_device(machine(), 0), 0);
+ floppy_drive_set_ready_state(floppy_get_device(machine(), 0), 1, 1);
+ }
+ if (((data >> 3) & 1)==1) {
+ wd17xx_set_drive(fdc,1);
+ floppy_mon_w(floppy_get_device(machine(), 1), 0);
+ floppy_drive_set_ready_state(floppy_get_device(machine(), 1), 1, 1);
+ }
+ wd17xx_set_side(fdc,data >> 7);
+ }
+}
+
+static void partner_iomap_bank(running_machine &machine,UINT8 *rom)
+{
+ partner_state *state = machine.driver_data<partner_state>();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ switch(state->m_win_mem_page) {
+ case 2 :
+ // FDD
+ space->install_write_handler(0xdc00, 0xddff, write8_delegate(FUNC(partner_state::partner_floppy_w),state));
+ space->install_read_handler (0xdc00, 0xddff, read8_delegate(FUNC(partner_state::partner_floppy_r),state));
+ break;
+ case 4 :
+ // Timer
+ break;
+ default : // BIOS
+ state->membank("bank11")->set_base(rom + 0x10000);
+ break;
+ }
+}
+static void partner_bank_switch(running_machine &machine)
+{
+ partner_state *state = machine.driver_data<partner_state>();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ UINT8 *rom = state->memregion("maincpu")->base();
+ UINT8 *ram = machine.device<ram_device>(RAM_TAG)->pointer();
+
+ space->install_write_bank(0x0000, 0x07ff, "bank1");
+ space->install_write_bank(0x0800, 0x3fff, "bank2");
+ space->install_write_bank(0x4000, 0x5fff, "bank3");
+ space->install_write_bank(0x6000, 0x7fff, "bank4");
+ space->install_write_bank(0x8000, 0x9fff, "bank5");
+ space->install_write_bank(0xa000, 0xb7ff, "bank6");
+ space->install_write_bank(0xb800, 0xbfff, "bank7");
+ space->install_write_bank(0xc000, 0xc7ff, "bank8");
+ space->install_write_bank(0xc800, 0xcfff, "bank9");
+ space->install_write_bank(0xd000, 0xd7ff, "bank10");
+ space->unmap_write(0xdc00, 0xddff);
+ space->install_read_bank (0xdc00, 0xddff, "bank11");
+ space->unmap_write(0xe000, 0xe7ff);
+ space->unmap_write(0xe800, 0xffff);
+
+ // BANK 1 (0x0000 - 0x07ff)
+ if (state->m_mem_page==0) {
+ space->unmap_write(0x0000, 0x07ff);
+ state->membank("bank1")->set_base(rom + 0x10000);
+ } else {
+ if (state->m_mem_page==7) {
+ state->membank("bank1")->set_base(ram + 0x8000);
+ } else {
+ state->membank("bank1")->set_base(ram + 0x0000);
+ }
+ }
+
+ // BANK 2 (0x0800 - 0x3fff)
+ if (state->m_mem_page==7) {
+ state->membank("bank2")->set_base(ram + 0x8800);
+ } else {
+ state->membank("bank2")->set_base(ram + 0x0800);
+ }
+
+ // BANK 3 (0x4000 - 0x5fff)
+ if (state->m_mem_page==7) {
+ state->membank("bank3")->set_base(ram + 0xC000);
+ } else {
+ if (state->m_mem_page==10) {
+ //window 1
+ space->unmap_write(0x4000, 0x5fff);
+ partner_window_1(machine, 3, 0, rom);
+ } else {
+ state->membank("bank3")->set_base(ram + 0x4000);
+ }
+ }
+
+ // BANK 4 (0x6000 - 0x7fff)
+ if (state->m_mem_page==7) {
+ state->membank("bank4")->set_base(ram + 0xe000);
+ } else {
+ state->membank("bank4")->set_base(ram + 0x6000);
+ }
+
+ // BANK 5 (0x8000 - 0x9fff)
+ switch (state->m_mem_page) {
+ case 5:
+ case 10:
+ //window 2
+ space->unmap_write(0x8000, 0x9fff);
+ partner_window_2(machine, 5, 0, rom);
+ break;
+ case 8:
+ case 9:
+ //window 1
+ space->unmap_write(0x8000, 0x9fff);
+ partner_window_1(machine, 5, 0, rom);
+ break;
+ case 7:
+ state->membank("bank5")->set_base(ram + 0x0000);
+ break;
+ default:
+ state->membank("bank5")->set_base(ram + 0x8000);
+ break;
+ }
+
+ // BANK 6 (0xa000 - 0xb7ff)
+ switch (state->m_mem_page) {
+ case 5:
+ case 10:
+ //window 2
+ space->unmap_write(0xa000, 0xb7ff);
+ partner_window_2(machine, 6, 0, rom);
+ break;
+ case 6:
+ case 8:
+ //BASIC
+ space->unmap_write(0xa000, 0xb7ff);
+ state->membank("bank6")->set_base(rom + 0x12000); // BASIC
+ break;
+ case 7:
+ state->membank("bank6")->set_base(ram + 0x2000);
+ break;
+ default:
+ state->membank("bank6")->set_base(ram + 0xa000);
+ break;
+ }
+
+ // BANK 7 (0xb800 - 0xbfff)
+ switch (state->m_mem_page) {
+ case 4:
+ case 5:
+ case 10:
+ //window 2
+ space->unmap_write(0xb800, 0xbfff);
+ partner_window_2(machine, 7, 0x1800, rom);
+ break;
+ case 6:
+ case 8:
+ //BASIC
+ space->unmap_write(0xb800, 0xbfff);
+ state->membank("bank7")->set_base(rom + 0x13800); // BASIC
+ break;
+ case 7:
+ state->membank("bank7")->set_base(ram + 0x3800);
+ break;
+ default:
+ state->membank("bank7")->set_base(ram + 0xb800);
+ break;
+ }
+
+ // BANK 8 (0xc000 - 0xc7ff)
+ switch (state->m_mem_page) {
+ case 7:
+ state->membank("bank8")->set_base(ram + 0x4000);
+ break;
+ case 8:
+ case 10:
+ space->unmap_write(0xc000, 0xc7ff);
+ state->membank("bank8")->set_base(rom + 0x10000);
+ break;
+ default:
+ state->membank("bank8")->set_base(ram + 0xc000);
+ break;
+ }
+
+ // BANK 9 (0xc800 - 0xcfff)
+ switch (state->m_mem_page) {
+ case 7:
+ state->membank("bank9")->set_base(ram + 0x4800);
+ break;
+ case 8:
+ case 9:
+ // window 2
+ space->unmap_write(0xc800, 0xcfff);
+ partner_window_2(machine, 9, 0, rom);
+ break;
+ case 10:
+ space->unmap_write(0xc800, 0xcfff);
+ state->membank("bank9")->set_base(rom + 0x10800);
+ break;
+ default:
+ state->membank("bank9")->set_base(ram + 0xc800);
+ break;
+ }
+
+ // BANK 10 (0xd000 - 0xd7ff)
+ switch (state->m_mem_page) {
+ case 7:
+ state->membank("bank10")->set_base(ram + 0x5000);
+ break;
+ case 8:
+ case 9:
+ // window 2
+ space->unmap_write(0xd000, 0xd7ff);
+ partner_window_2(machine, 10, 0x0800, rom);
+ break;
+ default:
+ state->membank("bank10")->set_base(ram + 0xd000);
+ break;
+ }
+
+ // BANK 11 (0xdc00 - 0xddff)
+ partner_iomap_bank(machine,rom);
+
+ // BANK 12 (0xe000 - 0xe7ff)
+ if (state->m_mem_page==1) {
+ state->membank("bank12")->set_base(rom + 0x10000);
+ } else {
+ //window 1
+ partner_window_1(machine, 12, 0, rom);
+ }
+
+ // BANK 13 (0xe800 - 0xffff)
+ switch (state->m_mem_page) {
+ case 3:
+ case 4:
+ case 5:
+ // window 1
+ partner_window_1(machine, 13, 0x800, rom);
+ break;
+ default:
+ // BIOS
+ state->membank("bank13")->set_base(rom + 0x10800);
+ break;
+ }
+}
+
+WRITE8_MEMBER(partner_state::partner_win_memory_page_w)
+{
+ m_win_mem_page = ~data;
+ partner_bank_switch(machine());
+}
+
+WRITE8_MEMBER(partner_state::partner_mem_page_w)
+{
+ m_mem_page = (data >> 4) & 0x0f;
+ partner_bank_switch(machine());
+}
+
+static WRITE_LINE_DEVICE_HANDLER( hrq_w )
+{
+ /* HACK - this should be connected to the BUSREQ line of Z80 */
+ cputag_set_input_line(device->machine(), "maincpu", INPUT_LINE_HALT, state);
+
+ /* HACK - this should be connected to the BUSACK line of Z80 */
+ i8257_hlda_w(device, state);
+}
+
+static UINT8 memory_read_byte(address_space *space, offs_t address) { return space->read_byte(address); }
+static void memory_write_byte(address_space *space, offs_t address, UINT8 data) { space->write_byte(address, data); }
+
+I8257_INTERFACE( partner_dma )
+{
+ DEVCB_LINE(hrq_w),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_MEMORY_HANDLER("maincpu", PROGRAM, memory_read_byte),
+ DEVCB_MEMORY_HANDLER("maincpu", PROGRAM, memory_write_byte),
+ { DEVCB_DEVICE_HANDLER("wd1793", wd17xx_data_r), DEVCB_NULL, DEVCB_NULL, DEVCB_NULL },
+ { DEVCB_DEVICE_HANDLER("wd1793", wd17xx_data_w), DEVCB_NULL, DEVCB_DEVICE_HANDLER("i8275", i8275_dack_w), DEVCB_NULL }
+};
+
+
+MACHINE_RESET( partner )
+{
+ partner_state *state = machine.driver_data<partner_state>();
+ state->m_mem_page = 0;
+ state->m_win_mem_page = 0;
+ partner_bank_switch(machine);
+}
diff --git a/src/mess/machine/pc.c b/src/mess/machine/pc.c
new file mode 100644
index 00000000000..fc31cbaa70b
--- /dev/null
+++ b/src/mess/machine/pc.c
@@ -0,0 +1,1787 @@
+/***************************************************************************
+
+ machine/pc.c
+
+ Functions to emulate general aspects of the machine
+ (RAM, ROM, interrupts, I/O ports)
+
+ The information herein is heavily based on
+ 'Ralph Browns Interrupt List'
+ Release 52, Last Change 20oct96
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/pc.h"
+
+#include "machine/i8255.h"
+#include "machine/ins8250.h"
+#include "machine/mc146818.h"
+#include "machine/pic8259.h"
+#include "machine/pc_turbo.h"
+
+#include "video/pc_vga.h"
+#include "video/pc_cga.h"
+#include "video/pc_t1t.h"
+
+#include "machine/pit8253.h"
+
+#include "machine/pckeybrd.h"
+#include "machine/pc_lpt.h"
+#include "machine/pc_fdc.h"
+#include "machine/upd765.h"
+#include "includes/amstr_pc.h"
+#include "includes/europc.h"
+#include "machine/pcshare.h"
+#include "imagedev/cassette.h"
+#include "sound/speaker.h"
+
+#include "machine/8237dma.h"
+#include "machine/wd17xx.h"
+
+#include "machine/ram.h"
+
+#include "imagedev/cassette.h"
+#include "machine/pit8253.h"
+#include "machine/pcshare.h"
+#include "coreutil.h"
+
+#define VERBOSE_PIO 0 /* PIO (keyboard controller) */
+
+#define PIO_LOG(N,M,A) \
+ do { \
+ if(VERBOSE_PIO>=N) \
+ { \
+ if( M ) \
+ logerror("%11.6f: %-24s",machine.time().as_double(),(char*)M ); \
+ logerror A; \
+ } \
+ } while (0)
+
+#define VERBOSE_DBG 0 /* general debug messages */
+
+#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)
+
+/*
+ * EC-1841 memory controller. The machine can hold four memory boards;
+ * each board has a control register, its address is set by a DIP switch
+ * on the board itself.
+ *
+ * Only one board should be enabled for read, and one for write.
+ * Normally, this is the same board.
+ *
+ * Each board is divided into 4 banks, internally numbererd 0..3.
+ * POST tests each board on startup, and an error (indicated by
+ * I/O CH CK bus signal) causes it to disable failing bank(s) by writing
+ * 'reconfiguration code' (inverted number of failing memory bank) to
+ * the register.
+
+ * bit 1-0 'reconfiguration code'
+ * bit 2 enable read access
+ * bit 3 enable write access
+ */
+
+READ8_MEMBER(pc_state::ec1841_memboard_r)
+{
+ pc_state *st = space.machine().driver_data<pc_state>();
+ return st->m_memboard[(offset % 4)];
+}
+
+WRITE8_MEMBER(pc_state::ec1841_memboard_w)
+{
+ pc_state *st = space.machine().driver_data<pc_state>();
+ address_space *program = space.machine().device("maincpu")->memory().space(AS_PROGRAM);
+ running_machine &machine = space.machine();
+ UINT8 current;
+
+ DBG_LOG(1,"ec1841_memboard_w",("(%d) <- %02X at %s\n", offset, data, machine.describe_context()));
+
+ // for now, handle only board 0
+ if (offset > 0) {
+ st->m_memboard[offset] = data;
+ return;
+ }
+
+ current = st->m_memboard[offset];
+
+ if (BIT(current, 2) && !BIT(data, 2)) {
+ // disable read access
+ program->unmap_read(0, 0x7ffff);
+ DBG_LOG(1,"ec1841_memboard_w",("unmap_read(%d)\n", offset));
+ }
+
+ if (BIT(current, 3) && !BIT(data, 3)) {
+ // disable write access
+ program->unmap_write(0, 0x7ffff);
+ DBG_LOG(1,"ec1841_memboard_w",("unmap_write(%d)\n", offset));
+ }
+
+ if (!BIT(current, 2) && BIT(data, 2)) {
+ // enable read access
+ program->install_read_bank(0, 0x7ffff, "bank10");
+ DBG_LOG(1,"ec1841_memboard_w",("map_read(%d)\n", offset));
+ }
+
+ if (!BIT(current, 3) && BIT(data, 3)) {
+ // enable write access
+ program->install_write_bank(0, 0x7ffff, "bank10");
+ DBG_LOG(1,"ec1841_memboard_w",("map_write(%d)\n", offset));
+ }
+
+ st->m_memboard[offset] = data;
+}
+
+/*************************************************************************
+ *
+ * PC DMA stuff
+ *
+ *************************************************************************/
+
+READ8_MEMBER(pc_state::pc_page_r)
+{
+ return 0xFF;
+}
+
+
+WRITE8_MEMBER(pc_state::pc_page_w)
+{
+ switch(offset % 4)
+ {
+ case 1:
+ m_dma_offset[0][2] = data;
+ break;
+ case 2:
+ m_dma_offset[0][3] = data;
+ break;
+ case 3:
+ m_dma_offset[0][0] = m_dma_offset[0][1] = data;
+ break;
+ }
+}
+
+
+static WRITE_LINE_DEVICE_HANDLER( pc_dma_hrq_changed )
+{
+ pc_state *st = device->machine().driver_data<pc_state>();
+ device_set_input_line(st->m_maincpu, INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE);
+
+ /* Assert HLDA */
+ i8237_hlda_w( device, state );
+}
+
+
+READ8_MEMBER(pc_state::pc_dma_read_byte)
+{
+ UINT8 result;
+ offs_t page_offset = (((offs_t) m_dma_offset[0][m_dma_channel]) << 16)
+ & 0x0F0000;
+
+ result = space.read_byte( page_offset + offset);
+ return result;
+}
+
+
+WRITE8_MEMBER(pc_state::pc_dma_write_byte)
+{
+ offs_t page_offset = (((offs_t) m_dma_offset[0][m_dma_channel]) << 16)
+ & 0x0F0000;
+
+ space.write_byte( page_offset + offset, data);
+}
+
+
+static READ8_DEVICE_HANDLER( pc_dma8237_fdc_dack_r )
+{
+ return pc_fdc_dack_r(device->machine());
+}
+
+
+static READ8_DEVICE_HANDLER( pc_dma8237_hdc_dack_r )
+{
+ return 0xff;
+}
+
+
+static WRITE8_DEVICE_HANDLER( pc_dma8237_fdc_dack_w )
+{
+ pc_fdc_dack_w( device->machine(), data );
+}
+
+
+static WRITE8_DEVICE_HANDLER( pc_dma8237_hdc_dack_w )
+{
+}
+
+
+static WRITE8_DEVICE_HANDLER( pc_dma8237_0_dack_w )
+{
+ pc_state *st = device->machine().driver_data<pc_state>();
+ st->m_u73_q2 = 0;
+ i8237_dreq0_w( st->m_dma8237, st->m_u73_q2 );
+}
+
+
+static WRITE_LINE_DEVICE_HANDLER( pc_dma8237_out_eop )
+{
+ pc_fdc_set_tc_state( device->machine(), state == ASSERT_LINE ? 0 : 1 );
+}
+
+static void set_dma_channel(device_t *device, int channel, int state)
+{
+ pc_state *st = device->machine().driver_data<pc_state>();
+
+ if (!state) st->m_dma_channel = channel;
+}
+
+static WRITE_LINE_DEVICE_HANDLER( pc_dack0_w ) { set_dma_channel(device, 0, state); }
+static WRITE_LINE_DEVICE_HANDLER( pc_dack1_w ) { set_dma_channel(device, 1, state); }
+static WRITE_LINE_DEVICE_HANDLER( pc_dack2_w ) { set_dma_channel(device, 2, state); }
+static WRITE_LINE_DEVICE_HANDLER( pc_dack3_w ) { set_dma_channel(device, 3, state); }
+
+I8237_INTERFACE( ibm5150_dma8237_config )
+{
+ DEVCB_DEVICE_LINE("dma8237", pc_dma_hrq_changed),
+ DEVCB_DEVICE_LINE("dma8237", pc_dma8237_out_eop),
+ DEVCB_DRIVER_MEMBER(pc_state, pc_dma_read_byte),
+ DEVCB_DRIVER_MEMBER(pc_state, pc_dma_write_byte),
+ { DEVCB_NULL, DEVCB_NULL, DEVCB_DEVICE_HANDLER("dma8237", pc_dma8237_fdc_dack_r), DEVCB_DEVICE_HANDLER("dma8237", pc_dma8237_hdc_dack_r) },
+ { DEVCB_DEVICE_HANDLER("dma8237", pc_dma8237_0_dack_w), DEVCB_NULL, DEVCB_DEVICE_HANDLER("dma8237", pc_dma8237_fdc_dack_w), DEVCB_DEVICE_HANDLER("dma8237", pc_dma8237_hdc_dack_w) },
+ { DEVCB_DEVICE_LINE("dma8237", pc_dack0_w), DEVCB_DEVICE_LINE("dma8237", pc_dack1_w), DEVCB_DEVICE_LINE("dma8237", pc_dack2_w), DEVCB_DEVICE_LINE("dma8237", pc_dack3_w) }
+};
+
+
+/*************************************************************
+ *
+ * pic8259 configuration
+ *
+ *************************************************************/
+
+const struct pic8259_interface ibm5150_pic8259_config =
+{
+ DEVCB_CPU_INPUT_LINE("maincpu", 0),
+ DEVCB_LINE_VCC,
+ DEVCB_NULL
+};
+
+
+/*************************************************************
+ *
+ * PCJR pic8259 configuration
+ *
+ * Part of the PCJR CRT POST test at address F0452/F0454 writes
+ * to the PIC enabling an IRQ which is then immediately fired,
+ * however it is expected that the actual IRQ is taken one
+ * instruction later (the irq bit is reset by the instruction
+ * at F0454). Delaying taking of an IRQ by one instruction for
+ * all cases breaks floppy emulation. This seems to be a really
+ * tight corner case. For now we delay the IRQ by one instruction
+ * only for the PCJR and only when it's inside the POST checks.
+ *
+ *************************************************************/
+
+static emu_timer *pc_int_delay_timer;
+
+static TIMER_CALLBACK( pcjr_delayed_pic8259_irq )
+{
+ device_set_input_line(machine.firstcpu, 0, param ? ASSERT_LINE : CLEAR_LINE);
+}
+
+static WRITE_LINE_DEVICE_HANDLER( pcjr_pic8259_set_int_line )
+{
+ if ( cpu_get_reg( device->machine().firstcpu, STATE_GENPC ) == 0xF0454 )
+ {
+ pc_int_delay_timer->adjust( device->machine().firstcpu->cycles_to_attotime(1), state );
+ }
+ else
+ {
+ device_set_input_line(device->machine().firstcpu, 0, state ? ASSERT_LINE : CLEAR_LINE);
+ }
+}
+
+const struct pic8259_interface pcjr_pic8259_config =
+{
+ DEVCB_LINE(pcjr_pic8259_set_int_line),
+ DEVCB_LINE_VCC,
+ DEVCB_NULL
+};
+
+
+/*************************************************************************
+ *
+ * PC Speaker related
+ *
+ *************************************************************************/
+UINT8 pc_speaker_get_spk(running_machine &machine)
+{
+ pc_state *st = machine.driver_data<pc_state>();
+ return st->m_pc_spkrdata & st->m_pc_input;
+}
+
+
+void pc_speaker_set_spkrdata(running_machine &machine, UINT8 data)
+{
+ device_t *speaker = machine.device(SPEAKER_TAG);
+ pc_state *st = machine.driver_data<pc_state>();
+ st->m_pc_spkrdata = data ? 1 : 0;
+ speaker_level_w( speaker, pc_speaker_get_spk(machine) );
+}
+
+
+void pc_speaker_set_input(running_machine &machine, UINT8 data)
+{
+ device_t *speaker = machine.device(SPEAKER_TAG);
+ pc_state *st = machine.driver_data<pc_state>();
+ st->m_pc_input = data ? 1 : 0;
+ speaker_level_w( speaker, pc_speaker_get_spk(machine) );
+}
+
+
+/*************************************************************
+ *
+ * pit8253 configuration
+ *
+ *************************************************************/
+
+static WRITE_LINE_DEVICE_HANDLER( ibm5150_pit8253_out1_changed )
+{
+ pc_state *st = device->machine().driver_data<pc_state>();
+ /* Trigger DMA channel #0 */
+ if ( st->m_out1 == 0 && state == 1 && st->m_u73_q2 == 0 )
+ {
+ st->m_u73_q2 = 1;
+ i8237_dreq0_w( st->m_dma8237, st->m_u73_q2 );
+ }
+ st->m_out1 = state;
+}
+
+
+static WRITE_LINE_DEVICE_HANDLER( ibm5150_pit8253_out2_changed )
+{
+ pc_speaker_set_input( device->machine(), state );
+}
+
+
+const struct pit8253_config ibm5150_pit8253_config =
+{
+ {
+ {
+ XTAL_14_31818MHz/12, /* heartbeat IRQ */
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE("pic8259", pic8259_ir0_w)
+ }, {
+ XTAL_14_31818MHz/12, /* dram refresh */
+ DEVCB_NULL,
+ DEVCB_LINE(ibm5150_pit8253_out1_changed)
+ }, {
+ XTAL_14_31818MHz/12, /* pio port c pin 4, and speaker polling enough */
+ DEVCB_NULL,
+ DEVCB_LINE(ibm5150_pit8253_out2_changed)
+ }
+ }
+};
+
+
+/*
+ On the PC Jr the input for clock 1 seems to be selectable
+ based on bit 4(/5?) written to output port A0h. This is not
+ supported yet.
+ */
+
+const struct pit8253_config pcjr_pit8253_config =
+{
+ {
+ {
+ XTAL_14_31818MHz/12, /* heartbeat IRQ */
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE("pic8259", pic8259_ir0_w)
+ }, {
+ XTAL_14_31818MHz/12, /* dram refresh */
+ DEVCB_NULL,
+ DEVCB_NULL
+ }, {
+ XTAL_14_31818MHz/12, /* pio port c pin 4, and speaker polling enough */
+ DEVCB_NULL,
+ DEVCB_LINE(ibm5150_pit8253_out2_changed)
+ }
+ }
+};
+
+/* MC1502 uses single XTAL for everything -- incl. CGA? check */
+
+const struct pit8253_config mc1502_pit8253_config =
+{
+ {
+ {
+ XTAL_16MHz/12, /* heartbeat IRQ */
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE("pic8259", pic8259_ir0_w)
+ }, {
+ XTAL_16MHz/12, /* serial port */
+ DEVCB_NULL,
+ DEVCB_NULL
+ }, {
+ XTAL_16MHz/12, /* pio port c pin 4, and speaker polling enough */
+ DEVCB_NULL,
+ DEVCB_LINE(ibm5150_pit8253_out2_changed)
+ }
+ }
+};
+
+/**********************************************************
+ *
+ * COM hardware
+ *
+ **********************************************************/
+
+/* called when a interrupt is set/cleared from com hardware */
+static WRITE_LINE_DEVICE_HANDLER( pc_com_interrupt_1 )
+{
+ pc_state *st = device->machine().driver_data<pc_state>();
+ pic8259_ir4_w(st->m_pic8259, state);
+}
+
+static WRITE_LINE_DEVICE_HANDLER( pc_com_interrupt_2 )
+{
+ pc_state *st = device->machine().driver_data<pc_state>();
+ pic8259_ir3_w(st->m_pic8259, state);
+}
+
+const ins8250_interface ibm5150_com_interface[4]=
+{
+ {
+ DEVCB_DEVICE_LINE_MEMBER("serport0", serial_port_device, tx),
+ DEVCB_DEVICE_LINE_MEMBER("serport0", rs232_port_device, dtr_w),
+ DEVCB_DEVICE_LINE_MEMBER("serport0", rs232_port_device, rts_w),
+ DEVCB_LINE(pc_com_interrupt_1),
+ DEVCB_NULL,
+ DEVCB_NULL
+ },
+ {
+ DEVCB_DEVICE_LINE_MEMBER("serport1", serial_port_device, tx),
+ DEVCB_DEVICE_LINE_MEMBER("serport1", rs232_port_device, dtr_w),
+ DEVCB_DEVICE_LINE_MEMBER("serport1", rs232_port_device, rts_w),
+ DEVCB_LINE(pc_com_interrupt_2),
+ DEVCB_NULL,
+ DEVCB_NULL
+ },
+ {
+ DEVCB_DEVICE_LINE_MEMBER("serport2", serial_port_device, tx),
+ DEVCB_DEVICE_LINE_MEMBER("serport2", rs232_port_device, dtr_w),
+ DEVCB_DEVICE_LINE_MEMBER("serport2", rs232_port_device, rts_w),
+ DEVCB_LINE(pc_com_interrupt_1),
+ DEVCB_NULL,
+ DEVCB_NULL
+ },
+ {
+ DEVCB_DEVICE_LINE_MEMBER("serport3", serial_port_device, tx),
+ DEVCB_DEVICE_LINE_MEMBER("serport3", rs232_port_device, dtr_w),
+ DEVCB_DEVICE_LINE_MEMBER("serport3", rs232_port_device, rts_w),
+ DEVCB_LINE(pc_com_interrupt_2),
+ DEVCB_NULL,
+ DEVCB_NULL
+ }
+};
+
+const rs232_port_interface ibm5150_serport_config[4] =
+{
+ {
+ DEVCB_DEVICE_LINE_MEMBER("ins8250_0", ins8250_uart_device, rx_w),
+ DEVCB_DEVICE_LINE_MEMBER("ins8250_0", ins8250_uart_device, dcd_w),
+ DEVCB_DEVICE_LINE_MEMBER("ins8250_0", ins8250_uart_device, dsr_w),
+ DEVCB_DEVICE_LINE_MEMBER("ins8250_0", ins8250_uart_device, ri_w),
+ DEVCB_DEVICE_LINE_MEMBER("ins8250_0", ins8250_uart_device, cts_w)
+ },
+ {
+ DEVCB_DEVICE_LINE_MEMBER("ins8250_1", ins8250_uart_device, rx_w),
+ DEVCB_DEVICE_LINE_MEMBER("ins8250_1", ins8250_uart_device, dcd_w),
+ DEVCB_DEVICE_LINE_MEMBER("ins8250_1", ins8250_uart_device, dsr_w),
+ DEVCB_DEVICE_LINE_MEMBER("ins8250_1", ins8250_uart_device, ri_w),
+ DEVCB_DEVICE_LINE_MEMBER("ins8250_1", ins8250_uart_device, cts_w)
+ },
+ {
+ DEVCB_DEVICE_LINE_MEMBER("ins8250_2", ins8250_uart_device, rx_w),
+ DEVCB_DEVICE_LINE_MEMBER("ins8250_2", ins8250_uart_device, dcd_w),
+ DEVCB_DEVICE_LINE_MEMBER("ins8250_2", ins8250_uart_device, dsr_w),
+ DEVCB_DEVICE_LINE_MEMBER("ins8250_2", ins8250_uart_device, ri_w),
+ DEVCB_DEVICE_LINE_MEMBER("ins8250_2", ins8250_uart_device, cts_w)
+ },
+ {
+ DEVCB_DEVICE_LINE_MEMBER("ins8250_3", ins8250_uart_device, rx_w),
+ DEVCB_DEVICE_LINE_MEMBER("ins8250_3", ins8250_uart_device, dcd_w),
+ DEVCB_DEVICE_LINE_MEMBER("ins8250_3", ins8250_uart_device, dsr_w),
+ DEVCB_DEVICE_LINE_MEMBER("ins8250_3", ins8250_uart_device, ri_w),
+ DEVCB_DEVICE_LINE_MEMBER("ins8250_3", ins8250_uart_device, cts_w)
+ }
+};
+
+/**********************************************************
+ *
+ * NMI handling
+ *
+ **********************************************************/
+
+static UINT8 nmi_enabled;
+
+WRITE8_MEMBER(pc_state::pc_nmi_enable_w)
+{
+ logerror( "%08X: changing NMI state to %s\n", cpu_get_pc(&space.device()), data & 0x80 ? "enabled" : "disabled" );
+
+ nmi_enabled = data & 0x80;
+}
+
+/*************************************************************
+ *
+ * PCJR NMI and raw keybaord handling
+ *
+ * raw signals on the keyboard cable:
+ * ---_-b0b1b2b3b4b5b6b7pa----------------------
+ * | | | | | | | | | | |
+ * | | | | | | | | | | *--- 11 stop bits ( -- = 1 stop bit )
+ * | | | | | | | | | *----- parity bit ( 0 = _-, 1 = -_ )
+ * | | | | | | | | *------- bit 7 ( 0 = _-, 1 = -_ )
+ * | | | | | | | *--------- bit 6 ( 0 = _-, 1 = -_ )
+ * | | | | | | *----------- bit 5 ( 0 = _-, 1 = -_ )
+ * | | | | | *------------- bit 4 ( 0 = _-, 1 = -_ )
+ * | | | | *--------------- bit 3 ( 0 = _-, 1 = -_ )
+ * | | | *----------------- bit 2 ( 0 = _-, 1 = -_ )
+ * | | *------------------- bit 1 ( 0 = _-, 1 = -_ )
+ * | *--------------------- bit 0 ( 0 = _-, 1 = -_ )
+ * *----------------------- start bit (always _- )
+ *
+ * An entire bit lasts for 440 uSec, half bit time is 220 uSec.
+ * Transferring an entire byte takes 21 x 440uSec. The extra
+ * time of the stop bits is to allow the CPU to do other things
+ * besides decoding keyboard signals.
+ *
+ * These signals get inverted before going to the PCJR
+ * handling hardware. The sequence for the start then
+ * becomes:
+ *
+ * __-_b0b1.....
+ * |
+ * *---- on the 0->1 transition of the start bit a keyboard
+ * latch signal is set to 1 and an NMI is generated
+ * when enabled.
+ * The keyboard latch is reset by reading from the
+ * NMI enable port (A0h).
+ *
+ *************************************************************/
+
+static struct {
+ UINT8 transferring;
+ UINT8 latch;
+ UINT32 raw_keyb_data;
+ int signal_count;
+ emu_timer *keyb_signal_timer;
+} pcjr_keyb;
+
+
+READ8_MEMBER(pc_state::pcjr_nmi_enable_r)
+{
+ pcjr_keyb.latch = 0;
+
+ return nmi_enabled;
+}
+
+
+static TIMER_CALLBACK( pcjr_keyb_signal_callback )
+{
+ pcjr_keyb.raw_keyb_data = pcjr_keyb.raw_keyb_data >> 1;
+ pcjr_keyb.signal_count--;
+
+ if ( pcjr_keyb.signal_count <= 0 )
+ {
+ pcjr_keyb.keyb_signal_timer->adjust( attotime::never, 0, attotime::never );
+ pcjr_keyb.transferring = 0;
+ }
+}
+
+
+static void pcjr_set_keyb_int(running_machine &machine, int state)
+{
+ pc_state *st = machine.driver_data<pc_state>();
+ if ( state )
+ {
+ UINT8 data = pc_keyb_read();
+ UINT8 parity = 0;
+ int i;
+
+ /* Calculate the raw data */
+ for( i = 0; i < 8; i++ )
+ {
+ if ( ( 1 << i ) & data )
+ {
+ parity ^= 1;
+ }
+ }
+ pcjr_keyb.raw_keyb_data = 0;
+ pcjr_keyb.raw_keyb_data = ( pcjr_keyb.raw_keyb_data << 2 ) | ( parity ? 1 : 2 );
+ for( i = 0; i < 8; i++ )
+ {
+ pcjr_keyb.raw_keyb_data = ( pcjr_keyb.raw_keyb_data << 2 ) | ( ( data & 0x80 ) ? 1 : 2 );
+ data <<= 1;
+ }
+ /* Insert start bit */
+ pcjr_keyb.raw_keyb_data = ( pcjr_keyb.raw_keyb_data << 2 ) | 1;
+ pcjr_keyb.signal_count = 20 + 22;
+
+ /* we are now transferring a byte of keyboard data */
+ pcjr_keyb.transferring = 1;
+
+ /* Set timer */
+ pcjr_keyb.keyb_signal_timer->adjust( attotime::from_usec(220), 0, attotime::from_usec(220) );
+
+ /* Trigger NMI */
+ if ( ! pcjr_keyb.latch )
+ {
+ pcjr_keyb.latch = 1;
+ if ( nmi_enabled & 0x80 )
+ {
+ device_set_input_line( st->m_pit8253->machine().firstcpu, INPUT_LINE_NMI, PULSE_LINE );
+ }
+ }
+ }
+}
+
+
+static void pcjr_keyb_init(running_machine &machine)
+{
+ pcjr_keyb.transferring = 0;
+ pcjr_keyb.latch = 0;
+ pcjr_keyb.raw_keyb_data = 0;
+ pc_keyb_set_clock( 1 );
+}
+
+
+
+/**********************************************************
+ *
+ * PPI8255 interface
+ *
+ *
+ * PORT A (input)
+ *
+ * Directly attached to shift register which stores data
+ * received from the keyboard.
+ *
+ * PORT B (output)
+ * 0 - PB0 - TIM2GATESPK - Enable/disable counting on timer 2 of the 8253
+ * 1 - PB1 - SPKRDATA - Speaker data
+ * 2 - PB2 - - Enable receiving data from the keyboard when keyboard is not locked.
+ * 3 - PB3 - - Dipsswitch set selector
+ * 4 - PB4 - ENBRAMPCK - Enable ram parity check
+ * 5 - PB5 - ENABLEI/OCK - Enable expansion I/O check
+ * 6 - PB6 - - Connected to keyboard clock signal
+ * 0 = ignore keyboard signals
+ * 1 = accept keyboard signals
+ * 7 - PB7 - - Clear/disable shift register and IRQ1 line
+ * 0 = normal operation
+ * 1 = clear and disable shift register and clear IRQ1 flip flop
+ *
+ * PORT C
+ * 0 - PC0 - - Dipswitch 0/4 SW1
+ * 1 - PC1 - - Dipswitch 1/5 SW1
+ * 2 - PC2 - - Dipswitch 2/6 SW1
+ * 3 - PC3 - - Dipswitch 3/7 SW1
+ * 4 - PC4 - SPK - Speaker/cassette data
+ * 5 - PC5 - I/OCHCK - Expansion I/O check result
+ * 6 - PC6 - T/C2OUT - Output of 8253 timer 2
+ * 7 - PC7 - PCK - Parity check result
+ *
+ * IBM5150 SW1:
+ * 0 - OFF - One or more floppy drives
+ * ON - Diskless operation
+ * 1 - OFF - 8087 present
+ * ON - No 8087 present
+ * 2+3 - Used to determine on board memory configuration
+ * OFF OFF - 64KB
+ * ON OFF - 48KB
+ * OFF ON - 32KB
+ * ON ON - 16KB
+ * 4+5 - Used to select display
+ * OFF OFF - Monochrome
+ * ON OFF - CGA, 80 column
+ * OFF ON - CGA, 40 column
+ * ON ON - EGA/VGA display
+ * 6+7 - Used to select number of disk drives
+ * OFF OFF - four disk drives
+ * ON OFF - three disk drives
+ * OFF ON - two disk drives
+ * ON ON - one disk drive
+ *
+ **********************************************************/
+
+WRITE_LINE_MEMBER( pc_state::keyboard_clock_w )
+{
+ if ( m_ppi_clock_signal != state )
+ {
+ if ( m_ppi_keyb_clock && m_ppi_shift_enable )
+ {
+ m_ppi_clock_signal = state;
+ if ( ! m_ppi_keyboard_clear )
+ {
+ /* Data is clocked in on a high->low transition */
+ if ( ! state )
+ {
+ UINT8 trigger_irq = m_ppi_shift_register & 0x01;
+
+ m_ppi_shift_register = ( m_ppi_shift_register >> 1 ) | ( m_ppi_data_signal << 7 );
+ if ( trigger_irq )
+ {
+ pic8259_ir1_w(m_pic8259, 1);
+ m_ppi_shift_enable = 0;
+ m_ppi_clock_signal = 0;
+ m_pc_kbdc->clock_write_from_mb(m_ppi_clock_signal);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+WRITE_LINE_MEMBER( pc_state::keyboard_data_w )
+{
+ m_ppi_data_signal = state;
+}
+
+
+static READ8_DEVICE_HANDLER (ibm5160_ppi_porta_r)
+{
+ int data = 0xFF;
+ running_machine &machine = device->machine();
+ pc_state *st = device->machine().driver_data<pc_state>();
+
+ /* KB port A */
+ if (st->m_ppi_keyboard_clear)
+ {
+ /* 0 0 - no floppy drives
+ * 1 Not used
+ * 2-3 The number of memory banks on the system board
+ * 4-5 Display mode
+ * 11 = monochrome
+ * 10 - color 80x25
+ * 01 - color 40x25
+ * 6-7 The number of floppy disk drives
+ */
+ data = device->machine().root_device().ioport("DSW0")->read();
+ }
+ else
+ {
+ data = st->m_ppi_shift_register;
+ }
+ PIO_LOG(1,"PIO_A_r",("$%02x\n", data));
+ return data;
+}
+
+
+static READ8_DEVICE_HANDLER ( ibm5160_ppi_portc_r )
+{
+ pc_state *st = device->machine().driver_data<pc_state>();
+ int timer2_output = pit8253_get_output( st->m_pit8253, 2 );
+ int data=0xff;
+ running_machine &machine = device->machine();
+
+ data&=~0x80; // no parity error
+ data&=~0x40; // no error on expansion board
+ /* KB port C: equipment flags */
+// if (pc_port[0x61] & 0x08)
+ if (st->m_ppi_portc_switch_high)
+ {
+ /* read hi nibble of S2 */
+ data = (data & 0xf0) | ((device->machine().root_device().ioport("DSW0")->read() >> 4) & 0x0f);
+ PIO_LOG(1,"PIO_C_r (hi)",("$%02x\n", data));
+ }
+ else
+ {
+ /* read lo nibble of S2 */
+ data = (data & 0xf0) | (device->machine().root_device().ioport("DSW0")->read() & 0x0f);
+ PIO_LOG(1,"PIO_C_r (lo)",("$%02x\n", data));
+ }
+
+ if ( st->m_ppi_portb & 0x01 )
+ {
+ data = ( data & ~0x10 ) | ( timer2_output ? 0x10 : 0x00 );
+ }
+ data = ( data & ~0x20 ) | ( timer2_output ? 0x20 : 0x00 );
+
+ return data;
+}
+
+
+static WRITE8_DEVICE_HANDLER( ibm5160_ppi_portb_w )
+{
+ pc_state *st = device->machine().driver_data<pc_state>();
+
+ /* PPI controller port B*/
+ st->m_ppi_portb = data;
+ st->m_ppi_portc_switch_high = data & 0x08;
+ st->m_ppi_keyboard_clear = data & 0x80;
+ st->m_ppi_keyb_clock = data & 0x40;
+ pit8253_gate2_w(st->m_pit8253, BIT(data, 0));
+ pc_speaker_set_spkrdata( device->machine(), data & 0x02 );
+
+ st->m_ppi_clock_signal = ( st->m_ppi_keyb_clock ) ? 1 : 0;
+ st->m_pc_kbdc->clock_write_from_mb(st->m_ppi_clock_signal);
+
+ /* If PB7 is set clear the shift register and reset the IRQ line */
+ if ( st->m_ppi_keyboard_clear )
+ {
+ pic8259_ir1_w(st->m_pic8259, 0);
+ st->m_ppi_shift_register = 0;
+ st->m_ppi_shift_enable = 1;
+ }
+}
+
+
+I8255_INTERFACE( ibm5160_ppi8255_interface )
+{
+ DEVCB_HANDLER(ibm5160_ppi_porta_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(ibm5160_ppi_portb_w),
+ DEVCB_HANDLER(ibm5160_ppi_portc_r),
+ DEVCB_NULL
+};
+
+
+static READ8_DEVICE_HANDLER (pc_ppi_porta_r)
+{
+ int data = 0xFF;
+ running_machine &machine = device->machine();
+ pc_state *st = device->machine().driver_data<pc_state>();
+
+ /* KB port A */
+ if (st->m_ppi_keyboard_clear)
+ {
+ /* 0 0 - no floppy drives
+ * 1 Not used
+ * 2-3 The number of memory banks on the system board
+ * 4-5 Display mode
+ * 11 = monochrome
+ * 10 - color 80x25
+ * 01 - color 40x25
+ * 6-7 The number of floppy disk drives
+ */
+ data = device->machine().root_device().ioport("DSW0")->read();
+ }
+ else
+ {
+ data = pc_keyb_read();
+ }
+ PIO_LOG(1,"PIO_A_r",("$%02x\n", data));
+ return data;
+}
+
+
+static WRITE8_DEVICE_HANDLER( pc_ppi_portb_w )
+{
+ pc_state *st = device->machine().driver_data<pc_state>();
+ /* PPI controller port B*/
+ st->m_ppi_portb = data;
+ st->m_ppi_portc_switch_high = data & 0x08;
+ st->m_ppi_keyboard_clear = data & 0x80;
+ st->m_ppi_keyb_clock = data & 0x40;
+ pit8253_gate2_w(st->m_pit8253, BIT(data, 0));
+ pc_speaker_set_spkrdata( device->machine(), data & 0x02 );
+ pc_keyb_set_clock( st->m_ppi_keyb_clock );
+
+ if ( st->m_ppi_keyboard_clear )
+ pc_keyb_clear();
+}
+
+
+I8255_INTERFACE( pc_ppi8255_interface )
+{
+ DEVCB_HANDLER(pc_ppi_porta_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(pc_ppi_portb_w),
+ DEVCB_HANDLER(ibm5160_ppi_portc_r),
+ DEVCB_NULL
+};
+
+
+static struct {
+ UINT8 pulsing;
+ UINT8 latch; /* keyboard scan code */
+ UINT16 mask; /* input lines */
+ emu_timer *keyb_signal_timer;
+} mc1502_keyb;
+
+
+/* check if any keys are pressed, raise IRQ1 if so */
+
+static TIMER_CALLBACK( mc1502_keyb_signal_callback )
+{
+ pc_state *st = machine.driver_data<pc_state>();
+ UINT8 key = 0;
+
+ key |= machine.root_device().ioport("Y1")->read();
+ key |= machine.root_device().ioport("Y2")->read();
+ key |= machine.root_device().ioport("Y3")->read();
+ key |= machine.root_device().ioport("Y4")->read();
+ key |= machine.root_device().ioport("Y5")->read();
+ key |= machine.root_device().ioport("Y6")->read();
+ key |= machine.root_device().ioport("Y7")->read();
+ key |= machine.root_device().ioport("Y8")->read();
+ key |= machine.root_device().ioport("Y9")->read();
+ key |= machine.root_device().ioport("Y10")->read();
+ key |= machine.root_device().ioport("Y11")->read();
+ key |= machine.root_device().ioport("Y12")->read();
+ DBG_LOG(1,"mc1502_k_s_c",("= %02X (%d) %s\n", key, mc1502_keyb.pulsing,
+ (key || mc1502_keyb.pulsing) ? " will IRQ" : ""));
+
+ /*
+ If a key is pressed and we're not pulsing yet, start pulsing the IRQ1;
+ keep pulsing while any key is pressed, and pulse one time after all keys
+ are released.
+ */
+ if (key) {
+ if (mc1502_keyb.pulsing < 2) {
+ mc1502_keyb.pulsing += 2;
+ }
+ }
+
+ if (mc1502_keyb.pulsing) {
+ pic8259_ir1_w(st->m_pic8259, (mc1502_keyb.pulsing & 1));
+ mc1502_keyb.pulsing--;
+ }
+}
+
+static READ8_DEVICE_HANDLER ( mc1502_ppi_porta_r )
+{
+ running_machine &machine = device->machine();
+
+ DBG_LOG(1,"mc1502_ppi_porta_r",("= %02X\n", mc1502_keyb.latch));
+ return mc1502_keyb.latch;
+}
+
+static WRITE8_DEVICE_HANDLER ( mc1502_ppi_porta_w )
+{
+ pc_state *st = device->machine().driver_data<pc_state>();
+ running_machine &machine = device->machine();
+
+ DBG_LOG(1,"mc1502_ppi_porta_w",("( %02X )\n", data));
+ mc1502_keyb.latch = data;
+ if (mc1502_keyb.pulsing)
+ mc1502_keyb.pulsing--;
+ pic8259_ir1_w(st->m_pic8259, 0);
+}
+
+static WRITE8_DEVICE_HANDLER ( mc1502_ppi_portb_w )
+{
+ pc_state *st = device->machine().driver_data<pc_state>();
+ running_machine &machine = device->machine();
+
+ DBG_LOG(2,"mc1502_ppi_portb_w",("( %02X )\n", data));
+ st->m_ppi_portb = data;
+ pit8253_gate2_w(device->machine().device("pit8253"), BIT(data, 0));
+ pc_speaker_set_spkrdata( device->machine(), data & 0x02 );
+}
+
+static READ8_DEVICE_HANDLER ( mc1502_ppi_portc_r )
+{
+ running_machine &machine = device->machine();
+ pc_state *st = device->machine().driver_data<pc_state>();
+ int timer2_output = pit8253_get_output( device->machine().device("pit8253"), 2 );
+ int data = 0xff;
+ double tap_val = (device->machine().device<cassette_image_device>(CASSETTE_TAG)->input());
+
+// 0x80 -- serial RxD
+// 0x40 -- CASS IN, also loops back T2OUT (gated by CASWR)
+ data = ( data & ~0x40 ) | ( tap_val < 0 ? 0x40 : 0x00 ) | ( (BIT(st->m_ppi_portb, 7) && timer2_output) ? 0x40 : 0x00 );
+// 0x20 -- T2OUT
+ data = ( data & ~0x20 ) | ( timer2_output ? 0x20 : 0x00 );
+// 0x10 -- SNDOUT
+ data = ( data & ~0x10 ) | ( (BIT(st->m_ppi_portb, 1) && timer2_output) ? 0x10 : 0x00 );
+
+ DBG_LOG(2,"mc1502_ppi_portc_r",("= %02X (tap_val %f t2out %d) at %s\n",
+ data, tap_val, timer2_output, machine.describe_context()));
+ return data;
+}
+
+static READ8_DEVICE_HANDLER ( mc1502_kppi_porta_r )
+{
+ running_machine &machine = device->machine();
+ UINT8 key = 0;
+
+ if (mc1502_keyb.mask & 0x0001) { key |= machine.root_device().ioport("Y1")->read(); }
+ if (mc1502_keyb.mask & 0x0002) { key |= machine.root_device().ioport("Y2")->read(); }
+ if (mc1502_keyb.mask & 0x0004) { key |= machine.root_device().ioport("Y3")->read(); }
+ if (mc1502_keyb.mask & 0x0008) { key |= machine.root_device().ioport("Y4")->read(); }
+ if (mc1502_keyb.mask & 0x0010) { key |= machine.root_device().ioport("Y5")->read(); }
+ if (mc1502_keyb.mask & 0x0020) { key |= machine.root_device().ioport("Y6")->read(); }
+ if (mc1502_keyb.mask & 0x0040) { key |= machine.root_device().ioport("Y7")->read(); }
+ if (mc1502_keyb.mask & 0x0080) { key |= machine.root_device().ioport("Y8")->read(); }
+ if (mc1502_keyb.mask & 0x0100) { key |= machine.root_device().ioport("Y9")->read(); }
+ if (mc1502_keyb.mask & 0x0200) { key |= machine.root_device().ioport("Y10")->read(); }
+ if (mc1502_keyb.mask & 0x0400) { key |= machine.root_device().ioport("Y11")->read(); }
+ if (mc1502_keyb.mask & 0x0800) { key |= machine.root_device().ioport("Y12")->read(); }
+ key ^= 0xff;
+ DBG_LOG(2,"mc1502_kppi_porta_r",("= %02X\n", key));
+ return key;
+}
+
+static WRITE8_DEVICE_HANDLER ( mc1502_kppi_portb_w )
+{
+ running_machine &machine = device->machine();
+
+ mc1502_keyb.mask &= ~255;
+ mc1502_keyb.mask |= data ^ 255;
+ if (!BIT(data, 0))
+ mc1502_keyb.mask |= 1 << 11;
+ else
+ mc1502_keyb.mask &= ~(1 << 11);
+ DBG_LOG(2,"mc1502_kppi_portb_w",("( %02X -> %04X )\n", data, mc1502_keyb.mask));
+}
+
+static WRITE8_DEVICE_HANDLER ( mc1502_kppi_portc_w )
+{
+ running_machine &machine = device->machine();
+
+ mc1502_keyb.mask &= ~(7 << 8);
+ mc1502_keyb.mask |= ((data ^ 7) & 7) << 8;
+ DBG_LOG(2,"mc1502_kppi_portc_w",("( %02X -> %04X )\n", data, mc1502_keyb.mask));
+}
+
+
+static WRITE8_DEVICE_HANDLER ( pcjr_ppi_portb_w )
+{
+ pc_state *st = device->machine().driver_data<pc_state>();
+ /* KB controller port B */
+ st->m_ppi_portb = data;
+ st->m_ppi_portc_switch_high = data & 0x08;
+ pit8253_gate2_w(device->machine().device("pit8253"), BIT(data, 0));
+ pc_speaker_set_spkrdata( device->machine(), data & 0x02 );
+
+ device->machine().device<cassette_image_device>(CASSETTE_TAG)->change_state(( data & 0x08 ) ? CASSETTE_MOTOR_DISABLED : CASSETTE_MOTOR_ENABLED,CASSETTE_MASK_MOTOR);
+}
+
+
+/*
+ * On a PCJR none of the port A bits are connected.
+ */
+static READ8_DEVICE_HANDLER (pcjr_ppi_porta_r )
+{
+ int data;
+ running_machine &machine = device->machine();
+
+ data = 0xff;
+ PIO_LOG(1,"PIO_A_r",("$%02x\n", data));
+ return data;
+}
+
+
+/*
+ * Port C connections on a PCJR (notes from schematics):
+ * PC0 - KYBD LATCH
+ * PC1 - MODEM CD INSTALLED
+ * PC2 - DISKETTE CD INSTALLED
+ * PC3 - ATR CD IN
+ * PC4 - cassette audio
+ * PC5 - OUT2 from 8253
+ * PC6 - KYBD IN
+ * PC7 - (keyboard) CABLE CONNECTED
+ */
+static READ8_DEVICE_HANDLER ( pcjr_ppi_portc_r )
+{
+ pc_state *st = device->machine().driver_data<pc_state>();
+ int timer2_output = pit8253_get_output( device->machine().device("pit8253"), 2 );
+ int data=0xff;
+
+ data&=~0x80;
+ data &= ~0x04; /* floppy drive installed */
+ if ( device->machine().device<ram_device>(RAM_TAG)->size() > 64 * 1024 ) /* more than 64KB ram installed */
+ data &= ~0x08;
+ data = ( data & ~0x01 ) | ( pcjr_keyb.latch ? 0x01: 0x00 );
+ if ( ! ( st->m_ppi_portb & 0x08 ) )
+ {
+ double tap_val = (device->machine().device<cassette_image_device>(CASSETTE_TAG)->input());
+
+ if ( tap_val < 0 )
+ {
+ data &= ~0x10;
+ }
+ else
+ {
+ data |= 0x10;
+ }
+ }
+ else
+ {
+ if ( st->m_ppi_portb & 0x01 )
+ {
+ data = ( data & ~0x10 ) | ( timer2_output ? 0x10 : 0x00 );
+ }
+ }
+ data = ( data & ~0x20 ) | ( timer2_output ? 0x20 : 0x00 );
+ data = ( data & ~0x40 ) | ( ( pcjr_keyb.raw_keyb_data & 0x01 ) ? 0x40 : 0x00 );
+
+ return data;
+}
+
+
+I8255_INTERFACE( pcjr_ppi8255_interface )
+{
+ DEVCB_HANDLER(pcjr_ppi_porta_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(pcjr_ppi_portb_w),
+ DEVCB_HANDLER(pcjr_ppi_portc_r),
+ DEVCB_NULL
+};
+
+I8255_INTERFACE( mc1502_ppi8255_interface )
+{
+ DEVCB_HANDLER(mc1502_ppi_porta_r),
+ DEVCB_HANDLER(mc1502_ppi_porta_w),
+ DEVCB_NULL,
+ DEVCB_HANDLER(mc1502_ppi_portb_w),
+ DEVCB_HANDLER(mc1502_ppi_portc_r),
+ DEVCB_NULL
+};
+
+I8255_INTERFACE( mc1502_ppi8255_interface_2 )
+{
+ DEVCB_HANDLER(mc1502_kppi_porta_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(mc1502_kppi_portb_w),
+ DEVCB_NULL,
+ DEVCB_HANDLER(mc1502_kppi_portc_w)
+};
+
+
+/**********************************************************
+ *
+ * NEC uPD765 floppy interface
+ *
+ **********************************************************/
+
+static void pc_fdc_interrupt(running_machine &machine, int state)
+{
+ pc_state *st = machine.driver_data<pc_state>();
+ if (st->m_pic8259)
+ {
+ pic8259_ir6_w(st->m_pic8259, state);
+ }
+}
+
+static void pc_fdc_dma_drq(running_machine &machine, int state)
+{
+ pc_state *st = machine.driver_data<pc_state>();
+ i8237_dreq2_w( st->m_dma8237, state);
+}
+
+static device_t * pc_get_device(running_machine &machine )
+{
+ return machine.device("upd765");
+}
+
+static const struct pc_fdc_interface fdc_interface_nc =
+{
+ pc_fdc_interrupt,
+ pc_fdc_dma_drq,
+ NULL,
+ pc_get_device
+};
+
+
+static const struct pc_fdc_interface pcjr_fdc_interface_nc =
+{
+ pc_fdc_interrupt,
+ NULL,
+ NULL,
+ pc_get_device
+};
+
+
+static void pc_set_irq_line(running_machine &machine,int irq, int state)
+{
+ pc_state *st = machine.driver_data<pc_state>();
+
+ switch (irq)
+ {
+ case 0: pic8259_ir0_w(st->m_pic8259, state); break;
+ case 1: pic8259_ir1_w(st->m_pic8259, state); break;
+ case 2: pic8259_ir2_w(st->m_pic8259, state); break;
+ case 3: pic8259_ir3_w(st->m_pic8259, state); break;
+ case 4: pic8259_ir4_w(st->m_pic8259, state); break;
+ case 5: pic8259_ir5_w(st->m_pic8259, state); break;
+ case 6: pic8259_ir6_w(st->m_pic8259, state); break;
+ case 7: pic8259_ir7_w(st->m_pic8259, state); break;
+ }
+}
+
+static void pc_set_keyb_int(running_machine &machine, int state)
+{
+ pc_set_irq_line( machine, 1, state );
+}
+
+/*
+ * MC1502 uses a FD1793 clone instead of uPD765
+ */
+
+READ8_DEVICE_HANDLER( mc1502_wd17xx_aux_r )
+{
+ UINT8 data;
+
+ data = 0;
+
+ return data;
+}
+
+WRITE8_DEVICE_HANDLER( mc1502_wd17xx_aux_w )
+{
+ // master reset
+ wd17xx_mr_w(device, BIT(data, 0));
+
+ // SIDE ONE
+ wd17xx_set_side(device, BIT(data, 1));
+
+ // bits 2, 3 -- motor on (drive 0, 1)
+
+ // DRIVE SEL
+ wd17xx_set_drive(device, BIT(data, 4));
+}
+
+/*
+ * Accesses to this port block (halt the CPU until DRQ, INTRQ or MOTOR ON)
+ */
+READ8_DEVICE_HANDLER( mc1502_wd17xx_drq_r )
+{
+ UINT8 data;
+ UINT64 newpc;
+
+ data = wd17xx_drq_r(device);
+ if (!data && !wd17xx_intrq_r(device)) {
+ /* fake cpu halt by resetting PC one insn back */
+ newpc = cpu_get_reg( device->machine().firstcpu, STATE_GENPC );
+ cpu_set_reg( device->machine().firstcpu, STATE_GENPC, newpc - 1 );
+ }
+
+ return data;
+}
+
+READ8_DEVICE_HANDLER( mc1502_wd17xx_motor_r )
+{
+ UINT8 data;
+
+ /* fake motor being always on */
+ data = 1;
+
+ return data;
+}
+
+
+/**********************************************************
+ *
+ * Initialization code
+ *
+ **********************************************************/
+
+void mess_init_pc_common(running_machine &machine, UINT32 flags, void (*set_keyb_int_func)(running_machine &, int), void (*set_hdc_int_func)(running_machine &,int,int))
+{
+ pc_state *state = machine.driver_data<pc_state>();
+ if ( set_keyb_int_func != NULL )
+ init_pc_common(machine, flags, set_keyb_int_func);
+
+ /* MESS managed RAM */
+ if ( machine.device<ram_device>(RAM_TAG)->pointer() )
+ state->membank( "bank10" )->set_base( machine.device<ram_device>(RAM_TAG)->pointer() );
+}
+
+
+DRIVER_INIT_MEMBER(pc_state,ibm5150)
+{
+ mess_init_pc_common(machine(), PCCOMMON_KEYBOARD_PC, NULL, pc_set_irq_line);
+ pc_rtc_init(machine());
+}
+
+
+DRIVER_INIT_MEMBER(pc_state,pccga)
+{
+ mess_init_pc_common(machine(), PCCOMMON_KEYBOARD_PC, NULL, pc_set_irq_line);
+ pc_rtc_init(machine());
+}
+
+
+DRIVER_INIT_MEMBER(pc_state,bondwell)
+{
+ mess_init_pc_common(machine(), PCCOMMON_KEYBOARD_PC, NULL, pc_set_irq_line);
+ pc_turbo_setup(machine(), machine().firstcpu, "DSW2", 0x02, 4.77/12, 1);
+}
+
+DRIVER_INIT_MEMBER(pc_state,pcmda)
+{
+ mess_init_pc_common(machine(), PCCOMMON_KEYBOARD_PC, pc_set_keyb_int, pc_set_irq_line);
+}
+
+DRIVER_INIT_MEMBER(pc_state,europc)
+{
+ UINT8 *gfx = &machine().root_device().memregion("gfx1")->base()[0x8000];
+ UINT8 *rom = &machine().root_device().memregion("maincpu")->base()[0];
+ int i;
+
+ /* just a plain bit pattern for graphics data generation */
+ for (i = 0; i < 256; i++)
+ gfx[i] = i;
+
+ /*
+ fix century rom bios bug !
+ if year <79 month (and not CENTURY) is loaded with 0x20
+ */
+ if (rom[0xff93e]==0xb6){ // mov dh,
+ UINT8 a;
+ rom[0xff93e]=0xb5; // mov ch,
+ for (i=0xf8000, a=0; i<0xfffff; i++ ) a+=rom[i];
+ rom[0xfffff]=256-a;
+ }
+
+ mess_init_pc_common(machine(), PCCOMMON_KEYBOARD_PC, pc_set_keyb_int, pc_set_irq_line);
+
+ europc_rtc_init(machine());
+// europc_rtc_set_time(machine());
+}
+
+DRIVER_INIT_MEMBER(pc_state,t1000hx)
+{
+ mess_init_pc_common(machine(), PCCOMMON_KEYBOARD_PC, pc_set_keyb_int, pc_set_irq_line);
+ pc_turbo_setup(machine(), machine().firstcpu, "DSW2", 0x02, 4.77/12, 1);
+}
+
+DRIVER_INIT_MEMBER(pc_state,pc200)
+{
+ UINT8 *gfx = &machine().root_device().memregion("gfx1")->base()[0x8000];
+ int i;
+
+ /* just a plain bit pattern for graphics data generation */
+ for (i = 0; i < 256; i++)
+ gfx[i] = i;
+
+ mess_init_pc_common(machine(), PCCOMMON_KEYBOARD_PC, pc_set_keyb_int, pc_set_irq_line);
+}
+
+DRIVER_INIT_MEMBER(pc_state,ppc512)
+{
+ UINT8 *gfx = &machine().root_device().memregion("gfx1")->base()[0x8000];
+ int i;
+
+ /* just a plain bit pattern for graphics data generation */
+ for (i = 0; i < 256; i++)
+ gfx[i] = i;
+
+ mess_init_pc_common(machine(), PCCOMMON_KEYBOARD_PC, pc_set_keyb_int, pc_set_irq_line);
+}
+DRIVER_INIT_MEMBER(pc_state,pc1512)
+{
+ UINT8 *gfx = &machine().root_device().memregion("gfx1")->base()[0x8000];
+ int i;
+
+ /* just a plain bit pattern for graphics data generation */
+ for (i = 0; i < 256; i++)
+ gfx[i] = i;
+
+ mess_init_pc_common(machine(), PCCOMMON_KEYBOARD_PC, pc_set_keyb_int, pc_set_irq_line);
+}
+
+
+DRIVER_INIT_MEMBER(pc_state,pcjr)
+{
+ mess_init_pc_common(machine(), PCCOMMON_KEYBOARD_PC, pcjr_set_keyb_int, pc_set_irq_line);
+}
+
+DRIVER_INIT_MEMBER(pc_state,mc1502)
+{
+ mess_init_pc_common(machine(), 0, NULL, pc_set_irq_line);
+}
+
+static READ8_HANDLER( input_port_0_r ) { return space->machine().root_device().ioport("IN0")->read(); }
+
+DRIVER_INIT_MEMBER(pc_state,pc1640)
+{
+ address_space *io_space = machine().firstcpu->memory().space( AS_IO );
+
+ io_space->install_legacy_read_handler(0x278, 0x27b, FUNC(pc1640_port278_r), 0xffff);
+ io_space->install_legacy_read_handler(0x4278, 0x427b, FUNC(pc1640_port4278_r), 0xffff);
+
+ mess_init_pc_common(machine(), PCCOMMON_KEYBOARD_PC, pc_set_keyb_int, pc_set_irq_line);
+}
+
+DRIVER_INIT_MEMBER(pc_state,pc_vga)
+{
+ mess_init_pc_common(machine(), PCCOMMON_KEYBOARD_PC, pc_set_keyb_int, pc_set_irq_line);
+
+ pc_vga_init(machine(), ::input_port_0_r, NULL);
+ pc_vga_io_init(machine(), machine().device("maincpu")->memory().space(AS_PROGRAM), 0xa0000, machine().device("maincpu")->memory().space(AS_IO), 0x0000);
+}
+
+static IRQ_CALLBACK(pc_irq_callback)
+{
+ pc_state *st = device->machine().driver_data<pc_state>();
+ return pic8259_acknowledge( st->m_pic8259 );
+}
+
+
+MACHINE_START( pc )
+{
+ pc_state *st = machine.driver_data<pc_state>();
+
+ st->m_pic8259 = machine.device("pic8259");
+ st->m_dma8237 = machine.device("dma8237");
+ st->m_pit8253 = machine.device("pit8253");
+ pc_fdc_init( machine, &fdc_interface_nc );
+}
+
+
+MACHINE_RESET( pc )
+{
+ device_t *speaker = machine.device(SPEAKER_TAG);
+ pc_state *st = machine.driver_data<pc_state>();
+ st->m_maincpu = machine.device("maincpu" );
+ device_set_irq_callback(st->m_maincpu, pc_irq_callback);
+
+ st->m_u73_q2 = 0;
+ st->m_out1 = 0;
+ st->m_pc_spkrdata = 0;
+ st->m_pc_input = 1;
+ st->m_dma_channel = 0;
+ memset(st->m_dma_offset,0,sizeof(st->m_dma_offset));
+ st->m_ppi_portc_switch_high = 0;
+ st->m_ppi_speaker = 0;
+ st->m_ppi_keyboard_clear = 0;
+ st->m_ppi_keyb_clock = 0;
+ st->m_ppi_portb = 0;
+ st->m_ppi_clock_signal = 0;
+ st->m_ppi_data_signal = 0;
+ st->m_ppi_shift_register = 0;
+ st->m_ppi_shift_enable = 0;
+
+ speaker_level_w( speaker, 0 );
+}
+
+
+MACHINE_START( mc1502 )
+{
+ pc_state *st = machine.driver_data<pc_state>();
+ st->m_maincpu = machine.device("maincpu" );
+ device_set_irq_callback(st->m_maincpu, pc_irq_callback);
+
+ st->m_pic8259 = machine.device("pic8259");
+ st->m_dma8237 = NULL;
+ st->m_pit8253 = machine.device("pit8253");
+
+ /*
+ Keyboard polling circuit holds IRQ1 high until a key is
+ pressed, then it starts a timer that pulses IRQ1 low each
+ 40ms (check) for 20ms (check) until all keys are released.
+ Last pulse causes BIOS to write a 'break' scancode into port 60h.
+ */
+ pic8259_ir1_w(st->m_pic8259, 1);
+ memset(&mc1502_keyb, 0, sizeof(mc1502_keyb));
+ mc1502_keyb.keyb_signal_timer = machine.scheduler().timer_alloc(FUNC(mc1502_keyb_signal_callback));
+ mc1502_keyb.keyb_signal_timer->adjust( attotime::from_msec(20), 0, attotime::from_msec(20) );
+}
+
+
+MACHINE_START( pcjr )
+{
+ pc_state *st = machine.driver_data<pc_state>();
+ pc_fdc_init( machine, &pcjr_fdc_interface_nc );
+ pcjr_keyb.keyb_signal_timer = machine.scheduler().timer_alloc(FUNC(pcjr_keyb_signal_callback));
+ pc_int_delay_timer = machine.scheduler().timer_alloc(FUNC(pcjr_delayed_pic8259_irq));
+ st->m_maincpu = machine.device("maincpu" );
+ device_set_irq_callback(st->m_maincpu, pc_irq_callback);
+
+ st->m_pic8259 = machine.device("pic8259");
+ st->m_dma8237 = NULL;
+ st->m_pit8253 = machine.device("pit8253");
+}
+
+
+MACHINE_RESET( pcjr )
+{
+ device_t *speaker = machine.device(SPEAKER_TAG);
+ pc_state *st = machine.driver_data<pc_state>();
+ st->m_u73_q2 = 0;
+ st->m_out1 = 0;
+ st->m_pc_spkrdata = 0;
+ st->m_pc_input = 1;
+ st->m_dma_channel = 0;
+ memset(st->m_memboard,0xc,sizeof(st->m_memboard)); // check
+ memset(st->m_dma_offset,0,sizeof(st->m_dma_offset));
+ st->m_ppi_portc_switch_high = 0;
+ st->m_ppi_speaker = 0;
+ st->m_ppi_keyboard_clear = 0;
+ st->m_ppi_keyb_clock = 0;
+ st->m_ppi_portb = 0;
+ st->m_ppi_clock_signal = 0;
+ st->m_ppi_data_signal = 0;
+ st->m_ppi_shift_register = 0;
+ st->m_ppi_shift_enable = 0;
+ speaker_level_w( speaker, 0 );
+
+ pcjr_keyb_init(machine);
+}
+
+
+DEVICE_IMAGE_LOAD( pcjr_cartridge )
+{
+ UINT32 address;
+ UINT32 size;
+
+ address = ( ! strcmp( ":cart2", image.device().tag() ) ) ? 0xd0000 : 0xe0000;
+
+ if ( image.software_entry() )
+ {
+ UINT8 *cart = image.get_software_region( "rom" );
+
+ size = image.get_software_region_length("rom" );
+
+ memcpy( image.device().machine().root_device().memregion("maincpu")->base() + address, cart, size );
+ }
+ else
+ {
+ UINT8 header[0x200];
+
+ unsigned image_size = image.length();
+
+ /* Check for supported image sizes */
+ switch( image_size )
+ {
+ case 0x2200:
+ case 0x4200:
+ case 0x8200:
+ case 0x10200:
+ break;
+ default:
+ image.seterror(IMAGE_ERROR_UNSUPPORTED, "Invalid rom file size" );
+ return IMAGE_INIT_FAIL;
+ }
+
+ /* Read and verify the header */
+ if ( 512 != image.fread( header, 512 ) )
+ {
+ image.seterror(IMAGE_ERROR_UNSUPPORTED, "Unable to read header" );
+ return IMAGE_INIT_FAIL;
+ }
+
+ /* Read the cartridge contents */
+ if ( ( image_size - 0x200 ) != image.fread(image.device().machine().root_device().memregion("maincpu")->base() + address, image_size - 0x200 ) )
+ {
+ image.seterror(IMAGE_ERROR_UNSUPPORTED, "Unable to read cartridge contents" );
+ return IMAGE_INIT_FAIL;
+ }
+ }
+
+ return IMAGE_INIT_PASS;
+}
+
+
+/**************************************************************************
+ *
+ * Interrupt handlers.
+ *
+ **************************************************************************/
+
+TIMER_DEVICE_CALLBACK( pc_frame_interrupt )
+{
+ int scanline = param;
+
+ if((scanline % 64) == 0)
+ pc_keyboard();
+}
+
+TIMER_DEVICE_CALLBACK( pc_vga_frame_interrupt )
+{
+ int scanline = param;
+
+ if((scanline % 64) == 0)
+ {
+ //vga_timer();
+ pc_keyboard();
+ }
+}
+
+TIMER_DEVICE_CALLBACK( pcjr_frame_interrupt )
+{
+ int scanline = param;
+
+ if((scanline % 64) == 0 && pcjr_keyb.transferring == 0 )
+ pc_keyboard();
+}
+
+/*
+ibm xt bios
+-----------
+
+fe0ac
+fe10c
+fe12b: hangs after reset
+fe15e
+fe19c
+fe2c6
+ graphics adapter sync signals
+fe332
+ search roms
+fe35d
+ pic test
+fe38f
+fe3c6
+fe3e6
+ 301 written
+ expect 0xaa after reset, send when lines activated in short time
+ (keyboard polling in frame interrupt is not quick enough now)
+fe424
+fe448
+ i/o expansion test
+fe49c
+ memory test
+fe500
+ harddisk bios used
+fe55c
+ disk booting
+
+ f0bef
+ f0b85
+ f096d
+ disk related
+ feca0
+ prueft kanal 0 address register (memory refresh!?)
+
+ibm pc bios
+-----------
+fe104
+fe165
+fe1b4
+fe205
+fe23f
+fe256
+fe363
+fe382 expansion test
+fe3c4
+ memory test
+fe43b
+fe443 call fe643 keyboard test
+fe4a1 call ff979 tape!!! test
+*/
+
+
+// damned old checkit doesn't test at standard addresses
+// will do more when I have a program supporting it
+static struct {
+ int data[0x18];
+ emu_timer *timer;
+} pc_rtc;
+
+static TIMER_CALLBACK(pc_rtc_timer)
+{
+ int year;
+ if (++pc_rtc.data[2]>=60) {
+ pc_rtc.data[2]=0;
+ if (++pc_rtc.data[3]>=60) {
+ pc_rtc.data[3]=0;
+ if (++pc_rtc.data[4]>=24) {
+ pc_rtc.data[4]=0;
+ pc_rtc.data[5]=(pc_rtc.data[5]%7)+1;
+ year=pc_rtc.data[9]+2000;
+ if (++pc_rtc.data[6]>=gregorian_days_in_month(pc_rtc.data[7], year)) {
+ pc_rtc.data[6]=1;
+ if (++pc_rtc.data[7]>12) {
+ pc_rtc.data[7]=1;
+ pc_rtc.data[9]=(pc_rtc.data[9]+1)%100;
+ }
+ }
+ }
+ }
+ }
+}
+
+void pc_rtc_init(running_machine &machine)
+{
+ memset(&pc_rtc,0,sizeof(pc_rtc));
+ pc_rtc.timer = machine.scheduler().timer_alloc(FUNC(pc_rtc_timer));
+ pc_rtc.timer->adjust(attotime::zero, 0, attotime(1,0));
+}
+
+READ8_MEMBER(pc_state::pc_rtc_r)
+{
+ int data;
+ switch (offset) {
+ default:
+ data=pc_rtc.data[offset];
+ }
+ logerror( "rtc read %.2x %.2x\n", offset, data);
+ return data;
+}
+
+WRITE8_MEMBER(pc_state::pc_rtc_w)
+{
+ logerror( "rtc write %.2x %.2x\n", offset, data);
+ switch(offset) {
+ default:
+ pc_rtc.data[offset]=data;
+ }
+}
+
+/*************************************************************************
+ *
+ * EXP
+ * expansion port
+ *
+ *************************************************************************/
+
+// I even don't know what it is!
+static struct {
+ /*
+ reg 0 ram behaviour if in
+ reg 3 write 1 to enable it
+ reg 4 ram behaviour ???
+ reg 5,6 (5 hi, 6 lowbyte) ???
+ */
+ /* selftest in ibmpc, ibmxt */
+ UINT8 reg[8];
+} pc_expansion={ { 0,0,0,0,0,0,1 } };
+
+WRITE8_MEMBER(pc_state::pc_EXP_w)
+{
+ //DBG_LOG(1,"EXP_unit_w",("%.2x $%02x\n", offset, data));
+ switch (offset) {
+ case 4:
+ pc_expansion.reg[4]=pc_expansion.reg[5]=pc_expansion.reg[6]=data;
+ break;
+ default:
+ pc_expansion.reg[offset] = data;
+ }
+}
+
+READ8_MEMBER(pc_state::pc_EXP_r)
+{
+ int data;
+ UINT16 a;
+ switch (offset) {
+ case 6:
+ data = pc_expansion.reg[offset];
+ a=(pc_expansion.reg[5]<<8)|pc_expansion.reg[6];
+ a<<=1;
+ pc_expansion.reg[5]=a>>8;
+ pc_expansion.reg[6]=a&0xff;
+ break;
+ default:
+ data = pc_expansion.reg[offset];
+ }
+ //DBG_LOG(1,"EXP_unit_r",("%.2x $%02x\n", offset, data));
+ return data;
+}
+
+
+
diff --git a/src/mess/machine/pc1251.c b/src/mess/machine/pc1251.c
new file mode 100644
index 00000000000..7d7841d6ec3
--- /dev/null
+++ b/src/mess/machine/pc1251.c
@@ -0,0 +1,118 @@
+#include "emu.h"
+#include "cpu/sc61860/sc61860.h"
+
+#include "includes/pocketc.h"
+#include "includes/pc1251.h"
+
+/* C-CE while reset, program will not be destroyed! */
+
+
+
+void pc1251_outa(device_t *device, int data)
+{
+ pc1251_state *state = device->machine().driver_data<pc1251_state>();
+ state->m_outa = data;
+}
+
+void pc1251_outb(device_t *device, int data)
+{
+ pc1251_state *state = device->machine().driver_data<pc1251_state>();
+ state->m_outb = data;
+}
+
+void pc1251_outc(device_t *device, int data)
+{
+}
+
+int pc1251_ina(device_t *device)
+{
+ pc1251_state *state = device->machine().driver_data<pc1251_state>();
+ int data = state->m_outa;
+ running_machine &machine = device->machine();
+
+ if (state->m_outb & 0x01)
+ {
+ data |= machine.root_device().ioport("KEY0")->read();
+
+ /* At Power Up we fake a 'CL' pressure */
+ if (state->m_power)
+ data |= 0x02; // problem with the deg lcd
+ }
+
+ if (state->m_outb & 0x02)
+ data |= machine.root_device().ioport("KEY1")->read();
+
+ if (state->m_outb & 0x04)
+ data |= machine.root_device().ioport("KEY2")->read();
+
+ if (state->m_outa & 0x01)
+ data |= machine.root_device().ioport("KEY3")->read();
+
+ if (state->m_outa & 0x02)
+ data |= machine.root_device().ioport("KEY4")->read();
+
+ if (state->m_outa & 0x04)
+ data |= machine.root_device().ioport("KEY5")->read();
+
+ if (state->m_outa & 0x08)
+ data |= machine.root_device().ioport("KEY6")->read();
+
+ if (state->m_outa & 0x10)
+ data |= machine.root_device().ioport("KEY7")->read();
+
+ if (state->m_outa & 0x20)
+ data |= machine.root_device().ioport("KEY8")->read();
+
+ if (state->m_outa & 0x40)
+ data |= machine.root_device().ioport("KEY9")->read();
+
+ return data;
+}
+
+int pc1251_inb(device_t *device)
+{
+ pc1251_state *state = device->machine().driver_data<pc1251_state>();
+ int data = state->m_outb;
+
+ if (state->m_outb & 0x08)
+ data |= (state->ioport("MODE")->read() & 0x07);
+
+ return data;
+}
+
+int pc1251_brk(device_t *device)
+{
+ return (device->machine().root_device().ioport("EXTRA")->read() & 0x01);
+}
+
+int pc1251_reset(device_t *device)
+{
+ return (device->machine().root_device().ioport("EXTRA")->read() & 0x02);
+}
+
+MACHINE_START( pc1251 )
+{
+ device_t *main_cpu = machine.device("maincpu");
+ UINT8 *ram = machine.root_device().memregion("maincpu")->base() + 0x8000;
+ UINT8 *cpu = sc61860_internal_ram(main_cpu);
+
+ machine.device<nvram_device>("cpu_nvram")->set_base(cpu, 96);
+ machine.device<nvram_device>("ram_nvram")->set_base(ram, 0x4800);
+}
+
+static TIMER_CALLBACK(pc1251_power_up)
+{
+ pc1251_state *state = machine.driver_data<pc1251_state>();
+ state->m_power = 0;
+}
+
+DRIVER_INIT_MEMBER(pc1251_state,pc1251)
+{
+ int i;
+ UINT8 *gfx = memregion("gfx1")->base();
+ for (i=0; i<128; i++) gfx[i]=i;
+
+ m_power = 1;
+ machine().scheduler().timer_set(attotime::from_seconds(1), FUNC(pc1251_power_up));
+}
+
diff --git a/src/mess/machine/pc1350.c b/src/mess/machine/pc1350.c
new file mode 100644
index 00000000000..4d75ad63d73
--- /dev/null
+++ b/src/mess/machine/pc1350.c
@@ -0,0 +1,136 @@
+#include "emu.h"
+#include "cpu/sc61860/sc61860.h"
+
+#include "includes/pocketc.h"
+#include "includes/pc1350.h"
+#include "machine/ram.h"
+
+
+
+void pc1350_outa(device_t *device, int data)
+{
+ pc1350_state *state = device->machine().driver_data<pc1350_state>();
+ state->m_outa=data;
+}
+
+void pc1350_outb(device_t *device, int data)
+{
+ pc1350_state *state = device->machine().driver_data<pc1350_state>();
+ state->m_outb=data;
+}
+
+void pc1350_outc(device_t *device, int data)
+{
+
+}
+
+int pc1350_ina(device_t *device)
+{
+ pc1350_state *state = device->machine().driver_data<pc1350_state>();
+ running_machine &machine = device->machine();
+ int data = state->m_outa;
+ int t = pc1350_keyboard_line_r(machine);
+
+ if (t & 0x01)
+ data |= machine.root_device().ioport("KEY0")->read();
+
+ if (t & 0x02)
+ data |= machine.root_device().ioport("KEY1")->read();
+
+ if (t & 0x04)
+ data |= machine.root_device().ioport("KEY2")->read();
+
+ if (t & 0x08)
+ data |= machine.root_device().ioport("KEY3")->read();
+
+ if (t & 0x10)
+ data |= machine.root_device().ioport("KEY4")->read();
+
+ if (t & 0x20)
+ data |= machine.root_device().ioport("KEY5")->read();
+
+ if (state->m_outa & 0x01)
+ data |= machine.root_device().ioport("KEY6")->read();
+
+ if (state->m_outa & 0x02)
+ data |= machine.root_device().ioport("KEY7")->read();
+
+ if (state->m_outa & 0x04)
+ {
+ data |= machine.root_device().ioport("KEY8")->read();
+
+ /* At Power Up we fake a 'CLS' pressure */
+ if (state->m_power)
+ data |= 0x08;
+ }
+
+ if (state->m_outa & 0x08)
+ data |= machine.root_device().ioport("KEY9")->read();
+
+ if (state->m_outa & 0x10)
+ data |= machine.root_device().ioport("KEY10")->read();
+
+ if (state->m_outa & 0xc0)
+ data |= machine.root_device().ioport("KEY11")->read();
+
+ // missing lshift
+
+ return data;
+}
+
+int pc1350_inb(device_t *device)
+{
+ pc1350_state *state = device->machine().driver_data<pc1350_state>();
+ int data=state->m_outb;
+ return data;
+}
+
+int pc1350_brk(device_t *device)
+{
+ return (device->machine().root_device().ioport("EXTRA")->read() & 0x01);
+}
+
+static TIMER_CALLBACK(pc1350_power_up)
+{
+ pc1350_state *state = machine.driver_data<pc1350_state>();
+ state->m_power=0;
+}
+
+MACHINE_START( pc1350 )
+{
+ pc1350_state *state = machine.driver_data<pc1350_state>();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ state->m_power = 1;
+ machine.scheduler().timer_set(attotime::from_seconds(1), FUNC(pc1350_power_up));
+
+ space->install_readwrite_bank(0x6000, 0x6fff, "bank1");
+ state->membank("bank1")->set_base(&machine.device<ram_device>(RAM_TAG)->pointer()[0x0000]);
+
+ if (machine.device<ram_device>(RAM_TAG)->size() >= 0x3000)
+ {
+ space->install_readwrite_bank(0x4000, 0x5fff, "bank2");
+ state->membank("bank2")->set_base(&machine.device<ram_device>(RAM_TAG)->pointer()[0x1000]);
+ }
+ else
+ {
+ space->nop_readwrite(0x4000, 0x5fff);
+ }
+
+ if (machine.device<ram_device>(RAM_TAG)->size() >= 0x5000)
+ {
+ space->install_readwrite_bank(0x2000, 0x3fff, "bank3");
+ state->membank("bank3")->set_base(&machine.device<ram_device>(RAM_TAG)->pointer()[0x3000]);
+ }
+ else
+ {
+ space->nop_readwrite(0x2000, 0x3fff);
+ }
+
+ device_t *main_cpu = machine.device("maincpu");
+ UINT8 *ram = machine.root_device().memregion("maincpu")->base() + 0x2000;
+ UINT8 *cpu = sc61860_internal_ram(main_cpu);
+
+ machine.device<nvram_device>("cpu_nvram")->set_base(cpu, 96);
+ machine.device<nvram_device>("ram_nvram")->set_base(ram, 0x5000);
+}
diff --git a/src/mess/machine/pc1401.c b/src/mess/machine/pc1401.c
new file mode 100644
index 00000000000..f8305f56895
--- /dev/null
+++ b/src/mess/machine/pc1401.c
@@ -0,0 +1,238 @@
+#include "emu.h"
+#include "cpu/sc61860/sc61860.h"
+
+#include "includes/pocketc.h"
+#include "includes/pc1401.h"
+#include "machine/ram.h"
+
+/* C-CE while reset, program will not be destroyed! */
+
+/* error codes
+1 syntax error
+2 calculation error
+3 illegal function argument
+4 too large a line number
+5 next without for
+ return without gosub
+6 memory overflow
+7 print using error
+8 i/o device error
+9 other errors*/
+
+
+
+void pc1401_outa(device_t *device, int data)
+{
+ pc1401_state *state = device->machine().driver_data<pc1401_state>();
+ state->m_outa = data;
+}
+
+void pc1401_outb(device_t *device, int data)
+{
+ pc1401_state *state = device->machine().driver_data<pc1401_state>();
+ state->m_outb = data;
+}
+
+void pc1401_outc(device_t *device, int data)
+{
+ pc1401_state *state = device->machine().driver_data<pc1401_state>();
+ //logerror("%g outc %.2x\n", machine.time().as_double(), data);
+ state->m_portc = data;
+}
+
+int pc1401_ina(device_t *device)
+{
+ pc1401_state *state = device->machine().driver_data<pc1401_state>();
+ int data = state->m_outa;
+
+ if (state->m_outb & 0x01)
+ data |= device->machine().root_device().ioport("KEY0")->read();
+
+ if (state->m_outb & 0x02)
+ data |= device->machine().root_device().ioport("KEY1")->read();
+
+ if (state->m_outb & 0x04)
+ data |= device->machine().root_device().ioport("KEY2")->read();
+
+ if (state->m_outb & 0x08)
+ data |= device->machine().root_device().ioport("KEY3")->read();
+
+ if (state->m_outb & 0x10)
+ data |= device->machine().root_device().ioport("KEY4")->read();
+
+ if (state->m_outb & 0x20)
+ {
+ data |= state->ioport("KEY5")->read();
+
+ /* At Power Up we fake a 'C-CE' pressure */
+ if (state->m_power)
+ data |= 0x01;
+ }
+
+ if (state->m_outa & 0x01)
+ data |= device->machine().root_device().ioport("KEY6")->read();
+
+ if (state->m_outa & 0x02)
+ data |= device->machine().root_device().ioport("KEY7")->read();
+
+ if (state->m_outa & 0x04)
+ data |= device->machine().root_device().ioport("KEY8")->read();
+
+ if (state->m_outa & 0x08)
+ data |= device->machine().root_device().ioport("KEY9")->read();
+
+ if (state->m_outa & 0x10)
+ data |= device->machine().root_device().ioport("KEY10")->read();
+
+ if (state->m_outa & 0x20)
+ data |= device->machine().root_device().ioport("KEY11")->read();
+
+ if (state->m_outa & 0x40)
+ data |= device->machine().root_device().ioport("KEY12")->read();
+
+ return data;
+}
+
+int pc1401_inb(device_t *device)
+{
+ pc1401_state *state = device->machine().driver_data<pc1401_state>();
+ int data=state->m_outb;
+
+ if (state->ioport("EXTRA")->read() & 0x04)
+ data |= 0x01;
+
+ return data;
+}
+
+int pc1401_brk(device_t *device)
+{
+ return (device->machine().root_device().ioport("EXTRA")->read() & 0x01);
+}
+
+int pc1401_reset(device_t *device)
+{
+ return (device->machine().root_device().ioport("EXTRA")->read() & 0x02);
+}
+
+MACHINE_START( pc1401 )
+{
+ device_t *main_cpu = machine.device("maincpu");
+ UINT8 *ram = machine.root_device().memregion("maincpu")->base() + 0x2000;
+ UINT8 *cpu = sc61860_internal_ram(main_cpu);
+
+ machine.device<nvram_device>("cpu_nvram")->set_base(cpu, 96);
+ machine.device<nvram_device>("ram_nvram")->set_base(ram, 0x2800);
+}
+
+static TIMER_CALLBACK(pc1401_power_up)
+{
+ pc1401_state *state = machine.driver_data<pc1401_state>();
+ state->m_power = 0;
+}
+
+DRIVER_INIT_MEMBER(pc1401_state,pc1401)
+{
+ int i;
+ UINT8 *gfx=memregion("gfx1")->base();
+#if 0
+ static const char sucker[]={
+ /* this routine dump the memory (start 0)
+ in an endless loop,
+ the pc side must be started before this
+ its here to allow verification of the decimal data
+ in mame disassembler
+ */
+#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 */
+ };
+
+ for (i=0; i<sizeof(sucker);i++) pc1401_mem[0x4000+i]=sucker[i];
+ logerror("%d %d\n",i, 0x4000+i);
+#endif
+
+ for (i=0; i<128; i++)
+ gfx[i]=i;
+
+ m_power = 1;
+ machine().scheduler().timer_set(attotime::from_seconds(1), FUNC(pc1401_power_up));
+}
diff --git a/src/mess/machine/pc1403.c b/src/mess/machine/pc1403.c
new file mode 100644
index 00000000000..39485839d01
--- /dev/null
+++ b/src/mess/machine/pc1403.c
@@ -0,0 +1,172 @@
+#include "emu.h"
+#include "cpu/sc61860/sc61860.h"
+
+#include "includes/pocketc.h"
+#include "includes/pc1403.h"
+#include "machine/ram.h"
+
+/* C-CE while reset, program will not be destroyed! */
+
+
+
+
+/*
+ port 2:
+ bits 0,1: external rom a14,a15 lines
+ port 3:
+ bits 0..6 keyboard output select matrix line
+*/
+
+WRITE8_HANDLER(pc1403_asic_write)
+{
+ pc1403_state *state = space->machine().driver_data<pc1403_state>();
+ state->m_asic[offset>>9]=data;
+ switch( (offset>>9) ){
+ case 0/*0x3800*/:
+ // output
+ logerror ("asic write %.4x %.2x\n",offset, data);
+ break;
+ case 1/*0x3a00*/:
+ logerror ("asic write %.4x %.2x\n",offset, data);
+ break;
+ case 2/*0x3c00*/:
+ state->membank("bank1")->set_base(state->memregion("user1")->base()+((data&7)<<14));
+ logerror ("asic write %.4x %.2x\n",offset, data);
+ break;
+ case 3/*0x3e00*/: break;
+ }
+}
+
+READ8_HANDLER(pc1403_asic_read)
+{
+ pc1403_state *state = space->machine().driver_data<pc1403_state>();
+ UINT8 data=state->m_asic[offset>>9];
+ switch( (offset>>9) ){
+ case 0: case 1: case 2:
+ logerror ("asic read %.4x %.2x\n",offset, data);
+ break;
+ }
+ return data;
+}
+
+void pc1403_outa(device_t *device, int data)
+{
+ pc1403_state *state = device->machine().driver_data<pc1403_state>();
+ state->m_outa=data;
+}
+
+int pc1403_ina(device_t *device)
+{
+ pc1403_state *state = device->machine().driver_data<pc1403_state>();
+ UINT8 data=state->m_outa;
+
+ if (state->m_asic[3] & 0x01)
+ data |= device->machine().root_device().ioport("KEY0")->read();
+
+ if (state->m_asic[3] & 0x02)
+ data |= device->machine().root_device().ioport("KEY1")->read();
+
+ if (state->m_asic[3] & 0x04)
+ data |= device->machine().root_device().ioport("KEY2")->read();
+
+ if (state->m_asic[3] & 0x08)
+ data |= device->machine().root_device().ioport("KEY3")->read();
+
+ if (state->m_asic[3] & 0x10)
+ data |= device->machine().root_device().ioport("KEY4")->read();
+
+ if (state->m_asic[3] & 0x20)
+ data |= device->machine().root_device().ioport("KEY5")->read();
+
+ if (state->m_asic[3] & 0x40)
+ data |= device->machine().root_device().ioport("KEY6")->read();
+
+ if (state->m_outa & 0x01)
+ {
+ data |= state->ioport("KEY7")->read();
+
+ /* At Power Up we fake a 'C-CE' pressure */
+ if (state->m_power)
+ data |= 0x02;
+ }
+
+ if (state->m_outa & 0x02)
+ data |= device->machine().root_device().ioport("KEY8")->read();
+
+ if (state->m_outa & 0x04)
+ data |= device->machine().root_device().ioport("KEY9")->read();
+
+ if (state->m_outa & 0x08)
+ data |= device->machine().root_device().ioport("KEY10")->read();
+
+ if (state->m_outa & 0x10)
+ data |= device->machine().root_device().ioport("KEY11")->read();
+
+ if (state->m_outa & 0x20)
+ data |= device->machine().root_device().ioport("KEY12")->read();
+
+ if (state->m_outa & 0x40)
+ data |= device->machine().root_device().ioport("KEY13")->read();
+
+ return data;
+}
+
+#if 0
+int pc1403_inb(void)
+{
+ pc1403_state *state = machine.driver_data<pc140_state>();
+ int data = state->m_outb;
+
+ if (machine.root_device().ioport("KEY13")->read())
+ data |= 1;
+
+ return data;
+}
+#endif
+
+void pc1403_outc(device_t *device, int data)
+{
+ pc1403_state *state = device->machine().driver_data<pc1403_state>();
+ state->m_portc = data;
+// logerror("%g pc %.4x outc %.2x\n", device->machine().time().as_double(), cpu_get_pc(device->machine().device("maincpu")), data);
+}
+
+
+int pc1403_brk(device_t *device)
+{
+ return (device->machine().root_device().ioport("EXTRA")->read() & 0x01);
+}
+
+int pc1403_reset(device_t *device)
+{
+ return (device->machine().root_device().ioport("EXTRA")->read() & 0x02);
+}
+
+MACHINE_START( pc1403 )
+{
+ device_t *main_cpu = machine.device("maincpu");
+ UINT8 *ram = machine.root_device().memregion("maincpu")->base() + 0x8000;
+ UINT8 *cpu = sc61860_internal_ram(main_cpu);
+
+ machine.device<nvram_device>("cpu_nvram")->set_base(cpu, 96);
+ machine.device<nvram_device>("ram_nvram")->set_base(ram, 0x8000);
+}
+
+static TIMER_CALLBACK(pc1403_power_up)
+{
+ pc1403_state *state = machine.driver_data<pc1403_state>();
+ state->m_power=0;
+}
+
+DRIVER_INIT_MEMBER(pc1403_state,pc1403)
+{
+ int i;
+ UINT8 *gfx=machine().root_device().memregion("gfx1")->base();
+
+ for (i=0; i<128; i++) gfx[i]=i;
+
+ m_power = 1;
+ machine().scheduler().timer_set(attotime::from_seconds(1), FUNC(pc1403_power_up));
+
+ membank("bank1")->set_base(memregion("user1")->base());
+}
diff --git a/src/mess/machine/pc1512kb.c b/src/mess/machine/pc1512kb.c
new file mode 100644
index 00000000000..14dc29497aa
--- /dev/null
+++ b/src/mess/machine/pc1512kb.c
@@ -0,0 +1,524 @@
+/**********************************************************************
+
+ Amstrad PC1512 Keyboard emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "pc1512kb.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define I8048_TAG "ic801"
+
+
+enum
+{
+ LED_CAPS = 0,
+ LED_NUM
+};
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type PC1512_KEYBOARD = &device_creator<pc1512_keyboard_device>;
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void pc1512_keyboard_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const pc1512_keyboard_interface *intf = reinterpret_cast<const pc1512_keyboard_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<pc1512_keyboard_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_data_cb, 0, sizeof(m_out_data_cb));
+ memset(&m_out_clock_cb, 0, sizeof(m_out_clock_cb));
+ }
+
+ m_shortname = "pc1512kb";
+}
+
+
+//-------------------------------------------------
+// ROM( pc1512_keyboard )
+//-------------------------------------------------
+
+ROM_START( pc1512_keyboard )
+ ROM_REGION( 0x400, I8048_TAG, 0 )
+ ROM_LOAD( "40042.ic801", 0x000, 0x400, CRC(607edaf6) SHA1(4422c6475596c3881c11b6a6266811c336d55d19) )
+ROM_END
+
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *pc1512_keyboard_device::device_rom_region() const
+{
+ return ROM_NAME( pc1512_keyboard );
+}
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( pc1512_keyboard_io )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( pc1512_keyboard_io, AS_IO, 8, pc1512_keyboard_device )
+ AM_RANGE(MCS48_PORT_BUS, MCS48_PORT_BUS) AM_READ(kb_bus_r)
+ AM_RANGE(MCS48_PORT_P1, MCS48_PORT_P1) AM_WRITE(kb_p1_w)
+ AM_RANGE(MCS48_PORT_P2, MCS48_PORT_P2) AM_READWRITE(kb_p2_r, kb_p2_w)
+ AM_RANGE(MCS48_PORT_T0, MCS48_PORT_T0) AM_READ(kb_t0_r)
+ AM_RANGE(MCS48_PORT_T1, MCS48_PORT_T1) AM_READ(kb_t1_r)
+ADDRESS_MAP_END
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( pc1512_keyboard )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( pc1512_keyboard )
+ MCFG_CPU_ADD(I8048_TAG, I8048, XTAL_6MHz)
+ MCFG_CPU_IO_MAP(pc1512_keyboard_io)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor pc1512_keyboard_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( pc1512_keyboard );
+}
+
+
+//-------------------------------------------------
+// INPUT_PORTS( pc1512_keyboard )
+//-------------------------------------------------
+
+INPUT_PORTS_START( pc1512_keyboard )
+ PORT_START("Y1")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F1") PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1))
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F2") PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2))
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F3") PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3))
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F4") PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4))
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F5") PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5))
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F6") PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6))
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F7") PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7))
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F8") PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8))
+
+ PORT_START("Y2")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Esc") PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC))
+ 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_NAME("TAB") PORT_CODE(KEYCODE_TAB) PORT_CHAR('\t')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q')
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("CTRL") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL))
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A')
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Left SHIFT") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH2) PORT_CHAR('\'') PORT_CHAR('|')
+
+ PORT_START("Y3")
+ 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_3) PORT_CHAR('3') PORT_CHAR('?')
+ 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_S) PORT_CHAR('s') PORT_CHAR('S')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D')
+ 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("Y4")
+ 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_5) PORT_CHAR('5') PORT_CHAR('%')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R')
+ 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_F) PORT_CHAR('f') PORT_CHAR('F')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G')
+ 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("Y5")
+ 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_7) PORT_CHAR('7') PORT_CHAR('&')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y')
+ 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_H) PORT_CHAR('h') PORT_CHAR('H')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J')
+ 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("Y6")
+ 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_9) PORT_CHAR('9') PORT_CHAR('(')
+ 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_K) PORT_CHAR('k') PORT_CHAR('K')
+ 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_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("Y7")
+ 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_MINUS) PORT_CHAR('-') PORT_CHAR('_')
+ 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_COLON) PORT_CHAR(';') PORT_CHAR(':')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('@')
+ 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("Y8")
+ 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_NAME(UTF8_LEFT" Del") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8)
+ 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_NAME("Keypad 7 Home") PORT_CODE(KEYCODE_7_PAD)
+ 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_NAME("Enter") PORT_CODE(KEYCODE_ENTER) PORT_CHAR('\r')
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Right SHIFT") PORT_CODE(KEYCODE_RSHIFT)
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("* PrtSc") PORT_CODE(KEYCODE_PRTSCR)
+
+ PORT_START("Y9")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Num Lock") PORT_CODE(KEYCODE_NUMLOCK) PORT_CHAR(UCHAR_MAMEKEY(NUMLOCK))
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Break Scroll Lock") PORT_CODE(KEYCODE_SCRLOCK) PORT_CHAR(UCHAR_MAMEKEY(SCRLOCK))
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 8 "UTF8_UP) PORT_CODE(KEYCODE_8_PAD)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 9 Pg Up") PORT_CODE(KEYCODE_9_PAD)
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 4 "UTF8_LEFT) PORT_CODE(KEYCODE_4_PAD)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 5") PORT_CODE(KEYCODE_5_PAD)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 1 End") PORT_CODE(KEYCODE_1_PAD)
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 2 "UTF8_DOWN) PORT_CODE(KEYCODE_2_PAD)
+
+ PORT_START("Y10")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad Enter") PORT_CODE(KEYCODE_ENTER_PAD)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad -") PORT_CODE(KEYCODE_MINUS_PAD)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 6 "UTF8_RIGHT) PORT_CODE(KEYCODE_6_PAD)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 3 Pg Dn") PORT_CODE(KEYCODE_3_PAD)
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Del "UTF8_RIGHT) PORT_CODE(KEYCODE_DEL) PORT_CHAR(UCHAR_MAMEKEY(DEL))
+
+ PORT_START("Y11")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F9") PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9))
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F10") PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10))
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Alt") PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_MAMEKEY(LALT))
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Space") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
+ 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("Keypad 0 Ins") PORT_CODE(KEYCODE_0_PAD)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad . Del") PORT_CODE(KEYCODE_DEL_PAD)
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad +") PORT_CODE(KEYCODE_PLUS_PAD)
+
+ PORT_START("COM")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON2 )
+ 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 pc1512_keyboard_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( pc1512_keyboard );
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// pc1512_keyboard_device - constructor
+//-------------------------------------------------
+
+pc1512_keyboard_device::pc1512_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, PC1512_KEYBOARD, "Amstrad PC1512 Keyboard", tag, owner, clock),
+ m_maincpu(*this, I8048_TAG),
+ m_data_in(1),
+ m_clock_in(1),
+ m_kb_y(0xffff),
+ m_joy_com(1),
+ m_m1(1),
+ m_m2(1)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void pc1512_keyboard_device::device_start()
+{
+ // allocate timers
+ m_reset_timer = timer_alloc();
+
+ // resolve callbacks
+ m_out_data_func.resolve(m_out_data_cb, *this);
+ m_out_clock_func.resolve(m_out_clock_cb, *this);
+
+ // state saving
+ save_item(NAME(m_data_in));
+ save_item(NAME(m_clock_in));
+ save_item(NAME(m_kb_y));
+ save_item(NAME(m_joy_com));
+ save_item(NAME(m_m1));
+ save_item(NAME(m_m2));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void pc1512_keyboard_device::device_reset()
+{
+ device_set_input_line(m_maincpu, MCS48_INPUT_EA, CLEAR_LINE);
+}
+
+
+//-------------------------------------------------
+// device_timer - handler timer events
+//-------------------------------------------------
+
+void pc1512_keyboard_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ if (!m_clock_in)
+ {
+ device_set_input_line(m_maincpu, INPUT_LINE_RESET, ASSERT_LINE);
+ }
+}
+
+
+//-------------------------------------------------
+// data_w - keyboard data input
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( pc1512_keyboard_device::data_w )
+{
+ m_data_in = state;
+}
+
+
+//-------------------------------------------------
+// clock_w - keyboard clock input
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( pc1512_keyboard_device::clock_w )
+{
+ if (m_clock_in != state)
+ {
+ if (!state)
+ {
+ m_reset_timer->adjust(attotime::from_msec(10));
+ }
+ else
+ {
+ device_set_input_line(m_maincpu, INPUT_LINE_RESET, CLEAR_LINE);
+ }
+ }
+
+ m_clock_in = state;
+}
+
+
+//-------------------------------------------------
+// m1_w - mouse button 1
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( pc1512_keyboard_device::m1_w )
+{
+ m_m1 = state;
+}
+
+
+//-------------------------------------------------
+// m2_w - mouse button 2
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( pc1512_keyboard_device::m2_w )
+{
+ m_m2 = state;
+}
+
+
+//-------------------------------------------------
+// kb_bus_r -
+//-------------------------------------------------
+
+READ8_MEMBER( pc1512_keyboard_device::kb_bus_r )
+{
+ /*
+
+ bit description
+
+ 0 X1
+ 1 X2
+ 2 X3
+ 3 X4
+ 4 X5
+ 5 X6
+ 6 X7
+ 7 X8
+
+ */
+
+ UINT8 data = 0xff;
+
+ if (!BIT(m_kb_y, 0)) data &= ioport("Y1")->read();
+ if (!BIT(m_kb_y, 1)) data &= ioport("Y2")->read();
+ if (!BIT(m_kb_y, 2)) data &= ioport("Y3")->read();
+ if (!BIT(m_kb_y, 3)) data &= ioport("Y4")->read();
+ if (!BIT(m_kb_y, 4)) data &= ioport("Y5")->read();
+ if (!BIT(m_kb_y, 5)) data &= ioport("Y6")->read();
+ if (!BIT(m_kb_y, 6)) data &= ioport("Y7")->read();
+ if (!BIT(m_kb_y, 7)) data &= ioport("Y8")->read();
+ if (!BIT(m_kb_y, 8)) data &= ioport("Y9")->read();
+ if (!BIT(m_kb_y, 9)) data &= ioport("Y10")->read();
+ if (!BIT(m_kb_y, 10)) data &= ioport("Y11")->read();
+ if (!m_joy_com) data &= ioport("COM")->read();
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// kb_p1_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( pc1512_keyboard_device::kb_p1_w )
+{
+ /*
+
+ bit description
+
+ 0 Y1
+ 1 Y2
+ 2 Y3
+ 3 Y4
+ 4 Y5
+ 5 Y6
+ 6 Y7
+ 7 Y8
+
+ */
+
+ m_kb_y = (m_kb_y & 0xff00) | data;
+}
+
+
+//-------------------------------------------------
+// kb_p2_r -
+//-------------------------------------------------
+
+READ8_MEMBER( pc1512_keyboard_device::kb_p2_r )
+{
+ /*
+
+ bit description
+
+ 0 SERIAL DATA
+ 1 SERIAL CLOCK
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+
+ */
+
+ UINT8 data = 0;
+
+ data |= m_data_in;
+ data |= m_clock_in << 1;
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// kb_p2_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( pc1512_keyboard_device::kb_p2_w )
+{
+ /*
+
+ bit description
+
+ 0 SERIAL DATA
+ 1 SERIAL CLOCK
+ 2 CAPS LED
+ 3 NUM LED
+ 4 Y9
+ 5 Y10
+ 6 Y11
+ 7 joystick COM
+
+ */
+
+ // keyboard data
+ m_out_data_func(BIT(data, 0));
+
+ // keyboard clock
+ m_out_clock_func(BIT(data, 1));
+
+ // CAPS LOCK
+ output_set_led_value(LED_CAPS, BIT(data, 2));
+
+ // NUM LOCK
+ output_set_led_value(LED_NUM, BIT(data, 3));
+
+ // keyboard row
+ m_kb_y = (((data >> 4) & 0x07) << 8) | (m_kb_y & 0xff);
+
+ // joystick common
+ m_joy_com = BIT(data, 7);
+}
+
+
+//-------------------------------------------------
+// kb_t0_r -
+//-------------------------------------------------
+
+READ8_MEMBER( pc1512_keyboard_device::kb_t0_r )
+{
+ return m_m1;
+}
+
+
+//-------------------------------------------------
+// kb_t1_r -
+//-------------------------------------------------
+
+READ8_MEMBER( pc1512_keyboard_device::kb_t1_r )
+{
+ return m_m2;
+}
diff --git a/src/mess/machine/pc1512kb.h b/src/mess/machine/pc1512kb.h
new file mode 100644
index 00000000000..6e272d1badb
--- /dev/null
+++ b/src/mess/machine/pc1512kb.h
@@ -0,0 +1,111 @@
+/**********************************************************************
+
+ Amstrad PC1512 Keyboard emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __PC1512_KEYBOARD__
+#define __PC1512_KEYBOARD__
+
+
+#include "emu.h"
+#include "cpu/mcs48/mcs48.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define PC1512_KEYBOARD_TAG "pc1512_keyboard"
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_PC1512_KEYBOARD_ADD(_config) \
+ MCFG_DEVICE_ADD(PC1512_KEYBOARD_TAG, PC1512_KEYBOARD, 0) \
+ MCFG_DEVICE_CONFIG(_config)
+
+
+#define PC1512_KEYBOARD_INTERFACE(_name) \
+ const pc1512_keyboard_interface (_name) =
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> pc1512_keyboard_interface
+
+struct pc1512_keyboard_interface
+{
+ devcb_write_line m_out_data_cb;
+ devcb_write_line m_out_clock_cb;
+};
+
+
+// ======================> pc1512_keyboard_device
+
+class pc1512_keyboard_device : public device_t,
+ public pc1512_keyboard_interface
+{
+public:
+ // construction/destruction
+ pc1512_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_WRITE_LINE_MEMBER( data_w );
+ DECLARE_WRITE_LINE_MEMBER( clock_w );
+ DECLARE_WRITE_LINE_MEMBER( m1_w );
+ DECLARE_WRITE_LINE_MEMBER( m2_w );
+
+ DECLARE_READ8_MEMBER( kb_bus_r );
+ DECLARE_WRITE8_MEMBER( kb_p1_w );
+ DECLARE_READ8_MEMBER( kb_p2_r );
+ DECLARE_WRITE8_MEMBER( kb_p2_w );
+ DECLARE_READ8_MEMBER( kb_t0_r );
+ 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);
+ virtual void device_config_complete();
+
+private:
+ devcb_resolved_write_line m_out_data_func;
+ devcb_resolved_write_line m_out_clock_func;
+
+ required_device<cpu_device> m_maincpu;
+
+ int m_data_in;
+ int m_clock_in;
+ int m_kb_y;
+ int m_joy_com;
+ int m_m1;
+ int m_m2;
+
+ emu_timer *m_reset_timer;
+};
+
+
+// device type definition
+extern const device_type PC1512_KEYBOARD;
+
+
+
+#endif
diff --git a/src/mess/machine/pc_fdc.c b/src/mess/machine/pc_fdc.c
new file mode 100644
index 00000000000..0a90aa9c722
--- /dev/null
+++ b/src/mess/machine/pc_fdc.c
@@ -0,0 +1,581 @@
+/**********************************************************************
+
+ 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"
+#include "machine/upd765.h"
+
+
+/* if not 1, DACK and TC inputs to FDC are disabled, and DRQ and IRQ are held
+ * at high impedance i.e they are not affective */
+#define PC_FDC_FLAGS_DOR_DMA_ENABLED (1<<3)
+#define PC_FDC_FLAGS_DOR_FDC_ENABLED (1<<2)
+#define PC_FDC_FLAGS_DOR_MOTOR_ON (1<<4)
+
+#define LOG_FDC 0
+
+/* registers etc */
+struct pc_fdc
+{
+ int status_register_a;
+ int status_register_b;
+ int digital_output_register;
+ int tape_drive_register;
+ int data_rate_register;
+ int digital_input_register;
+ int configuration_control_register;
+
+ /* stored tc state - state present at pins */
+ int tc_state;
+ /* stored dma drq state */
+ int dma_state;
+ /* stored int state */
+ int int_state;
+
+ /* PCJR watchdog timer */
+ emu_timer *watchdog;
+
+ struct pc_fdc_interface fdc_interface;
+};
+
+static struct pc_fdc *fdc;
+
+/* Prototypes */
+
+static TIMER_CALLBACK( watchdog_timeout );
+
+static WRITE_LINE_DEVICE_HANDLER( pc_fdc_hw_interrupt );
+static WRITE_LINE_DEVICE_HANDLER( pc_fdc_hw_dma_drq );
+static UPD765_GET_IMAGE ( pc_fdc_get_image );
+static UPD765_GET_IMAGE ( pcjr_fdc_get_image );
+
+const upd765_interface pc_fdc_upd765_connected_interface =
+{
+ DEVCB_LINE(pc_fdc_hw_interrupt),
+ DEVCB_LINE(pc_fdc_hw_dma_drq),
+ pc_fdc_get_image,
+ UPD765_RDY_PIN_CONNECTED,
+ {FLOPPY_0, FLOPPY_1, NULL, NULL}
+};
+
+const upd765_interface pc_fdc_upd765_connected_1_drive_interface =
+{
+ DEVCB_LINE(pc_fdc_hw_interrupt),
+ DEVCB_LINE(pc_fdc_hw_dma_drq),
+ pc_fdc_get_image,
+ UPD765_RDY_PIN_CONNECTED,
+ {FLOPPY_0, NULL, NULL, NULL}
+};
+
+
+const upd765_interface pc_fdc_upd765_not_connected_interface =
+{
+ DEVCB_LINE(pc_fdc_hw_interrupt),
+ DEVCB_LINE(pc_fdc_hw_dma_drq),
+ pc_fdc_get_image,
+ UPD765_RDY_PIN_NOT_CONNECTED,
+ {FLOPPY_0, FLOPPY_1, NULL, NULL}
+};
+
+const upd765_interface pcjr_fdc_upd765_interface =
+{
+ DEVCB_LINE(pc_fdc_hw_interrupt),
+ DEVCB_NULL,
+ pcjr_fdc_get_image,
+ UPD765_RDY_PIN_NOT_CONNECTED,
+ {FLOPPY_0, NULL, NULL, NULL}
+};
+
+
+static device_t* pc_get_device(running_machine &machine)
+{
+ return (*fdc->fdc_interface.get_device)(machine);
+}
+
+void pc_fdc_reset(running_machine &machine)
+{
+ /* setup reset condition */
+ fdc->data_rate_register = 2;
+ fdc->digital_output_register = 0;
+
+ /* bit 7 is disk change */
+ fdc->digital_input_register = 0x07f;
+
+ upd765_reset(pc_get_device(machine),0);
+
+ /* set FDC at reset */
+ upd765_reset_w(pc_get_device(machine), 1);
+}
+
+
+
+void pc_fdc_init(running_machine &machine, const struct pc_fdc_interface *iface)
+{
+ /* initialize fdc structure */
+ fdc = auto_alloc_clear(machine, struct pc_fdc);
+
+ /* copy specified interface */
+ if (iface)
+ memcpy(&fdc->fdc_interface, iface, sizeof(fdc->fdc_interface));
+
+ fdc->watchdog = machine.scheduler().timer_alloc(FUNC(watchdog_timeout));
+
+ pc_fdc_reset(machine);
+}
+
+
+
+static UPD765_GET_IMAGE ( pc_fdc_get_image )
+{
+ device_t *image = NULL;
+
+ if (!fdc->fdc_interface.get_image)
+ {
+ image = floppy_get_device(device->machine(), (fdc->digital_output_register & 0x03));
+ }
+ else
+ {
+ image = fdc->fdc_interface.get_image(device->machine(), (fdc->digital_output_register & 0x03));
+ }
+ return image;
+}
+
+static UPD765_GET_IMAGE ( pcjr_fdc_get_image )
+{
+ device_t *image = NULL;
+
+ if (!fdc->fdc_interface.get_image)
+ {
+ image = floppy_get_device(device->machine(), 0);
+ }
+ else
+ {
+ image = fdc->fdc_interface.get_image(device->machine(), 0);
+ }
+ return image;
+}
+
+void pc_fdc_set_tc_state(running_machine &machine, int state)
+{
+ /* store state */
+ fdc->tc_state = state;
+
+ /* if dma is not enabled, tc's are not acknowledged */
+ if ((fdc->digital_output_register & PC_FDC_FLAGS_DOR_DMA_ENABLED)!=0)
+ {
+ upd765_tc_w(pc_get_device(machine), state);
+ }
+}
+
+
+
+static WRITE_LINE_DEVICE_HANDLER( pc_fdc_hw_interrupt )
+{
+ fdc->int_state = state;
+
+ /* if dma is not enabled, irq's are masked */
+ if ((fdc->digital_output_register & PC_FDC_FLAGS_DOR_DMA_ENABLED)==0)
+ return;
+
+ /* send irq */
+ if (fdc->fdc_interface.pc_fdc_interrupt)
+ fdc->fdc_interface.pc_fdc_interrupt(device->machine(), state);
+}
+
+
+
+int pc_fdc_dack_r(running_machine &machine)
+{
+ int data;
+
+ /* what is output if dack is not acknowledged? */
+ data = 0x0ff;
+
+ /* if dma is not enabled, dacks are not acknowledged */
+ if ((fdc->digital_output_register & PC_FDC_FLAGS_DOR_DMA_ENABLED)!=0)
+ {
+ data = upd765_dack_r(pc_get_device(machine), 0);
+ }
+
+ return data;
+}
+
+
+
+void pc_fdc_dack_w(running_machine &machine, int data)
+{
+ /* if dma is not enabled, dacks are not issued */
+ if ((fdc->digital_output_register & PC_FDC_FLAGS_DOR_DMA_ENABLED)!=0)
+ {
+ /* dma acknowledge - and send byte to fdc */
+ upd765_dack_w(pc_get_device(machine), 0,data);
+ }
+}
+
+
+
+static WRITE_LINE_DEVICE_HANDLER( pc_fdc_hw_dma_drq )
+{
+ fdc->dma_state = state;
+
+ /* if dma is not enabled, drqs are masked */
+ if ((fdc->digital_output_register & PC_FDC_FLAGS_DOR_DMA_ENABLED)==0)
+ return;
+
+ if (fdc->fdc_interface.pc_fdc_dma_drq)
+ fdc->fdc_interface.pc_fdc_dma_drq(device->machine(), state);
+}
+
+
+
+static void pc_fdc_data_rate_w(running_machine &machine, UINT8 data)
+{
+ if ((data & 0x080)!=0)
+ {
+ /* set ready state */
+ upd765_ready_w(pc_get_device(machine),1);
+
+ /* toggle reset state */
+ upd765_reset_w(pc_get_device(machine), 1);
+ upd765_reset_w(pc_get_device(machine), 0);
+
+ /* bit is self-clearing */
+ data &= ~0x080;
+ }
+
+ fdc->data_rate_register = data;
+}
+
+
+
+/* FDC Digitial Output Register (DOR)
+
+ |7|6|5|4|3|2|1|0|
+ | | | | | | `------ floppy drive select (0=A, 1=B, 2=floppy C, ...)
+ | | | | | `-------- 1 = FDC enable, 0 = hold FDC at reset
+ | | | | `---------- 1 = DMA & I/O interface enabled
+ | | | `------------ 1 = turn floppy drive A motor on
+ | | `-------------- 1 = turn floppy drive B motor on
+ | `---------------- 1 = turn floppy drive C motor on
+ `------------------ 1 = turn floppy drive D motor on
+ */
+
+static void pc_fdc_dor_w(running_machine &machine, UINT8 data)
+{
+ int selected_drive;
+ int floppy_count;
+
+ floppy_count = floppy_get_count(machine);
+
+ if (floppy_count > (fdc->digital_output_register & 0x03))
+ floppy_drive_set_ready_state(floppy_get_device(machine, fdc->digital_output_register & 0x03), 1, 0);
+
+ fdc->digital_output_register = data;
+
+ selected_drive = data & 0x03;
+
+ /* set floppy drive motor state */
+ if (floppy_count > 0)
+ floppy_mon_w(floppy_get_device(machine, 0), !BIT(data, 4));
+ if (floppy_count > 1)
+ floppy_mon_w(floppy_get_device(machine, 1), !BIT(data, 5));
+ if (floppy_count > 2)
+ floppy_mon_w(floppy_get_device(machine, 2), !BIT(data, 6));
+ if (floppy_count > 3)
+ floppy_mon_w(floppy_get_device(machine, 3), !BIT(data, 7));
+
+ if ((data>>4) & (1<<selected_drive))
+ {
+ if (floppy_count > selected_drive)
+ floppy_drive_set_ready_state(floppy_get_device(machine, selected_drive), 1, 0);
+ }
+
+ /* changing the DMA enable bit, will affect the terminal count state
+ from reaching the fdc - if dma is enabled this will send it through
+ otherwise it will be ignored */
+ pc_fdc_set_tc_state(machine, fdc->tc_state);
+
+ /* changing the DMA enable bit, will affect the dma drq state
+ from reaching us - if dma is enabled this will send it through
+ otherwise it will be ignored */
+ pc_fdc_hw_dma_drq(pc_get_device(machine), fdc->dma_state);
+
+ /* changing the DMA enable bit, will affect the irq state
+ from reaching us - if dma is enabled this will send it through
+ otherwise it will be ignored */
+ pc_fdc_hw_interrupt(pc_get_device(machine), fdc->int_state);
+
+ /* reset? */
+ if ((fdc->digital_output_register & PC_FDC_FLAGS_DOR_FDC_ENABLED)==0)
+ {
+ /* yes */
+
+ /* pc-xt expects a interrupt to be generated
+ when the fdc is reset.
+ In the FDC docs, it states that a INT will
+ be generated if READY input is true when the
+ fdc is reset.
+
+ It also states, that outputs to drive are set to 0.
+ Maybe this causes the drive motor to go on, and therefore
+ the ready line is set.
+
+ This in return causes a int?? ---
+
+
+ what is not yet clear is if this is a result of the drives ready state
+ changing...
+ */
+ upd765_ready_w(pc_get_device(machine),1);
+
+ /* set FDC at reset */
+ upd765_reset_w(pc_get_device(machine), 1);
+ }
+ else
+ {
+ pc_fdc_set_tc_state(machine, 0);
+
+ /* release reset on fdc */
+ upd765_reset_w(pc_get_device(machine), 0);
+ }
+}
+
+/* PCJr FDC Digitial Output Register (DOR)
+
+ On a PC Jr the DOR is wired up a bit differently:
+ |7|6|5|4|3|2|1|0|
+ | | | | | | | `--- Drive enable ( 0 = off, 1 = on )
+ | | | | | | `----- Reserved
+ | | | | | `------- Reserved
+ | | | | `--------- Reserved
+ | | | `----------- Reserved
+ | | `------------- Watchdog Timer Enable ( 0 = watchdog disabled, 1 = watchdog enabled )
+ | `--------------- Watchdog Timer Trigger ( on a 1->0 transition to strobe the trigger )
+ `----------------- FDC Reset ( 0 = hold reset, 1 = release reset )
+ */
+
+static TIMER_CALLBACK( watchdog_timeout )
+{
+ /* Trigger a watchdog timeout signal */
+ if ( fdc->fdc_interface.pc_fdc_interrupt && ( fdc->digital_output_register & 0x20 ) )
+ {
+ fdc->fdc_interface.pc_fdc_interrupt(machine, 1 );
+ }
+ else
+ {
+ fdc->fdc_interface.pc_fdc_interrupt(machine, 0 );
+ }
+}
+
+static void pcjr_fdc_dor_w(running_machine &machine, UINT8 data)
+{
+ int floppy_count;
+
+ floppy_count = floppy_get_count(machine);
+
+ /* set floppy drive motor state */
+ if (floppy_count > 0)
+ floppy_mon_w(floppy_get_device(machine, 0), BIT(data, 0) ? CLEAR_LINE : ASSERT_LINE);
+
+ if ( data & 0x01 )
+ {
+ if ( floppy_count )
+ floppy_drive_set_ready_state(floppy_get_device(machine, 0), 1, 0);
+ }
+
+ /* Is the watchdog timer disabled */
+ if ( ! ( data & 0x20 ) )
+ {
+ fdc->watchdog->adjust( attotime::never );
+ if ( fdc->fdc_interface.pc_fdc_interrupt )
+ {
+ fdc->fdc_interface.pc_fdc_interrupt(machine, 0 );
+ }
+ } else {
+ /* Check for 1->0 watchdog trigger */
+ if ( ( fdc->digital_output_register & 0x40 ) && ! ( data & 0x40 ) )
+ {
+ /* Start watchdog timer here */
+ fdc->watchdog->adjust( attotime::from_seconds(3) );
+ }
+ }
+
+ /* reset? */
+ if ( ! (data & 0x80) )
+ {
+ /* yes */
+
+ /* pc-xt expects a interrupt to be generated
+ when the fdc is reset.
+ In the FDC docs, it states that a INT will
+ be generated if READY input is true when the
+ fdc is reset.
+
+ It also states, that outputs to drive are set to 0.
+ Maybe this causes the drive motor to go on, and therefore
+ the ready line is set.
+
+ This in return causes a int?? ---
+
+
+ what is not yet clear is if this is a result of the drives ready state
+ changing...
+ */
+ upd765_ready_w(pc_get_device(machine),1);
+
+ /* set FDC at reset */
+ upd765_reset_w(pc_get_device(machine), 1);
+ }
+ else
+ {
+ pc_fdc_set_tc_state(machine, 0);
+
+ /* release reset on fdc */
+ upd765_reset_w(pc_get_device(machine), 0);
+ }
+
+ logerror("pcjr_fdc_dor_w: changing dor from %02x to %02x\n", fdc->digital_output_register, data);
+
+ fdc->digital_output_register = data;
+}
+
+#define RATE_250 2
+#define RATE_300 1
+#define RATE_500 0
+#define RATE_1000 3
+
+static void pc_fdc_check_data_rate(running_machine &machine)
+{
+ device_t *device = floppy_get_device(machine, fdc->digital_output_register & 0x03);
+ floppy_image_legacy *image;
+ int tracks, sectors, rate;
+
+ upd765_set_bad(pc_get_device(machine), 0); // unset in case format is unknown
+ if (!device) return;
+ image = flopimg_get_image(device);
+ if (!image) return;
+ tracks = floppy_get_tracks_per_disk(image);
+ tracks -= (tracks % 10); // ignore extra tracks
+ floppy_get_sector_count(image, 0, 0, &sectors);
+
+ if (tracks == 40) {
+ if ((fdc->data_rate_register != RATE_250) && (fdc->data_rate_register != RATE_300))
+ upd765_set_bad(pc_get_device(machine), 1);
+ return;
+ } else if (tracks == 80) {
+ if (sectors <= 14) rate = RATE_250; // 720KB 5 1/4 and 3 1/2
+ else if (sectors <= 24) rate = RATE_500; // 1.2MB 5 1/4 and 1.44MB 3 1/2
+ else rate = RATE_1000; // 2.88MB 3 1/2
+ } else return;
+
+ if (rate != (fdc->data_rate_register & 3))
+ upd765_set_bad(pc_get_device(machine), 1);
+}
+
+READ8_HANDLER ( pc_fdc_r )
+{
+ UINT8 data = 0xff;
+
+ switch(offset)
+ {
+ case 0: /* status register a */
+ case 1: /* status register b */
+ data = 0x00;
+ break;
+ case 2:
+ data = fdc->digital_output_register;
+ break;
+ case 3: /* tape drive select? */
+ break;
+ case 4:
+ data = upd765_status_r(pc_get_device(space->machine()), 0);
+ break;
+ case 5:
+ data = upd765_data_r(pc_get_device(space->machine()), offset);
+ break;
+ case 6: /* FDC reserved */
+ break;
+ case 7:
+ device_t *dev = floppy_get_device(space->machine(), fdc->digital_output_register & 0x03);
+ data = fdc->digital_input_register;
+ if(dev) data |= (!floppy_dskchg_r(dev)<<7);
+ break;
+ }
+
+ if (LOG_FDC)
+ logerror("pc_fdc_r(): pc=0x%08x offset=%d result=0x%02X\n", (unsigned) cpu_get_reg(space->machine().firstcpu,STATE_GENPC), offset, data);
+ return data;
+}
+
+
+
+WRITE8_HANDLER ( pc_fdc_w )
+{
+ if (LOG_FDC)
+ logerror("pc_fdc_w(): pc=0x%08x offset=%d data=0x%02X\n", (unsigned) cpu_get_reg(space->machine().firstcpu,STATE_GENPC), offset, data);
+
+ pc_fdc_check_data_rate(space->machine()); // check every time a command may start
+ switch(offset)
+ {
+ case 0: /* n/a */
+ case 1: /* n/a */
+ break;
+ case 2:
+ pc_fdc_dor_w(space->machine(), data);
+ break;
+ case 3:
+ /* tape drive select? */
+ break;
+ case 4:
+ pc_fdc_data_rate_w(space->machine(), data);
+ break;
+ case 5:
+ upd765_data_w(pc_get_device(space->machine()), 0, data);
+ break;
+ case 6:
+ /* FDC reserved */
+ break;
+ case 7:
+ /* Configuration Control Register
+ *
+ * Currently unimplemented; bits 1-0 are supposed to control data
+ * flow rates:
+ * 0 0 500 kbps
+ * 0 1 300 kbps
+ * 1 0 250 kbps
+ * 1 1 1000 kbps
+ */
+ pc_fdc_data_rate_w(space->machine(), data & 3);
+ break;
+ }
+}
+
+WRITE8_HANDLER ( pcjr_fdc_w )
+{
+ if (LOG_FDC)
+ logerror("pcjr_fdc_w(): pc=0x%08x offset=%d data=0x%02X\n", (unsigned) cpu_get_reg(space->machine().firstcpu,STATE_GENPC), offset, data);
+
+ switch(offset)
+ {
+ case 2:
+ pcjr_fdc_dor_w( space->machine(), data );
+ break;
+ case 4:
+ case 7:
+ break;
+ default:
+ pc_fdc_w( space, offset, data );
+ break;
+ }
+}
+
diff --git a/src/mess/machine/pc_fdc.h b/src/mess/machine/pc_fdc.h
new file mode 100644
index 00000000000..e60738869aa
--- /dev/null
+++ b/src/mess/machine/pc_fdc.h
@@ -0,0 +1,52 @@
+/**********************************************************************
+
+ PC-style floppy disk controller emulation
+
+**********************************************************************/
+
+#ifndef PC_FDC_H
+#define PC_FDC_H
+
+#include "emu.h"
+#include "machine/upd765.h"
+
+/* interface has been seperated, so that it can be used in the super i/o chip */
+
+#define PC_FDC_STATUS_REGISTER_A 0
+#define PC_FDC_STATUS_REGISTER_B 1
+#define PC_FDC_DIGITAL_OUTPUT_REGISTER 2
+#define PC_FDC_TAPE_DRIVE_REGISTER 3
+#define PC_FDC_MAIN_STATUS_REGISTER 4
+#define PC_FDC_DATA_RATE_REGISTER 4
+#define PC_FDC_DATA_REGISTER 5
+#define PC_FDC_RESERVED_REGISTER 6
+#define PC_FDC_DIGITIAL_INPUT_REGISTER 7
+#define PC_FDC_CONFIGURATION_CONTROL_REGISTER 8
+
+/* main interface */
+struct pc_fdc_interface
+{
+ void (*pc_fdc_interrupt)(running_machine&,int);
+ void (*pc_fdc_dma_drq)(running_machine&,int);
+ device_t *(*get_image)(running_machine&, int floppy_index);
+ device_t *(*get_device)(running_machine&);
+};
+
+extern const upd765_interface pc_fdc_upd765_connected_interface;
+extern const upd765_interface pc_fdc_upd765_not_connected_interface;
+extern const upd765_interface pc_fdc_upd765_connected_1_drive_interface;
+extern const upd765_interface pcjr_fdc_upd765_interface;
+
+void pc_fdc_reset(running_machine &machine);
+void pc_fdc_init(running_machine &machine, const struct pc_fdc_interface *iface);
+void pc_fdc_set_tc_state(running_machine &machine, int state);
+int pc_fdc_dack_r(running_machine &machine);
+void pc_fdc_dack_w(running_machine &machine, int);
+
+READ8_HANDLER(pc_fdc_r);
+WRITE8_HANDLER(pc_fdc_w);
+WRITE8_HANDLER ( pcjr_fdc_w );
+
+#endif /* PC_FDC_H */
+
+
diff --git a/src/mess/machine/pc_joy.c b/src/mess/machine/pc_joy.c
new file mode 100644
index 00000000000..7797afca285
--- /dev/null
+++ b/src/mess/machine/pc_joy.c
@@ -0,0 +1,91 @@
+/*************************************************************************
+ *
+ * pc_joy.h
+ *
+ * joystick port
+ *
+ *************************************************************************/
+
+#include "emu.h"
+#include "pc_joy.h"
+
+
+static attotime JOY_time;
+
+
+READ8_HANDLER ( pc_JOY_r )
+{
+ UINT8 data = 0xf;
+ int delta;
+ attotime new_time = space->machine().time();
+ ioport_port *joystick_port = space->machine().root_device().ioport("pc_joy");
+ delta = ((new_time - JOY_time) * 256 * 1000).seconds;
+
+ if (joystick_port != NULL)
+ {
+ data = joystick_port->read() ^ 0xf0;
+
+ /* timer overflow? Nope, otherwise some HWs can't verify the port properly */
+ //if ((new_time - JOY_time) > attotime::from_msec(10))
+ //{
+
+ //}
+ //else
+ {
+ if (space->machine().root_device().ioport("pc_joy_1")->read() < delta) data &= ~0x01;
+ if (space->machine().root_device().ioport("pc_joy_2")->read() < delta) data &= ~0x02;
+ if (space->machine().root_device().ioport("pc_joy_3")->read() < delta) data &= ~0x04;
+ if (space->machine().root_device().ioport("pc_joy_4")->read() < delta) data &= ~0x08;
+ }
+ }
+ else
+ {
+ data = 0xf0;
+ // TODO: find decay rate with no joystick connected
+ }
+ return data;
+}
+
+
+
+WRITE8_HANDLER ( pc_JOY_w )
+{
+ JOY_time = space->machine().time();
+}
+
+INPUT_PORTS_START( pc_joystick_none )
+ PORT_START("pc_joy")
+ PORT_BIT ( 0xffff, 0x0000, IPT_UNUSED )
+ PORT_START("pc_joy_1")
+ PORT_BIT ( 0xffff, 0x0000, IPT_UNUSED )
+ PORT_START("pc_joy_2")
+ PORT_BIT ( 0xffff, 0x0000, IPT_UNUSED )
+ PORT_START("pc_joy_3")
+ PORT_BIT ( 0xffff, 0x0000, IPT_UNUSED )
+ PORT_START("pc_joy_4")
+ PORT_BIT ( 0xffff, 0x0000, IPT_UNUSED )
+INPUT_PORTS_END
+
+
+
+INPUT_PORTS_START( pc_joystick )
+ PORT_START("pc_joy")
+ PORT_BIT ( 0xf, 0xf, IPT_UNUSED )
+ PORT_BIT( 0x0010, 0x0000, IPT_BUTTON1) PORT_NAME("Joystick 1 Button 1")
+ PORT_BIT( 0x0020, 0x0000, IPT_BUTTON2) PORT_NAME("Joystick 1 Button 2")
+ PORT_BIT( 0x0040, 0x0000, IPT_BUTTON1) PORT_NAME("Joystick 2 Button 1") PORT_CODE(JOYCODE_BUTTON1) PORT_PLAYER(2)
+ PORT_BIT( 0x0080, 0x0000, IPT_BUTTON2) PORT_NAME("Joystick 2 Button 2") PORT_CODE(JOYCODE_BUTTON2) PORT_PLAYER(2)
+
+ PORT_START("pc_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("pc_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)
+
+ PORT_START("pc_joy_3")
+ 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("pc_joy_4")
+ 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
+
diff --git a/src/mess/machine/pc_joy.h b/src/mess/machine/pc_joy.h
new file mode 100644
index 00000000000..4336e6209cc
--- /dev/null
+++ b/src/mess/machine/pc_joy.h
@@ -0,0 +1,20 @@
+/*************************************************************************
+ *
+ * pc_joy.h
+ *
+ * joystick port
+ *
+ *************************************************************************/
+
+#ifndef PC_JOY_H
+#define PC_JOY_H
+
+
+READ8_HANDLER ( pc_JOY_r );
+WRITE8_HANDLER ( pc_JOY_w );
+
+INPUT_PORTS_EXTERN( pc_joystick_none );
+INPUT_PORTS_EXTERN( pc_joystick );
+
+
+#endif /* PC_JOY_H */
diff --git a/src/mess/machine/pc_kbdc.c b/src/mess/machine/pc_kbdc.c
new file mode 100644
index 00000000000..07febf7ac04
--- /dev/null
+++ b/src/mess/machine/pc_kbdc.c
@@ -0,0 +1,252 @@
+/***************************************************************************
+
+ 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 "machine/pc_kbdc.h"
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type PC_KBDC_SLOT = &device_creator<pc_kbdc_slot_device>;
+
+//**************************************************************************
+// 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),
+ 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<pc_kbdc_slot_device &>(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<device_pc_kbd_interface *>(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>;
+
+
+//-------------------------------------------------
+// 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),
+ m_keyboard( NULL )
+{
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+void pc_kbdc_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const pc_kbdc_interface *intf = reinterpret_cast<const pc_kbdc_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<pc_kbdc_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_clock_cb, 0, sizeof(m_out_clock_cb));
+ memset(&m_out_data_cb, 0, sizeof(m_out_data_cb));
+ }
+}
+
+
+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_func.resolve(m_out_clock_cb, *this);
+ m_out_data_func.resolve(m_out_data_cb, *this);
+}
+
+
+//-------------------------------------------------
+// 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_func( 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_func( 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_interface &>(device);
+ pc_kbd.m_pc_kbdc = dynamic_cast<pc_kbdc_device *>(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/mess/machine/pc_kbdc.h b/src/mess/machine/pc_kbdc.h
new file mode 100644
index 00000000000..58c997ecde8
--- /dev/null
+++ b/src/mess/machine/pc_kbdc.h
@@ -0,0 +1,147 @@
+/***************************************************************************
+
+ 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_ADD(_tag, _config) \
+ MCFG_DEVICE_ADD(_tag, PC_KBDC, 0) \
+ MCFG_DEVICE_CONFIG(_config) \
+
+#define MCFG_PC_KBDC_SLOT_ADD(_kbdc_tag, _tag, _slot_intf, _def_slot, _def_inp ) \
+ MCFG_DEVICE_ADD(_tag, PC_KBDC_SLOT, 0 ) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, 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;
+
+
+struct pc_kbdc_interface
+{
+ devcb_write_line m_out_clock_cb;
+ devcb_write_line m_out_data_cb;
+};
+
+
+class device_pc_kbd_interface;
+
+class pc_kbdc_device : public device_t,
+ public pc_kbdc_interface
+{
+public:
+ // construction/destruction
+ pc_kbdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ 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();
+ virtual void device_config_complete();
+
+ void update_clock_state();
+ void update_data_state();
+
+ devcb_resolved_write_line m_out_clock_func;
+ devcb_resolved_write_line m_out_data_func;
+
+ 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/mess/machine/pc_keyboards.c b/src/mess/machine/pc_keyboards.c
new file mode 100644
index 00000000000..5094744acb5
--- /dev/null
+++ b/src/mess/machine/pc_keyboards.c
@@ -0,0 +1,16 @@
+
+#include "emu.h"
+#include "machine/pc_keyboards.h"
+#include "machine/kb_keytro.h"
+#include "machine/kb_msnat.h"
+
+SLOT_INTERFACE_START(pc_xt_keyboards)
+ SLOT_INTERFACE(STR_KBD_KEYTRONIC_PC3270, PC_KBD_KEYTRONIC_PC3270)
+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_END
+
diff --git a/src/mess/machine/pc_keyboards.h b/src/mess/machine/pc_keyboards.h
new file mode 100644
index 00000000000..3c793eea065
--- /dev/null
+++ b/src/mess/machine/pc_keyboards.h
@@ -0,0 +1,25 @@
+/***************************************************************************
+
+ PC Keyboards
+
+***************************************************************************/
+
+#ifndef __PC_KEYBOARDS_H__
+#define __PC_KEYBOARDS_H__
+
+
+// PC XT protocol keyboards
+#define STR_KBD_KEYTRONIC_PC3270 "keytronc_pc3270"
+
+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"
+
+SLOT_INTERFACE_EXTERN(pc_at_keyboards);
+
+#endif /* __KB_KEYBOARDS_H__ */
+
+
diff --git a/src/mess/machine/pc_lpt.c b/src/mess/machine/pc_lpt.c
new file mode 100644
index 00000000000..2f227f3f8d0
--- /dev/null
+++ b/src/mess/machine/pc_lpt.c
@@ -0,0 +1,342 @@
+/***************************************************************************
+
+ IBM-PC printer interface
+
+***************************************************************************/
+
+#include "emu.h"
+#include "pc_lpt.h"
+#include "machine/ctronics.h"
+#include "cntr_covox.h"
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static WRITE_LINE_DEVICE_HANDLER( pc_lpt_ack_w );
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _pc_lpt_state pc_lpt_state;
+struct _pc_lpt_state
+{
+ centronics_device *centronics;
+
+ devcb_resolved_write_line out_irq_func;
+
+ UINT8 data;
+
+ int ack;
+
+ /* control latch */
+ int strobe;
+ int autofd;
+ int init;
+ int select;
+ int irq_enabled;
+};
+
+
+/***************************************************************************
+ CENTRONICS INTERFACE
+***************************************************************************/
+
+static const centronics_interface pc_centronics_config =
+{
+ DEVCB_LINE(pc_lpt_ack_w),
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+static SLOT_INTERFACE_START(pc_centronics)
+ SLOT_INTERFACE("printer", CENTRONICS_PRINTER)
+ SLOT_INTERFACE("covox", CENTRONICS_COVOX)
+ SLOT_INTERFACE("covox_stereo", CENTRONICS_COVOX_STEREO)
+SLOT_INTERFACE_END
+
+static MACHINE_CONFIG_FRAGMENT( pc_lpt )
+ MCFG_CENTRONICS_ADD("centronics", pc_centronics_config, pc_centronics, "printer", NULL)
+MACHINE_CONFIG_END
+
+
+/*****************************************************************************
+ INLINE FUNCTIONS
+*****************************************************************************/
+
+INLINE pc_lpt_state *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == PC_LPT);
+
+ return (pc_lpt_state *)downcast<legacy_device_base *>(device)->token();
+}
+
+
+/***************************************************************************
+ DEVICE INTERFACE
+***************************************************************************/
+
+static DEVICE_START( pc_lpt )
+{
+ pc_lpt_state *lpt = get_safe_token(device);
+ const pc_lpt_interface *intf = (const pc_lpt_interface *)device->static_config();
+ /* validate some basic stuff */
+ assert(device->static_config() != NULL);
+
+ /* get centronics device */
+ lpt->centronics = device->subdevice<centronics_device>("centronics");
+ assert(lpt->centronics != NULL);
+
+ /* resolve callbacks */
+ lpt->out_irq_func.resolve(intf->out_irq_func, *device);
+
+ /* register for state saving */
+ device->save_item(NAME(lpt->ack));
+ device->save_item(NAME(lpt->strobe));
+ device->save_item(NAME(lpt->autofd));
+ device->save_item(NAME(lpt->init));
+ device->save_item(NAME(lpt->select));
+ device->save_item(NAME(lpt->irq_enabled));
+}
+
+static DEVICE_RESET( pc_lpt )
+{
+ pc_lpt_state *lpt = get_safe_token(device);
+
+ lpt->strobe = TRUE;
+ lpt->autofd = TRUE;
+ lpt->init = FALSE;
+ lpt->select = TRUE;
+ lpt->irq_enabled = FALSE;
+ lpt->data = 0xff;
+}
+
+DEVICE_GET_INFO( pc_lpt )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(pc_lpt_state); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+
+ /* --- the following bits of info are returned as pointers --- */
+ case DEVINFO_PTR_MACHINE_CONFIG: info->machine_config = MACHINE_CONFIG_NAME(pc_lpt); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(pc_lpt); break;
+ case DEVINFO_FCT_STOP: /* Nothing */ break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(pc_lpt); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "PC-LPT"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "Parallel port"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright MESS Team"); break;
+ }
+}
+
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+static WRITE_LINE_DEVICE_HANDLER( pc_lpt_ack_w )
+{
+ pc_lpt_state *lpt = get_safe_token(device->owner());
+
+ if (lpt->irq_enabled && lpt->ack == TRUE && state == FALSE)
+ {
+ /* pulse irq when going from high to low */
+ lpt->out_irq_func(TRUE);
+ lpt->out_irq_func(FALSE);
+ }
+
+ lpt->ack = state;
+}
+
+
+READ8_DEVICE_HANDLER( pc_lpt_data_r )
+{
+ pc_lpt_state *lpt = get_safe_token(device);
+ // pull up mechanism for input lines, zeros are provided by pheripherial
+ return lpt->data & ~lpt->centronics->read(*device->machine().memory().first_space(), 0);
+}
+
+
+WRITE8_DEVICE_HANDLER( pc_lpt_data_w )
+{
+ pc_lpt_state *lpt = get_safe_token(device);
+ lpt->data = data;
+ lpt->centronics->write(*device->machine().memory().first_space(), 0, data);
+}
+
+
+READ8_DEVICE_HANDLER( pc_lpt_status_r )
+{
+ pc_lpt_state *lpt = get_safe_token(device);
+ UINT8 result = 0;
+
+ result |= lpt->centronics->fault_r() << 3;
+ result |= lpt->centronics->vcc_r() << 4; /* SELECT is connected to VCC */
+ result |= !lpt->centronics->pe_r() << 5;
+ result |= lpt->centronics->ack_r() << 6;
+ result |= !lpt->centronics->busy_r() << 7;
+
+ return result;
+}
+
+
+READ8_DEVICE_HANDLER( pc_lpt_control_r )
+{
+ pc_lpt_state *lpt = get_safe_token(device);
+ UINT8 result = 0;
+
+ /* return latch state */
+ result |= lpt->strobe << 0;
+ result |= lpt->autofd << 1;
+ result |= lpt->init << 2;
+ result |= lpt->select << 3;
+ result |= lpt->irq_enabled << 4;
+
+ return result;
+}
+
+
+WRITE8_DEVICE_HANDLER( pc_lpt_control_w )
+{
+ pc_lpt_state *lpt = get_safe_token(device);
+
+// logerror("pc_lpt_control_w: 0x%02x\n", data);
+
+ /* save to latch */
+ lpt->strobe = BIT(data, 0);
+ lpt->autofd = BIT(data, 1);
+ lpt->init = BIT(data, 2);
+ lpt->select = BIT(data, 3);
+ lpt->irq_enabled = BIT(data, 4);
+
+ /* output to centronics */
+ lpt->centronics->strobe_w(lpt->strobe);
+ lpt->centronics->autofeed_w(lpt->autofd);
+ lpt->centronics->init_prime_w(lpt->init);
+}
+
+
+READ8_DEVICE_HANDLER( pc_lpt_r )
+{
+ switch (offset)
+ {
+ case 0: return pc_lpt_data_r(device, 0);
+ case 1: return pc_lpt_status_r(device, 0);
+ case 2: return pc_lpt_control_r(device, 0);
+ }
+
+ /* if we reach this its an error */
+ logerror("PC-LPT %s: Read from invalid offset %x\n", device->tag(), offset);
+
+ return 0xff;
+}
+
+
+WRITE8_DEVICE_HANDLER( pc_lpt_w )
+{
+ switch (offset)
+ {
+ case 0: pc_lpt_data_w(device, 0, data); break;
+ case 1: break;
+ case 2: pc_lpt_control_w(device, 0, data); break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(PC_LPT, pc_lpt);
+
+static WRITE_LINE_DEVICE_HANDLER(pc_cpu_line)
+{
+ isa8_lpt_device *lpt = downcast<isa8_lpt_device *>(device->owner());
+ if (lpt->is_primary())
+ lpt->m_isa->irq7_w(state);
+ else
+ lpt->m_isa->irq5_w(state);
+}
+static const pc_lpt_interface pc_lpt_config =
+{
+ DEVCB_LINE(pc_cpu_line)
+};
+
+static MACHINE_CONFIG_FRAGMENT( lpt_config )
+ MCFG_PC_LPT_ADD("lpt", pc_lpt_config)
+MACHINE_CONFIG_END
+
+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
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_LPT = &device_creator<isa8_lpt_device>;
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa8_lpt_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( lpt_config );
+}
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+ioport_constructor isa8_lpt_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( lpt_dsw );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// isa8_lpt_device - constructor
+//-------------------------------------------------
+
+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),
+ device_isa8_card_interface(mconfig, *this)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa8_lpt_device::device_start()
+{
+ set_isa_device();
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa8_lpt_device::device_reset()
+{
+ m_is_primary = (ioport("DSW")->read() & 1) ? false : true;
+ if (m_is_primary) {
+ m_isa->install_device(subdevice("lpt"), 0x0378, 0x037b, 0, 0, FUNC(pc_lpt_r), FUNC(pc_lpt_w) );
+ } else {
+ m_isa->install_device(subdevice("lpt"), 0x0278, 0x027b, 0, 0, FUNC(pc_lpt_r), FUNC(pc_lpt_w) );
+ }
+}
diff --git a/src/mess/machine/pc_lpt.h b/src/mess/machine/pc_lpt.h
new file mode 100644
index 00000000000..d04c027d8d1
--- /dev/null
+++ b/src/mess/machine/pc_lpt.h
@@ -0,0 +1,85 @@
+/***************************************************************************
+
+ IBM-PC printer interface
+
+***************************************************************************/
+
+#ifndef __PC_LPT_H__
+#define __PC_LPT_H__
+
+#include "isa.h"
+#include "devcb.h"
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _pc_lpt_interface pc_lpt_interface;
+struct _pc_lpt_interface
+{
+ devcb_write_line out_irq_func;
+};
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+READ8_DEVICE_HANDLER( pc_lpt_r );
+WRITE8_DEVICE_HANDLER( pc_lpt_w );
+
+READ8_DEVICE_HANDLER( pc_lpt_data_r );
+WRITE8_DEVICE_HANDLER( pc_lpt_data_w );
+READ8_DEVICE_HANDLER( pc_lpt_status_r );
+READ8_DEVICE_HANDLER( pc_lpt_control_r );
+WRITE8_DEVICE_HANDLER( pc_lpt_control_w );
+
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+DECLARE_LEGACY_DEVICE(PC_LPT, pc_lpt);
+
+#define MCFG_PC_LPT_ADD(_tag, _intf) \
+ MCFG_DEVICE_ADD(_tag, PC_LPT, 0) \
+ MCFG_DEVICE_CONFIG(_intf)
+
+#define MCFG_PC_LPT_REMOVE(_tag) \
+ MCFG_DEVICE_REMOVE(_tag)
+
+
+//**************************************************************************
+// 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; }
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "isa_lpt"; }
+private:
+ // internal state
+ bool m_is_primary;
+};
+
+
+// device type definition
+extern const device_type ISA8_LPT;
+
+#endif /* __PC_LPT__ */
diff --git a/src/mess/machine/pc_turbo.c b/src/mess/machine/pc_turbo.c
new file mode 100644
index 00000000000..e01cb528ebf
--- /dev/null
+++ b/src/mess/machine/pc_turbo.c
@@ -0,0 +1,54 @@
+/*********************************************************************
+
+ pc_turbo.c
+
+ The PC "turbo" button
+
+**********************************************************************/
+
+#include "emu.h"
+#include "pc_turbo.h"
+
+
+struct pc_turbo_info
+{
+ device_t *cpu;
+ const char *port;
+ int mask;
+ int cur_val;
+ double off_speed;
+ double on_speed;
+};
+
+
+
+static TIMER_CALLBACK(pc_turbo_callback)
+{
+ struct pc_turbo_info *ti = (struct pc_turbo_info *) ptr;
+ int val;
+
+ val = machine.root_device().ioport(ti->port)->read() & ti->mask;
+
+ if (val != ti->cur_val)
+ {
+ ti->cur_val = val;
+ ti->cpu->set_clock_scale(val ? ti->on_speed : ti->off_speed);
+ }
+}
+
+
+
+int pc_turbo_setup(running_machine &machine, device_t *cpu, const char *port, int mask, double off_speed, double on_speed)
+{
+ struct pc_turbo_info *ti;
+
+ ti = auto_alloc(machine, struct pc_turbo_info);
+ ti->cpu = cpu;
+ ti->port = port;
+ ti->mask = mask;
+ ti->cur_val = -1;
+ ti->off_speed = off_speed;
+ ti->on_speed = on_speed;
+ machine.scheduler().timer_pulse(attotime::from_msec(100), FUNC(pc_turbo_callback), 0, ti);
+ return 0;
+}
diff --git a/src/mess/machine/pc_turbo.h b/src/mess/machine/pc_turbo.h
new file mode 100644
index 00000000000..f6c21e3710f
--- /dev/null
+++ b/src/mess/machine/pc_turbo.h
@@ -0,0 +1,15 @@
+/*********************************************************************
+
+ pc_turbo.h
+
+ The PC "turbo" button
+
+**********************************************************************/
+
+#ifndef PC_TURBO_H
+#define PC_TURBO_H
+
+int pc_turbo_setup(running_machine &machine, device_t *cpu, const char *port, int mask, double off_speed, double on_speed);
+
+
+#endif /* PC_TURBO_H */
diff --git a/src/mess/machine/pce.c b/src/mess/machine/pce.c
new file mode 100644
index 00000000000..8a486e79c37
--- /dev/null
+++ b/src/mess/machine/pce.c
@@ -0,0 +1,1827 @@
+/************************************************************
+
+PC Engine CD HW notes:
+
+CD Interface Register 0x00 - CDC status
+x--- ---- busy signal
+-x-- ---- request signal
+---x ---- cd signal
+---- x--- i/o signal
+
+CD Interface Register 0x03 - BRAM lock / CD status
+-x-- ---- acknowledge signal
+--x- ---- done signal
+---x ---- bram signal
+---- x--- ADPCM 2
+---- -x-- ADPCM 1
+---- --x- CDDA left/right speaker select
+
+CD Interface Register 0x05 - CD-DA Volume low 8-bit port
+
+CD Interface Register 0x06 - CD-DA Volume high 8-bit port
+
+CD Interface Register 0x07 - BRAM unlock / CD status
+x--- ---- Enables BRAM
+
+CD Interface Register 0x0c - ADPCM status
+x--- ---- ADPCM is reading data
+---- x--- ADPCM playback (0) stopped (1) currently playing
+---- -x-- pending ADPCM data write
+---- ---x ADPCM playback (1) stopped (0) currently playing
+
+CD Interface Register 0x0d - ADPCM address control
+x--- ---- ADPCM reset
+-x-- ---- ADPCM play
+--x- ---- ADPCM repeat
+---x ---- ADPCM set length
+---- x--- ADPCM set read address
+---- --xx ADPCM set write address
+(note: some games reads bit 5 and wants it to be low otherwise they hangs, surely NOT an ADPCM repeat flag read because it doesn't make sense)
+
+CD Interface Register 0x0e - ADPCM playback rate
+
+CD Interface Register 0x0f - ADPCM fade in/out register
+---- xxxx command setting:
+0x00 ADPCM/CD-DA Fade-in
+0x01 CD-DA fade-in
+0x08 CD-DA fade-out (short) ADPCM fade-in
+0x09 CD-DA fade-out (long)
+0x0a ADPCM fade-out (long)
+0x0c CD-DA fade-out (short) ADPCM fade-in
+0x0d CD-DA fade-out (short)
+0x0e ADPCM fade-out (short)
+
+*************************************************************/
+
+#include "emu.h"
+#include "coreutil.h"
+#include "cpu/h6280/h6280.h"
+#include "includes/pce.h"
+#include "imagedev/chd_cd.h"
+#include "sound/msm5205.h"
+#include "sound/cdda.h"
+
+
+#define PCE_BRAM_SIZE 0x800
+#define PCE_ADPCM_RAM_SIZE 0x10000
+#define PCE_ACARD_RAM_SIZE 0x200000
+#define PCE_CD_COMMAND_BUFFER_SIZE 0x100
+
+#define PCE_CD_IRQ_TRANSFER_READY 0x40
+#define PCE_CD_IRQ_TRANSFER_DONE 0x20
+#define PCE_CD_IRQ_SAMPLE_FULL_PLAY 0x08
+#define PCE_CD_IRQ_SAMPLE_HALF_PLAY 0x04
+
+#define PCE_CD_ADPCM_PLAY_FLAG 0x08
+#define PCE_CD_ADPCM_STOP_FLAG 0x01
+
+#define PCE_CD_DATA_FRAMES_PER_SECOND 75
+
+enum {
+ PCE_CD_CDDA_OFF=0,
+ PCE_CD_CDDA_PLAYING,
+ PCE_CD_CDDA_PAUSED
+};
+
+
+/* CD Unit RAM */
+
+/* MSM5205 ADPCM decoder definition */
+static void pce_cd_msm5205_int(device_t *device);
+const msm5205_interface pce_cd_msm5205_interface = {
+ pce_cd_msm5205_int, /* interrupt function */
+ MSM5205_S48_4B /* 1/48 prescaler, 4bit data */
+};
+
+
+/* joystick related data*/
+
+#define JOY_CLOCK 0x01
+#define JOY_RESET 0x02
+
+
+/* prototypes */
+static void pce_cd_init( running_machine &machine );
+static void pce_cd_set_irq_line( running_machine &machine, int num, int state );
+static TIMER_CALLBACK( pce_cd_adpcm_dma_timer_callback );
+static TIMER_CALLBACK( pce_cd_cdda_fadeout_callback );
+static TIMER_CALLBACK( pce_cd_cdda_fadein_callback );
+static TIMER_CALLBACK( pce_cd_adpcm_fadeout_callback );
+static TIMER_CALLBACK( pce_cd_adpcm_fadein_callback );
+
+WRITE8_MEMBER(pce_state::pce_sf2_banking_w)
+{
+ membank( "bank2" )->set_base( memregion("user1")->base() + offset * 0x080000 + 0x080000 );
+ membank( "bank3" )->set_base( memregion("user1")->base() + offset * 0x080000 + 0x088000 );
+ membank( "bank4" )->set_base( memregion("user1")->base() + offset * 0x080000 + 0x0D0000 );
+}
+
+WRITE8_MEMBER(pce_state::pce_cartridge_ram_w)
+{
+ m_cartridge_ram[offset] = data;
+}
+
+DEVICE_IMAGE_LOAD(pce_cart)
+{
+ pce_state *state = image.device().machine().driver_data<pce_state>();
+ UINT32 size;
+ int split_rom = 0, offset = 0;
+ const char *extrainfo = NULL;
+ unsigned char *ROM;
+ logerror("*** DEVICE_IMAGE_LOAD(pce_cart) : %s\n", image.filename());
+
+ /* open file to get size */
+ ROM = state->memregion("user1")->base();
+
+ if (image.software_entry() == NULL)
+ size = image.length();
+ else
+ size = image.get_software_region_length("rom");
+
+ /* handle header accordingly */
+ if ((size / 512) & 1)
+ {
+ logerror("*** DEVICE_IMAGE_LOAD(pce_cart) : Header present\n");
+ size -= 512;
+ offset = 512;
+ }
+
+ if (size > PCE_ROM_MAXSIZE)
+ size = PCE_ROM_MAXSIZE;
+
+ if (image.software_entry() == NULL)
+ {
+ image.fseek(offset, SEEK_SET);
+ image.fread( ROM, size);
+ }
+ else
+ memcpy(ROM, image.get_software_region("rom") + offset, size);
+
+ if (extrainfo)
+ {
+ logerror("extrainfo: %s\n", extrainfo);
+ if (strstr(extrainfo, "ROM_SPLIT"))
+ split_rom = 1;
+ }
+
+ if (ROM[0x1fff] < 0xe0)
+ {
+ int i;
+ UINT8 decrypted[256];
+
+ logerror( "*** DEVICE_IMAGE_LOAD(pce_cart) : ROM image seems encrypted, decrypting...\n" );
+
+ /* Initialize decryption table */
+ for (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 (i = 0; i < size; i++)
+ ROM[i] = decrypted[ROM[i]];
+ }
+
+ /* check if we're dealing with a split rom image */
+ if (size == 384 * 1024)
+ {
+ split_rom = 1;
+ /* Mirror the upper 128KB part of the image */
+ memcpy(ROM + 0x060000, ROM + 0x040000, 0x020000); /* Set up 060000 - 07FFFF mirror */
+ }
+
+ /* set up the memory for a split rom image */
+ if (split_rom)
+ {
+ logerror("Split rom detected, setting up memory accordingly\n");
+ /* Set up ROM address space as follows: */
+ /* 000000 - 03FFFF : ROM data 000000 - 03FFFF */
+ /* 040000 - 07FFFF : ROM data 000000 - 03FFFF */
+ /* 080000 - 0BFFFF : ROM data 040000 - 07FFFF */
+ /* 0C0000 - 0FFFFF : ROM data 040000 - 07FFFF */
+ memcpy(ROM + 0x080000, ROM + 0x040000, 0x040000); /* Set up 080000 - 0BFFFF region */
+ memcpy(ROM + 0x0C0000, ROM + 0x040000, 0x040000); /* Set up 0C0000 - 0FFFFF region */
+ memcpy(ROM + 0x040000, ROM, 0x040000); /* Set up 040000 - 07FFFF region */
+ }
+ else
+ {
+ /* mirror 256KB rom data */
+ if (size <= 0x040000)
+ memcpy(ROM + 0x040000, ROM, 0x040000);
+
+ /* mirror 512KB rom data */
+ if (size <= 0x080000)
+ memcpy(ROM + 0x080000, ROM, 0x080000);
+ }
+
+ state->membank("bank1")->set_base(ROM);
+ state->membank("bank2")->set_base(ROM + 0x080000);
+ state->membank("bank3")->set_base(ROM + 0x088000);
+ state->membank("bank4")->set_base(ROM + 0x0d0000);
+
+ /* Check for Street fighter 2 */
+ if (size == PCE_ROM_MAXSIZE)
+ {
+ image.device().machine().device("maincpu")->memory().space(AS_PROGRAM)->install_write_handler(0x01ff0, 0x01ff3, write8_delegate(FUNC(pce_state::pce_sf2_banking_w),state));
+ }
+
+ /* Check for Populous */
+ if (!memcmp(ROM + 0x1F26, "POPULOUS", 8))
+ {
+ state->m_cartridge_ram = auto_alloc_array(image.device().machine(), UINT8, 0x8000);
+ state->membank("bank2")->set_base(state->m_cartridge_ram);
+ image.device().machine().device("maincpu")->memory().space(AS_PROGRAM)->install_write_handler(0x080000, 0x087FFF, write8_delegate(FUNC(pce_state::pce_cartridge_ram_w),state));
+ }
+
+ /* Check for CD system card */
+ state->m_sys3_card = 0;
+ if (!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)) { state->m_sys3_card = 1; } // JP version
+ else if(!memcmp(ROM + 0x29C4, "VER. 3.", 7 )) { state->m_sys3_card = 3; } // US version
+
+ if(state->m_sys3_card)
+ {
+ state->m_cartridge_ram = auto_alloc_array(image.device().machine(), UINT8, 0x30000);
+ state->membank("bank4")->set_base(state->m_cartridge_ram);
+ image.device().machine().device("maincpu")->memory().space(AS_PROGRAM)->install_write_handler(0x0D0000, 0x0FFFFF, write8_delegate(FUNC(pce_state::pce_cartridge_ram_w),state));
+ image.device().machine().device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_handler(0x080000, 0x087FFF, read8_delegate(FUNC(pce_state::pce_cd_acard_wram_r),state),write8_delegate(FUNC(pce_state::pce_cd_acard_wram_w),state));
+ }
+ }
+ return 0;
+}
+
+DRIVER_INIT_MEMBER(pce_state,mess_pce)
+{
+ m_io_port_options = PCE_JOY_SIG | CONST_SIG;
+}
+
+DRIVER_INIT_MEMBER(pce_state,tg16)
+{
+ m_io_port_options = TG_16_JOY_SIG | CONST_SIG;
+}
+
+DRIVER_INIT_MEMBER(pce_state,sgx)
+{
+ m_io_port_options = PCE_JOY_SIG | CONST_SIG;
+}
+
+MACHINE_START( pce )
+{
+ pce_state *state = machine.driver_data<pce_state>();
+ pce_cd_init( machine );
+ machine.device<nvram_device>("nvram")->set_base(state->m_cd.bram, PCE_BRAM_SIZE);
+}
+
+MACHINE_RESET( mess_pce )
+{
+ pce_state *state = machine.driver_data<pce_state>();
+ pce_cd_t &pce_cd = state->m_cd;
+ int joy_i;
+
+ for (joy_i = 0; joy_i < 5; joy_i++)
+ state->m_joy_6b_packet[joy_i] = 0;
+
+ pce_cd.adpcm_read_buf = 0;
+ pce_cd.adpcm_write_buf = 0;
+
+ // TODO: add CD-DA stop command here
+ //pce_cd.cdda_status = PCE_CD_CDDA_OFF;
+ //cdda_stop_audio( machine.device( "cdda" ) );
+
+ pce_cd.regs[0x0c] |= PCE_CD_ADPCM_STOP_FLAG;
+ pce_cd.regs[0x0c] &= ~PCE_CD_ADPCM_PLAY_FLAG;
+ //pce_cd.regs[0x03] = (pce_cd.regs[0x03] & ~0x0c) | (PCE_CD_SAMPLE_STOP_PLAY);
+ pce_cd.msm_idle = 1;
+
+ /* Note: Arcade Card BIOS contents are the same as System 3, only internal HW differs.
+ We use a category to select between modes (some games can be run in either S-CD or A-CD modes) */
+ state->m_acard = machine.root_device().ioport("A_CARD")->read() & 1;
+}
+
+/* todo: how many input ports does the PCE have? */
+WRITE8_MEMBER(pce_state::mess_pce_joystick_w)
+{
+ int joy_i;
+ UINT8 joy_type = ioport("JOY_TYPE")->read();
+
+ h6280io_set_buffer(&space.device(), data);
+
+ /* bump counter on a low-to-high transition of bit 1 */
+ if ((!m_joystick_data_select) && (data & JOY_CLOCK))
+ {
+ m_joystick_port_select = (m_joystick_port_select + 1) & 0x07;
+ }
+
+ /* do we want buttons or direction? */
+ m_joystick_data_select = data & JOY_CLOCK;
+
+ /* clear counter if bit 2 is set */
+ if (data & JOY_RESET)
+ {
+ m_joystick_port_select = 0;
+
+ for (joy_i = 0; joy_i < 5; joy_i++)
+ {
+ if (((joy_type >> (joy_i*2)) & 3) == 2)
+ m_joy_6b_packet[joy_i] ^= 1;
+ }
+ }
+}
+
+READ8_MEMBER(pce_state::mess_pce_joystick_r)
+{
+ static const char *const joyname[4][5] = {
+ { "JOY_P1", "JOY_P2", "JOY_P3", "JOY_P4", "JOY_P5" },
+ { },
+ { "JOY6B_P1", "JOY6B_P2", "JOY6B_P3", "JOY6B_P4", "JOY6B_P5" },
+ { }
+ };
+ UINT8 joy_type = ioport("JOY_TYPE")->read();
+ UINT8 ret, data;
+
+ if (m_joystick_port_select <= 4)
+ {
+ switch((joy_type >> (m_joystick_port_select*2)) & 3)
+ {
+ case 0: //2-buttons pad
+ data = ioport(joyname[0][m_joystick_port_select])->read();
+ break;
+ case 2: //6-buttons pad
+ /*
+ Two packets:
+ 1st packet: directions + I, II, Run, Select
+ 2nd packet: 6 buttons "header" (high 4 bits active low) + III, IV, V, VI
+ Note that six buttons pad just doesn't work with (almost?) every single 2-button-only games, it's really just an after-thought and it is like this
+ on real HW.
+ */
+ data = ioport(joyname[2][m_joystick_port_select])->read() >> (m_joy_6b_packet[m_joystick_port_select]*8);
+ break;
+ default:
+ data = 0xff;
+ break;
+ }
+ }
+ else
+ data = 0xff;
+
+
+ if (m_joystick_data_select)
+ data >>= 4;
+
+ ret = (data & 0x0f) | m_io_port_options;
+#ifdef UNIFIED_PCE
+ ret &= ~0x40;
+#endif
+
+ return (ret);
+}
+
+static void pce_set_cd_bram( running_machine &machine )
+{
+ pce_state *state = machine.driver_data<pce_state>();
+ pce_cd_t &pce_cd = state->m_cd;
+ state->membank( "bank10" )->set_base( pce_cd.bram + ( pce_cd.bram_locked ? PCE_BRAM_SIZE : 0 ) );
+}
+
+static void adpcm_stop(running_machine &machine, UINT8 irq_flag)
+{
+ pce_state *state = machine.driver_data<pce_state>();
+ pce_cd_t &pce_cd = state->m_cd;
+ pce_cd.regs[0x0c] |= PCE_CD_ADPCM_STOP_FLAG;
+ pce_cd.regs[0x0c] &= ~PCE_CD_ADPCM_PLAY_FLAG;
+ //pce_cd.regs[0x03] = (pce_cd.regs[0x03] & ~0x0c) | (PCE_CD_SAMPLE_STOP_PLAY);
+ if(irq_flag)
+ pce_cd_set_irq_line( machine, PCE_CD_IRQ_SAMPLE_FULL_PLAY, ASSERT_LINE );
+ pce_cd.regs[0x0d] &= ~0x60;
+ pce_cd.msm_idle = 1;
+}
+
+static void adpcm_play(running_machine &machine)
+{
+ pce_state *state = machine.driver_data<pce_state>();
+ pce_cd_t &pce_cd = state->m_cd;
+ pce_cd.regs[0x0c] &= ~PCE_CD_ADPCM_STOP_FLAG;
+ pce_cd.regs[0x0c] |= PCE_CD_ADPCM_PLAY_FLAG;
+ pce_cd_set_irq_line( machine, PCE_CD_IRQ_SAMPLE_FULL_PLAY, CLEAR_LINE );
+ pce_cd.regs[0x03] = (pce_cd.regs[0x03] & ~0x0c);
+ pce_cd.msm_idle = 0;
+}
+
+
+/* Callback for new data from the MSM5205.
+ The PCE cd unit actually divides the clock signal supplied to
+ the MSM5205. Currently we can only use static clocks for the
+ MSM5205.
+ */
+static void pce_cd_msm5205_int(device_t *device)
+{
+ pce_state *state = device->machine().driver_data<pce_state>();
+ pce_cd_t &pce_cd = state->m_cd;
+ UINT8 msm_data;
+
+// popmessage("%08x %08x %08x %02x %02x",pce_cd.msm_start_addr,pce_cd.msm_end_addr,pce_cd.msm_half_addr,pce_cd.regs[0x0c],pce_cd.regs[0x0d]);
+
+ if ( pce_cd.msm_idle )
+ return;
+
+ /* Supply new ADPCM data */
+ msm_data = (pce_cd.msm_nibble) ? (pce_cd.adpcm_ram[pce_cd.msm_start_addr] & 0x0f) : ((pce_cd.adpcm_ram[pce_cd.msm_start_addr] & 0xf0) >> 4);
+
+ msm5205_data_w(device, msm_data);
+ pce_cd.msm_nibble ^= 1;
+
+ if(pce_cd.msm_nibble == 0)
+ {
+ pce_cd.msm_start_addr++;
+
+ if(pce_cd.msm_start_addr == pce_cd.msm_half_addr)
+ {
+ //pce_cd_set_irq_line( device->machine(), PCE_CD_IRQ_SAMPLE_FULL_PLAY, CLEAR_LINE );
+ //pce_cd_set_irq_line( device->machine(), PCE_CD_IRQ_SAMPLE_HALF_PLAY, ASSERT_LINE );
+ }
+
+ if(pce_cd.msm_start_addr > pce_cd.msm_end_addr)
+ {
+ //pce_cd_set_irq_line( device->machine(), PCE_CD_IRQ_SAMPLE_HALF_PLAY, CLEAR_LINE );
+ //pce_cd_set_irq_line( device->machine(), PCE_CD_IRQ_SAMPLE_FULL_PLAY, CLEAR_LINE );
+ adpcm_stop(device->machine(),1);
+ msm5205_reset_w(device, 1);
+ }
+ }
+}
+
+#define SCSI_STATUS_OK 0x00
+#define SCSI_CHECK_CONDITION 0x02
+
+static void pce_cd_reply_status_byte( pce_state *state, UINT8 status )
+{
+ pce_cd_t &pce_cd = state->m_cd;
+logerror("Setting CD in reply_status_byte\n");
+ pce_cd.scsi_CD = pce_cd.scsi_IO = pce_cd.scsi_REQ = 1;
+ pce_cd.scsi_MSG = 0;
+ pce_cd.message_after_status = 1;
+ pce_cd.status_sent = pce_cd.message_sent = 0;
+
+ if ( status == SCSI_STATUS_OK )
+ {
+ pce_cd.regs[0x01] = 0x00;
+ }
+ else
+ {
+ pce_cd.regs[0x01] = 0x01;
+ }
+}
+
+/* 0x00 - TEST UNIT READY */
+static void pce_cd_test_unit_ready( running_machine &machine )
+{
+ pce_state *state = machine.driver_data<pce_state>();
+ pce_cd_t &pce_cd = state->m_cd;
+ logerror("test unit ready\n");
+ if ( pce_cd.cd )
+ {
+ logerror( "Sending STATUS_OK status\n" );
+ pce_cd_reply_status_byte( state, SCSI_STATUS_OK );
+ }
+ else
+ {
+ logerror( "Sending CHECK_CONDITION status\n" );
+ pce_cd_reply_status_byte( state, SCSI_CHECK_CONDITION );
+ }
+}
+
+/* 0x08 - READ (6) */
+static void pce_cd_read_6( running_machine &machine )
+{
+ pce_state *state = machine.driver_data<pce_state>();
+ pce_cd_t &pce_cd = state->m_cd;
+ UINT32 frame = ( ( pce_cd.command_buffer[1] & 0x1F ) << 16 ) | ( pce_cd.command_buffer[2] << 8 ) | pce_cd.command_buffer[3];
+ UINT32 frame_count = pce_cd.command_buffer[4];
+
+ /* Check for presence of a CD */
+ if ( ! pce_cd.cd )
+ {
+ pce_cd_reply_status_byte( state, SCSI_CHECK_CONDITION );
+ return;
+ }
+
+ if ( pce_cd.cdda_status != PCE_CD_CDDA_OFF )
+ {
+ pce_cd.cdda_status = PCE_CD_CDDA_OFF;
+ cdda_stop_audio( machine.device( "cdda" ) );
+ pce_cd.end_mark = 0;
+ }
+
+ pce_cd.current_frame = frame;
+ pce_cd.end_frame = frame + frame_count;
+
+ if ( frame_count == 0 )
+ {
+ /* Star Breaker uses this */
+ popmessage("Read Sector frame count == 0, contact MESSdev");
+ pce_cd_reply_status_byte( state, SCSI_STATUS_OK );
+ }
+ else
+ {
+ pce_cd.data_timer->adjust(attotime::from_hz( PCE_CD_DATA_FRAMES_PER_SECOND ), 0, attotime::from_hz( PCE_CD_DATA_FRAMES_PER_SECOND ));
+ }
+}
+
+/* 0xD8 - SET AUDIO PLAYBACK START POSITION (NEC) */
+static void pce_cd_nec_set_audio_start_position( running_machine &machine )
+{
+ pce_state *state = machine.driver_data<pce_state>();
+ pce_cd_t &pce_cd = state->m_cd;
+ UINT32 frame = 0;
+
+ if ( ! pce_cd.cd )
+ {
+ /* Throw some error here */
+ pce_cd_reply_status_byte( state, SCSI_CHECK_CONDITION );
+ return;
+ }
+
+ switch( pce_cd.command_buffer[9] & 0xC0 )
+ {
+ case 0x00:
+ popmessage("CD-DA set start mode 0x00, contact MESSdev");
+ frame = ( pce_cd.command_buffer[3] << 16 ) | ( pce_cd.command_buffer[4] << 8 ) | pce_cd.command_buffer[5];
+ break;
+ case 0x40:
+ {
+ UINT8 m,s,f;
+
+ m = bcd_2_dec( pce_cd.command_buffer[2]);
+ s = bcd_2_dec( pce_cd.command_buffer[3]);
+ f = bcd_2_dec( pce_cd.command_buffer[4]);
+
+ frame = f + 75 * (s + m * 60);
+ if(frame >= 525) // TODO: seven seconds gap? O_o
+ frame -= 525;
+ break;
+ }
+ case 0x80:
+ frame = pce_cd.toc->tracks[ bcd_2_dec( pce_cd.command_buffer[2] ) - 1 ].physframeofs;
+ break;
+ default:
+ popmessage("CD-DA set start mode 0xc0, contact MESSdev");
+ //assert( NULL == pce_cd_nec_set_audio_start_position );
+ break;
+ }
+
+ pce_cd.current_frame = frame;
+
+ if ( pce_cd.cdda_status == PCE_CD_CDDA_PAUSED )
+ {
+ pce_cd.cdda_status = PCE_CD_CDDA_OFF;
+ cdda_stop_audio( machine.device( "cdda" ) );
+ pce_cd.end_frame = pce_cd.last_frame;
+ pce_cd.end_mark = 0;
+ }
+ else
+ {
+ if(pce_cd.command_buffer[1] & 0x03)
+ {
+ pce_cd.cdda_status = PCE_CD_CDDA_PLAYING;
+ pce_cd.end_frame = pce_cd.last_frame; //get the end of the CD
+ cdda_start_audio( machine.device( "cdda" ), pce_cd.current_frame, pce_cd.end_frame - pce_cd.current_frame );
+ pce_cd.cdda_play_mode = (pce_cd.command_buffer[1] & 0x02) ? 2 : 3; // mode 2 sets IRQ at end
+ pce_cd.end_mark = (pce_cd.command_buffer[1] & 0x02) ? 1 : 0;
+ }
+ else
+ {
+ pce_cd.cdda_status = PCE_CD_CDDA_PLAYING;
+ pce_cd.end_frame = pce_cd.toc->tracks[ cdrom_get_track(pce_cd.cd, pce_cd.current_frame) + 1 ].physframeofs; //get the end of THIS track
+ cdda_start_audio( machine.device( "cdda" ), pce_cd.current_frame, pce_cd.end_frame - pce_cd.current_frame );
+ pce_cd.end_mark = 0;
+ pce_cd.cdda_play_mode = 3;
+ }
+ }
+
+ pce_cd_reply_status_byte( state, SCSI_STATUS_OK );
+ pce_cd_set_irq_line( machine, PCE_CD_IRQ_TRANSFER_DONE, ASSERT_LINE );
+}
+
+/* 0xD9 - SET AUDIO PLAYBACK END POSITION (NEC) */
+static void pce_cd_nec_set_audio_stop_position( running_machine &machine )
+{
+ pce_state *state = machine.driver_data<pce_state>();
+ pce_cd_t &pce_cd = state->m_cd;
+ UINT32 frame = 0;
+
+ if ( ! pce_cd.cd )
+ {
+ /* Throw some error here */
+ pce_cd_reply_status_byte( state, SCSI_CHECK_CONDITION );
+ return;
+ }
+
+ switch( pce_cd.command_buffer[9] & 0xC0 )
+ {
+ case 0x00:
+ popmessage("CD-DA set end mode 0x00, contact MESSdev");
+ frame = ( pce_cd.command_buffer[3] << 16 ) | ( pce_cd.command_buffer[4] << 8 ) | pce_cd.command_buffer[5];
+ break;
+ case 0x40:
+ {
+ UINT8 m,s,f;
+
+ m = bcd_2_dec( pce_cd.command_buffer[2]);
+ s = bcd_2_dec( pce_cd.command_buffer[3]);
+ f = bcd_2_dec( pce_cd.command_buffer[4]);
+
+ frame = f + 75 * (s + m * 60);
+ if(frame >= 525) // TODO: seven seconds gap? O_o
+ frame -= 525;
+ break;
+ }
+ case 0x80:
+ frame = pce_cd.toc->tracks[ bcd_2_dec( pce_cd.command_buffer[2] ) - 1 ].physframeofs;
+ break;
+ default:
+ popmessage("CD-DA set end mode 0xc0, contact MESSdev");
+ //assert( NULL == pce_cd_nec_set_audio_start_position );
+ break;
+ }
+
+ pce_cd.end_frame = frame;
+ pce_cd.cdda_play_mode = pce_cd.command_buffer[1] & 0x03;
+
+ if ( pce_cd.cdda_play_mode )
+ {
+ if ( pce_cd.cdda_status == PCE_CD_CDDA_PAUSED )
+ {
+ cdda_pause_audio( machine.device( "cdda" ), 0 );
+ }
+ else
+ {
+ cdda_start_audio( machine.device( "cdda" ), pce_cd.current_frame, pce_cd.end_frame - pce_cd.current_frame );
+ pce_cd.end_mark = 1;
+ }
+ pce_cd.cdda_status = PCE_CD_CDDA_PLAYING;
+ }
+ else
+ {
+ pce_cd.cdda_status = PCE_CD_CDDA_OFF;
+ cdda_stop_audio( machine.device( "cdda" ) );
+ pce_cd.end_frame = pce_cd.last_frame;
+ pce_cd.end_mark = 0;
+// assert( NULL == pce_cd_nec_set_audio_stop_position );
+ }
+
+ pce_cd_reply_status_byte( state, SCSI_STATUS_OK );
+ pce_cd_set_irq_line( machine, PCE_CD_IRQ_TRANSFER_DONE, ASSERT_LINE );
+}
+
+/* 0xDA - PAUSE (NEC) */
+static void pce_cd_nec_pause( running_machine &machine )
+{
+ pce_state *state = machine.driver_data<pce_state>();
+ pce_cd_t &pce_cd = state->m_cd;
+
+ /* If no cd mounted throw an error */
+ if ( ! pce_cd.cd )
+ {
+ pce_cd_reply_status_byte( state, SCSI_CHECK_CONDITION );
+ return;
+ }
+
+ /* If there was no cdda playing, throw an error */
+ if ( pce_cd.cdda_status == PCE_CD_CDDA_OFF )
+ {
+ pce_cd_reply_status_byte( state, SCSI_CHECK_CONDITION );
+ return;
+ }
+
+ pce_cd.cdda_status = PCE_CD_CDDA_PAUSED;
+ pce_cd.current_frame = cdda_get_audio_lba( machine.device( "cdda" ) );
+ cdda_pause_audio( machine.device( "cdda" ), 1 );
+ pce_cd_reply_status_byte( state, SCSI_STATUS_OK );
+}
+
+/* 0xDD - READ SUBCHANNEL Q (NEC) */
+static void pce_cd_nec_get_subq( running_machine &machine )
+{
+ pce_state *state = machine.driver_data<pce_state>();
+ pce_cd_t &pce_cd = state->m_cd;
+ /* WP - I do not have access to chds with subchannel information yet, so I'm faking something here */
+ UINT32 msf_abs, msf_rel, track, frame;
+
+ if ( ! pce_cd.cd )
+ {
+ /* Throw some error here */
+ pce_cd_reply_status_byte( state, SCSI_CHECK_CONDITION );
+ return;
+ }
+
+ frame = pce_cd.current_frame;
+
+ switch( pce_cd.cdda_status )
+ {
+ case PCE_CD_CDDA_PAUSED:
+ pce_cd.data_buffer[0] = 2;
+ frame = cdda_get_audio_lba( machine.device( "cdda" ) );
+ break;
+ case PCE_CD_CDDA_PLAYING:
+ pce_cd.data_buffer[0] = 0;
+ frame = cdda_get_audio_lba( machine.device( "cdda" ) );
+ break;
+ default:
+ pce_cd.data_buffer[0] = 3;
+ break;
+ }
+
+ msf_abs = lba_to_msf_alt( frame );
+ track = cdrom_get_track( pce_cd.cd, frame );
+ msf_rel = lba_to_msf_alt( frame - cdrom_get_track_start( pce_cd.cd, track ) );
+
+ pce_cd.data_buffer[1] = 0x01 | ((cdrom_get_track_type(pce_cd.cd, cdrom_get_track(pce_cd.cd, track+1)) == CD_TRACK_AUDIO) ? 0x00 : 0x40);
+ pce_cd.data_buffer[2] = dec_2_bcd( track+1 ); /* track */
+ pce_cd.data_buffer[3] = 1; /* index */
+ pce_cd.data_buffer[4] = dec_2_bcd(( msf_rel >> 16 ) & 0xFF);/* M (relative) */
+ pce_cd.data_buffer[5] = dec_2_bcd(( msf_rel >> 8 ) & 0xFF); /* S (relative) */
+ pce_cd.data_buffer[6] = dec_2_bcd(msf_rel & 0xFF); /* F (relative) */
+ pce_cd.data_buffer[7] = dec_2_bcd(( msf_abs >> 16 ) & 0xFF);/* M (absolute) */
+ pce_cd.data_buffer[8] = dec_2_bcd(( msf_abs >> 8 ) & 0xFF); /* S (absolute) */
+ pce_cd.data_buffer[9] = dec_2_bcd(msf_abs & 0xFF); /* F (absolute) */
+ pce_cd.data_buffer_size = 10;
+
+ pce_cd.data_buffer_index = 0;
+ pce_cd.data_transferred = 1;
+ pce_cd.scsi_IO = 1;
+ pce_cd.scsi_CD = 0;
+}
+
+/* 0xDE - GET DIR INFO (NEC) */
+static void pce_cd_nec_get_dir_info( running_machine &machine )
+{
+ pce_state *state = machine.driver_data<pce_state>();
+ pce_cd_t &pce_cd = state->m_cd;
+ UINT32 frame, msf, track = 0;
+ const cdrom_toc *toc;
+ logerror("nec get dir info\n");
+
+ if ( ! pce_cd.cd )
+ {
+ /* Throw some error here */
+ pce_cd_reply_status_byte( state, SCSI_CHECK_CONDITION );
+ }
+
+ toc = cdrom_get_toc( pce_cd.cd );
+
+ switch( pce_cd.command_buffer[1] )
+ {
+ case 0x00: /* Get first and last track numbers */
+ pce_cd.data_buffer[0] = dec_2_bcd(1);
+ pce_cd.data_buffer[1] = dec_2_bcd(toc->numtrks);
+ pce_cd.data_buffer_size = 2;
+ break;
+ case 0x01: /* Get total disk size in MSF format */
+ frame = toc->tracks[toc->numtrks-1].physframeofs;
+ frame += toc->tracks[toc->numtrks-1].frames;
+ msf = lba_to_msf( frame + 150 );
+
+ pce_cd.data_buffer[0] = ( msf >> 16 ) & 0xFF; /* M */
+ pce_cd.data_buffer[1] = ( msf >> 8 ) & 0xFF; /* S */
+ pce_cd.data_buffer[2] = msf & 0xFF; /* F */
+ pce_cd.data_buffer_size = 3;
+ break;
+ case 0x02: /* Get track information */
+ if ( pce_cd.command_buffer[2] == 0xAA )
+ {
+ frame = toc->tracks[toc->numtrks-1].physframeofs;
+ frame += toc->tracks[toc->numtrks-1].frames;
+ pce_cd.data_buffer[3] = 0x04; /* correct? */
+ } else
+ {
+ track = MAX( bcd_2_dec( pce_cd.command_buffer[2] ), 1 );
+ frame = toc->tracks[track-1].physframeofs;
+ pce_cd.data_buffer[3] = ( toc->tracks[track-1].trktype == CD_TRACK_AUDIO ) ? 0x00 : 0x04;
+ }
+ logerror("track = %d, frame = %d\n", track, frame );
+ msf = lba_to_msf( frame + 150 );
+ pce_cd.data_buffer[0] = ( msf >> 16 ) & 0xFF; /* M */
+ pce_cd.data_buffer[1] = ( msf >> 8 ) & 0xFF; /* S */
+ pce_cd.data_buffer[2] = msf & 0xFF; /* F */
+ pce_cd.data_buffer_size = 4;
+ break;
+ default:
+// assert( pce_cd_nec_get_dir_info == NULL ); // Not implemented yet
+ break;
+ }
+
+ pce_cd.data_buffer_index = 0;
+ pce_cd.data_transferred = 1;
+ pce_cd.scsi_IO = 1;
+ pce_cd.scsi_CD = 0;
+}
+
+static void pce_cd_end_of_list( running_machine &machine )
+{
+ pce_state *state = machine.driver_data<pce_state>();
+ pce_cd_reply_status_byte( state, SCSI_CHECK_CONDITION );
+}
+
+static void pce_cd_handle_data_output( running_machine &machine )
+{
+ pce_state *state = machine.driver_data<pce_state>();
+ pce_cd_t &pce_cd = state->m_cd;
+ static const struct {
+ UINT8 command_byte;
+ UINT8 command_size;
+ void (*command_handler)(running_machine &machine);
+ } pce_cd_commands[] = {
+ { 0x00, 6, pce_cd_test_unit_ready }, /* TEST UNIT READY */
+ { 0x08, 6, pce_cd_read_6 }, /* READ (6) */
+ { 0xD8,10, pce_cd_nec_set_audio_start_position }, /* NEC SET AUDIO PLAYBACK START POSITION */
+ { 0xD9,10, pce_cd_nec_set_audio_stop_position }, /* NEC SET AUDIO PLAYBACK END POSITION */
+ { 0xDA,10, pce_cd_nec_pause }, /* NEC PAUSE */
+ { 0xDD,10, pce_cd_nec_get_subq }, /* NEC GET SUBCHANNEL Q */
+ { 0xDE,10, pce_cd_nec_get_dir_info }, /* NEC GET DIR INFO */
+ { 0xFF, 1, pce_cd_end_of_list } /* end of list marker */
+ };
+
+ if ( pce_cd.scsi_REQ && pce_cd.scsi_ACK )
+ {
+ /* Command byte received */
+ logerror( "Command byte $%02X received\n", pce_cd.regs[0x01] );
+
+ /* Check for buffer overflow */
+ assert( pce_cd.command_buffer_index < PCE_CD_COMMAND_BUFFER_SIZE );
+
+ pce_cd.command_buffer[pce_cd.command_buffer_index] = pce_cd.regs[0x01];
+ pce_cd.command_buffer_index++;
+ pce_cd.scsi_REQ = 0;
+ }
+
+ if ( ! pce_cd.scsi_REQ && ! pce_cd.scsi_ACK && pce_cd.command_buffer_index )
+ {
+ int i = 0;
+
+ logerror( "Check if command done\n" );
+
+ for( i = 0; pce_cd.command_buffer[0] > pce_cd_commands[i].command_byte; i++ );
+
+ /* Check for unknown commands */
+ if ( pce_cd.command_buffer[0] != pce_cd_commands[i].command_byte )
+ {
+ logerror("Unrecognized command: %02X\n", pce_cd.command_buffer[0] );
+ if(pce_cd.command_buffer[0] == 0x03)
+ popmessage("CD command 0x03 issued (Request Sense), contact MESSdev");
+ }
+ assert( pce_cd.command_buffer[0] == pce_cd_commands[i].command_byte );
+
+ if ( pce_cd.command_buffer_index == pce_cd_commands[i].command_size )
+ {
+ (pce_cd_commands[i].command_handler)( machine );
+ pce_cd.command_buffer_index = 0;
+ }
+ else
+ {
+ pce_cd.scsi_REQ = 1;
+ }
+ }
+}
+
+static void pce_cd_handle_data_input( running_machine &machine )
+{
+ pce_state *state = machine.driver_data<pce_state>();
+ pce_cd_t &pce_cd = state->m_cd;
+ if ( pce_cd.scsi_CD )
+ {
+ /* Command / Status byte */
+ if ( pce_cd.scsi_REQ && pce_cd.scsi_ACK )
+ {
+ logerror( "status sent\n" );
+ pce_cd.scsi_REQ = 0;
+ pce_cd.status_sent = 1;
+ }
+
+ if ( ! pce_cd.scsi_REQ && ! pce_cd.scsi_ACK && pce_cd.status_sent )
+ {
+ pce_cd.status_sent = 0;
+ if ( pce_cd.message_after_status )
+ {
+ logerror( "message after status\n" );
+ pce_cd.message_after_status = 0;
+ pce_cd.scsi_MSG = pce_cd.scsi_REQ = 1;
+ pce_cd.regs[0x01] = 0;
+ }
+ }
+ }
+ else
+ {
+ /* Data */
+ if ( pce_cd.scsi_REQ && pce_cd.scsi_ACK )
+ {
+ pce_cd.scsi_REQ = 0;
+ }
+
+ if ( ! pce_cd.scsi_REQ && ! pce_cd.scsi_ACK )
+ {
+ if ( pce_cd.data_buffer_index == pce_cd.data_buffer_size )
+ {
+ pce_cd_set_irq_line( machine, PCE_CD_IRQ_TRANSFER_READY, CLEAR_LINE );
+ if ( pce_cd.data_transferred )
+ {
+ pce_cd.data_transferred = 0;
+ pce_cd_reply_status_byte( state, SCSI_STATUS_OK );
+ pce_cd_set_irq_line( machine, PCE_CD_IRQ_TRANSFER_DONE, ASSERT_LINE );
+ }
+ }
+ else
+ {
+ logerror("Transfer byte from offset %d\n", pce_cd.data_buffer_index);
+ pce_cd.regs[0x01] = pce_cd.data_buffer[pce_cd.data_buffer_index];
+ pce_cd.data_buffer_index++;
+ pce_cd.scsi_REQ = 1;
+ }
+ }
+ }
+}
+
+static void pce_cd_handle_message_output( pce_state *state )
+{
+ pce_cd_t &pce_cd = state->m_cd;
+ if ( pce_cd.scsi_REQ && pce_cd.scsi_ACK )
+ {
+ pce_cd.scsi_REQ = 0;
+ }
+}
+
+static void pce_cd_handle_message_input( pce_state *state )
+{
+ pce_cd_t &pce_cd = state->m_cd;
+ if ( pce_cd.scsi_REQ && pce_cd.scsi_ACK )
+ {
+ pce_cd.scsi_REQ = 0;
+ pce_cd.message_sent = 1;
+ }
+
+ if ( ! pce_cd.scsi_REQ && ! pce_cd.scsi_ACK && pce_cd.message_sent )
+ {
+ pce_cd.message_sent = 0;
+ pce_cd.scsi_BSY = 0;
+ }
+}
+
+/* Update internal CD statuses */
+static void pce_cd_update( running_machine &machine )
+{
+ pce_state *state = machine.driver_data<pce_state>();
+ pce_cd_t &pce_cd = state->m_cd;
+ /* Check for reset of CD unit */
+ if ( pce_cd.scsi_RST != pce_cd.scsi_last_RST )
+ {
+ if ( pce_cd.scsi_RST )
+ {
+ logerror("Performing CD reset\n");
+ /* Reset internal data */
+ pce_cd.scsi_BSY = pce_cd.scsi_SEL = pce_cd.scsi_CD = pce_cd.scsi_IO = 0;
+ pce_cd.scsi_MSG = pce_cd.scsi_REQ = pce_cd.scsi_ATN = 0;
+ pce_cd.cd_motor_on = 0;
+ pce_cd.selected = 0;
+ pce_cd.cdda_status = PCE_CD_CDDA_OFF;
+ cdda_stop_audio( machine.device( "cdda" ) );
+ pce_cd.adpcm_dma_timer->adjust(attotime::never); // stop ADPCM DMA here
+ }
+ pce_cd.scsi_last_RST = pce_cd.scsi_RST;
+ }
+
+ /* Check if bus can be freed */
+ if ( ! pce_cd.scsi_SEL && ! pce_cd.scsi_BSY && pce_cd.selected )
+ {
+ logerror( "freeing bus\n" );
+ pce_cd.selected = 0;
+ pce_cd.scsi_CD = pce_cd.scsi_MSG = pce_cd.scsi_IO = pce_cd.scsi_REQ = 0;
+ pce_cd_set_irq_line( machine, PCE_CD_IRQ_TRANSFER_DONE, CLEAR_LINE );
+ }
+
+ /* Select the CD device */
+ if ( pce_cd.scsi_SEL )
+ {
+ if ( ! pce_cd.selected )
+ {
+ pce_cd.selected = 1;
+ logerror("Setting CD in device selection\n");
+ pce_cd.scsi_BSY = pce_cd.scsi_REQ = pce_cd.scsi_CD = 1;
+ pce_cd.scsi_MSG = pce_cd.scsi_IO = 0;
+ }
+ }
+
+ if ( pce_cd.scsi_ATN )
+ {
+ }
+ else
+ {
+ /* Check for data and pessage phases */
+ if ( pce_cd.scsi_BSY )
+ {
+ if ( pce_cd.scsi_MSG )
+ {
+ /* message phase */
+ if ( pce_cd.scsi_IO )
+ {
+ pce_cd_handle_message_input(state);
+ }
+ else
+ {
+ pce_cd_handle_message_output(state);
+ }
+ }
+ else
+ {
+ /* data phase */
+ if ( pce_cd.scsi_IO )
+ {
+ /* Reading data from target */
+ pce_cd_handle_data_input( machine );
+ }
+ else
+ {
+ /* Sending data to target */
+ pce_cd_handle_data_output( machine );
+ }
+ }
+ }
+ }
+
+ /* FIXME: presumably CD-DA needs an irq interface for this */
+ if(cdda_audio_ended(machine.device("cdda")) && pce_cd.end_mark == 1)
+ {
+ switch(pce_cd.cdda_play_mode & 3)
+ {
+ case 1: cdda_start_audio( machine.device( "cdda" ), pce_cd.current_frame, pce_cd.end_frame - pce_cd.current_frame ); pce_cd.end_mark = 1; break; //play with repeat
+ case 2: pce_cd_set_irq_line( machine, PCE_CD_IRQ_TRANSFER_DONE, ASSERT_LINE ); pce_cd.end_mark = 0; break; //irq when finished
+ case 3: pce_cd.end_mark = 0; break; //play without repeat
+ }
+ }
+}
+
+static void pce_cd_set_irq_line( running_machine &machine, int num, int state )
+{
+ pce_state *drvstate = machine.driver_data<pce_state>();
+ pce_cd_t &pce_cd = drvstate->m_cd;
+ switch( num )
+ {
+ case PCE_CD_IRQ_TRANSFER_DONE:
+ if ( state == ASSERT_LINE )
+ {
+ pce_cd.regs[0x03] |= PCE_CD_IRQ_TRANSFER_DONE;
+ }
+ else
+ {
+ pce_cd.regs[0x03] &= ~ PCE_CD_IRQ_TRANSFER_DONE;
+ }
+ break;
+ case PCE_CD_IRQ_TRANSFER_READY:
+ if ( state == ASSERT_LINE )
+ {
+ pce_cd.regs[0x03] |= PCE_CD_IRQ_TRANSFER_READY;
+ }
+ else
+ {
+ pce_cd.regs[0x03] &= ~ PCE_CD_IRQ_TRANSFER_READY;
+ }
+ break;
+ case PCE_CD_IRQ_SAMPLE_FULL_PLAY:
+ if ( state == ASSERT_LINE )
+ {
+ pce_cd.regs[0x03] |= PCE_CD_IRQ_SAMPLE_FULL_PLAY;
+ //printf("x %02x %02x\n",pce_cd.regs[0x02],pce_cd.regs[0x03]);
+ }
+ else
+ {
+ pce_cd.regs[0x03] &= ~ PCE_CD_IRQ_SAMPLE_FULL_PLAY;
+ }
+ break;
+ case PCE_CD_IRQ_SAMPLE_HALF_PLAY:
+ if ( state == ASSERT_LINE )
+ {
+ pce_cd.regs[0x03] |= PCE_CD_IRQ_SAMPLE_HALF_PLAY;
+ //printf("y %02x %02x\n",pce_cd.regs[0x02],pce_cd.regs[0x03]);
+ }
+ else
+ {
+ pce_cd.regs[0x03] &= ~ PCE_CD_IRQ_SAMPLE_HALF_PLAY;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if ( pce_cd.regs[0x02] & pce_cd.regs[0x03] & ( PCE_CD_IRQ_TRANSFER_DONE | PCE_CD_IRQ_TRANSFER_READY | PCE_CD_IRQ_SAMPLE_HALF_PLAY | PCE_CD_IRQ_SAMPLE_FULL_PLAY) )
+ {
+ cputag_set_input_line(machine, "maincpu", 1, ASSERT_LINE );
+ }
+ else
+ {
+ cputag_set_input_line(machine, "maincpu", 1, CLEAR_LINE );
+ }
+}
+
+static TIMER_CALLBACK( pce_cd_data_timer_callback )
+{
+ pce_state *state = machine.driver_data<pce_state>();
+ pce_cd_t &pce_cd = state->m_cd;
+ if ( pce_cd.data_buffer_index == pce_cd.data_buffer_size )
+ {
+ /* Read next data sector */
+ logerror("read sector %d\n", pce_cd.current_frame );
+ if ( ! cdrom_read_data( pce_cd.cd, pce_cd.current_frame, pce_cd.data_buffer, CD_TRACK_MODE1 ) )
+ {
+ logerror("Mode1 CD read failed for frame #%d\n", pce_cd.current_frame );
+ }
+ else
+ {
+ logerror("Succesfully read mode1 frame #%d\n", pce_cd.current_frame );
+ }
+
+ pce_cd.data_buffer_index = 0;
+ pce_cd.data_buffer_size = 2048;
+ pce_cd.current_frame++;
+
+ pce_cd.scsi_IO = 1;
+ pce_cd.scsi_CD = 0;
+
+ if ( pce_cd.current_frame == pce_cd.end_frame )
+ {
+ /* We are done, disable the timer */
+ logerror("Last frame read from CD\n");
+ pce_cd.data_transferred = 1;
+ pce_cd.data_timer->adjust(attotime::never);
+ }
+ else
+ {
+ pce_cd.data_transferred = 0;
+ }
+ }
+}
+
+static void pce_cd_init( running_machine &machine )
+{
+ pce_state *state = machine.driver_data<pce_state>();
+ pce_cd_t &pce_cd = state->m_cd;
+ cdrom_image_device *device;
+
+ /* Initialize pce_cd struct */
+ memset( &pce_cd, 0, sizeof(pce_cd) );
+
+ /* Initialize BRAM */
+ pce_cd.bram = auto_alloc_array(machine, UINT8, PCE_BRAM_SIZE * 2 );
+ memset( pce_cd.bram, 0, PCE_BRAM_SIZE );
+ memset( pce_cd.bram + PCE_BRAM_SIZE, 0xFF, PCE_BRAM_SIZE );
+ pce_cd.bram_locked = 1;
+ pce_set_cd_bram(machine);
+
+ /* set up adpcm related things */
+ pce_cd.adpcm_ram = auto_alloc_array(machine, UINT8, PCE_ADPCM_RAM_SIZE );
+ memset( pce_cd.adpcm_ram, 0, PCE_ADPCM_RAM_SIZE );
+ pce_cd.adpcm_clock_divider = 1;
+ msm5205_change_clock_w(machine.device("msm5205"), (PCE_CD_CLOCK / 6) / pce_cd.adpcm_clock_divider);
+
+ /* Set up cd command buffer */
+ pce_cd.command_buffer = auto_alloc_array(machine, UINT8, PCE_CD_COMMAND_BUFFER_SIZE );
+ memset( pce_cd.command_buffer, 0, PCE_CD_COMMAND_BUFFER_SIZE );
+ pce_cd.command_buffer_index = 0;
+
+ /* Set up Arcade Card RAM buffer */
+ pce_cd.acard_ram = auto_alloc_array(machine, UINT8, PCE_ACARD_RAM_SIZE );
+ memset( pce_cd.acard_ram, 0, PCE_ACARD_RAM_SIZE );
+
+ pce_cd.data_buffer = auto_alloc_array(machine, UINT8, 8192 );
+ memset( pce_cd.data_buffer, 0, 8192 );
+ pce_cd.data_buffer_size = 0;
+ pce_cd.data_buffer_index = 0;
+
+ pce_cd.subcode_buffer = auto_alloc_array(machine, UINT8, 96 );
+
+ device = machine.device<cdrom_image_device>("cdrom");
+ if ( device )
+ {
+ pce_cd.cd = device->get_cdrom_file();
+ if ( pce_cd.cd )
+ {
+ pce_cd.toc = cdrom_get_toc( pce_cd.cd );
+ cdda_set_cdrom( machine.device("cdda"), pce_cd.cd );
+ pce_cd.last_frame = cdrom_get_track_start( pce_cd.cd, cdrom_get_last_track( pce_cd.cd ) - 1 );
+ pce_cd.last_frame += pce_cd.toc->tracks[ cdrom_get_last_track( pce_cd.cd ) - 1 ].frames;
+ pce_cd.end_frame = pce_cd.last_frame;
+ }
+ }
+
+ pce_cd.data_timer = machine.scheduler().timer_alloc(FUNC(pce_cd_data_timer_callback));
+ pce_cd.data_timer->adjust(attotime::never);
+ pce_cd.adpcm_dma_timer = machine.scheduler().timer_alloc(FUNC(pce_cd_adpcm_dma_timer_callback));
+ pce_cd.adpcm_dma_timer->adjust(attotime::never);
+
+ pce_cd.cdda_fadeout_timer = machine.scheduler().timer_alloc(FUNC(pce_cd_cdda_fadeout_callback));
+ pce_cd.cdda_fadeout_timer->adjust(attotime::never);
+ pce_cd.cdda_fadein_timer = machine.scheduler().timer_alloc(FUNC(pce_cd_cdda_fadein_callback));
+ pce_cd.cdda_fadein_timer->adjust(attotime::never);
+
+ pce_cd.adpcm_fadeout_timer = machine.scheduler().timer_alloc(FUNC(pce_cd_adpcm_fadeout_callback));
+ pce_cd.adpcm_fadeout_timer->adjust(attotime::never);
+ pce_cd.adpcm_fadein_timer = machine.scheduler().timer_alloc(FUNC(pce_cd_adpcm_fadein_callback));
+ pce_cd.adpcm_fadein_timer->adjust(attotime::never);
+}
+
+WRITE8_MEMBER(pce_state::pce_cd_bram_w)
+{
+ pce_cd_t &pce_cd = m_cd;
+ if ( ! pce_cd.bram_locked )
+ {
+ pce_cd.bram[ offset ] = data;
+ }
+}
+
+static void pce_cd_set_adpcm_ram_byte(running_machine &machine, UINT8 val)
+{
+ pce_state *state = machine.driver_data<pce_state>();
+ pce_cd_t &pce_cd = state->m_cd;
+ if(pce_cd.adpcm_write_buf > 0)
+ {
+ pce_cd.adpcm_write_buf--;
+ }
+ else
+ {
+ pce_cd.adpcm_ram[pce_cd.adpcm_write_ptr] = val;
+ pce_cd.adpcm_write_ptr = ((pce_cd.adpcm_write_ptr + 1) & 0xffff);
+ //TODO: length + 1
+ }
+}
+
+static TIMER_CALLBACK( pce_cd_cdda_fadeout_callback )
+{
+ pce_state *state = machine.driver_data<pce_state>();
+ pce_cd_t &pce_cd = state->m_cd;
+ pce_cd.cdda_volume-= 0.1;
+
+ if(pce_cd.cdda_volume <= 0)
+ {
+ pce_cd.cdda_volume = 0.0;
+ cdda_set_volume(machine.device("cdda"), 0.0);
+ pce_cd.cdda_fadeout_timer->adjust(attotime::never);
+ }
+ else
+ {
+ cdda_set_volume(machine.device("cdda"), pce_cd.cdda_volume);
+ pce_cd.cdda_fadeout_timer->adjust(attotime::from_usec(param), param);
+ }
+}
+
+static TIMER_CALLBACK( pce_cd_cdda_fadein_callback )
+{
+ pce_state *state = machine.driver_data<pce_state>();
+ pce_cd_t &pce_cd = state->m_cd;
+ pce_cd.cdda_volume+= 0.1;
+
+ if(pce_cd.cdda_volume >= 100.0)
+ {
+ pce_cd.cdda_volume = 100.0;
+ cdda_set_volume(machine.device("cdda"), 100.0);
+ pce_cd.cdda_fadein_timer->adjust(attotime::never);
+ }
+ else
+ {
+ cdda_set_volume(machine.device("cdda"), pce_cd.cdda_volume);
+ pce_cd.cdda_fadein_timer->adjust(attotime::from_usec(param), param);
+ }
+}
+
+static TIMER_CALLBACK( pce_cd_adpcm_fadeout_callback )
+{
+ pce_state *state = machine.driver_data<pce_state>();
+ pce_cd_t &pce_cd = state->m_cd;
+ pce_cd.adpcm_volume-= 0.1;
+
+ if(pce_cd.adpcm_volume <= 0)
+ {
+ pce_cd.adpcm_volume = 0.0;
+ msm5205_set_volume(machine.device("msm5205"), 0.0);
+ pce_cd.adpcm_fadeout_timer->adjust(attotime::never);
+ }
+ else
+ {
+ msm5205_set_volume(machine.device("msm5205"), pce_cd.adpcm_volume);
+ pce_cd.adpcm_fadeout_timer->adjust(attotime::from_usec(param), param);
+ }
+}
+
+static TIMER_CALLBACK( pce_cd_adpcm_fadein_callback )
+{
+ pce_state *state = machine.driver_data<pce_state>();
+ pce_cd_t &pce_cd = state->m_cd;
+ pce_cd.adpcm_volume+= 0.1;
+
+ if(pce_cd.adpcm_volume >= 100.0)
+ {
+ pce_cd.adpcm_volume = 100.0;
+ msm5205_set_volume(machine.device("msm5205"), 100.0);
+ pce_cd.adpcm_fadein_timer->adjust(attotime::never);
+ }
+ else
+ {
+ msm5205_set_volume(machine.device("msm5205"), pce_cd.adpcm_volume);
+ pce_cd.adpcm_fadein_timer->adjust(attotime::from_usec(param), param);
+ }
+}
+
+
+WRITE8_MEMBER(pce_state::pce_cd_intf_w)
+{
+ pce_cd_t &pce_cd = m_cd;
+ pce_cd_update(machine());
+
+ if(offset & 0x200 && m_sys3_card && m_acard) // route Arcade Card handling ports
+ return pce_cd_acard_w(space,offset,data);
+
+ logerror("%04X: write to CD interface offset %02X, data %02X\n", cpu_get_pc(&space.device()), offset, data );
+
+ switch( offset & 0xf )
+ {
+ case 0x00: /* CDC status */
+ /* select device (which bits??) */
+ pce_cd.scsi_SEL = 1;
+ pce_cd_update(machine());
+ pce_cd.scsi_SEL = 0;
+ pce_cd.adpcm_dma_timer->adjust(attotime::never); // stop ADPCM DMA here
+ /* any write here clears CD transfer irqs */
+ pce_cd.regs[0x03] &= ~0x70;
+ cputag_set_input_line(machine(), "maincpu", 1, CLEAR_LINE );
+ break;
+ case 0x01: /* CDC command / status / data */
+ break;
+ case 0x02: /* ADPCM / CD control / IRQ enable/disable */
+ /* bit 6 - transfer ready irq */
+ /* bit 5 - transfer done irq */
+ /* bit 4 - ?? irq */
+ /* bit 3 - ?? irq */
+ /* bit 2 - ?? irq */
+ pce_cd.scsi_ACK = data & 0x80;
+ /* Update register now otherwise it won't catch the irq enable/disable change */
+ pce_cd.regs[0x02] = data;
+ /* Don't set or reset any irq lines, but just verify the current state */
+ pce_cd_set_irq_line( machine(), 0, 0 );
+ break;
+ case 0x03: /* BRAM lock / CD status / IRQ - Read Only register */
+ break;
+ case 0x04: /* CD reset */
+ pce_cd.scsi_RST = data & 0x02;
+ break;
+ case 0x05: /* Convert PCM data / PCM data */
+ case 0x06: /* PCM data */
+ break;
+ case 0x07: /* BRAM unlock / CD status */
+ if ( data & 0x80 )
+ {
+ pce_cd.bram_locked = 0;
+ pce_set_cd_bram(machine());
+ }
+ break;
+ case 0x08: /* ADPCM address (LSB) / CD data */
+ break;
+ case 0x09: /* ADPCM address (MSB) */
+ break;
+ case 0x0A: /* ADPCM RAM data port */
+ pce_cd_set_adpcm_ram_byte(machine(), data);
+ break;
+ case 0x0B: /* ADPCM DMA control */
+ if ( data & 0x03 )
+ {
+ /* Start CD to ADPCM transfer */
+ pce_cd.adpcm_dma_timer->adjust(attotime::from_hz( PCE_CD_DATA_FRAMES_PER_SECOND * 2048 ), 0, attotime::from_hz( PCE_CD_DATA_FRAMES_PER_SECOND * 2048 ) );
+ pce_cd.regs[0x0c] |= 4;
+ }
+ break;
+ case 0x0C: /* ADPCM status */
+ break;
+ case 0x0D: /* ADPCM address control */
+ if ( ( pce_cd.regs[0x0D] & 0x80 ) && ! ( data & 0x80 ) ) // ADPCM reset
+ {
+ /* Reset ADPCM hardware */
+ pce_cd.adpcm_read_ptr = 0;
+ pce_cd.adpcm_write_ptr = 0;
+ pce_cd.msm_start_addr = 0;
+ pce_cd.msm_end_addr = 0;
+ pce_cd.msm_half_addr = 0;
+ pce_cd.msm_nibble = 0;
+ adpcm_stop(machine(), 0);
+ msm5205_reset_w( machine().device( "msm5205"), 1 );
+ }
+
+ if ( ( data & 0x40) && ((pce_cd.regs[0x0D] & 0x40) == 0) ) // ADPCM play
+ {
+ pce_cd.msm_start_addr = (pce_cd.adpcm_read_ptr);
+ pce_cd.msm_end_addr = (pce_cd.adpcm_read_ptr + pce_cd.adpcm_length) & 0xffff;
+ pce_cd.msm_half_addr = (pce_cd.adpcm_read_ptr + (pce_cd.adpcm_length / 2)) & 0xffff;
+ pce_cd.msm_nibble = 0;
+ adpcm_play(machine());
+ msm5205_reset_w( machine().device( "msm5205"), 0 );
+
+ //popmessage("%08x %08x",pce_cd.adpcm_read_ptr,pce_cd.adpcm_length);
+ }
+ else if ( (data & 0x40) == 0 )
+ {
+ /* used by Buster Bros to cancel an in-flight sample */
+ adpcm_stop(machine(), 0);
+ msm5205_reset_w( machine().device( "msm5205"), 1 );
+ }
+
+ pce_cd.msm_repeat = (data & 0x20) >> 5;
+
+ if ( data & 0x10 ) //ADPCM set length
+ {
+ pce_cd.adpcm_length = ( pce_cd.regs[0x09] << 8 ) | pce_cd.regs[0x08];
+ }
+ if ( data & 0x08 ) //ADPCM set read address
+ {
+ pce_cd.adpcm_read_ptr = ( pce_cd.regs[0x09] << 8 ) | pce_cd.regs[0x08];
+ pce_cd.adpcm_read_buf = 2;
+ }
+ if ( ( data & 0x02 ) == 0x02 ) //ADPCM set write address
+ {
+ pce_cd.adpcm_write_ptr = ( pce_cd.regs[0x09] << 8 ) | pce_cd.regs[0x08];
+ pce_cd.adpcm_write_buf = data & 1;
+ }
+ break;
+ case 0x0E: /* ADPCM playback rate */
+ pce_cd.adpcm_clock_divider = 0x10 - ( data & 0x0F );
+ msm5205_change_clock_w(machine().device("msm5205"), (PCE_CD_CLOCK / 6) / pce_cd.adpcm_clock_divider);
+ break;
+ case 0x0F: /* ADPCM and CD audio fade timer */
+ /* TODO: timers needs HW tests */
+ if(pce_cd.regs[0xf] != data)
+ {
+ switch(data & 0xf)
+ {
+ case 0x00: //CD-DA / ADPCM enable (100 msecs)
+ pce_cd.cdda_volume = 0.0;
+ pce_cd.cdda_fadein_timer->adjust(attotime::from_usec(100), 100);
+ pce_cd.adpcm_volume = 0.0;
+ pce_cd.adpcm_fadein_timer->adjust(attotime::from_usec(100), 100);
+ pce_cd.cdda_fadeout_timer->adjust(attotime::never);
+ pce_cd.adpcm_fadeout_timer->adjust(attotime::never);
+ break;
+ case 0x01: //CD-DA enable (100 msecs)
+ pce_cd.cdda_volume = 0.0;
+ pce_cd.cdda_fadein_timer->adjust(attotime::from_usec(100), 100);
+ pce_cd.cdda_fadeout_timer->adjust(attotime::never);
+ break;
+ case 0x08: //CD-DA short (1500 msecs) fade out / ADPCM enable
+ pce_cd.cdda_volume = 100.0;
+ pce_cd.cdda_fadeout_timer->adjust(attotime::from_usec(1500), 1500);
+ pce_cd.adpcm_volume = 0.0;
+ pce_cd.adpcm_fadein_timer->adjust(attotime::from_usec(100), 100);
+ pce_cd.cdda_fadein_timer->adjust(attotime::never);
+ pce_cd.adpcm_fadeout_timer->adjust(attotime::never);
+ break;
+ case 0x09: //CD-DA long (5000 msecs) fade out
+ pce_cd.cdda_volume = 100.0;
+ pce_cd.cdda_fadeout_timer->adjust(attotime::from_usec(5000), 5000);
+ pce_cd.cdda_fadein_timer->adjust(attotime::never);
+ break;
+ case 0x0a: //ADPCM long (5000 msecs) fade out
+ pce_cd.adpcm_volume = 100.0;
+ pce_cd.adpcm_fadeout_timer->adjust(attotime::from_usec(5000), 5000);
+ pce_cd.adpcm_fadein_timer->adjust(attotime::never);
+ break;
+ case 0x0c: //CD-DA short (1500 msecs) fade out / ADPCM enable
+ pce_cd.cdda_volume = 100.0;
+ pce_cd.cdda_fadeout_timer->adjust(attotime::from_usec(1500), 1500);
+ pce_cd.adpcm_volume = 0.0;
+ pce_cd.adpcm_fadein_timer->adjust(attotime::from_usec(100), 100);
+ pce_cd.cdda_fadein_timer->adjust(attotime::never);
+ pce_cd.adpcm_fadeout_timer->adjust(attotime::never);
+ break;
+ case 0x0d: //CD-DA short (1500 msecs) fade out
+ pce_cd.cdda_volume = 100.0;
+ pce_cd.cdda_fadeout_timer->adjust(attotime::from_usec(1500), 1500);
+ pce_cd.cdda_fadein_timer->adjust(attotime::never);
+ break;
+ case 0x0e: //ADPCM short (1500 msecs) fade out
+ pce_cd.adpcm_volume = 100.0;
+ pce_cd.adpcm_fadeout_timer->adjust(attotime::from_usec(1500), 1500);
+ pce_cd.adpcm_fadein_timer->adjust(attotime::never);
+ break;
+ default:
+ popmessage("CD-DA / ADPCM Fade effect mode %02x, contact MESSdev",data & 0x0f);
+ break;
+ }
+ }
+ break;
+ default:
+ return;
+ }
+ pce_cd.regs[offset & 0xf] = data;
+ pce_cd_update(machine());
+}
+
+static TIMER_CALLBACK( pce_cd_clear_ack )
+{
+ pce_state *state = machine.driver_data<pce_state>();
+ pce_cd_t &pce_cd = state->m_cd;
+ pce_cd_update(machine);
+ pce_cd.scsi_ACK = 0;
+ pce_cd_update(machine);
+ if ( pce_cd.scsi_CD )
+ {
+ pce_cd.regs[0x0B] &= 0xFE;
+ }
+}
+
+static UINT8 pce_cd_get_cd_data_byte(running_machine &machine)
+{
+ pce_state *state = machine.driver_data<pce_state>();
+ pce_cd_t &pce_cd = state->m_cd;
+ UINT8 data = pce_cd.regs[0x01];
+ if ( pce_cd.scsi_REQ && ! pce_cd.scsi_ACK && ! pce_cd.scsi_CD )
+ {
+ if ( pce_cd.scsi_IO )
+ {
+ pce_cd.scsi_ACK = 1;
+ machine.scheduler().timer_set(machine.device<cpu_device>("maincpu")->cycles_to_attotime(15), FUNC(pce_cd_clear_ack));
+ }
+ }
+ return data;
+}
+
+
+static TIMER_CALLBACK( pce_cd_adpcm_dma_timer_callback )
+{
+ pce_state *state = machine.driver_data<pce_state>();
+ pce_cd_t &pce_cd = state->m_cd;
+ if ( pce_cd.scsi_REQ && ! pce_cd.scsi_ACK && ! pce_cd.scsi_CD && pce_cd.scsi_IO )
+ {
+ pce_cd.adpcm_ram[pce_cd.adpcm_write_ptr] = pce_cd_get_cd_data_byte(machine);
+ pce_cd.adpcm_write_ptr = ( pce_cd.adpcm_write_ptr + 1 ) & 0xFFFF;
+
+ pce_cd.regs[0x0c] &= ~4;
+ }
+}
+
+static UINT8 pce_cd_get_adpcm_ram_byte(running_machine &machine)
+{
+ pce_state *state = machine.driver_data<pce_state>();
+ pce_cd_t &pce_cd = state->m_cd;
+ if(pce_cd.adpcm_read_buf > 0)
+ {
+ pce_cd.adpcm_read_buf--;
+ return 0;
+ }
+ else
+ {
+ UINT8 res;
+
+ res = pce_cd.adpcm_ram[pce_cd.adpcm_read_ptr];
+ pce_cd.adpcm_read_ptr = ((pce_cd.adpcm_read_ptr + 1) & 0xffff);
+
+ return res;
+ }
+}
+
+READ8_MEMBER(pce_state::pce_cd_intf_r)
+{
+ pce_cd_t &pce_cd = m_cd;
+ UINT8 data = pce_cd.regs[offset & 0x0F];
+
+ pce_cd_update(machine());
+
+ if(offset & 0x200 && m_sys3_card && m_acard) // route Arcade Card handling ports
+ return pce_cd_acard_r(space,offset);
+
+ logerror("%04X: read from CD interface offset %02X\n", cpu_get_pc(&space.device()), offset );
+
+ if((offset & 0xc0) == 0xc0 && m_sys3_card) //System 3 Card header handling
+ {
+ switch(offset & 0xcf)
+ {
+ case 0xc1: return 0xaa;
+ case 0xc2: return 0x55;
+ case 0xc3: return 0x00;
+ case 0xc5: return (m_sys3_card & 2) ? 0x55 : 0xaa;
+ case 0xc6: return (m_sys3_card & 2) ? 0xaa : 0x55;
+ case 0xc7: return 0x03;
+ }
+ }
+
+ switch( offset & 0xf )
+ {
+ case 0x00: /* CDC status */
+ data &= 0x07;
+ data |= pce_cd.scsi_BSY ? 0x80 : 0;
+ data |= pce_cd.scsi_REQ ? 0x40 : 0;
+ data |= pce_cd.scsi_MSG ? 0x20 : 0;
+ data |= pce_cd.scsi_CD ? 0x10 : 0;
+ data |= pce_cd.scsi_IO ? 0x08 : 0;
+ break;
+ case 0x01: /* CDC command / status / data */
+ break;
+ case 0x02: /* ADPCM / CD control */
+ break;
+ case 0x03: /* BRAM lock / CD status */
+ /* bit 4 set when CD motor is on */
+ /* bit 2 set when less than half of the ADPCM data is remaining ?? */
+ pce_cd.bram_locked = 1;
+ pce_set_cd_bram(machine());
+ data = data & 0x6E;
+ data |= ( pce_cd.cd_motor_on ? 0x10 : 0 );
+ pce_cd.regs[0x03] ^= 0x02; /* TODO: get rid of this hack */
+ break;
+ case 0x04: /* CD reset */
+ break;
+ case 0x05: /* Convert PCM data / PCM data */
+ case 0x06: /* PCM data */
+ break;
+ case 0x07: /* BRAM unlock / CD status */
+ data = ( pce_cd.bram_locked ? ( data & 0x7F ) : ( data | 0x80 ) );
+ break;
+ case 0x08: /* ADPCM address (LSB) / CD data */
+ data = pce_cd_get_cd_data_byte(machine());
+ break;
+ case 0x0A: /* ADPCM RAM data port */
+ data = pce_cd_get_adpcm_ram_byte(machine());
+ break;
+ case 0x0B: /* ADPCM DMA control */
+ break;
+ case 0x0C: /* ADPCM status */
+ break;
+ case 0x0D: /* ADPCM address control */
+ break;
+ /* These are read-only registers */
+ case 0x09: /* ADPCM address (MSB) */
+ case 0x0E: /* ADPCM playback rate */
+ case 0x0F: /* ADPCM and CD audio fade timer */
+ return 0;
+ default:
+ data = 0xFF;
+ break;
+ }
+
+ return data;
+}
+
+
+/*
+
+PC Engine Arcade Card emulation
+
+*/
+
+READ8_MEMBER(pce_state::pce_cd_acard_r)
+{
+ pce_cd_t &pce_cd = m_cd;
+ UINT8 r_num;
+
+ if((offset & 0x2e0) == 0x2e0)
+ {
+ switch(offset & 0x2ef)
+ {
+ case 0x2e0: return (pce_cd.acard_shift >> 0) & 0xff;
+ case 0x2e1: return (pce_cd.acard_shift >> 8) & 0xff;
+ case 0x2e2: return (pce_cd.acard_shift >> 16) & 0xff;
+ case 0x2e3: return (pce_cd.acard_shift >> 24) & 0xff;
+ case 0x2e4: return (pce_cd.acard_shift_reg);
+ case 0x2e5: return pce_cd.acard_latch;
+ case 0x2ee: return 0x10;
+ case 0x2ef: return 0x51;
+ }
+
+ return 0;
+ }
+
+ r_num = (offset & 0x30) >> 4;
+
+ switch(offset & 0x0f)
+ {
+ case 0x00:
+ case 0x01:
+ {
+ UINT8 res;
+ if(pce_cd.acard_ctrl[r_num] & 2)
+ res = pce_cd.acard_ram[(pce_cd.acard_base_addr[r_num] + pce_cd.acard_addr_offset[r_num]) & 0x1fffff];
+ else
+ res = pce_cd.acard_ram[pce_cd.acard_base_addr[r_num] & 0x1fffff];
+
+ if(pce_cd.acard_ctrl[r_num] & 0x1)
+ {
+ if(pce_cd.acard_ctrl[r_num] & 0x10)
+ {
+ pce_cd.acard_base_addr[r_num] += pce_cd.acard_addr_inc[r_num];
+ pce_cd.acard_base_addr[r_num] &= 0xffffff;
+ }
+ else
+ {
+ pce_cd.acard_addr_offset[r_num] += pce_cd.acard_addr_inc[r_num];
+ }
+ }
+
+ return res;
+ }
+ case 0x02: return (pce_cd.acard_base_addr[r_num] >> 0) & 0xff;
+ case 0x03: return (pce_cd.acard_base_addr[r_num] >> 8) & 0xff;
+ case 0x04: return (pce_cd.acard_base_addr[r_num] >> 16) & 0xff;
+ case 0x05: return (pce_cd.acard_addr_offset[r_num] >> 0) & 0xff;
+ case 0x06: return (pce_cd.acard_addr_offset[r_num] >> 8) & 0xff;
+ case 0x07: return (pce_cd.acard_addr_inc[r_num] >> 0) & 0xff;
+ case 0x08: return (pce_cd.acard_addr_inc[r_num] >> 8) & 0xff;
+ case 0x09: return pce_cd.acard_ctrl[r_num];
+ default: return 0;
+ }
+
+ return 0;
+}
+
+WRITE8_MEMBER(pce_state::pce_cd_acard_w)
+{
+ pce_cd_t &pce_cd = m_cd;
+ UINT8 w_num;
+
+ if((offset & 0x2e0) == 0x2e0)
+ {
+ switch(offset & 0x0f)
+ {
+ case 0: pce_cd.acard_shift = (data & 0xff) | (pce_cd.acard_shift & 0xffffff00); break;
+ case 1: pce_cd.acard_shift = (data << 8) | (pce_cd.acard_shift & 0xffff00ff); break;
+ case 2: pce_cd.acard_shift = (data << 16) | (pce_cd.acard_shift & 0xff00ffff); break;
+ case 3: pce_cd.acard_shift = (data << 24) | (pce_cd.acard_shift & 0x00ffffff); break;
+ case 4:
+ {
+ pce_cd.acard_shift_reg = data & 0x0f;
+
+ if(pce_cd.acard_shift_reg != 0)
+ {
+ pce_cd.acard_shift = (pce_cd.acard_shift_reg < 8) ?
+ (pce_cd.acard_shift << pce_cd.acard_shift_reg)
+ : (pce_cd.acard_shift >> (16 - pce_cd.acard_shift_reg));
+ }
+ }
+ break;
+ case 5: pce_cd.acard_latch = data; break;
+ }
+ }
+ else
+ {
+ w_num = (offset & 0x30) >> 4;
+
+ switch(offset & 0x0f)
+ {
+ case 0x00:
+ case 0x01:
+ if(pce_cd.acard_ctrl[w_num] & 2)
+ pce_cd.acard_ram[(pce_cd.acard_base_addr[w_num] + pce_cd.acard_addr_offset[w_num]) & 0x1fffff] = data;
+ else
+ pce_cd.acard_ram[pce_cd.acard_base_addr[w_num] & 0x1FFFFF] = data;
+
+ if(pce_cd.acard_ctrl[w_num] & 0x1)
+ {
+ if(pce_cd.acard_ctrl[w_num] & 0x10)
+ {
+ pce_cd.acard_base_addr[w_num] += pce_cd.acard_addr_inc[w_num];
+ pce_cd.acard_base_addr[w_num] &= 0xffffff;
+ }
+ else
+ {
+ pce_cd.acard_addr_offset[w_num] += pce_cd.acard_addr_inc[w_num];
+ }
+ }
+
+ break;
+
+ case 0x02: pce_cd.acard_base_addr[w_num] = (data & 0xff) | (pce_cd.acard_base_addr[w_num] & 0xffff00); break;
+ case 0x03: pce_cd.acard_base_addr[w_num] = (data << 8) | (pce_cd.acard_base_addr[w_num] & 0xff00ff); break;
+ case 0x04: pce_cd.acard_base_addr[w_num] = (data << 16) | (pce_cd.acard_base_addr[w_num] & 0x00ffff); break;
+ case 0x05: pce_cd.acard_addr_offset[w_num] = (data & 0xff) | (pce_cd.acard_addr_offset[w_num] & 0xff00); break;
+ case 0x06:
+ pce_cd.acard_addr_offset[w_num] = (data << 8) | (pce_cd.acard_addr_offset[w_num] & 0x00ff);
+
+ if((pce_cd.acard_ctrl[w_num] & 0x60) == 0x40)
+ {
+ pce_cd.acard_base_addr[w_num] += pce_cd.acard_addr_offset[w_num] + ((pce_cd.acard_ctrl[w_num] & 0x08) ? 0xff0000 : 0);
+ pce_cd.acard_base_addr[w_num] &= 0xffffff;
+ }
+ break;
+ case 0x07: pce_cd.acard_addr_inc[w_num] = (data & 0xff) | (pce_cd.acard_addr_inc[w_num] & 0xff00); break;
+ case 0x08: pce_cd.acard_addr_inc[w_num] = (data << 8) | (pce_cd.acard_addr_inc[w_num] & 0x00ff); break;
+ case 0x09: pce_cd.acard_ctrl[w_num] = data & 0x7f; break;
+ case 0x0a:
+ if((pce_cd.acard_ctrl[w_num] & 0x60) == 0x60)
+ {
+ pce_cd.acard_base_addr[w_num] += pce_cd.acard_addr_offset[w_num];
+ pce_cd.acard_base_addr[w_num] &= 0xffffff;
+ }
+ break;
+ }
+ }
+}
+
+READ8_MEMBER(pce_state::pce_cd_acard_wram_r)
+{
+ return pce_cd_intf_r(space,0x200 | (offset & 0x6000) >> 9);
+}
+
+WRITE8_MEMBER(pce_state::pce_cd_acard_wram_w)
+{
+ pce_cd_intf_w(space,0x200 | (offset & 0x6000) >> 9,data);
+}
+
diff --git a/src/mess/machine/pce220_ser.c b/src/mess/machine/pce220_ser.c
new file mode 100644
index 00000000000..67d7f1fef3d
--- /dev/null
+++ b/src/mess/machine/pce220_ser.c
@@ -0,0 +1,306 @@
+/****************************************************************************
+
+ pce220_ser.c
+
+ Sharp PC-E220/PC-G850V Serial I/O
+
+****************************************************************************/
+
+#include "emu.h"
+#include "pce220_ser.h"
+
+// SIO configuration
+#define SIO_BAUD_RATE 1200
+#define SIO_EOT_BYTE 0x1a
+#define SIO_DATA_BIT 8 // number of data bit
+#define SIO_PARITY 0 // 0=none 1=odd 2=even
+#define SIO_STOP_BIT 1 // number of stop bit
+
+//SIO states
+enum
+{
+ SIO_WAIT = 0,
+ SIO_SEND_START,
+ SIO_SEND_BIT0,
+ SIO_SEND_BIT1,
+ SIO_SEND_BIT2,
+ SIO_SEND_BIT3,
+ SIO_SEND_BIT4,
+ SIO_SEND_BIT5,
+ SIO_SEND_BIT6,
+ SIO_SEND_BIT7,
+ SIO_SEND_PARITY,
+ SIO_SEND_STOP1,
+ SIO_SEND_STOP2
+};
+
+// device type definition
+const device_type PCE220SERIAL = &device_creator<pce220_serial_device>;
+
+//-------------------------------------------------
+// pce220_serial_device - constructor
+//-------------------------------------------------
+
+pce220_serial_device::pce220_serial_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, PCE220SERIAL, "Sharp PC-E220 serial", tag, owner, clock),
+ device_image_interface(mconfig, *this)
+{
+}
+
+//-------------------------------------------------
+// pce220_serial_device - destructor
+//-------------------------------------------------
+
+pce220_serial_device::~pce220_serial_device()
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void pce220_serial_device::device_start()
+{
+ m_send_timer = timer_alloc(TIMER_SEND);
+ m_receive_timer = timer_alloc(TIMER_RECEIVE);
+ m_send_timer->reset();
+ m_receive_timer->reset();
+}
+
+
+//-------------------------------------------------
+// device_reset - reset up the device
+//-------------------------------------------------
+
+void pce220_serial_device::device_reset()
+{
+ m_state = SIO_WAIT;
+ m_bytes_count = 0;
+ m_dout = m_busy = m_xout = 0;
+ m_din = m_xin = m_ack = 0;
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void pce220_serial_device::device_config_complete()
+{
+ // set brief and instance name
+ update_names();
+}
+
+
+//-------------------------------------------------
+// device_timer - handler timer events
+//-------------------------------------------------
+
+void pce220_serial_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ if (id == TIMER_SEND && m_enabled)
+ {
+ //send data
+ if (m_bytes_count <= length())
+ {
+ switch(m_state)
+ {
+ case SIO_WAIT:
+ m_ack = 1; //data send request
+ //waits until is ready to receive
+ if(!m_busy)
+ return;
+ break;
+ case SIO_SEND_START:
+ //send start bit
+ m_xin = 1;
+ break;
+ case SIO_SEND_BIT0:
+ case SIO_SEND_BIT1:
+ case SIO_SEND_BIT2:
+ case SIO_SEND_BIT3:
+ case SIO_SEND_BIT4:
+ case SIO_SEND_BIT5:
+ case SIO_SEND_BIT6:
+ case SIO_SEND_BIT7:
+ m_xin = BIT(~m_current_byte, m_state - SIO_SEND_BIT0);
+ break;
+ case SIO_SEND_PARITY:
+ m_xin = calc_parity(m_current_byte);
+ break;
+ case SIO_SEND_STOP1:
+ case SIO_SEND_STOP2:
+ //stop bit
+ m_xin = m_ack = 0;
+ break;
+ }
+
+ if (m_state == (SIO_SEND_PARITY + SIO_STOP_BIT))
+ {
+ //next byte
+ m_bytes_count++;
+ popmessage("Send %d/%d bytes\n", m_bytes_count , (UINT32)length());
+ m_state = SIO_WAIT;
+ if (m_bytes_count < length())
+ fread(&m_current_byte, 1);
+ else
+ m_current_byte = SIO_EOT_BYTE;
+ }
+ else
+ {
+ m_state = get_next_state();
+ }
+
+ }
+ else
+ {
+ m_din = m_xin = m_ack = 0;
+ }
+ }
+ else if (id == TIMER_RECEIVE && m_enabled)
+ {
+ //receive data
+ switch(m_state)
+ {
+ case SIO_WAIT:
+ //wait send request
+ if(m_busy)
+ return;
+ m_ack = 1; //acknowledge
+ break;
+ case SIO_SEND_START:
+ //wait for the start bit
+ if (!m_xout)
+ return;
+ break;
+ case SIO_SEND_BIT0:
+ case SIO_SEND_BIT1:
+ case SIO_SEND_BIT2:
+ case SIO_SEND_BIT3:
+ case SIO_SEND_BIT4:
+ case SIO_SEND_BIT5:
+ case SIO_SEND_BIT6:
+ case SIO_SEND_BIT7:
+ m_current_byte |= ((~m_xout)&1) << (m_state - SIO_SEND_BIT0);
+ break;
+ case SIO_SEND_PARITY:
+ if (m_xout != calc_parity(m_current_byte))
+ logerror("SIO %s: byte %d has wrong parity!\n", tag(), m_bytes_count);
+ break;
+ case SIO_SEND_STOP1:
+ case SIO_SEND_STOP2:
+ //receive stop bit
+ m_ack = 0;
+ break;
+ }
+
+ if (m_state == (SIO_SEND_PARITY + SIO_STOP_BIT))
+ {
+ //next byte
+ m_bytes_count++;
+ popmessage("Received %d bytes\n", m_bytes_count);
+ m_state = SIO_WAIT;
+ if (m_current_byte != SIO_EOT_BYTE)
+ fwrite(&m_current_byte, 1);
+ m_current_byte = 0;
+ }
+ else
+ {
+ m_state = get_next_state();
+ }
+ }
+ else
+ {
+ m_din = m_xin = m_ack = 0;
+ }
+}
+
+/*-------------------------------------------------
+ DEVICE_IMAGE_LOAD( pce220_serial )
+-------------------------------------------------*/
+
+bool pce220_serial_device::call_load()
+{
+ m_state = SIO_WAIT;
+ m_bytes_count = 0;
+ m_send_timer->adjust(attotime::from_hz(SIO_BAUD_RATE), 0, attotime::from_hz(SIO_BAUD_RATE));
+
+ //read the first byte
+ fread(&m_current_byte, 1);
+
+ return IMAGE_INIT_PASS;
+}
+
+/*-------------------------------------------------
+ DEVICE_IMAGE_CREATE( pce220_serial )
+-------------------------------------------------*/
+
+bool pce220_serial_device::call_create(int format_type, option_resolution *format_options)
+{
+ m_state = SIO_WAIT;
+ m_bytes_count = 0;
+ m_current_byte = 0;
+ m_receive_timer->adjust(attotime::from_hz(SIO_BAUD_RATE), 0, attotime::from_hz(SIO_BAUD_RATE));
+
+ return IMAGE_INIT_PASS;
+}
+
+
+/*-------------------------------------------------
+ DEVICE_IMAGE_UNLOAD( pce220_serial )
+-------------------------------------------------*/
+
+void pce220_serial_device::call_unload()
+{
+ m_send_timer->reset();
+ m_receive_timer->reset();
+ m_state = SIO_WAIT;
+ m_bytes_count = 0;
+ m_current_byte = 0;
+}
+
+
+/*-------------------------------------------------
+ calculate the byte parity
+-------------------------------------------------*/
+
+int pce220_serial_device::calc_parity(UINT8 data)
+{
+ UINT8 count = 0;
+
+ while(data != 0)
+ {
+ count++;
+ data &= (data-1);
+ }
+
+ return (count ^ BIT(SIO_PARITY, 1)) & 1;
+}
+
+
+/*-------------------------------------------------
+ returns the next SIO state basing on the
+ configuration
+-------------------------------------------------*/
+
+int pce220_serial_device::get_next_state()
+{
+ switch(m_state)
+ {
+ case SIO_SEND_BIT6:
+ if (SIO_DATA_BIT == 8)
+ return SIO_SEND_BIT7;
+ //fall through
+ case SIO_SEND_BIT7:
+ return (SIO_PARITY ? SIO_SEND_PARITY : SIO_SEND_STOP1);
+ case SIO_SEND_STOP1:
+ case SIO_SEND_STOP2:
+ return (SIO_STOP_BIT == 2 ? SIO_SEND_STOP2 : SIO_SEND_STOP1);
+ default:
+ return m_state + 1;
+ }
+}
+
diff --git a/src/mess/machine/pce220_ser.h b/src/mess/machine/pce220_ser.h
new file mode 100644
index 00000000000..8b22e99d26f
--- /dev/null
+++ b/src/mess/machine/pce220_ser.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+
+ pce220_ser.h
+
+ Sharp PC-E220/PC-G850V Serial I/O
+
+****************************************************************************/
+
+#ifndef __PCE220_SER_H__
+#define __PCE220_SER_H__
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+// ======================> pce220_serial_device
+
+class pce220_serial_device : public device_t,
+ public device_image_interface
+{
+public:
+ // construction/destruction
+ pce220_serial_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ virtual ~pce220_serial_device();
+
+ // image-level overrides
+ virtual bool call_load();
+ virtual void call_unload();
+ virtual bool call_create(int format_type, option_resolution *format_options);
+
+ 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 *image_interface() const { return NULL; }
+ virtual const char *file_extensions() const { return "txt,ihx"; }
+ virtual const option_guide *create_option_guide() const { return NULL; }
+
+ // specific implementation
+ UINT8 in_xin(void) { return m_xin & 0x01; }
+ UINT8 in_din(void) { return m_din & 0x01; }
+ UINT8 in_ack(void) { return m_ack & 0x01; }
+ void out_busy(UINT8 state) { m_busy = state & 0x01; }
+ void out_dout(UINT8 state) { m_dout = state & 0x01; }
+ void out_xout(UINT8 state) { m_xout = state & 0x01; }
+ void enable_interface(UINT8 state) { m_enabled = state & 0x01; }
+
+protected:
+ // internal helpers
+ int calc_parity(UINT8 data);
+ int get_next_state();
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+private:
+ // internal device state
+ static const device_timer_id TIMER_SEND = 0;
+ static const device_timer_id TIMER_RECEIVE = 1;
+
+ emu_timer* m_send_timer; // timer for send data
+ emu_timer* m_receive_timer; // timer for receive data
+ UINT8 m_state; // transfer status
+ UINT32 m_bytes_count; // number of bytes transferred
+ UINT8 m_current_byte; // byte in transfer
+ UINT8 m_enabled; // enable/disable
+
+ UINT8 m_busy; // CTS
+ UINT8 m_dout; // DTR
+ UINT8 m_xout; // TXD
+ UINT8 m_xin; // RXD
+ UINT8 m_din; // DSR
+ UINT8 m_ack; // RTS
+};
+
+// device type definition
+extern const device_type PCE220SERIAL;
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+#define PCE220SERIAL_TAG "serial"
+
+#define MCFG_PCE220_SERIAL_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, PCE220SERIAL, 0) \
+
+#endif /* __PCE220_SER_H__ */
diff --git a/src/mess/machine/pcf8593.c b/src/mess/machine/pcf8593.c
new file mode 100644
index 00000000000..3f29b847538
--- /dev/null
+++ b/src/mess/machine/pcf8593.c
@@ -0,0 +1,474 @@
+/*********************************************************************
+
+ Philips PCF8593 CMOS clock/calendar circuit
+
+ (c) 2001-2007 Tim Schuerewegen
+
+*********************************************************************/
+
+#include <time.h>
+#include "pcf8593.h"
+
+
+/***************************************************************************
+ PARAMETERS/CONSTANTS/MACROS
+***************************************************************************/
+
+#define LOG_LEVEL 1
+#define _logerror(level,x) do { if (LOG_LEVEL > level) logerror x; } while (0)
+
+#define RTC_MODE_NONE 0
+#define RTC_MODE_SEND 1
+#define RTC_MODE_RECV 2
+
+// get/set date
+#define RTC_GET_DATE_YEAR ((rtc->data[5] >> 6) & 3)
+#define RTC_SET_DATE_YEAR(x) rtc->data[5] = (rtc->data[5] & 0x3F) | (((x) % 4) << 6)
+#define RTC_GET_DATE_MONTH bcd_to_dec( rtc->data[6])
+#define RTC_SET_DATE_MONTH(x) rtc->data[6] = dec_to_bcd( x)
+#define RTC_GET_DATE_DAY (bcd_to_dec( rtc->data[5] & 0x3F))
+#define RTC_SET_DATE_DAY(x) rtc->data[5] = (rtc->data[5] & 0xC0) | dec_to_bcd( x)
+
+// get/set time
+#define RTC_GET_TIME_HOUR bcd_to_dec( rtc->data[4])
+#define RTC_SET_TIME_HOUR(x) rtc->data[4] = dec_to_bcd( x)
+#define RTC_GET_TIME_MINUTE bcd_to_dec( rtc->data[3])
+#define RTC_SET_TIME_MINUTE(x) rtc->data[3] = dec_to_bcd( x)
+#define RTC_GET_TIME_SECOND bcd_to_dec( rtc->data[2])
+#define RTC_SET_TIME_SECOND(x) rtc->data[2] = dec_to_bcd( x)
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _pcf8593_t pcf8593_t;
+struct _pcf8593_t
+{
+ UINT8 data[16];
+ int pin_scl, pin_sda, inp;
+ int active;
+ int bits;
+ UINT8 data_recv_index, data_recv[50];
+ UINT8 mode, pos;
+ emu_timer *timer;
+};
+
+
+/***************************************************************************
+ PROTOTYPES
+***************************************************************************/
+
+static void pcf8593_clear_buffer_rx(device_t *device);
+static TIMER_CALLBACK( pcf8593_timer_callback );
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+INLINE pcf8593_t *get_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == PCF8593);
+
+ return (pcf8593_t *) downcast<legacy_device_base *>(device)->token();
+}
+
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ DEVICE_START( pcf8593 )
+-------------------------------------------------*/
+
+static DEVICE_START( pcf8593 )
+{
+ pcf8593_t *rtc = get_token(device);
+
+ _logerror( 0, ("pcf8593_init\n"));
+ memset( rtc, 0, sizeof(*rtc));
+ rtc->timer = device->machine().scheduler().timer_alloc(FUNC(pcf8593_timer_callback), (void *) device);
+ rtc->timer->adjust(attotime::from_seconds(1), 0, attotime::from_seconds(1));
+}
+
+
+
+/*-------------------------------------------------
+ DEVICE_RESET( pcf8593 )
+-------------------------------------------------*/
+
+static DEVICE_RESET( pcf8593 )
+{
+ pcf8593_t *rtc = get_token(device);
+
+ _logerror( 0, ("pcf8593_reset\n"));
+ rtc->pin_scl = 1;
+ rtc->pin_sda = 1;
+ rtc->active = FALSE;
+ rtc->inp = 0;
+ rtc->mode = RTC_MODE_RECV;
+ rtc->bits = 0;
+ pcf8593_clear_buffer_rx(device);
+ rtc->pos = 0;
+}
+
+
+
+/*-------------------------------------------------
+ pcf8593_pin_scl
+-------------------------------------------------*/
+
+void pcf8593_pin_scl(device_t *device, int data)
+{
+ pcf8593_t *rtc = get_token(device);
+
+ // send bit
+ if ((rtc->active) && (!rtc->pin_scl) && (data))
+ {
+ switch (rtc->mode)
+ {
+ // HOST -> RTC
+ case RTC_MODE_RECV :
+ {
+ // get bit
+ if (rtc->pin_sda) rtc->data_recv[rtc->data_recv_index] = rtc->data_recv[rtc->data_recv_index] | (0x80 >> rtc->bits);
+ rtc->bits++;
+ // bit 9 = end
+ if (rtc->bits > 8)
+ {
+ _logerror( 2, ("pcf8593_write_byte(%02X)\n", rtc->data_recv[rtc->data_recv_index]));
+ // enter receive mode when 1st byte = 0xA3
+ if ((rtc->data_recv[0] == 0xA3) && (rtc->data_recv_index == 0))
+ {
+ rtc->mode = RTC_MODE_SEND;
+ }
+ // A2 + xx = "read from pos xx" command
+ if ((rtc->data_recv[0] == 0xA2) && (rtc->data_recv_index == 1))
+ {
+ rtc->pos = rtc->data_recv[1];
+ }
+ // A2 + xx + .. = write byte
+ if ((rtc->data_recv[0] == 0xA2) && (rtc->data_recv_index >= 2))
+ {
+ UINT8 rtc_pos, rtc_val;
+ rtc_pos = rtc->data_recv[1] + (rtc->data_recv_index - 2);
+ rtc_val = rtc->data_recv[rtc->data_recv_index];
+ //if (rtc_pos == 0) rtc_val = rtc_val & 3; // what is this doing here?
+ rtc->data[rtc_pos] = rtc_val;
+ }
+ // next byte
+ rtc->bits = 0;
+ rtc->data_recv_index++;
+ }
+ }
+ break;
+ // RTC -> HOST
+ case RTC_MODE_SEND :
+ {
+ // set bit
+ rtc->inp = (rtc->data[rtc->pos] >> (7 - rtc->bits)) & 1;
+ rtc->bits++;
+ // bit 9 = end
+ if (rtc->bits > 8)
+ {
+ _logerror( 2, ("pcf8593_read_byte(%02X)\n", rtc->data[rtc->pos]));
+ // end ?
+ if (rtc->pin_sda)
+ {
+ _logerror( 2, ("pcf8593 end\n"));
+ rtc->mode = RTC_MODE_RECV;
+ pcf8593_clear_buffer_rx(device);
+ }
+ // next byte
+ rtc->bits = 0;
+ rtc->pos++;
+ }
+ }
+ break;
+ }
+ }
+ // save scl
+ rtc->pin_scl = data;
+}
+
+
+
+/*-------------------------------------------------
+ pcf8593_pin_sda_w
+-------------------------------------------------*/
+
+void pcf8593_pin_sda_w(device_t *device, int data)
+{
+ pcf8593_t *rtc = get_token(device);
+
+ // clock is high
+ if (rtc->pin_scl)
+ {
+ // log init I2C
+ if (data) _logerror( 1, ("pcf8593 init i2c\n"));
+ // start condition (high to low when clock is high)
+ if ((!data) && (rtc->pin_sda))
+ {
+ _logerror( 1, ("pcf8593 start condition\n"));
+ rtc->active = TRUE;
+ rtc->bits = 0;
+ rtc->data_recv_index = 0;
+ pcf8593_clear_buffer_rx(device);
+ //rtc->pos = 0;
+ }
+ // stop condition (low to high when clock is high)
+ if ((data) && (!rtc->pin_sda))
+ {
+ _logerror( 1, ("pcf8593 stop condition\n"));
+ rtc->active = FALSE;
+ }
+ }
+ // save sda
+ rtc->pin_sda = data;
+}
+
+
+
+/*-------------------------------------------------
+ pcf8593_pin_sda_r
+-------------------------------------------------*/
+
+int pcf8593_pin_sda_r(device_t *device)
+{
+ pcf8593_t *rtc = get_token(device);
+ return rtc->inp;
+}
+
+
+
+/*-------------------------------------------------
+ pcf8593_clear_buffer_rx
+-------------------------------------------------*/
+
+void pcf8593_clear_buffer_rx(device_t *device)
+{
+ pcf8593_t *rtc = get_token(device);
+ memset( &rtc->data_recv[0], 0, sizeof( rtc->data_recv));
+ rtc->data_recv_index = 0;
+}
+
+
+
+/*-------------------------------------------------
+ dec_to_bcd
+-------------------------------------------------*/
+
+static UINT8 dec_to_bcd( UINT8 data)
+{
+ return ((data / 10) << 4) | ((data % 10) << 0);
+}
+
+
+
+/*-------------------------------------------------
+ bcd_to_dec
+-------------------------------------------------*/
+
+static UINT8 bcd_to_dec( UINT8 data)
+{
+ if ((data & 0x0F) >= 0x0A) data = data - 0x0A + 0x10;
+ if ((data & 0xF0) >= 0xA0) data = data - 0xA0;
+ return (data & 0x0F) + (((data & 0xF0) >> 4) * 10);
+}
+
+
+
+/*-------------------------------------------------
+ bcd_to_dec
+-------------------------------------------------*/
+
+static void pcf8593_set_time(device_t *device, int hour, int minute, int second)
+{
+ pcf8593_t *rtc = get_token(device);
+ RTC_SET_TIME_HOUR( hour);
+ RTC_SET_TIME_MINUTE( minute);
+ RTC_SET_TIME_SECOND( second);
+ rtc->data[1] = 0; // hundreds of a seconds
+}
+
+
+
+/*-------------------------------------------------
+ pcf8593_set_date
+-------------------------------------------------*/
+
+static void pcf8593_set_date(device_t *device, int year, int month, int day)
+{
+ pcf8593_t *rtc = get_token(device);
+ RTC_SET_DATE_YEAR( year);
+ RTC_SET_DATE_MONTH( month);
+ RTC_SET_DATE_DAY( day);
+}
+
+
+
+/*-------------------------------------------------
+ get_days_in_month
+-------------------------------------------------*/
+
+static int get_days_in_month( int year, int month)
+{
+ static const int table[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+ if ((month == 2) && ((year & 0x03) == 0)) return 29;
+ return table[month-1];
+}
+
+
+
+/*-------------------------------------------------
+ TIMER_CALLBACK( pcf8593_timer_callback )
+-------------------------------------------------*/
+
+static TIMER_CALLBACK( pcf8593_timer_callback )
+{
+ device_t *device = (device_t *) ptr;
+ pcf8593_t *rtc = get_token(device);
+ int value;
+
+ _logerror( 2, ("pcf8593_timer_callback (%d)\n", param));
+ // check if counting is enabled
+ if (rtc->data[0] & 0x80) return;
+ // increment second
+ value = RTC_GET_TIME_SECOND;
+ if (value < 59)
+ {
+ RTC_SET_TIME_SECOND( value + 1);
+ }
+ else
+ {
+ RTC_SET_TIME_SECOND( 0);
+ // increment minute
+ value = RTC_GET_TIME_MINUTE;
+ if (value < 59)
+ {
+ RTC_SET_TIME_MINUTE( value + 1);
+ }
+ else
+ {
+ RTC_SET_TIME_MINUTE( 0);
+ // increment hour
+ value = RTC_GET_TIME_HOUR;
+ if (value < 23)
+ {
+ RTC_SET_TIME_HOUR( value + 1);
+ }
+ else
+ {
+ RTC_SET_TIME_HOUR( 0);
+ // increment day
+ value = RTC_GET_DATE_DAY;
+ if (value < get_days_in_month( RTC_GET_DATE_YEAR, RTC_GET_DATE_MONTH))
+ {
+ RTC_SET_DATE_DAY( value + 1);
+ }
+ else
+ {
+ RTC_SET_DATE_DAY( 1);
+ // increase month
+ value = RTC_GET_DATE_MONTH;
+ if (value < 12)
+ {
+ RTC_SET_DATE_MONTH( value + 1);
+ }
+ else
+ {
+ RTC_SET_DATE_MONTH( 1);
+ // increase year
+ RTC_SET_DATE_YEAR( RTC_GET_DATE_YEAR + 1);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+
+/*-------------------------------------------------
+ pcf8593_load
+-------------------------------------------------*/
+
+void pcf8593_load(device_t *device, emu_file *file)
+{
+ pcf8593_t *rtc = get_token(device);
+ system_time systime;
+
+ _logerror( 0, ("pcf8593_load (%p)\n", file));
+ file->read(rtc->data, sizeof(rtc->data));
+ device->machine().current_datetime(systime);
+ pcf8593_set_date(device, systime.local_time.year, systime.local_time.month + 1, systime.local_time.mday);
+ pcf8593_set_time(device, systime.local_time.hour, systime.local_time.minute, systime.local_time.second);
+}
+
+
+
+/*-------------------------------------------------
+ pcf8593_save
+-------------------------------------------------*/
+
+void pcf8593_save(device_t *device, emu_file *file)
+{
+ pcf8593_t *rtc = get_token(device);
+
+ _logerror( 0, ("pcf8593_save (%p)\n", file));
+ file->write(rtc->data, sizeof(rtc->data));
+}
+
+#ifdef UNUSED_FUNCTION
+NVRAM_HANDLER( pcf8593 )
+{
+ _logerror( 0, ("nvram_handler_pcf8593 (%p/%d)\n", file, read_or_write));
+ if (read_or_write)
+ {
+ pcf8593_save( file);
+ }
+ else
+ {
+ if (file)
+ {
+ pcf8593_load( file);
+ }
+ else
+ {
+ memset( rtc->data, 0, rtc->size);
+ }
+ }
+}
+#endif
+
+
+/*-------------------------------------------------
+ DEVICE_GET_INFO( pcf8593 )
+-------------------------------------------------*/
+
+DEVICE_GET_INFO( pcf8593 )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(pcf8593_t); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(pcf8593); break;
+ case DEVINFO_FCT_STOP: /* Nothing */ break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(pcf8593); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "PCF8593 RTC"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "PCF8593 RTC"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: /* Nothing */ break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(PCF8593, pcf8593);
diff --git a/src/mess/machine/pcf8593.h b/src/mess/machine/pcf8593.h
new file mode 100644
index 00000000000..23be2198bb4
--- /dev/null
+++ b/src/mess/machine/pcf8593.h
@@ -0,0 +1,41 @@
+/*********************************************************************
+
+ Philips PCF8593 CMOS clock/calendar circuit
+
+ (c) 2001-2007 Tim Schuerewegen
+
+*********************************************************************/
+
+#ifndef __PCF8593_H__
+#define __PCF8593_H__
+
+#include "emu.h"
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+DECLARE_LEGACY_DEVICE(PCF8593, pcf8593);
+
+#define MCFG_PCF8593_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, PCF8593, 0) \
+
+#define MCFG_PCF8593_REMOVE(_tag) \
+ MCFG_DEVICE_REMOVE(_tag)
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+/* pins */
+void pcf8593_pin_scl(device_t *device, int data);
+void pcf8593_pin_sda_w(device_t *device, int data);
+int pcf8593_pin_sda_r(device_t *device);
+
+/* load/save */
+void pcf8593_load(device_t *device, emu_file *file);
+void pcf8593_save(device_t *device, emu_file *file);
+
+#endif /* __PCF8593_H__ */
diff --git a/src/mess/machine/pecom.c b/src/mess/machine/pecom.c
new file mode 100644
index 00000000000..4e590321996
--- /dev/null
+++ b/src/mess/machine/pecom.c
@@ -0,0 +1,193 @@
+/***************************************************************************
+
+ Pecom driver by Miodrag Milanovic
+
+ 08/11/2008 Preliminary driver.
+
+****************************************************************************/
+
+#include "emu.h"
+#include "cpu/cosmac/cosmac.h"
+#include "sound/cdp1869.h"
+#include "machine/ram.h"
+#include "includes/pecom.h"
+
+static TIMER_CALLBACK( reset_tick )
+{
+ pecom_state *state = machine.driver_data<pecom_state>();
+
+ state->m_reset = 1;
+}
+
+MACHINE_START( pecom )
+{
+ pecom_state *state = machine.driver_data<pecom_state>();
+ state->m_reset_timer = machine.scheduler().timer_alloc(FUNC(reset_tick));
+}
+
+MACHINE_RESET( pecom )
+{
+ UINT8 *rom = machine.root_device().memregion(CDP1802_TAG)->base();
+ address_space *space = machine.device(CDP1802_TAG)->memory().space(AS_PROGRAM);
+
+ pecom_state *state = machine.driver_data<pecom_state>();
+
+ space->unmap_write(0x0000, 0x3fff);
+ space->install_write_bank(0x4000, 0x7fff, "bank2");
+ space->unmap_write(0xf000, 0xf7ff);
+ space->unmap_write(0xf800, 0xffff);
+ space->install_read_bank (0xf000, 0xf7ff, "bank3");
+ space->install_read_bank (0xf800, 0xffff, "bank4");
+ state->membank("bank1")->set_base(rom + 0x8000);
+ state->membank("bank2")->set_base(machine.device<ram_device>(RAM_TAG)->pointer() + 0x4000);
+ state->membank("bank3")->set_base(rom + 0xf000);
+ state->membank("bank4")->set_base(rom + 0xf800);
+
+ state->m_reset = 0;
+ state->m_dma = 0;
+ state->m_reset_timer->adjust(attotime::from_msec(5));
+}
+
+READ8_MEMBER(pecom_state::pecom_cdp1869_charram_r)
+{
+ return m_cdp1869->char_ram_r(space, offset);
+}
+
+WRITE8_MEMBER(pecom_state::pecom_cdp1869_charram_w)
+{
+ return m_cdp1869->char_ram_w(space, offset, data);
+}
+
+READ8_MEMBER(pecom_state::pecom_cdp1869_pageram_r)
+{
+ return m_cdp1869->page_ram_r(space, offset);
+}
+
+WRITE8_MEMBER(pecom_state::pecom_cdp1869_pageram_w)
+{
+ return m_cdp1869->page_ram_w(space, offset, data);
+}
+
+WRITE8_MEMBER(pecom_state::pecom_bank_w)
+{
+ address_space *space2 = machine().device(CDP1802_TAG)->memory().space(AS_PROGRAM);
+ UINT8 *rom = memregion(CDP1802_TAG)->base();
+ machine().device(CDP1802_TAG)->memory().space(AS_PROGRAM)->install_write_bank(0x0000, 0x3fff, "bank1");
+ membank("bank1")->set_base(machine().device<ram_device>(RAM_TAG)->pointer() + 0x0000);
+
+ if (data==2)
+ {
+ space2->install_read_handler (0xf000, 0xf7ff, read8_delegate(FUNC(pecom_state::pecom_cdp1869_charram_r),this));
+ space2->install_write_handler(0xf000, 0xf7ff, write8_delegate(FUNC(pecom_state::pecom_cdp1869_charram_w),this));
+ space2->install_read_handler (0xf800, 0xffff, read8_delegate(FUNC(pecom_state::pecom_cdp1869_pageram_r),this));
+ space2->install_write_handler(0xf800, 0xffff, write8_delegate(FUNC(pecom_state::pecom_cdp1869_pageram_w),this));
+ }
+ else
+ {
+ space2->unmap_write(0xf000, 0xf7ff);
+ space2->unmap_write(0xf800, 0xffff);
+ space2->install_read_bank (0xf000, 0xf7ff, "bank3");
+ space2->install_read_bank (0xf800, 0xffff, "bank4");
+ membank("bank3")->set_base(rom + 0xf000);
+ membank("bank4")->set_base(rom + 0xf800);
+ }
+}
+
+READ8_MEMBER(pecom_state::pecom_keyboard_r)
+{
+ static const char *const keynames[] = {
+ "LINE0", "LINE1", "LINE2", "LINE3", "LINE4", "LINE5", "LINE6", "LINE7",
+ "LINE8", "LINE9", "LINE10", "LINE11", "LINE12", "LINE13", "LINE14", "LINE15", "LINE16",
+ "LINE17", "LINE18", "LINE19", "LINE20", "LINE21", "LINE22", "LINE23", "LINE24","LINE25"
+ };
+ /*
+ INP command BUS -> M(R(X)) BUS -> D
+ so on each input, address is also set, 8 lower bits are used as input for keyboard
+ Address is available on address bus during reading of value from port, and that is
+ used to determine keyboard line reading
+ */
+ UINT16 addr = cpu_get_reg(machine().device(CDP1802_TAG), COSMAC_R0 + cpu_get_reg(machine().device(CDP1802_TAG), COSMAC_X));
+ /* just in case somone is reading non existing ports */
+ if (addr<0x7cca || addr>0x7ce3) return 0;
+ return ioport(keynames[addr - 0x7cca])->read() & 0x03;
+}
+
+/* CDP1802 Interface */
+
+static READ_LINE_DEVICE_HANDLER( clear_r )
+{
+ pecom_state *state = device->machine().driver_data<pecom_state>();
+
+ return state->m_reset;
+}
+
+static READ_LINE_DEVICE_HANDLER( ef2_r )
+{
+ int shift = BIT(device->machine().root_device().ioport("CNT")->read(), 1);
+ double cas = dynamic_cast<cassette_image_device *>(device)->input();
+
+ return (cas > 0.0) | shift;
+}
+
+/*
+static COSMAC_EF_READ( pecom64_ef_r )
+{
+ int flags = 0x0f;
+ double valcas = (cassette_device_image(device->machine()));->input()
+ UINT8 val = device->machine().root_device().ioport("CNT")->read();
+
+ if ((val & 0x04)==0x04 && pecom_prev_caps_state==0)
+ {
+ pecom_caps_state = (pecom_caps_state==4) ? 0 : 4; // Change CAPS state
+ }
+ pecom_prev_caps_state = val & 0x04;
+ if (valcas!=0.0)
+ { // If there is any cassette signal
+ val = (val & 0x0D); // remove EF2 from SHIFT
+ flags -= EF2;
+ if ( valcas > 0.00) flags += EF2;
+ }
+ flags -= (val & 0x0b) + pecom_caps_state;
+ return flags;
+}
+*/
+static WRITE_LINE_DEVICE_HANDLER( pecom64_q_w )
+{
+ dynamic_cast<cassette_image_device *>(device)->output(state ? -1.0 : +1.0);
+}
+
+static COSMAC_SC_WRITE( pecom64_sc_w )
+{
+ switch (sc)
+ {
+ case COSMAC_STATE_CODE_S0_FETCH:
+ // not connected
+ break;
+
+ case COSMAC_STATE_CODE_S1_EXECUTE:
+ break;
+
+ case COSMAC_STATE_CODE_S2_DMA:
+ // DMA acknowledge clears the DMAOUT request
+ cputag_set_input_line(device->machine(), CDP1802_TAG, COSMAC_INPUT_LINE_DMAOUT, CLEAR_LINE);
+ break;
+ case COSMAC_STATE_CODE_S3_INTERRUPT:
+ break;
+ }
+}
+
+COSMAC_INTERFACE( pecom64_cdp1802_config )
+{
+ DEVCB_LINE_VCC,
+ DEVCB_LINE(clear_r),
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE(CASSETTE_TAG, ef2_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE(CASSETTE_TAG, pecom64_q_w),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ pecom64_sc_w,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
diff --git a/src/mess/machine/pet.c b/src/mess/machine/pet.c
new file mode 100644
index 00000000000..e39fa20668a
--- /dev/null
+++ b/src/mess/machine/pet.c
@@ -0,0 +1,840 @@
+/***************************************************************************
+ commodore pet series computer
+
+ peter.trauner@jk.uni-linz.ac.at
+***************************************************************************/
+
+#include "emu.h"
+#include "cpu/m6502/m6502.h"
+#include "cpu/m6809/m6809.h"
+
+#include "machine/6821pia.h"
+#include "machine/6522via.h"
+#include "machine/ieee488.h"
+
+#include "includes/pet.h"
+
+#include "imagedev/cartslot.h"
+#include "imagedev/cassette.h"
+#include "machine/ram.h"
+
+#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)
+
+
+
+/* pia at 0xe810
+ port a
+ 7 sense input (low for diagnostics)
+ 6 ieee eoi in
+ 5 cassette 2 switch in
+ 4 cassette 1 switch in
+ 3..0 keyboard line select
+
+ ca1 cassette 1 read
+ ca2 ieee eoi out
+
+ cb1 video sync in
+ cb2 cassette 1 motor out
+*/
+static READ8_DEVICE_HANDLER( pia0_pa_r )
+{
+ pet_state *state = device->machine().driver_data<pet_state>();
+ /*
+
+ bit description
+
+ PA0 KEY A
+ PA1 KEY B
+ PA2 KEY C
+ PA3 KEY D
+ PA4 #1 CASS SWITCH
+ PA5 #2 CASS SWITCH
+ PA6 _EOI IN
+ PA7 DIAG JUMPER
+
+ */
+
+ UINT8 data = 0;
+
+ /* key */
+ data |= state->m_keyline_select;
+
+ /* #1 cassette switch */
+ data |= ((device->machine().device<cassette_image_device>(CASSETTE_TAG)->get_state() & CASSETTE_MASK_UISTATE) == CASSETTE_STOPPED) << 4;
+
+ /* #2 cassette switch */
+ data |= ((device->machine().device<cassette_image_device>(CASSETTE2_TAG)->get_state() & CASSETTE_MASK_UISTATE) == CASSETTE_STOPPED) << 5;
+
+ /* end or identify in */
+ data |= state->m_ieee->eoi_r() << 6;
+
+ /* diagnostic jumper */
+ data |= 0x80;
+
+ return data;
+}
+
+static WRITE8_DEVICE_HANDLER( pia0_pa_w )
+{
+ pet_state *state = device->machine().driver_data<pet_state>();
+ /*
+
+ bit description
+
+ PA0 KEY A
+ PA1 KEY B
+ PA2 KEY C
+ PA3 KEY D
+ PA4 #1 CASS SWITCH
+ PA5 #2 CASS SWITCH
+ PA6 _EOI IN
+ PA7 DIAG JUMPER
+
+ */
+
+ /* key */
+ state->m_keyline_select = data & 0x0f;
+}
+
+/* Keyboard reading/handling for regular keyboard */
+static READ8_DEVICE_HANDLER( kin_r )
+{
+ pet_state *state = device->machine().driver_data<pet_state>();
+ /*
+
+ bit description
+
+ PB0 KIN0
+ PB1 KIN1
+ PB2 KIN2
+ PB3 KIN3
+ PB4 KIN4
+ PB5 KIN5
+ PB6 KIN6
+ PB7 KIN7
+
+ */
+
+ UINT8 data = 0xff;
+ static const char *const keynames[] = {
+ "ROW0", "ROW1", "ROW2", "ROW3", "ROW4",
+ "ROW5", "ROW6", "ROW7", "ROW8", "ROW9"
+ };
+
+ if (state->m_keyline_select < 10)
+ {
+ data = device->machine().root_device().ioport(keynames[state->m_keyline_select])->read();
+ /* Check for left-shift lock */
+ if ((state->m_keyline_select == 8) && (device->machine().root_device().ioport("SPECIAL")->read() & 0x80))
+ data &= 0xfe;
+ }
+ return data;
+}
+
+/* Keyboard handling for business keyboard */
+static READ8_DEVICE_HANDLER( petb_kin_r )
+{
+ UINT8 data = 0xff;
+ pet_state *state = device->machine().driver_data<pet_state>();
+ static const char *const keynames[] = {
+ "ROW0", "ROW1", "ROW2", "ROW3", "ROW4",
+ "ROW5", "ROW6", "ROW7", "ROW8", "ROW9"
+ };
+
+ if (state->m_keyline_select < 10)
+ {
+ data = device->machine().root_device().ioport(keynames[state->m_keyline_select])->read();
+ /* Check for left-shift lock */
+ /* 2008-05 FP: For some reason, superpet read it in the opposite way!! */
+ /* While waiting for confirmation from docs, we add a workaround here. */
+ if (state->m_superpet)
+ {
+ if ((state->m_keyline_select == 6) && !(device->machine().root_device().ioport("SPECIAL")->read() & 0x80))
+ data &= 0xfe;
+ }
+ else
+ {
+ if ((state->m_keyline_select == 6) && (device->machine().root_device().ioport("SPECIAL")->read() & 0x80))
+ data &= 0xfe;
+ }
+ }
+ return data;
+}
+
+static READ8_DEVICE_HANDLER( cass1_r )
+{
+ // cassette 1 read
+ return (device->machine().device<cassette_image_device>(CASSETTE_TAG)->input() > +0.0) ? 1 : 0;
+}
+
+static WRITE8_DEVICE_HANDLER( cass1_motor_w )
+{
+ pet_state *state = device->machine().driver_data<pet_state>();
+ if (!data)
+ {
+ device->machine().device<cassette_image_device>(CASSETTE_TAG)->change_state(CASSETTE_MOTOR_ENABLED,CASSETTE_MASK_MOTOR);
+ state->m_datasette1_timer->adjust(attotime::zero, 0, attotime::from_hz(48000)); // I put 48000 because I was given some .wav with this freq
+ }
+ else
+ {
+ device->machine().device<cassette_image_device>(CASSETTE_TAG)->change_state(CASSETTE_MOTOR_DISABLED ,CASSETTE_MASK_MOTOR);
+ state->m_datasette1_timer->reset();
+ }
+}
+
+static WRITE_LINE_DEVICE_HANDLER( pia0_irq_w )
+{
+ pet_state *driver_state = device->machine().driver_data<pet_state>();
+
+ driver_state->m_pia0_irq = state;
+ int level = (driver_state->m_pia0_irq | driver_state->m_pia1_irq | driver_state->m_via_irq) ? ASSERT_LINE : CLEAR_LINE;
+
+ device_set_input_line(device->machine().firstcpu, INPUT_LINE_IRQ0, level);
+}
+
+const pia6821_interface pet_pia0 =
+{
+ DEVCB_HANDLER(pia0_pa_r), /* in_a_func */
+ DEVCB_HANDLER(kin_r), /* in_b_func */
+ DEVCB_HANDLER(cass1_r), /* in_ca1_func */
+ DEVCB_NULL, /* in_cb1_func */
+ DEVCB_NULL, /* in_ca2_func */
+ DEVCB_NULL, /* in_cb2_func */
+ DEVCB_HANDLER(pia0_pa_w), /* out_a_func */
+ DEVCB_NULL, /* out_b_func */
+ DEVCB_DEVICE_LINE_MEMBER(IEEE488_TAG, ieee488_device, eoi_w), /* out_ca2_func */
+ DEVCB_HANDLER(cass1_motor_w), /* out_cb2_func */
+ DEVCB_LINE(pia0_irq_w), /* irq_a_func */
+ DEVCB_LINE(pia0_irq_w) /* irq_b_func */
+};
+
+const pia6821_interface petb_pia0 =
+{
+ DEVCB_HANDLER(pia0_pa_r), /* in_a_func */
+ DEVCB_HANDLER(petb_kin_r), /* in_b_func */
+ DEVCB_HANDLER(cass1_r), /* in_ca1_func */
+ DEVCB_NULL, /* in_cb1_func */
+ DEVCB_NULL, /* in_ca2_func */
+ DEVCB_NULL, /* in_cb2_func */
+ DEVCB_HANDLER(pia0_pa_w), /* out_a_func */
+ DEVCB_NULL, /* out_b_func */
+ DEVCB_DEVICE_LINE_MEMBER(IEEE488_TAG, ieee488_device, eoi_w), /* out_ca2_func */
+ DEVCB_HANDLER(cass1_motor_w), /* out_cb2_func */
+ DEVCB_LINE(pia0_irq_w), /* irq_a_func */
+ DEVCB_LINE(pia0_irq_w) /* irq_b_func */
+};
+
+/* pia at 0xe820 (ieee488)
+ port a data in
+ port b data out
+ ca1 atn in
+ ca2 ndac out
+ cb1 srq in
+ cb2 dav out
+ */
+
+static WRITE_LINE_DEVICE_HANDLER( pia1_irq_w )
+{
+ pet_state *driver_state = device->machine().driver_data<pet_state>();
+
+ driver_state->m_pia1_irq = state;
+ int level = (driver_state->m_pia0_irq | driver_state->m_pia1_irq | driver_state->m_via_irq) ? ASSERT_LINE : CLEAR_LINE;
+
+ device_set_input_line(device->machine().firstcpu, INPUT_LINE_IRQ0, level);
+}
+
+const pia6821_interface pet_pia1 =
+{
+ DEVCB_DEVICE_MEMBER(IEEE488_TAG, ieee488_device, dio_r),/* in_a_func */
+ DEVCB_NULL, /* in_b_func */
+ DEVCB_DEVICE_LINE_MEMBER(IEEE488_TAG, ieee488_device, atn_r), /* in_ca1_func */
+ DEVCB_DEVICE_LINE_MEMBER(IEEE488_TAG, ieee488_device, srq_r), /* in_cb1_func */
+ DEVCB_NULL, /* in_ca2_func */
+ DEVCB_NULL, /* in_cb2_func */
+ DEVCB_NULL, /* out_a_func */
+ DEVCB_DEVICE_MEMBER(IEEE488_TAG, ieee488_device, dio_w), /* out_b_func */
+ DEVCB_DEVICE_LINE_MEMBER(IEEE488_TAG, ieee488_device, ndac_w), /* out_ca2_func */
+ DEVCB_DEVICE_LINE_MEMBER(IEEE488_TAG, ieee488_device, dav_w), /* out_cb2_func */
+ DEVCB_LINE(pia1_irq_w), /* irq_a_func */
+ DEVCB_LINE(pia1_irq_w) /* irq_b_func */
+};
+
+/* userport, cassettes, rest ieee488
+ ca1 userport
+ ca2 character rom address line 11
+ pa user port
+
+ pb0 ieee ndac in
+ pb1 ieee nrfd out
+ pb2 ieee atn out
+ pb3 userport/cassettes
+ pb4 cassettes
+ pb5 userport/???
+ pb6 ieee nrfd in
+ pb7 ieee dav in
+
+ cb1 cassettes
+ cb2 user port
+ */
+static READ8_DEVICE_HANDLER( via_pb_r )
+{
+ /*
+
+ bit description
+
+ PB0 _NDAC IN
+ PB1 _NRFD OUT
+ PB2 _ATN OUT
+ PB3 CASS WRITE
+ PB4 #2 CASS MOTOR
+ PB5 SYNC IN
+ PB6 _NRFD IN
+ PB7 _DAV IN
+
+ */
+
+ pet_state *state = device->machine().driver_data<pet_state>();
+ UINT8 data = 0;
+
+ /* not data accepted in */
+ data |= state->m_ieee->ndac_r();
+
+ /* sync in */
+
+ /* not ready for data in */
+ data |= state->m_ieee->nrfd_r() << 6;
+
+ /* data valid in */
+ data |= state->m_ieee->dav_r() << 7;
+
+ return data;
+}
+
+static READ_LINE_DEVICE_HANDLER( cass2_r )
+{
+ // cassette 2 read
+ return (device->machine().device<cassette_image_device>(CASSETTE2_TAG)->input() > +0.0) ? 1 : 0;
+}
+
+static WRITE8_DEVICE_HANDLER( via_pb_w )
+{
+ /*
+
+ bit description
+
+ PB0 _NDAC IN
+ PB1 _NRFD OUT
+ PB2 _ATN OUT
+ PB3 CASS WRITE
+ PB4 #2 CASS MOTOR
+ PB5 SYNC IN
+ PB6 _NRFD IN
+ PB7 _DAV IN
+
+ */
+
+ pet_state *state = device->machine().driver_data<pet_state>();
+
+ /* not ready for data out */
+ state->m_ieee->nrfd_w(BIT(data, 1));
+
+ /* attention out */
+ state->m_ieee->atn_w(BIT(data, 2));
+
+ /* cassette write */
+ device->machine().device<cassette_image_device>(CASSETTE_TAG)->output(BIT(data, 3) ? -(0x5a9e >> 1) : +(0x5a9e >> 1));
+ device->machine().device<cassette_image_device>(CASSETTE2_TAG)->output(BIT(data, 3) ? -(0x5a9e >> 1) : +(0x5a9e >> 1));
+
+ /* #2 cassette motor */
+ if (BIT(data, 4))
+ {
+ device->machine().device<cassette_image_device>(CASSETTE2_TAG)->change_state(CASSETTE_MOTOR_ENABLED, CASSETTE_MASK_MOTOR);
+ state->m_datasette2_timer->adjust(attotime::zero, 0, attotime::from_hz(48000)); // I put 48000 because I was given some .wav with this freq
+ }
+ else
+ {
+ device->machine().device<cassette_image_device>(CASSETTE2_TAG)->change_state(CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR);
+ state->m_datasette2_timer->reset();
+ }
+}
+
+static WRITE_LINE_DEVICE_HANDLER( gb_w )
+{
+ pet_state *drvstate = device->machine().driver_data<pet_state>();
+ DBG_LOG(device->machine(), 1, "address line", ("%d\n", state));
+ if (state) drvstate->m_font |= 1;
+ else drvstate->m_font &= ~1;
+}
+
+static WRITE_LINE_DEVICE_HANDLER( via_irq_w )
+{
+ pet_state *driver_state = device->machine().driver_data<pet_state>();
+
+ driver_state->m_via_irq = state;
+ int level = (driver_state->m_pia0_irq | driver_state->m_pia1_irq | driver_state->m_via_irq) ? ASSERT_LINE : CLEAR_LINE;
+
+ device_set_input_line(device->machine().firstcpu, INPUT_LINE_IRQ0, level);
+}
+
+const via6522_interface pet_via =
+{
+ DEVCB_NULL, /* in_a_func */
+ DEVCB_HANDLER(via_pb_r), /* in_b_func */
+ DEVCB_NULL, /* in_ca1_func */
+ DEVCB_LINE(cass2_r), /* in_cb1_func */
+ DEVCB_NULL, /* in_ca2_func */
+ DEVCB_NULL, /* in_cb2_func */
+ DEVCB_NULL, /* out_a_func */
+ DEVCB_HANDLER(via_pb_w), /* out_b_func */
+ DEVCB_NULL, /* out_ca1_func */
+ DEVCB_LINE(gb_w), /* out_ca2_func */
+ DEVCB_NULL, /* out_ca2_func */
+ DEVCB_NULL, /* out_cb2_func */
+ DEVCB_LINE(via_irq_w) /* out_irq_func */
+};
+
+
+static WRITE8_HANDLER( cbm8096_io_w )
+{
+ via6522_device *via_0 = space->machine().device<via6522_device>("via6522_0");
+ pia6821_device *pia_0 = space->machine().device<pia6821_device>("pia_0");
+ pia6821_device *pia_1 = space->machine().device<pia6821_device>("pia_1");
+ mc6845_device *mc6845 = space->machine().device<mc6845_device>("crtc");
+
+ if (offset < 0x10) ;
+ else if (offset < 0x14) pia_0->write(*space, offset & 3, data);
+ else if (offset < 0x20) ;
+ else if (offset < 0x24) pia_1->write(*space, offset & 3, data);
+ else if (offset < 0x40) ;
+ else if (offset < 0x50) via_0->write(*space, offset & 0xf, data);
+ else if (offset < 0x80) ;
+ else if (offset == 0x80) mc6845->address_w(*space, 0, data);
+ else if (offset == 0x81) mc6845->register_w(*space, 0, data);
+}
+
+static READ8_HANDLER( cbm8096_io_r )
+{
+ via6522_device *via_0 = space->machine().device<via6522_device>("via6522_0");
+ pia6821_device *pia_0 = space->machine().device<pia6821_device>("pia_0");
+ pia6821_device *pia_1 = space->machine().device<pia6821_device>("pia_1");
+ mc6845_device *mc6845 = space->machine().device<mc6845_device>("crtc");
+
+ int data = 0xff;
+ if (offset < 0x10) ;
+ else if (offset < 0x14) data = pia_0->read(*space, offset & 3);
+ else if (offset < 0x20) ;
+ else if (offset < 0x24) data = pia_1->read(*space, offset & 3);
+ else if (offset < 0x40) ;
+ else if (offset < 0x50) data = via_0->read(*space, offset & 0xf);
+ else if (offset < 0x80) ;
+ else if (offset == 0x81) data = mc6845->register_r(*space, 0);
+ return data;
+}
+
+static WRITE8_HANDLER( pet80_bank1_w )
+{
+ pet_state *state = space->machine().driver_data<pet_state>();
+ state->m_pet80_bank1_base[offset] = data;
+}
+
+/*
+65520 8096 memory control register
+ bit 0 1=write protect $8000-BFFF
+ bit 1 1=write protect $C000-FFFF
+ bit 2 $8000-BFFF bank select
+ bit 3 $C000-FFFF bank select
+ bit 5 1=screen peek through
+ bit 6 1=I/O peek through
+ bit 7 1=enable expansion memory
+
+*/
+WRITE8_HANDLER( cbm8096_w )
+{
+ pet_state *state = space->machine().driver_data<pet_state>();
+ if (data & 0x80)
+ {
+ if (data & 0x40)
+ {
+ space->install_legacy_read_handler(0xe800, 0xefff, FUNC(cbm8096_io_r));
+ space->install_legacy_write_handler(0xe800, 0xefff, FUNC(cbm8096_io_w));
+ }
+ else
+ {
+ space->install_read_bank(0xe800, 0xefff, "bank7");
+ if (!(data & 2))
+ space->install_write_bank(0xe800, 0xefff, "bank7");
+ else
+ space->nop_write(0xe800, 0xefff);
+ }
+
+
+ if ((data & 2) == 0) {
+ space->install_write_bank(0xc000, 0xe7ff, "bank6");
+ space->install_write_bank(0xf000, 0xffef, "bank8");
+ space->install_write_bank(0xfff1, 0xffff, "bank9");
+ } else {
+ space->nop_write(0xc000, 0xe7ff);
+ space->nop_write(0xf000, 0xffef);
+ space->nop_write(0xfff1, 0xffff);
+ }
+
+ if (data & 0x20)
+ {
+ state->m_pet80_bank1_base = state->m_memory + 0x8000;
+ state->membank("bank1")->set_base(state->m_pet80_bank1_base);
+ space->install_legacy_write_handler(0x8000, 0x8fff, FUNC(pet80_bank1_w));
+ }
+ else
+ {
+ if (!(data & 1))
+ space->install_write_bank(0x8000, 0x8fff, "bank1");
+ else
+ space->nop_write(0x8000, 0x8fff);
+ }
+
+ if ((data & 1) == 0 ){
+ space->install_write_bank(0x9000, 0x9fff, "bank2");
+ space->install_write_bank(0xa000, 0xafff, "bank3");
+ space->install_write_bank(0xb000, 0xbfff, "bank4");
+ } else {
+ space->nop_write(0x9000, 0x9fff);
+ space->nop_write(0xa000, 0xafff);
+ space->nop_write(0xb000, 0xbfff);
+ }
+
+ if (data & 4)
+ {
+ if (!(data & 0x20))
+ {
+ state->m_pet80_bank1_base = state->m_memory + 0x14000;
+ state->membank("bank1")->set_base(state->m_pet80_bank1_base);
+ }
+ state->membank("bank2")->set_base(state->m_memory + 0x15000);
+ state->membank("bank3")->set_base(state->m_memory + 0x16000);
+ state->membank("bank4")->set_base(state->m_memory + 0x17000);
+ }
+ else
+ {
+ if (!(data & 0x20))
+ {
+ state->m_pet80_bank1_base = state->m_memory + 0x10000;
+ state->membank("bank1")->set_base(state->m_pet80_bank1_base);
+ }
+ state->membank("bank2")->set_base(state->m_memory + 0x11000);
+ state->membank("bank3")->set_base(state->m_memory + 0x12000);
+ state->membank("bank4")->set_base(state->m_memory + 0x13000);
+ }
+
+ if (data & 8)
+ {
+ if (!(data & 0x40))
+ {
+ state->membank("bank7")->set_base(state->m_memory + 0x1e800);
+ }
+ state->membank("bank6")->set_base(state->m_memory + 0x1c000);
+ state->membank("bank8")->set_base(state->m_memory + 0x1f000);
+ state->membank("bank9")->set_base(state->m_memory + 0x1fff1);
+ }
+ else
+ {
+ if (!(data & 0x40))
+ {
+ state->membank("bank7")->set_base(state->m_memory+ 0x1a800);
+ }
+ state->membank("bank6")->set_base(state->m_memory + 0x18000);
+ state->membank("bank8")->set_base(state->m_memory + 0x1b000);
+ state->membank("bank9")->set_base(state->m_memory + 0x1bff1);
+ }
+ }
+ else
+ {
+ state->m_pet80_bank1_base = state->m_memory + 0x8000;
+ state->membank("bank1")->set_base(state->m_pet80_bank1_base );
+ space->install_legacy_write_handler(0x8000, 0x8fff, FUNC(pet80_bank1_w));
+
+ state->membank("bank2")->set_base(state->m_memory + 0x9000);
+ space->unmap_write(0x9000, 0x9fff);
+
+ state->membank("bank3")->set_base(state->m_memory + 0xa000);
+ space->unmap_write(0xa000, 0xafff);
+
+ state->membank("bank4")->set_base(state->m_memory + 0xb000);
+ space->unmap_write(0xb000, 0xbfff);
+
+ state->membank("bank6")->set_base(state->m_memory + 0xc000);
+ space->unmap_write(0xc000, 0xe7ff);
+
+ space->install_legacy_read_handler(0xe800, 0xefff, FUNC(cbm8096_io_r));
+ space->install_legacy_write_handler(0xe800, 0xefff, FUNC(cbm8096_io_w));
+
+ state->membank("bank8")->set_base(state->m_memory + 0xf000);
+ space->unmap_write(0xf000, 0xffef);
+
+ state->membank("bank9")->set_base(state->m_memory + 0xfff1);
+ space->unmap_write(0xfff1, 0xffff);
+ }
+}
+
+READ8_HANDLER( superpet_r )
+{
+ return 0xff;
+}
+
+WRITE8_HANDLER( superpet_w )
+{
+ pet_state *state = space->machine().driver_data<pet_state>();
+ switch (offset)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ /* 3: 1 pull down diagnostic pin on the userport
+ 1: 1 if jumpered programable ram r/w
+ 0: 0 if jumpered programable m6809, 1 m6502 selected */
+ break;
+
+ case 4:
+ case 5:
+ state->m_spet.bank = data & 0xf;
+ state->membank("bank1")->configure_entries(0, 16, state->m_supermemory, 0x1000);
+ state->membank("bank1")->set_entry(state->m_spet.bank);
+ /* 7 low writeprotects systemlatch */
+ break;
+
+ case 6:
+ case 7:
+ state->m_spet.rom = data & 1;
+ break;
+ }
+}
+
+static TIMER_CALLBACK( pet_interrupt )
+{
+ pet_state *state = machine.driver_data<pet_state>();
+ pia6821_device *pia_0 = machine.device<pia6821_device>("pia_0");
+
+ pia_0->cb1_w(state->m_pia_level);
+ state->m_pia_level = !state->m_pia_level;
+}
+
+
+static TIMER_CALLBACK( pet_tape1_timer )
+{
+ pia6821_device *pia_0 = machine.device<pia6821_device>("pia_0");
+// cassette 1
+ UINT8 data = (machine.device<cassette_image_device>(CASSETTE_TAG)->input() > +0.0) ? 1 : 0;
+ pia_0->ca1_w(data);
+}
+
+static TIMER_CALLBACK( pet_tape2_timer )
+{
+ via6522_device *via_0 = machine.device<via6522_device>("via6522_0");
+// cassette 2
+ UINT8 data = (machine.device<cassette_image_device>(CASSETTE2_TAG)->input() > +0.0) ? 1 : 0;
+ via_0->write_cb1(data);
+}
+
+
+static void pet_common_driver_init( running_machine &machine )
+{
+ int i;
+ pet_state *state = machine.driver_data<pet_state>();
+
+ state->m_font = 0;
+
+ state->m_pet_basic1 = 0;
+ state->m_superpet = 0;
+ state->m_cbm8096 = 0;
+
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_readwrite_bank(0x0000, machine.device<ram_device>(RAM_TAG)->size() - 1, "bank10");
+ state->membank("bank10")->set_base(state->m_memory);
+
+ if (machine.device<ram_device>(RAM_TAG)->size() < 0x8000)
+ {
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->nop_readwrite(machine.device<ram_device>(RAM_TAG)->size(), 0x7FFF);
+ }
+
+ /* 2114 poweron ? 64 x 0xff, 64x 0, and so on */
+ for (i = 0; i < machine.device<ram_device>(RAM_TAG)->size(); i += 0x40)
+ {
+ memset (state->m_memory + i, i & 0x40 ? 0 : 0xff, 0x40);
+ }
+
+ /* pet clock */
+ machine.scheduler().timer_pulse(attotime::from_msec(10), FUNC(pet_interrupt));
+
+ /* datasette */
+ state->m_datasette1_timer = machine.scheduler().timer_alloc(FUNC(pet_tape1_timer));
+ state->m_datasette2_timer = machine.scheduler().timer_alloc(FUNC(pet_tape2_timer));
+}
+
+
+DRIVER_INIT_MEMBER(pet_state,pet2001)
+{
+ m_memory.set_target(machine().device<ram_device>(RAM_TAG)->pointer(),m_memory.bytes());
+ pet_common_driver_init(machine());
+ m_pet_basic1 = 1;
+ pet_vh_init(machine());
+}
+
+DRIVER_INIT_MEMBER(pet_state,pet)
+{
+ m_memory.set_target(machine().device<ram_device>(RAM_TAG)->pointer(),m_memory.bytes());
+ pet_common_driver_init(machine());
+ pet_vh_init(machine());
+}
+
+DRIVER_INIT_MEMBER(pet_state,pet80)
+{
+ m_memory.set_target(memregion("maincpu")->base(),m_memory.bytes());
+
+ pet_common_driver_init(machine());
+ m_cbm8096 = 1;
+ m_videoram.set_target(&m_memory[0x8000],m_videoram.bytes());
+ pet80_vh_init(machine());
+
+}
+
+DRIVER_INIT_MEMBER(pet_state,superpet)
+{
+ m_memory.set_target(machine().device<ram_device>(RAM_TAG)->pointer(),m_memory.bytes());
+ pet_common_driver_init(machine());
+ m_superpet = 1;
+
+ m_supermemory = auto_alloc_array(machine(), UINT8, 0x10000);
+
+ membank("bank1")->configure_entries(0, 16, m_supermemory, 0x1000);
+ membank("bank1")->set_entry(0);
+
+ superpet_vh_init(machine());
+}
+
+MACHINE_RESET( pet )
+{
+ pet_state *state = machine.driver_data<pet_state>();
+
+ if (state->m_superpet)
+ {
+ state->m_spet.rom = 0;
+ if (machine.root_device().ioport("CFG")->read() & 0x04)
+ {
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_HALT, 1);
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_HALT, 0);
+ state->m_font = 2;
+ }
+ else
+ {
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_HALT, 0);
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_HALT, 1);
+ state->m_font = 0;
+ }
+ }
+
+ if (state->m_cbm8096)
+ {
+ if (machine.root_device().ioport("CFG")->read() & 0x08)
+ {
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0xfff0, 0xfff0, FUNC(cbm8096_w));
+ }
+ else
+ {
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->nop_write(0xfff0, 0xfff0);
+ }
+ cbm8096_w(machine.device("maincpu")->memory().space(AS_PROGRAM), 0, 0);
+ }
+
+//removed cbm_drive_0_config (machine.root_device().ioport("CFG")->read() & 2 ? IEEE : 0, 8);
+//removed cbm_drive_1_config (machine.root_device().ioport("CFG")->read() & 1 ? IEEE : 0, 9);
+ machine.device("maincpu")->reset();
+
+ state->m_ieee->ren_w(0);
+ state->m_ieee->ifc_w(0);
+ state->m_ieee->ifc_w(1);
+}
+
+
+INTERRUPT_GEN( pet_frame_interrupt )
+{
+ pet_state *state = device->machine().driver_data<pet_state>();
+ if (state->m_superpet)
+ {
+ if (state->ioport("CFG")->read() & 0x04)
+ {
+ device_set_input_line(device, INPUT_LINE_HALT, 1);
+ device_set_input_line(device, INPUT_LINE_HALT, 0);
+ state->m_font |= 2;
+ }
+ else
+ {
+ device_set_input_line(device, INPUT_LINE_HALT, 0);
+ device_set_input_line(device, INPUT_LINE_HALT, 1);
+ state->m_font &= ~2;
+ }
+ }
+
+ set_led_status (device->machine(),1, device->machine().root_device().ioport("SPECIAL")->read() & 0x80 ? 1 : 0); /* Shift Lock */
+}
+
+
+/***********************************************
+
+ PET Cartridges
+
+***********************************************/
+
+static DEVICE_IMAGE_LOAD(pet_cart)
+{
+ pet_state *state = image.device().machine().driver_data<pet_state>();
+ UINT32 size = image.length();
+ const char *filetype = image.filetype();
+ int address = 0;
+
+ /* Assign loading address according to extension */
+ if (!mame_stricmp(filetype, "90"))
+ address = 0x9000;
+ else if (!mame_stricmp(filetype, "a0"))
+ address = 0xa000;
+ else if (!mame_stricmp(filetype, "b0"))
+ address = 0xb000;
+
+ logerror("Loading cart %s at %.4x size:%.4x\n", image.filename(), address, size);
+
+ image.fread(state->m_memory + address, size);
+
+ return IMAGE_INIT_PASS;
+}
+
+MACHINE_CONFIG_FRAGMENT(pet_cartslot)
+ MCFG_CARTSLOT_ADD("cart1")
+ MCFG_CARTSLOT_EXTENSION_LIST("90,a0,b0")
+ MCFG_CARTSLOT_NOT_MANDATORY
+ MCFG_CARTSLOT_LOAD(pet_cart)
+
+ MCFG_CARTSLOT_ADD("cart2")
+ MCFG_CARTSLOT_EXTENSION_LIST("90,a0,b0")
+ MCFG_CARTSLOT_NOT_MANDATORY
+ MCFG_CARTSLOT_LOAD(pet_cart)
+MACHINE_CONFIG_END
+
+// 2010-08, FP: this is used by CBM40 & CBM80, and I actually have only found .prg files for these... does cart dumps exist?
+MACHINE_CONFIG_FRAGMENT(pet4_cartslot)
+ MCFG_CARTSLOT_MODIFY("cart1")
+ MCFG_CARTSLOT_EXTENSION_LIST("a0")
+ MCFG_CARTSLOT_NOT_MANDATORY
+ MCFG_CARTSLOT_LOAD(pet_cart)
+
+ MCFG_CARTSLOT_MODIFY("cart2")
+ MCFG_CARTSLOT_EXTENSION_LIST("a0")
+ MCFG_CARTSLOT_NOT_MANDATORY
+ MCFG_CARTSLOT_LOAD(pet_cart)
+MACHINE_CONFIG_END
diff --git a/src/mess/machine/pf10.c b/src/mess/machine/pf10.c
new file mode 100644
index 00000000000..68d6bd0dac3
--- /dev/null
+++ b/src/mess/machine/pf10.c
@@ -0,0 +1,162 @@
+/***************************************************************************
+
+ Epson PF-10
+
+ Serial floppy drive
+
+ Skeleton driver, not working
+
+***************************************************************************/
+
+#include "emu.h"
+#include "pf10.h"
+#include "cpu/m6800/m6800.h"
+#include "machine/upd765.h"
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _pf10_state pf10_state;
+struct _pf10_state
+{
+ UINT8 dummy;
+};
+
+
+/*****************************************************************************
+ INLINE FUNCTIONS
+*****************************************************************************/
+
+INLINE pf10_state *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == PF10);
+
+ return (pf10_state *)downcast<legacy_device_base *>(device)->token();
+}
+
+
+/*****************************************************************************
+ ADDRESS MAPS
+*****************************************************************************/
+
+static ADDRESS_MAP_START( pf10_mem, AS_PROGRAM, 8, pf10_device )
+ AM_RANGE(0x0040, 0x013f) AM_RAM /* internal ram */
+ AM_RANGE(0x0800, 0x0fff) AM_RAM /* external 2k ram */
+ AM_RANGE(0xe000, 0xffff) AM_ROM AM_REGION("pf10", 0)
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( pf10_io, AS_IO, 8, pf10_device )
+ ADDRESS_MAP_UNMAP_HIGH
+ ADDRESS_MAP_GLOBAL_MASK(0xff)
+ADDRESS_MAP_END
+
+
+/*****************************************************************************
+ MACHINE CONFIG
+*****************************************************************************/
+
+static const upd765_interface pf10_upd765a_intf =
+{
+ DEVCB_NULL, /* interrupt line */
+ DEVCB_NULL,
+ NULL,
+ UPD765_RDY_PIN_NOT_CONNECTED, /* ??? */
+ {NULL, NULL, NULL, NULL}
+};
+
+static MACHINE_CONFIG_FRAGMENT( pf10 )
+ MCFG_CPU_ADD("pf10", M6803, XTAL_2_4576MHz / 4 /* ??? */) /* HD63A03 */
+ MCFG_CPU_PROGRAM_MAP(pf10_mem)
+ MCFG_CPU_IO_MAP(pf10_io)
+
+ MCFG_UPD765A_ADD("upd765a", pf10_upd765a_intf)
+MACHINE_CONFIG_END
+
+
+/***************************************************************************
+ ROM DEFINITIONS
+***************************************************************************/
+
+ROM_START( pf10 )
+ ROM_REGION(0x2000, "pf10", 0)
+ ROM_LOAD("k3pf1.bin", 0x0000, 0x2000, CRC(eef4593a) SHA1(bb176e4baf938fe58c2d32f7c46d7bb7b0627755))
+ROM_END
+
+
+/*****************************************************************************
+ DEVICE INTERFACE
+*****************************************************************************/
+
+static DEVICE_START( pf10 )
+{
+ pf10_state *pf10 = get_safe_token(device);
+
+ pf10->dummy = 0;
+}
+
+static DEVICE_RESET( pf10 )
+{
+}
+
+DEVICE_GET_INFO( pf10 )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(pf10_state); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+
+ /* --- the following bits of info are returned as pointers --- */
+ case DEVINFO_PTR_MACHINE_CONFIG: info->machine_config = MACHINE_CONFIG_NAME(pf10); break;
+ case DEVINFO_PTR_ROM_REGION: info->romregion = ROM_NAME(pf10); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(pf10); break;
+ case DEVINFO_FCT_STOP: /* Nothing */ break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(pf10); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "PF-10"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "Floppy drive"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright MESS Team"); break;
+ }
+}
+
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+/* serial interface in (to the host computer) */
+READ_LINE_DEVICE_HANDLER( pf10_txd1_r )
+{
+ logerror("%s: pf10_txd1_r\n", device->machine().describe_context());
+
+ return 0;
+}
+
+WRITE_LINE_DEVICE_HANDLER( pf10_rxd1_w )
+{
+ logerror("%s: pf10_rxd1_w %u\n", device->machine().describe_context(), state);
+}
+
+
+/* serial interface out (to another floppy drive) */
+READ_LINE_DEVICE_HANDLER( pf10_txd2_r )
+{
+ logerror("%s: pf10_txd2_r\n", device->machine().describe_context());
+
+ return 0;
+}
+
+WRITE_LINE_DEVICE_HANDLER( pf10_rxd2_w )
+{
+ logerror("%s: pf10_rxd2_w %u\n", device->machine().describe_context(), state);
+}
+
+DEFINE_LEGACY_DEVICE(PF10, pf10);
diff --git a/src/mess/machine/pf10.h b/src/mess/machine/pf10.h
new file mode 100644
index 00000000000..5f901bce042
--- /dev/null
+++ b/src/mess/machine/pf10.h
@@ -0,0 +1,49 @@
+/***************************************************************************
+
+ Epson PF-10
+
+ Serial floppy drive
+
+***************************************************************************/
+
+#ifndef __PF10_H__
+#define __PF10_H__
+
+#include "devcb.h"
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+#if 0
+typedef struct _pf10_interface pf10_interface;
+struct _pf10_interface
+{
+};
+#endif
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+/* serial interface in (to the host computer) */
+READ_LINE_DEVICE_HANDLER( pf10_txd1_r );
+WRITE_LINE_DEVICE_HANDLER( pf10_rxd1_w );
+
+/* serial interface out (to another floppy drive) */
+READ_LINE_DEVICE_HANDLER( pf10_txd2_r );
+WRITE_LINE_DEVICE_HANDLER( pf10_rxd2_w );
+
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+DECLARE_LEGACY_DEVICE(PF10, pf10);
+
+#define MCFG_PF10_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, PF10, 0) \
+
+
+#endif /* __PF10_H__ */
diff --git a/src/mess/machine/pk8020.c b/src/mess/machine/pk8020.c
new file mode 100644
index 00000000000..b408bcabf22
--- /dev/null
+++ b/src/mess/machine/pk8020.c
@@ -0,0 +1,1012 @@
+/***************************************************************************
+
+ PK-8020 driver by Miodrag Milanovic
+ based on work of Sergey Erokhin from pk8020.narod.ru
+
+ 18/07/2008 Preliminary driver.
+
+****************************************************************************/
+
+
+#include "emu.h"
+#include "includes/pk8020.h"
+#include "cpu/i8085/i8085.h"
+#include "machine/wd17xx.h"
+#include "machine/ram.h"
+#include "imagedev/flopdrv.h"
+
+static void pk8020_set_bank(running_machine &machine,UINT8 data);
+
+
+READ8_MEMBER(pk8020_state::keyboard_r)
+{
+ static const char *const keynames[] = {
+ "LINE0", "LINE1", "LINE2", "LINE3", "LINE4", "LINE5", "LINE6", "LINE7",
+ "LINE8", "LINE9", "LINE10", "LINE11", "LINE12", "LINE13", "LINE14", "LINE15"
+ };
+ UINT8 retVal=0x00;
+ UINT8 line = 0;
+ if (offset & 0x100) line=8;
+
+ if (offset & 0x0001) retVal|=ioport(keynames[line])->read();
+ line++;
+ if (offset & 0x0002) retVal|=ioport(keynames[line])->read();
+ line++;
+ if (offset & 0x0004) retVal|=ioport(keynames[line])->read();
+ line++;
+ if (offset & 0x0008) retVal|=ioport(keynames[line])->read();
+ line++;
+ if (offset & 0x0010) retVal|=ioport(keynames[line])->read();
+ line++;
+ if (offset & 0x0020) retVal|=ioport(keynames[line])->read();
+ line++;
+ if (offset & 0x0040) retVal|=ioport(keynames[line])->read();
+ line++;
+ if (offset & 0x0080) retVal|=ioport(keynames[line])->read();
+ line++;
+
+ return retVal;
+}
+
+READ8_MEMBER(pk8020_state::sysreg_r)
+{
+ return machine().device<ram_device>(RAM_TAG)->pointer()[offset];
+}
+WRITE8_MEMBER(pk8020_state::sysreg_w)
+{
+ if (BIT(offset,7)==0) {
+ pk8020_set_bank(machine(),data >> 2);
+ } else if (BIT(offset,6)==0) {
+ // Color
+ m_color = data;
+ } else if (BIT(offset,2)==0) {
+ // Palette set
+ UINT8 number = data & 0x0f;
+ UINT8 color = data >> 4;
+ UINT8 i = (color & 0x08) ? 0x3F : 0;
+ UINT8 r = ((color & 0x04) ? 0xC0 : 0) + i;
+ UINT8 g = ((color & 0x02) ? 0xC0 : 0) + i;
+ UINT8 b = ((color & 0x01) ? 0xC0 : 0) + i;
+ palette_set_color( machine(), number, MAKE_RGB(r,g,b) );
+ }
+}
+
+READ8_MEMBER(pk8020_state::text_r)
+{
+ if (m_attr == 3) m_text_attr=machine().device<ram_device>(RAM_TAG)->pointer()[0x40400+offset];
+ return machine().device<ram_device>(RAM_TAG)->pointer()[0x40000+offset];
+}
+
+WRITE8_MEMBER(pk8020_state::text_w)
+{
+ UINT8 *ram = machine().device<ram_device>(RAM_TAG)->pointer();
+ ram[0x40000+offset] = data;
+ switch (m_attr) {
+ case 0: break;
+ case 1: ram[0x40400+offset]=0x01;break;
+ case 2: ram[0x40400+offset]=0x00;break;
+ case 3: ram[0x40400+offset]=m_text_attr;break;
+ }
+}
+
+READ8_MEMBER(pk8020_state::gzu_r)
+{
+ UINT8 *addr = machine().device<ram_device>(RAM_TAG)->pointer() + 0x10000 + (m_video_page_access * 0xC000);
+ UINT8 p0 = addr[offset];
+ UINT8 p1 = addr[offset + 0x4000];
+ UINT8 p2 = addr[offset + 0x8000];
+ UINT8 retVal = 0;
+ if(m_color & 0x80) {
+ // Color mode
+ if (!(m_color & 0x10)) {
+ p0 ^= 0xff;
+ }
+ if (!(m_color & 0x20)) {
+ p1 ^= 0xff;
+ }
+ if (!(m_color & 0x40)) {
+ p2 ^= 0xff;
+ }
+ retVal = (p0 & p1 & p2) ^ 0xff;
+ } else {
+ // Plane mode
+ if (m_color & 0x10) {
+ retVal |= p0;
+ }
+ if (m_color & 0x20) {
+ retVal |= p1;
+ }
+ if (m_color & 0x40) {
+ retVal |= p2;
+ }
+ }
+ return retVal;
+}
+
+WRITE8_MEMBER(pk8020_state::gzu_w)
+{
+ UINT8 *addr = machine().device<ram_device>(RAM_TAG)->pointer() + 0x10000 + (m_video_page_access * 0xC000);
+ UINT8 *plane_0 = addr;
+ UINT8 *plane_1 = addr + 0x4000;
+ UINT8 *plane_2 = addr + 0x8000;
+
+ if(m_color & 0x80)
+ {
+ // Color mode
+ plane_0[offset] = (plane_0[offset] & ~data) | ((m_color & 2) ? data : 0);
+ plane_1[offset] = (plane_1[offset] & ~data) | ((m_color & 4) ? data : 0);
+ plane_2[offset] = (plane_2[offset] & ~data) | ((m_color & 8) ? data : 0);
+ } else {
+ // Plane mode
+ UINT8 mask = (m_color & 1) ? data : 0;
+ if (!(m_color & 0x02)) {
+ plane_0[offset] = (plane_0[offset] & ~data) | mask;
+ }
+ if (!(m_color & 0x04)) {
+ plane_1[offset] = (plane_1[offset] & ~data) | mask;
+ }
+ if (!(m_color & 0x08)) {
+ plane_2[offset] = (plane_2[offset] & ~data) | mask;
+ }
+ }
+}
+
+READ8_MEMBER(pk8020_state::devices_r)
+{
+ i8255_device *ppi1 = machine().device<i8255_device>("ppi8255_1");
+ i8255_device *ppi2 = machine().device<i8255_device>("ppi8255_2");
+ i8255_device *ppi3 = machine().device<i8255_device>("ppi8255_3");
+ device_t *pit = machine().device("pit8253");
+ device_t *pic = machine().device("pic8259");
+ i8251_device *rs232 = machine().device<i8251_device>("rs232");
+ i8251_device *lan = machine().device<i8251_device>("lan");
+ device_t *fdc = machine().device("wd1793");
+
+ switch(offset & 0x38)
+ {
+ case 0x00: return pit8253_r(pit,offset & 3);
+ case 0x08: return ppi3->read(space,offset & 3);
+ case 0x10: switch(offset & 1) {
+ case 0 : return rs232->data_r(space,0);
+ case 1 : return rs232->status_r(space,0);
+ }
+ break;
+ case 0x18: switch(offset & 3) {
+ case 0 : return wd17xx_status_r(fdc,0);
+ case 1 : return wd17xx_track_r(fdc,0);
+ case 2 : return wd17xx_sector_r(fdc,0);
+ case 3 : return wd17xx_data_r(fdc,0);
+ }
+ break;
+ case 0x20: switch(offset & 1) {
+ case 0 : return lan->data_r(space,0);
+ case 1 : return lan->status_r(space,0);
+ }
+ break;
+ case 0x28: return pic8259_r(pic,offset & 1);
+ case 0x30: return ppi2->read(space,offset & 3);
+ case 0x38: return ppi1->read(space,offset & 3);
+ }
+ return 0xff;
+}
+
+WRITE8_MEMBER(pk8020_state::devices_w)
+{
+ i8255_device *ppi1 = machine().device<i8255_device>("ppi8255_1");
+ i8255_device *ppi2 = machine().device<i8255_device>("ppi8255_2");
+ i8255_device *ppi3 = machine().device<i8255_device>("ppi8255_3");
+ device_t *pit = machine().device("pit8253");
+ device_t *pic = machine().device("pic8259");
+ i8251_device *rs232 = machine().device<i8251_device>("rs232");
+ i8251_device *lan = machine().device<i8251_device>("lan");
+ device_t *fdc = machine().device("wd1793");
+
+ switch(offset & 0x38)
+ {
+ case 0x00: pit8253_w(pit,offset & 3,data); break;
+ case 0x08: ppi3->write(space,offset & 3,data); break;
+ case 0x10: switch(offset & 1) {
+ case 0 : rs232->data_w(space,0,data); break;
+ case 1 : rs232->control_w(space,0,data); break;
+ }
+ break;
+ case 0x18: switch(offset & 3) {
+ case 0 : wd17xx_command_w(fdc,0,data);break;
+ case 1 : wd17xx_track_w(fdc,0,data);break;
+ case 2 : wd17xx_sector_w(fdc,0,data);break;
+ case 3 : wd17xx_data_w(fdc,0,data);break;
+ }
+ break;
+ case 0x20: switch(offset & 1) {
+ case 0 : lan->data_w(space,0,data); break;
+ case 1 : lan->control_w(space,0,data); break;
+ }
+ break;
+ case 0x28: pic8259_w(pic,offset & 1,data);break;
+ case 0x30: ppi2->write(space,offset & 3,data); break;
+ case 0x38: ppi1->write(space,offset & 3,data); break;
+ }
+}
+
+static void pk8020_set_bank(running_machine &machine,UINT8 data)
+{
+ pk8020_state *state = machine.driver_data<pk8020_state>();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ UINT8 *mem = state->memregion("maincpu")->base();
+ UINT8 *ram = machine.device<ram_device>(RAM_TAG)->pointer();
+
+ switch(data & 0x1F) {
+ case 0x00 :
+ {
+ // ROM
+ space->install_read_bank (0x0000, 0x37ff, "bank1");
+ space->install_write_bank(0x0000, 0x37ff, "bank2");
+ state->membank("bank1")->set_base(mem + 0x10000);
+ state->membank("bank2")->set_base(ram + 0x0000);
+ // Keyboard
+ space->install_read_handler (0x3800, 0x39ff, read8_delegate(FUNC(pk8020_state::keyboard_r),state));
+ space->install_write_bank(0x3800, 0x39ff, "bank3");
+ state->membank("bank3")->set_base(ram + 0x3800);
+ // System reg
+ space->install_read_handler (0x3a00, 0x3aff, read8_delegate(FUNC(pk8020_state::sysreg_r),state));
+ space->install_write_handler(0x3a00, 0x3aff, write8_delegate(FUNC(pk8020_state::sysreg_w),state));
+ // Devices
+ space->install_read_handler (0x3b00, 0x3bff, read8_delegate(FUNC(pk8020_state::devices_r),state));
+ space->install_write_handler(0x3b00, 0x3bff, write8_delegate(FUNC(pk8020_state::devices_w),state));
+ // Text Video Memory
+ space->install_read_handler (0x3c00, 0x3fff, read8_delegate(FUNC(pk8020_state::text_r),state));
+ space->install_write_handler(0x3c00, 0x3fff, write8_delegate(FUNC(pk8020_state::text_w),state));
+ // RAM
+ space->install_read_bank (0x4000, 0xffff, "bank4");
+ space->install_write_bank(0x4000, 0xffff, "bank5");
+ state->membank("bank4")->set_base(ram + 0x4000);
+ state->membank("bank5")->set_base(ram + 0x4000);
+ }
+ break;
+ case 0x01 : {
+ // ROM
+ space->install_read_bank (0x0000, 0x1fff, "bank1");
+ space->install_write_bank(0x0000, 0x1fff, "bank2");
+ state->membank("bank1")->set_base(mem + 0x10000);
+ state->membank("bank2")->set_base(ram + 0x0000);
+ // RAM
+ space->install_read_bank (0x2000, 0xffff, "bank3");
+ space->install_write_bank(0x2000, 0xffff, "bank4");
+ state->membank("bank3")->set_base(ram + 0x2000);
+ state->membank("bank4")->set_base(ram + 0x2000);
+ }
+ break;
+ case 0x02 : {
+ // ROM
+ space->install_read_bank (0x0000, 0x3fff, "bank1");
+ space->install_write_bank(0x0000, 0x3fff, "bank2");
+ state->membank("bank1")->set_base(mem + 0x10000);
+ state->membank("bank2")->set_base(ram + 0x0000);
+ // RAM
+ space->install_read_bank (0x4000, 0xffff, "bank3");
+ space->install_write_bank(0x4000, 0xffff, "bank4");
+ state->membank("bank3")->set_base(ram + 0x4000);
+ state->membank("bank4")->set_base(ram + 0x4000);
+ }
+ break;
+ case 0x03 : {
+ // RAM
+ space->install_read_bank (0x0000, 0xffff, "bank1");
+ space->install_write_bank(0x0000, 0xffff, "bank2");
+ state->membank("bank1")->set_base(ram);
+ state->membank("bank2")->set_base(ram);
+ }
+ break;
+ case 0x04 :
+ case 0x05 :
+ {
+ // ROM
+ space->install_read_bank (0x0000, 0x1fff, "bank1");
+ space->install_write_bank(0x0000, 0x1fff, "bank2");
+ state->membank("bank1")->set_base(mem + 0x10000);
+ state->membank("bank2")->set_base(ram + 0x0000);
+ // RAM
+ space->install_read_bank (0x2000, 0xf7ff, "bank3");
+ space->install_write_bank(0x2000, 0xf7ff, "bank4");
+ state->membank("bank3")->set_base(ram + 0x2000);
+ state->membank("bank4")->set_base(ram + 0x2000);
+ // Keyboard
+ space->install_read_handler (0xf800, 0xf9ff, read8_delegate(FUNC(pk8020_state::keyboard_r),state));
+ space->install_write_bank(0xf800, 0xf9ff, "bank5");
+ state->membank("bank5")->set_base(ram + 0xf800);
+ // System reg
+ space->install_read_handler (0xfa00, 0xfaff, read8_delegate(FUNC(pk8020_state::sysreg_r),state));
+ space->install_write_handler(0xfa00, 0xfaff, write8_delegate(FUNC(pk8020_state::sysreg_w),state));
+ // Devices
+ space->install_read_handler (0xfb00, 0xfbff, read8_delegate(FUNC(pk8020_state::devices_r),state));
+ space->install_write_handler(0xfb00, 0xfbff, write8_delegate(FUNC(pk8020_state::devices_w),state));
+ // Text Video Memory
+ space->install_read_handler (0xfc00, 0xffff, read8_delegate(FUNC(pk8020_state::text_r),state));
+ space->install_write_handler(0xfc00, 0xffff, write8_delegate(FUNC(pk8020_state::text_w),state));
+ }
+ break;
+ case 0x06 :
+ {
+ // ROM
+ space->install_read_bank (0x0000, 0x3fff, "bank1");
+ space->install_write_bank(0x0000, 0x3fff, "bank2");
+ state->membank("bank1")->set_base(mem + 0x10000);
+ state->membank("bank2")->set_base(ram + 0x0000);
+ // RAM
+ space->install_read_bank (0x4000, 0xf7ff, "bank3");
+ space->install_write_bank(0x4000, 0xf7ff, "bank4");
+ state->membank("bank3")->set_base(ram + 0x4000);
+ state->membank("bank4")->set_base(ram + 0x4000);
+ // Keyboard
+ space->install_read_handler (0xf800, 0xf9ff, read8_delegate(FUNC(pk8020_state::keyboard_r),state));
+ space->install_write_bank(0xf800, 0xf9ff, "bank5");
+ state->membank("bank5")->set_base(ram + 0xf800);
+ // System reg
+ space->install_read_handler (0xfa00, 0xfaff, read8_delegate(FUNC(pk8020_state::sysreg_r),state));
+ space->install_write_handler(0xfa00, 0xfaff, write8_delegate(FUNC(pk8020_state::sysreg_w),state));
+ // Devices
+ space->install_read_handler (0xfb00, 0xfbff, read8_delegate(FUNC(pk8020_state::devices_r),state));
+ space->install_write_handler(0xfb00, 0xfbff, write8_delegate(FUNC(pk8020_state::devices_w),state));
+ // Text Video Memory
+ space->install_read_handler (0xfc00, 0xffff, read8_delegate(FUNC(pk8020_state::text_r),state));
+ space->install_write_handler(0xfc00, 0xffff, write8_delegate(FUNC(pk8020_state::text_w),state));
+ }
+ break;
+ case 0x07 :
+ {
+ // RAM
+ space->install_read_bank (0x0000, 0xf7ff, "bank1");
+ space->install_write_bank(0x0000, 0xf7ff, "bank2");
+ state->membank("bank1")->set_base(ram);
+ state->membank("bank2")->set_base(ram);
+ // Keyboard
+ space->install_read_handler (0xf800, 0xf9ff, read8_delegate(FUNC(pk8020_state::keyboard_r),state));
+ space->install_write_bank(0xf800, 0xf9ff, "bank3");
+ state->membank("bank3")->set_base(ram + 0xf800);
+ // System reg
+ space->install_read_handler (0xfa00, 0xfaff, read8_delegate(FUNC(pk8020_state::sysreg_r),state));
+ space->install_write_handler(0xfa00, 0xfaff, write8_delegate(FUNC(pk8020_state::sysreg_w),state));
+ // Devices
+ space->install_read_handler (0xfb00, 0xfbff, read8_delegate(FUNC(pk8020_state::devices_r),state));
+ space->install_write_handler(0xfb00, 0xfbff, write8_delegate(FUNC(pk8020_state::devices_w),state));
+ // Text Video Memory
+ space->install_read_handler (0xfc00, 0xffff, read8_delegate(FUNC(pk8020_state::text_r),state));
+ space->install_write_handler(0xfc00, 0xffff, write8_delegate(FUNC(pk8020_state::text_w),state));
+ }
+ break;
+ case 0x08 :
+ {
+ // ROM
+ space->install_read_bank (0x0000, 0x3fff, "bank1");
+ space->install_write_bank(0x0000, 0x3fff, "bank2");
+ state->membank("bank1")->set_base(mem + 0x10000);
+ state->membank("bank2")->set_base(ram + 0x0000);
+ // Keyboard
+ space->install_read_handler (0x3800, 0x39ff, read8_delegate(FUNC(pk8020_state::keyboard_r),state));
+ space->install_write_bank(0x3800, 0x39ff, "bank3");
+ state->membank("bank3")->set_base(ram + 0x3800);
+ // System reg
+ space->install_read_handler (0x3a00, 0x3aff, read8_delegate(FUNC(pk8020_state::sysreg_r),state));
+ space->install_write_handler(0x3a00, 0x3aff, write8_delegate(FUNC(pk8020_state::sysreg_w),state));
+ // Devices
+ space->install_read_handler (0x3b00, 0x3bff, read8_delegate(FUNC(pk8020_state::devices_r),state));
+ space->install_write_handler(0x3b00, 0x3bff, write8_delegate(FUNC(pk8020_state::devices_w),state));
+ // Text Video Memory
+ space->install_read_handler (0x3c00, 0x3fff, read8_delegate(FUNC(pk8020_state::text_r),state));
+ space->install_write_handler(0x3c00, 0x3fff, write8_delegate(FUNC(pk8020_state::text_w),state));
+ // RAM
+ space->install_read_bank (0x4000, 0xbfff, "bank4");
+ space->install_write_bank(0x4000, 0xbfff, "bank5");
+ state->membank("bank4")->set_base(ram + 0x4000);
+ state->membank("bank5")->set_base(ram + 0x4000);
+ // Video RAM
+ space->install_read_handler (0xc000, 0xffff, read8_delegate(FUNC(pk8020_state::gzu_r),state));
+ space->install_write_handler(0xc000, 0xffff, write8_delegate(FUNC(pk8020_state::gzu_w),state));
+
+ }
+ break;
+ case 0x09 :
+ {
+ // ROM
+ space->install_read_bank (0x0000, 0x1fff, "bank1");
+ space->install_write_bank(0x0000, 0x1fff, "bank2");
+ state->membank("bank1")->set_base(mem + 0x10000);
+ state->membank("bank2")->set_base(ram + 0x0000);
+ // RAM
+ space->install_read_bank (0x2000, 0xbfff, "bank3");
+ space->install_write_bank(0x2000, 0xbfff, "bank4");
+ state->membank("bank3")->set_base(ram + 0x2000);
+ state->membank("bank4")->set_base(ram + 0x2000);
+ // Video RAM
+ space->install_read_handler (0xc000, 0xffff, read8_delegate(FUNC(pk8020_state::gzu_r),state));
+ space->install_write_handler(0xc000, 0xffff, write8_delegate(FUNC(pk8020_state::gzu_w),state));
+ }
+ break;
+ case 0x0A :
+ {
+ // ROM
+ space->install_read_bank (0x0000, 0x3fff, "bank1");
+ space->install_write_bank(0x0000, 0x3fff, "bank2");
+ state->membank("bank1")->set_base(mem + 0x10000);
+ state->membank("bank2")->set_base(ram + 0x0000);
+ // RAM
+ space->install_read_bank (0x4000, 0xbfff, "bank3");
+ space->install_write_bank(0x4000, 0xbfff, "bank4");
+ state->membank("bank3")->set_base(ram + 0x4000);
+ state->membank("bank4")->set_base(ram + 0x4000);
+ // Video RAM
+ space->install_read_handler (0xc000, 0xffff, read8_delegate(FUNC(pk8020_state::gzu_r),state));
+ space->install_write_handler(0xc000, 0xffff, write8_delegate(FUNC(pk8020_state::gzu_w),state));
+ }
+ break;
+ case 0x0B :
+ {
+ // RAM
+ space->install_read_bank (0x0000, 0xbfff, "bank1");
+ space->install_write_bank(0x0000, 0xbfff, "bank2");
+ state->membank("bank1")->set_base(ram + 0x0000);
+ state->membank("bank2")->set_base(ram + 0x0000);
+ // Video RAM
+ space->install_read_handler (0xc000, 0xffff, read8_delegate(FUNC(pk8020_state::gzu_r),state));
+ space->install_write_handler(0xc000, 0xffff, write8_delegate(FUNC(pk8020_state::gzu_w),state));
+ }
+ break;
+ case 0x0C :
+ case 0x0D :
+ {
+ // ROM
+ space->install_read_bank (0x0000, 0x1fff, "bank1");
+ space->install_write_bank(0x0000, 0x1fff, "bank2");
+ state->membank("bank1")->set_base(mem + 0x10000);
+ state->membank("bank2")->set_base(ram + 0x0000);
+ // RAM
+ space->install_read_bank (0x2000, 0x3fff, "bank3");
+ space->install_write_bank(0x2000, 0x3fff, "bank4");
+ state->membank("bank3")->set_base(ram + 0x2000);
+ state->membank("bank4")->set_base(ram + 0x2000);
+ // Video RAM
+ space->install_read_handler (0x4000, 0x7fff, read8_delegate(FUNC(pk8020_state::gzu_r),state));
+ space->install_write_handler(0x4000, 0x7fff, write8_delegate(FUNC(pk8020_state::gzu_w),state));
+ // RAM
+ space->install_read_bank (0x8000, 0xfdff, "bank5");
+ space->install_write_bank(0x8000, 0xfdff, "bank6");
+ state->membank("bank5")->set_base(ram + 0x8000);
+ state->membank("bank6")->set_base(ram + 0x8000);
+ // Devices
+ space->install_read_handler (0xfe00, 0xfeff, read8_delegate(FUNC(pk8020_state::devices_r),state));
+ space->install_write_handler(0xfe00, 0xfeff, write8_delegate(FUNC(pk8020_state::devices_w),state));
+ // System reg
+ space->install_read_handler (0xff00, 0xffff, read8_delegate(FUNC(pk8020_state::sysreg_r),state));
+ space->install_write_handler(0xff00, 0xffff, write8_delegate(FUNC(pk8020_state::sysreg_w),state));
+ }
+ break;
+ case 0x0E :
+ {
+ // ROM
+ space->install_read_bank (0x0000, 0x3fff, "bank1");
+ space->install_write_bank(0x0000, 0x3fff, "bank2");
+ state->membank("bank1")->set_base(mem + 0x10000);
+ state->membank("bank2")->set_base(ram + 0x0000);
+ // Video RAM
+ space->install_read_handler (0x4000, 0x7fff, read8_delegate(FUNC(pk8020_state::gzu_r),state));
+ space->install_write_handler(0x4000, 0x7fff, write8_delegate(FUNC(pk8020_state::gzu_w),state));
+ // RAM
+ space->install_read_bank (0x8000, 0xfdff, "bank5");
+ space->install_write_bank(0x8000, 0xfdff, "bank6");
+ state->membank("bank5")->set_base(ram + 0x8000);
+ state->membank("bank6")->set_base(ram + 0x8000);
+ // Devices
+ space->install_read_handler (0xfe00, 0xfeff, read8_delegate(FUNC(pk8020_state::devices_r),state));
+ space->install_write_handler(0xfe00, 0xfeff, write8_delegate(FUNC(pk8020_state::devices_w),state));
+ // System reg
+ space->install_read_handler (0xff00, 0xffff, read8_delegate(FUNC(pk8020_state::sysreg_r),state));
+ space->install_write_handler(0xff00, 0xffff, write8_delegate(FUNC(pk8020_state::sysreg_w),state));
+ }
+ break;
+ case 0x0F :
+ {
+ // RAM
+ space->install_read_bank (0x0000, 0x3fff, "bank1");
+ space->install_write_bank(0x0000, 0x3fff, "bank2");
+ state->membank("bank1")->set_base(ram + 0x0000);
+ state->membank("bank2")->set_base(ram + 0x0000);
+ // Video RAM
+ space->install_read_handler (0x4000, 0x7fff, read8_delegate(FUNC(pk8020_state::gzu_r),state));
+ space->install_write_handler(0x4000, 0x7fff, write8_delegate(FUNC(pk8020_state::gzu_w),state));
+ // RAM
+ space->install_read_bank (0x8000, 0xfdff, "bank3");
+ space->install_write_bank(0x8000, 0xfdff, "bank4");
+ state->membank("bank3")->set_base(ram + 0x8000);
+ state->membank("bank4")->set_base(ram + 0x8000);
+ // Devices
+ space->install_read_handler (0xfe00, 0xfeff, read8_delegate(FUNC(pk8020_state::devices_r),state));
+ space->install_write_handler(0xfe00, 0xfeff, write8_delegate(FUNC(pk8020_state::devices_w),state));
+ // System reg
+ space->install_read_handler (0xff00, 0xffff, read8_delegate(FUNC(pk8020_state::sysreg_r),state));
+ space->install_write_handler(0xff00, 0xffff, write8_delegate(FUNC(pk8020_state::sysreg_w),state));
+ }
+ break;
+ case 0x10 :
+ {
+ // ROM
+ space->install_read_bank (0x0000, 0x5fff, "bank1");
+ space->install_write_bank(0x0000, 0x5fff, "bank2");
+ state->membank("bank1")->set_base(mem + 0x10000);
+ state->membank("bank2")->set_base(ram + 0x0000);
+ // RAM
+ space->install_read_bank (0x6000, 0xf7ff, "bank3");
+ space->install_write_bank(0x6000, 0xf7ff, "bank4");
+ state->membank("bank3")->set_base(ram + 0x6000);
+ state->membank("bank4")->set_base(ram + 0x6000);
+ // Keyboard
+ space->install_read_handler (0xf800, 0xf9ff, read8_delegate(FUNC(pk8020_state::keyboard_r),state));
+ space->install_write_bank(0xf800, 0xf9ff, "bank5");
+ state->membank("bank5")->set_base(ram + 0xf800);
+ // System reg
+ space->install_read_handler (0xfa00, 0xfaff, read8_delegate(FUNC(pk8020_state::sysreg_r),state));
+ space->install_write_handler(0xfa00, 0xfaff, write8_delegate(FUNC(pk8020_state::sysreg_w),state));
+ // Devices
+ space->install_read_handler (0xfb00, 0xfbff, read8_delegate(FUNC(pk8020_state::devices_r),state));
+ space->install_write_handler(0xfb00, 0xfbff, write8_delegate(FUNC(pk8020_state::devices_w),state));
+ // Text Video Memory
+ space->install_read_handler (0xfc00, 0xffff, read8_delegate(FUNC(pk8020_state::text_r),state));
+ space->install_write_handler(0xfc00, 0xffff, write8_delegate(FUNC(pk8020_state::text_w),state));
+ }
+ break;
+ case 0x11 :
+ {
+ // ROM
+ space->install_read_bank (0x0000, 0x1fff, "bank1");
+ space->install_write_bank(0x0000, 0x1fff, "bank2");
+ state->membank("bank1")->set_base(mem + 0x10000);
+ state->membank("bank2")->set_base(ram + 0x0000);
+ // RAM
+ space->install_read_bank (0x2000, 0xf7ff, "bank3");
+ space->install_write_bank(0x2000, 0xf7ff, "bank4");
+ state->membank("bank3")->set_base(ram + 0x2000);
+ state->membank("bank4")->set_base(ram + 0x2000);
+ // Keyboard
+ space->install_read_handler (0xf800, 0xf9ff, read8_delegate(FUNC(pk8020_state::keyboard_r),state));
+ space->install_write_bank(0xf800, 0xf9ff, "bank5");
+ state->membank("bank5")->set_base(ram + 0xf800);
+ // System reg
+ space->install_read_handler (0xfa00, 0xfaff, read8_delegate(FUNC(pk8020_state::sysreg_r),state));
+ space->install_write_handler(0xfa00, 0xfaff, write8_delegate(FUNC(pk8020_state::sysreg_w),state));
+ // Devices
+ space->install_read_handler (0xfb00, 0xfbff, read8_delegate(FUNC(pk8020_state::devices_r),state));
+ space->install_write_handler(0xfb00, 0xfbff, write8_delegate(FUNC(pk8020_state::devices_w),state));
+ // Text Video Memory
+ space->install_read_handler (0xfc00, 0xffff, read8_delegate(FUNC(pk8020_state::text_r),state));
+ space->install_write_handler(0xfc00, 0xffff, write8_delegate(FUNC(pk8020_state::text_w),state));
+ }
+ break;
+ case 0x12 :
+ {
+ // ROM
+ space->install_read_bank (0x0000, 0x3fff, "bank1");
+ space->install_write_bank(0x0000, 0x3fff, "bank2");
+ state->membank("bank1")->set_base(mem + 0x10000);
+ state->membank("bank2")->set_base(ram + 0x0000);
+ // RAM
+ space->install_read_bank (0x4000, 0xf7ff, "bank3");
+ space->install_write_bank(0x4000, 0xf7ff, "bank4");
+ state->membank("bank3")->set_base(ram + 0x4000);
+ state->membank("bank4")->set_base(ram + 0x4000);
+ // Keyboard
+ space->install_read_handler (0xf800, 0xf9ff, read8_delegate(FUNC(pk8020_state::keyboard_r),state));
+ space->install_write_bank(0xf800, 0xf9ff, "bank5");
+ state->membank("bank5")->set_base(ram + 0xf800);
+ // System reg
+ space->install_read_handler (0xfa00, 0xfaff, read8_delegate(FUNC(pk8020_state::sysreg_r),state));
+ space->install_write_handler(0xfa00, 0xfaff, write8_delegate(FUNC(pk8020_state::sysreg_w),state));
+ // Devices
+ space->install_read_handler (0xfb00, 0xfbff, read8_delegate(FUNC(pk8020_state::devices_r),state));
+ space->install_write_handler(0xfb00, 0xfbff, write8_delegate(FUNC(pk8020_state::devices_w),state));
+ // Text Video Memory
+ space->install_read_handler (0xfc00, 0xffff, read8_delegate(FUNC(pk8020_state::text_r),state));
+ space->install_write_handler(0xfc00, 0xffff, write8_delegate(FUNC(pk8020_state::text_w),state));
+ }
+ break;
+ case 0x13 :
+ {
+ // RAM
+ space->install_read_bank (0x0000, 0xf7ff, "bank1");
+ space->install_write_bank(0x0000, 0xf7ff, "bank2");
+ state->membank("bank1")->set_base(ram + 0x0000);
+ state->membank("bank2")->set_base(ram + 0x0000);
+ // Keyboard
+ space->install_read_handler (0xf800, 0xf9ff, read8_delegate(FUNC(pk8020_state::keyboard_r),state));
+ space->install_write_bank(0xf800, 0xf9ff, "bank3");
+ state->membank("bank3")->set_base(ram + 0xf800);
+ // System reg
+ space->install_read_handler (0xfa00, 0xfaff, read8_delegate(FUNC(pk8020_state::sysreg_r),state));
+ space->install_write_handler(0xfa00, 0xfaff, write8_delegate(FUNC(pk8020_state::sysreg_w),state));
+ // Devices
+ space->install_read_handler (0xfb00, 0xfbff, read8_delegate(FUNC(pk8020_state::devices_r),state));
+ space->install_write_handler(0xfb00, 0xfbff, write8_delegate(FUNC(pk8020_state::devices_w),state));
+ // Text Video Memory
+ space->install_read_handler (0xfc00, 0xffff, read8_delegate(FUNC(pk8020_state::text_r),state));
+ space->install_write_handler(0xfc00, 0xffff, write8_delegate(FUNC(pk8020_state::text_w),state));
+ }
+ break;
+ case 0x14 :
+ {
+ // ROM
+ space->install_read_bank (0x0000, 0x5fff, "bank1");
+ space->install_write_bank(0x0000, 0x5fff, "bank2");
+ state->membank("bank1")->set_base(mem + 0x10000);
+ state->membank("bank2")->set_base(ram + 0x0000);
+ // RAM
+ space->install_read_bank (0x6000, 0xfdff, "bank3");
+ space->install_write_bank(0x6000, 0xfdff, "bank4");
+ state->membank("bank3")->set_base(ram + 0x6000);
+ state->membank("bank4")->set_base(ram + 0x6000);
+ // Devices
+ space->install_read_handler (0xfe00, 0xfeff, read8_delegate(FUNC(pk8020_state::devices_r),state));
+ space->install_write_handler(0xfe00, 0xfeff, write8_delegate(FUNC(pk8020_state::devices_w),state));
+ // System reg
+ space->install_read_handler (0xff00, 0xffff, read8_delegate(FUNC(pk8020_state::sysreg_r),state));
+ space->install_write_handler(0xff00, 0xffff, write8_delegate(FUNC(pk8020_state::sysreg_w),state));
+ }
+ break;
+ case 0x15 :
+ {
+ // ROM
+ space->install_read_bank (0x0000, 0x1fff, "bank1");
+ space->install_write_bank(0x0000, 0x1fff, "bank2");
+ state->membank("bank1")->set_base(mem + 0x10000);
+ state->membank("bank2")->set_base(ram + 0x0000);
+ // RAM
+ space->install_read_bank (0x2000, 0xfdff, "bank3");
+ space->install_write_bank(0x2000, 0xfdff, "bank4");
+ state->membank("bank3")->set_base(ram + 0x2000);
+ state->membank("bank4")->set_base(ram + 0x2000);
+ // Devices
+ space->install_read_handler (0xfe00, 0xfeff, read8_delegate(FUNC(pk8020_state::devices_r),state));
+ space->install_write_handler(0xfe00, 0xfeff, write8_delegate(FUNC(pk8020_state::devices_w),state));
+ // System reg
+ space->install_read_handler (0xff00, 0xffff, read8_delegate(FUNC(pk8020_state::sysreg_r),state));
+ space->install_write_handler(0xff00, 0xffff, write8_delegate(FUNC(pk8020_state::sysreg_w),state));
+ }
+ break;
+ case 0x16 :
+ {
+ // ROM
+ space->install_read_bank (0x0000, 0x3fff, "bank1");
+ space->install_write_bank(0x0000, 0x3fff, "bank2");
+ state->membank("bank1")->set_base(mem + 0x10000);
+ state->membank("bank2")->set_base(ram + 0x0000);
+ // RAM
+ space->install_read_bank (0x4000, 0xfdff, "bank3");
+ space->install_write_bank(0x4000, 0xfdff, "bank4");
+ state->membank("bank3")->set_base(ram + 0x4000);
+ state->membank("bank4")->set_base(ram + 0x4000);
+ // Devices
+ space->install_read_handler (0xfe00, 0xfeff, read8_delegate(FUNC(pk8020_state::devices_r),state));
+ space->install_write_handler(0xfe00, 0xfeff, write8_delegate(FUNC(pk8020_state::devices_w),state));
+ // System reg
+ space->install_read_handler (0xff00, 0xffff, read8_delegate(FUNC(pk8020_state::sysreg_r),state));
+ space->install_write_handler(0xff00, 0xffff, write8_delegate(FUNC(pk8020_state::sysreg_w),state));
+ }
+ break;
+ case 0x17 :
+ {
+ // RAM
+ space->install_read_bank (0x0000, 0xfdff, "bank1");
+ space->install_write_bank(0x0000, 0xfdff, "bank2");
+ state->membank("bank1")->set_base(ram);
+ state->membank("bank2")->set_base(ram);
+ // Devices
+ space->install_read_handler (0xfe00, 0xfeff, read8_delegate(FUNC(pk8020_state::devices_r),state));
+ space->install_write_handler(0xfe00, 0xfeff, write8_delegate(FUNC(pk8020_state::devices_w),state));
+ // System reg
+ space->install_read_handler (0xff00, 0xffff, read8_delegate(FUNC(pk8020_state::sysreg_r),state));
+ space->install_write_handler(0xff00, 0xffff, write8_delegate(FUNC(pk8020_state::sysreg_w),state));
+ }
+ break;
+ case 0x18 :
+ {
+ // ROM
+ space->install_read_bank (0x0000, 0x5fff, "bank1");
+ space->install_write_bank(0x0000, 0x5fff, "bank2");
+ state->membank("bank1")->set_base(mem + 0x10000);
+ state->membank("bank2")->set_base(ram + 0x0000);
+ // RAM
+ space->install_read_bank (0x6000, 0xbeff, "bank3");
+ space->install_write_bank(0x6000, 0xbeff, "bank4");
+ state->membank("bank3")->set_base(ram + 0x6000);
+ state->membank("bank4")->set_base(ram + 0x6000);
+ // System reg
+ space->install_read_handler (0xbf00, 0xbfff, read8_delegate(FUNC(pk8020_state::sysreg_r),state));
+ space->install_write_handler(0xbf00, 0xbfff, write8_delegate(FUNC(pk8020_state::sysreg_w),state));
+ // Video RAM
+ space->install_read_handler (0xc000, 0xffff, read8_delegate(FUNC(pk8020_state::gzu_r),state));
+ space->install_write_handler(0xc000, 0xffff, write8_delegate(FUNC(pk8020_state::gzu_w),state));
+ }
+ break;
+ case 0x19 :
+ {
+ // ROM
+ space->install_read_bank (0x0000, 0x1fff, "bank1");
+ space->install_write_bank(0x0000, 0x1fff, "bank2");
+ state->membank("bank1")->set_base(mem + 0x10000);
+ state->membank("bank2")->set_base(ram + 0x0000);
+ // RAM
+ space->install_read_bank (0x2000, 0xbeff, "bank3");
+ space->install_write_bank(0x2000, 0xbeff, "bank4");
+ state->membank("bank3")->set_base(ram + 0x2000);
+ state->membank("bank4")->set_base(ram + 0x2000);
+ // System reg
+ space->install_read_handler (0xbf00, 0xbfff, read8_delegate(FUNC(pk8020_state::sysreg_r),state));
+ space->install_write_handler(0xbf00, 0xbfff, write8_delegate(FUNC(pk8020_state::sysreg_w),state));
+ // Video RAM
+ space->install_read_handler (0xc000, 0xffff, read8_delegate(FUNC(pk8020_state::gzu_r),state));
+ space->install_write_handler(0xc000, 0xffff, write8_delegate(FUNC(pk8020_state::gzu_w),state));
+ }
+ break;
+ case 0x1A :
+ {
+ // ROM
+ space->install_read_bank (0x0000, 0x3fff, "bank1");
+ space->install_write_bank(0x0000, 0x3fff, "bank2");
+ state->membank("bank1")->set_base(mem + 0x10000);
+ state->membank("bank2")->set_base(ram + 0x0000);
+ // RAM
+ space->install_read_bank (0x4000, 0xbeff, "bank3");
+ space->install_write_bank(0x4000, 0xbeff, "bank4");
+ state->membank("bank3")->set_base(ram + 0x4000);
+ state->membank("bank4")->set_base(ram + 0x4000);
+ // System reg
+ space->install_read_handler (0xbf00, 0xbfff, read8_delegate(FUNC(pk8020_state::sysreg_r),state));
+ space->install_write_handler(0xbf00, 0xbfff, write8_delegate(FUNC(pk8020_state::sysreg_w),state));
+ // Video RAM
+ space->install_read_handler (0xc000, 0xffff, read8_delegate(FUNC(pk8020_state::gzu_r),state));
+ space->install_write_handler(0xc000, 0xffff, write8_delegate(FUNC(pk8020_state::gzu_w),state));
+ }
+ break;
+ case 0x1B :
+ {
+ // RAM
+ space->install_read_bank (0x0000, 0xbeff, "bank1");
+ space->install_write_bank(0x0000, 0xbeff, "bank2");
+ state->membank("bank1")->set_base(ram);
+ state->membank("bank2")->set_base(ram);
+ // System reg
+ space->install_read_handler (0xbf00, 0xbfff, read8_delegate(FUNC(pk8020_state::sysreg_r),state));
+ space->install_write_handler(0xbf00, 0xbfff, write8_delegate(FUNC(pk8020_state::sysreg_w),state));
+ // Video RAM
+ space->install_read_handler (0xc000, 0xffff, read8_delegate(FUNC(pk8020_state::gzu_r),state));
+ space->install_write_handler(0xc000, 0xffff, write8_delegate(FUNC(pk8020_state::gzu_w),state));
+ }
+ break;
+ case 0x1C :
+ {
+ // ROM
+ space->install_read_bank (0x0000, 0x5fff, "bank1");
+ space->install_write_bank(0x0000, 0x5fff, "bank2");
+ state->membank("bank1")->set_base(mem + 0x10000);
+ state->membank("bank2")->set_base(ram + 0x0000);
+ // RAM
+ space->install_read_bank (0x6000, 0xbfff, "bank3");
+ space->install_write_bank(0x6000, 0xbfff, "bank4");
+ state->membank("bank3")->set_base(ram + 0x6000);
+ state->membank("bank4")->set_base(ram + 0x6000);
+ // Video RAM
+ space->install_read_handler (0xc000, 0xffff, read8_delegate(FUNC(pk8020_state::gzu_r),state));
+ space->install_write_handler(0xc000, 0xffff, write8_delegate(FUNC(pk8020_state::gzu_w),state));
+ }
+ break;
+ case 0x1D :
+ {
+ // ROM
+ space->install_read_bank (0x0000, 0x1fff, "bank1");
+ space->install_write_bank(0x0000, 0x1fff, "bank2");
+ state->membank("bank1")->set_base(mem + 0x10000);
+ state->membank("bank2")->set_base(ram + 0x0000);
+ // RAM
+ space->install_read_bank (0x2000, 0xbfff, "bank3");
+ space->install_write_bank(0x2000, 0xbfff, "bank4");
+ state->membank("bank3")->set_base(ram + 0x2000);
+ state->membank("bank4")->set_base(ram + 0x2000);
+ // Video RAM
+ space->install_read_handler (0xc000, 0xffff, read8_delegate(FUNC(pk8020_state::gzu_r),state));
+ space->install_write_handler(0xc000, 0xffff, write8_delegate(FUNC(pk8020_state::gzu_w),state));
+ }
+ break;
+ case 0x1E :
+ {
+ // ROM
+ space->install_read_bank (0x0000, 0x3fff, "bank1");
+ space->install_write_bank(0x0000, 0x3fff, "bank2");
+ state->membank("bank1")->set_base(mem + 0x10000);
+ state->membank("bank2")->set_base(ram + 0x0000);
+ // RAM
+ space->install_read_bank (0x4000, 0xbfff, "bank3");
+ space->install_write_bank(0x4000, 0xbfff, "bank4");
+ state->membank("bank3")->set_base(ram + 0x4000);
+ state->membank("bank4")->set_base(ram + 0x4000);
+ // Video RAM
+ space->install_read_handler (0xc000, 0xffff, read8_delegate(FUNC(pk8020_state::gzu_r),state));
+ space->install_write_handler(0xc000, 0xffff, write8_delegate(FUNC(pk8020_state::gzu_w),state));
+ }
+ break;
+ case 0x1F :
+ {
+ // RAM
+ space->install_read_bank (0x0000, 0xbfff, "bank1");
+ space->install_write_bank(0x0000, 0xbfff, "bank2");
+ state->membank("bank1")->set_base(ram);
+ state->membank("bank2")->set_base(ram);
+ // Video RAM
+ space->install_read_handler (0xc000, 0xffff, read8_delegate(FUNC(pk8020_state::gzu_r),state));
+ space->install_write_handler(0xc000, 0xffff, write8_delegate(FUNC(pk8020_state::gzu_w),state));
+ }
+ break;
+
+ }
+}
+
+static READ8_DEVICE_HANDLER(pk8020_porta_r)
+{
+ pk8020_state *state = device->machine().driver_data<pk8020_state>();
+ return 0xf0 | (state->m_takt <<1) | (state->m_text_attr)<<3;
+}
+
+static WRITE8_DEVICE_HANDLER(pk8020_portc_w)
+{
+ pk8020_state *state = device->machine().driver_data<pk8020_state>();
+ state->m_video_page_access =(data>>6) & 3;
+ state->m_attr = (data >> 4) & 3;
+ state->m_wide = (data >> 3) & 1;
+ state->m_font = (data >> 2) & 1;
+ state->m_video_page = (data & 3);
+
+
+ state->m_portc_data = data;
+}
+
+static WRITE8_DEVICE_HANDLER(pk8020_portb_w)
+{
+ device_t *fdc = device->machine().device("wd1793");
+ // Turn all motors off
+ floppy_mon_w(floppy_get_device(device->machine(), 0), 1);
+ floppy_mon_w(floppy_get_device(device->machine(), 1), 1);
+ floppy_mon_w(floppy_get_device(device->machine(), 2), 1);
+ floppy_mon_w(floppy_get_device(device->machine(), 3), 1);
+ wd17xx_set_side(fdc,BIT(data,4));
+ if (BIT(data,0)) {
+ wd17xx_set_drive(fdc,0);
+ floppy_mon_w(floppy_get_device(device->machine(), 0), 0);
+ floppy_drive_set_ready_state(floppy_get_device(device->machine(), 0), 1, 1);
+ } else if (BIT(data,1)) {
+ wd17xx_set_drive(fdc,1);
+ floppy_mon_w(floppy_get_device(device->machine(), 1), 0);
+ floppy_drive_set_ready_state(floppy_get_device(device->machine(), 1), 1, 1);
+ } else if (BIT(data,2)) {
+ wd17xx_set_drive(fdc,2);
+ floppy_mon_w(floppy_get_device(device->machine(), 2), 0);
+ floppy_drive_set_ready_state(floppy_get_device(device->machine(), 2), 1, 1);
+ } else if (BIT(data,3)) {
+ wd17xx_set_drive(fdc,3);
+ floppy_mon_w(floppy_get_device(device->machine(), 3), 0);
+ floppy_drive_set_ready_state(floppy_get_device(device->machine(), 3), 1, 1);
+ }
+}
+
+static READ8_DEVICE_HANDLER(pk8020_portc_r)
+{
+ pk8020_state *state = device->machine().driver_data<pk8020_state>();
+ return state->m_portc_data;
+}
+
+
+I8255A_INTERFACE( pk8020_ppi8255_interface_1 )
+{
+ DEVCB_HANDLER(pk8020_porta_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(pk8020_portb_w),
+ DEVCB_HANDLER(pk8020_portc_r),
+ DEVCB_HANDLER(pk8020_portc_w)
+};
+
+static WRITE8_DEVICE_HANDLER(pk8020_2_portc_w)
+{
+ pk8020_state *state = device->machine().driver_data<pk8020_state>();
+ device_t *speaker = device->machine().device(SPEAKER_TAG);
+
+ state->m_sound_gate = BIT(data,3);
+
+ speaker_level_w(speaker, state->m_sound_gate ? state->m_sound_level : 0);
+}
+
+I8255A_INTERFACE( pk8020_ppi8255_interface_2 )
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(pk8020_2_portc_w)
+};
+
+I8255A_INTERFACE( pk8020_ppi8255_interface_3 )
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+static WRITE_LINE_DEVICE_HANDLER( pk8020_pit_out0 )
+{
+ pk8020_state *drvstate = device->machine().driver_data<pk8020_state>();
+ device_t *speaker = device->machine().device(SPEAKER_TAG);
+
+ drvstate->m_sound_level = state;
+
+ speaker_level_w(speaker, drvstate->m_sound_gate ? drvstate->m_sound_level : 0);
+}
+
+
+static WRITE_LINE_DEVICE_HANDLER(pk8020_pit_out1)
+{
+}
+
+
+const struct pit8253_config pk8020_pit8253_intf =
+{
+ {
+ {
+ XTAL_20MHz / 10,
+ DEVCB_NULL,
+ DEVCB_LINE(pk8020_pit_out0)
+ },
+ {
+ XTAL_20MHz / 10,
+ DEVCB_NULL,
+ DEVCB_LINE(pk8020_pit_out1)
+ },
+ {
+ (XTAL_20MHz / 8) / 164,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE("pic8259", pic8259_ir5_w)
+ }
+ }
+};
+
+static WRITE_LINE_DEVICE_HANDLER( pk8020_pic_set_int_line )
+{
+ cputag_set_input_line(device->machine(), "maincpu", 0, state ? HOLD_LINE : CLEAR_LINE);
+}
+
+const struct pic8259_interface pk8020_pic8259_config =
+{
+ DEVCB_LINE(pk8020_pic_set_int_line),
+ DEVCB_LINE_VCC,
+ DEVCB_NULL
+};
+
+static IRQ_CALLBACK( pk8020_irq_callback )
+{
+ return pic8259_acknowledge(device->machine().device("pic8259"));
+}
+
+MACHINE_RESET( pk8020 )
+{
+ pk8020_state *state = machine.driver_data<pk8020_state>();
+ pk8020_set_bank(machine,0);
+ device_set_irq_callback(machine.device("maincpu"), pk8020_irq_callback);
+
+ state->m_sound_gate = 0;
+ state->m_sound_level = 0;
+}
+
+INTERRUPT_GEN( pk8020_interrupt )
+{
+ pk8020_state *state = device->machine().driver_data<pk8020_state>();
+ state->m_takt ^= 1;
+ pic8259_ir4_w(device->machine().device("pic8259"), 1);
+}
diff --git a/src/mess/machine/plus4_sid.c b/src/mess/machine/plus4_sid.c
new file mode 100644
index 00000000000..7b821ec58ed
--- /dev/null
+++ b/src/mess/machine/plus4_sid.c
@@ -0,0 +1,184 @@
+/**********************************************************************
+
+ Commodore Plus/4 SID cartridge emulation
+
+ http://solder.dyndns.info/cgi-bin/showdir.pl?dir=files/commodore/plus4/hardware/SID-Card
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ TODO:
+
+ - GAL16V8 dump
+ - get SID clock from expansion port
+
+*/
+
+#include "plus4_sid.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define MOS8580_TAG "mos8580"
+#define CONTROL1_TAG "joy1"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type PLUS4_SID = &device_creator<plus4_sid_cartridge_device>;
+
+
+//-------------------------------------------------
+// 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 );
+}
+
+
+//-------------------------------------------------
+// sid6581_interface sid_intf
+//-------------------------------------------------
+
+static int paddle_read( device_t *device, int which )
+{
+ return 0;
+}
+
+static const sid6581_interface sid_intf =
+{
+ paddle_read
+};
+
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( plus4_sid )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( plus4_sid )
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+ MCFG_SOUND_ADD(MOS8580_TAG, SID8580, XTAL_17_73447MHz/20)
+ MCFG_SOUND_CONFIG(sid_intf)
+ 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, vic20_control_port_devices, NULL, 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),
+ 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, int ba, int cs0, int c1l, int c2l, int cs1, int c1h, int c2h)
+{
+ UINT8 data = 0;
+
+ if ((offset >= 0xfe80 && offset < 0xfea0) || (offset >= 0xfd40 && offset < 0xfd60))
+ {
+ data = sid6581_r(m_sid, 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))
+ {
+ sid6581_w(m_sid, 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/mess/machine/plus4_sid.h b/src/mess/machine/plus4_sid.h
new file mode 100644
index 00000000000..fb3757660f6
--- /dev/null
+++ b/src/mess/machine/plus4_sid.h
@@ -0,0 +1,63 @@
+/**********************************************************************
+
+ Commodore Plus/4 SID cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __PLUS4_SID_CARTRIDGE__
+#define __PLUS4_SID_CARTRIDGE__
+
+
+#include "emu.h"
+#include "machine/plus4exp.h"
+#include "sound/dac.h"
+#include "sound/sid6581.h"
+#include "machine/cbmipt.h"
+#include "machine/vcsctrl.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_config_complete() { m_shortname = "plus4_sid"; }
+ 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, 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<device_t> m_sid;
+ required_device<vcs_control_port_device> m_joy;
+};
+
+
+// device type definition
+extern const device_type PLUS4_SID;
+
+
+#endif
diff --git a/src/mess/machine/plus4_std.c b/src/mess/machine/plus4_std.c
new file mode 100644
index 00000000000..6e26b451445
--- /dev/null
+++ b/src/mess/machine/plus4_std.c
@@ -0,0 +1,72 @@
+/**********************************************************************
+
+ Commodore Plus/4 standard cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "plus4_std.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type PLUS4_STD = &device_creator<plus4_standard_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ 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, int ba, int cs0, int c1l, int c2l, int cs1, int c1h, int c2h)
+{
+ UINT8 data = 0;
+
+ if (!c1l && m_c1l_mask)
+ {
+ data = m_c1l[offset & m_c1l_mask];
+ }
+ else if (!c1h && m_c1h_mask)
+ {
+ data = m_c1h[offset & m_c1h_mask];
+ }
+ else if (!c2l && m_c2l_mask)
+ {
+ data = m_c2l[offset & m_c2l_mask];
+ }
+ else if (!c2h && m_c2h_mask)
+ {
+ data = m_c2h[offset & m_c2h_mask];
+ }
+
+ return data;
+}
diff --git a/src/mess/machine/plus4_std.h b/src/mess/machine/plus4_std.h
new file mode 100644
index 00000000000..59dee13cf2b
--- /dev/null
+++ b/src/mess/machine/plus4_std.h
@@ -0,0 +1,49 @@
+/**********************************************************************
+
+ Commodore Plus/4 standard cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __PLUS4_STANDARD_CARTRIDGE__
+#define __PLUS4_STANDARD_CARTRIDGE__
+
+
+#include "emu.h"
+#include "imagedev/cartslot.h"
+#include "machine/plus4exp.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_config_complete() { m_shortname = "plus4_standard"; }
+ virtual void device_start();
+
+ // device_plus4_expansion_card_interface overrides
+ virtual UINT8 plus4_cd_r(address_space &space, offs_t offset, 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/mess/machine/plus4exp.c b/src/mess/machine/plus4exp.c
new file mode 100644
index 00000000000..0d19b311194
--- /dev/null
+++ b/src/mess/machine/plus4exp.c
@@ -0,0 +1,404 @@
+/**********************************************************************
+
+ Commodore Plus/4 Expansion Port emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "machine/plus4exp.h"
+
+
+
+//**************************************************************************
+// MACROS/CONSTANTS
+//**************************************************************************
+
+#define LOG 0
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type PLUS4_EXPANSION_SLOT = &device_creator<plus4_expansion_slot_device>;
+
+
+
+//**************************************************************************
+// 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(NULL),
+ m_c1h(NULL),
+ m_c2l(NULL),
+ m_c2h(NULL),
+ m_ram(NULL),
+ m_nvram(NULL),
+ m_nvram_size(0),
+ m_c1l_mask(0),
+ m_c1h_mask(0),
+ m_c2l_mask(0),
+ m_c2h_mask(0),
+ m_ram_mask(0)
+{
+ m_slot = dynamic_cast<plus4_expansion_slot_device *>(device.owner());
+}
+
+
+//-------------------------------------------------
+// ~device_plus4_expansion_card_interface - destructor
+//-------------------------------------------------
+
+device_plus4_expansion_card_interface::~device_plus4_expansion_card_interface()
+{
+}
+
+
+//-------------------------------------------------
+// plus4_c1l_pointer - get low ROM 1 pointer
+//-------------------------------------------------
+
+UINT8* device_plus4_expansion_card_interface::plus4_c1l_pointer(running_machine &machine, size_t size)
+{
+ if (m_c1l == NULL)
+ {
+ m_c1l = auto_alloc_array(machine, UINT8, size);
+
+ m_c1l_mask = size - 1;
+ }
+
+ return m_c1l;
+}
+
+
+//-------------------------------------------------
+// plus4_c1h_pointer - get low ROM 1 pointer
+//-------------------------------------------------
+
+UINT8* device_plus4_expansion_card_interface::plus4_c1h_pointer(running_machine &machine, size_t size)
+{
+ if (m_c1h == NULL)
+ {
+ m_c1h = auto_alloc_array(machine, UINT8, size);
+
+ m_c1h_mask = size - 1;
+ }
+
+ return m_c1h;
+}
+
+
+//-------------------------------------------------
+// plus4_c2l_pointer - get low ROM 1 pointer
+//-------------------------------------------------
+
+UINT8* device_plus4_expansion_card_interface::plus4_c2l_pointer(running_machine &machine, size_t size)
+{
+ if (m_c2l == NULL)
+ {
+ m_c2l = auto_alloc_array(machine, UINT8, size);
+
+ m_c2l_mask = size - 1;
+ }
+
+ return m_c2l;
+}
+
+
+//-------------------------------------------------
+// plus4_c2h_pointer - get low ROM 1 pointer
+//-------------------------------------------------
+
+UINT8* device_plus4_expansion_card_interface::plus4_c2h_pointer(running_machine &machine, size_t size)
+{
+ if (m_c2h == NULL)
+ {
+ m_c2h = auto_alloc_array(machine, UINT8, size);
+
+ m_c2h_mask = size - 1;
+ }
+
+ return m_c2h;
+}
+
+
+//-------------------------------------------------
+// plus4_ram_pointer - get RAM pointer
+//-------------------------------------------------
+
+UINT8* device_plus4_expansion_card_interface::plus4_ram_pointer(running_machine &machine, size_t size)
+{
+ if (m_ram == NULL)
+ {
+ m_ram = auto_alloc_array(machine, UINT8, size);
+
+ m_ram_mask = size - 1;
+ }
+
+ return m_ram;
+}
+
+
+//-------------------------------------------------
+// plus4_ram_pointer - get NVRAM pointer
+//-------------------------------------------------
+
+UINT8* device_plus4_expansion_card_interface::plus4_nvram_pointer(running_machine &machine, size_t size)
+{
+ if (m_nvram == NULL)
+ {
+ m_nvram = auto_alloc_array(machine, UINT8, size);
+
+ m_nvram_mask = size - 1;
+ m_nvram_size = size;
+ }
+
+ return m_nvram;
+}
+
+
+
+//**************************************************************************
+// 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),
+ device_slot_interface(mconfig, *this),
+ device_image_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// plus4_expansion_slot_device - destructor
+//-------------------------------------------------
+
+plus4_expansion_slot_device::~plus4_expansion_slot_device()
+{
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void plus4_expansion_slot_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const plus4_expansion_slot_interface *intf = reinterpret_cast<const plus4_expansion_slot_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<plus4_expansion_slot_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_in_dma_cd_cb, 0, sizeof(m_in_dma_cd_cb));
+ memset(&m_out_dma_cd_cb, 0, sizeof(m_out_dma_cd_cb));
+ memset(&m_out_irq_cb, 0, sizeof(m_out_irq_cb));
+ memset(&m_out_aec_cb, 0, sizeof(m_out_aec_cb));
+ }
+
+ // set brief and instance name
+ update_names();
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void plus4_expansion_slot_device::device_start()
+{
+ m_cart = dynamic_cast<device_plus4_expansion_card_interface *>(get_card_device());
+
+ // resolve callbacks
+ m_in_dma_cd_func.resolve(m_in_dma_cd_cb, *this);
+ m_out_dma_cd_func.resolve(m_out_dma_cd_cb, *this);
+ m_out_irq_func.resolve(m_out_irq_cb, *this);
+ m_out_aec_func.resolve(m_out_aec_cb, *this);
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void plus4_expansion_slot_device::device_reset()
+{
+ breset_w(ASSERT_LINE);
+ breset_w(CLEAR_LINE);
+}
+
+
+//-------------------------------------------------
+// call_load -
+//-------------------------------------------------
+
+bool plus4_expansion_slot_device::call_load()
+{
+ if (m_cart)
+ {
+ size_t size = 0;
+
+ if (software_entry() == NULL)
+ {
+ // TODO
+ }
+ else
+ {
+ size = get_software_region_length("c1l");
+ if (size) memcpy(m_cart->plus4_c1l_pointer(machine(), size), get_software_region("c1l"), size);
+
+ size = get_software_region_length("c1h");
+ if (size) memcpy(m_cart->plus4_c1h_pointer(machine(), size), get_software_region("c1h"), size);
+
+ size = get_software_region_length("c2l");
+ if (size) memcpy(m_cart->plus4_c2l_pointer(machine(), size), get_software_region("c2l"), size);
+
+ size = get_software_region_length("c2h");
+ if (size) memcpy(m_cart->plus4_c2h_pointer(machine(), size), get_software_region("c2h"), size);
+
+ size = get_software_region_length("ram");
+ if (size) memset(m_cart->plus4_ram_pointer(machine(), size), 0, size);
+
+ size = get_software_region_length("nvram");
+ if (size) memset(m_cart->plus4_nvram_pointer(machine(), size), 0, size);
+ }
+ }
+
+ return IMAGE_INIT_PASS;
+}
+
+
+//-------------------------------------------------
+// call_softlist_load -
+//-------------------------------------------------
+
+bool plus4_expansion_slot_device::call_softlist_load(char *swlist, char *swname, rom_entry *start_entry)
+{
+ load_software_part_region(this, swlist, swname, start_entry);
+
+ return true;
+}
+
+
+//-------------------------------------------------
+// get_default_card_software -
+//-------------------------------------------------
+
+const char * plus4_expansion_slot_device::get_default_card_software(const machine_config &config, emu_options &options)
+{
+ return software_get_default_slot(config, options, this, "standard");
+}
+
+
+//-------------------------------------------------
+// cd_r - cartridge data read
+//-------------------------------------------------
+
+UINT8 plus4_expansion_slot_device::cd_r(address_space &space, offs_t offset, int ba, int cs0, int c1l, int c2l, int cs1, int c1h, int c2h)
+{
+ UINT8 data = 0;
+
+ if (m_cart != NULL)
+ {
+ data = m_cart->plus4_cd_r(space, offset, 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_cart != NULL)
+ {
+ m_cart->plus4_cd_w(space, offset, data, ba, cs0, c1l, c1h, cs1, c2l, c2h);
+ }
+}
+
+
+//-------------------------------------------------
+// screen_update -
+//-------------------------------------------------
+
+UINT32 plus4_expansion_slot_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ bool value = false;
+
+ if (m_cart != NULL)
+ {
+ value = m_cart->plus4_screen_update(screen, bitmap, cliprect);
+ }
+
+ return value;
+}
+
+
+//-------------------------------------------------
+// breset_w - buffered reset write
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( plus4_expansion_slot_device::breset_w )
+{
+ if (m_cart != NULL)
+ {
+ m_cart->plus4_breset_w(state);
+ }
+}
+
+
+//-------------------------------------------------
+// dma_cd_r - DMA read
+//-------------------------------------------------
+
+UINT8 plus4_expansion_slot_device::dma_cd_r(offs_t offset)
+{
+ return m_in_dma_cd_func(offset);
+}
+
+
+//-------------------------------------------------
+// dma_cd_w - DMA write
+//-------------------------------------------------
+
+void plus4_expansion_slot_device::dma_cd_w(offs_t offset, UINT8 data)
+{
+ m_out_dma_cd_func(offset, data);
+}
+
+
+WRITE_LINE_MEMBER( plus4_expansion_slot_device::irq_w ) { m_out_irq_func(state); }
+WRITE_LINE_MEMBER( plus4_expansion_slot_device::aec_w ) { m_out_aec_func(state); }
+
+
+//-------------------------------------------------
+// phi2 - system clock frequency
+//-------------------------------------------------
+
+int plus4_expansion_slot_device::phi2()
+{
+ return clock();
+}
diff --git a/src/mess/machine/plus4exp.h b/src/mess/machine/plus4exp.h
new file mode 100644
index 00000000000..056a0b0516f
--- /dev/null
+++ b/src/mess/machine/plus4exp.h
@@ -0,0 +1,197 @@
+/**********************************************************************
+
+ Commodore Plus/4 Expansion Port emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+
+ 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 PLUS4_EXPANSION_INTERFACE(_name) \
+ const plus4_expansion_slot_interface (_name) =
+
+
+#define MCFG_PLUS4_EXPANSION_SLOT_ADD(_tag, _clock, _config, _slot_intf, _def_slot, _def_inp) \
+ MCFG_DEVICE_ADD(_tag, PLUS4_EXPANSION_SLOT, _clock) \
+ MCFG_DEVICE_CONFIG(_config) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false)
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> plus4_expansion_slot_interface
+
+struct plus4_expansion_slot_interface
+{
+ devcb_read8 m_in_dma_cd_cb;
+ devcb_write8 m_out_dma_cd_cb;
+ devcb_write_line m_out_irq_cb;
+ devcb_write_line m_out_aec_cb;
+};
+
+
+// ======================> plus4_expansion_slot_device
+
+class device_plus4_expansion_card_interface;
+
+class plus4_expansion_slot_device : public device_t,
+ public plus4_expansion_slot_interface,
+ 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);
+ virtual ~plus4_expansion_slot_device();
+
+ // computer interface
+ UINT8 cd_r(address_space &space, offs_t offset, 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);
+ UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+ DECLARE_WRITE_LINE_MEMBER( breset_w );
+
+ // cartridge interface
+ UINT8 dma_cd_r(offs_t offset);
+ void dma_cd_w(offs_t offset, UINT8 data);
+ DECLARE_WRITE_LINE_MEMBER( irq_w );
+ DECLARE_WRITE_LINE_MEMBER( aec_w );
+ int phi2();
+ int dotclock();
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+ virtual void device_start();
+ virtual void device_reset();
+
+ // image-level overrides
+ virtual bool call_load();
+ virtual bool call_softlist_load(char *swlist, char *swname, 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 const char * get_default_card_software(const machine_config &config, emu_options &options);
+
+ devcb_resolved_read8 m_in_dma_cd_func;
+ devcb_resolved_write8 m_out_dma_cd_func;
+ devcb_resolved_write_line m_out_irq_func;
+ devcb_resolved_write_line m_out_aec_func;
+
+ device_plus4_expansion_card_interface *m_cart;
+};
+
+
+// ======================> 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();
+
+ // initialization
+ virtual UINT8* plus4_c1l_pointer(running_machine &machine, size_t size);
+ virtual UINT8* plus4_c1h_pointer(running_machine &machine, size_t size);
+ virtual UINT8* plus4_c2l_pointer(running_machine &machine, size_t size);
+ virtual UINT8* plus4_c2h_pointer(running_machine &machine, size_t size);
+ virtual UINT8* plus4_ram_pointer(running_machine &machine, size_t size);
+ virtual UINT8* plus4_nvram_pointer(running_machine &machine, size_t size);
+
+ // runtime
+ virtual UINT8 plus4_cd_r(address_space &space, offs_t offset, int ba, int cs0, int c1l, int c2l, int cs1, int c1h, int c2h) { return 0; };
+ 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 UINT32 plus4_screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { return 0; }
+ virtual void plus4_breset_w(int state) { };
+
+protected:
+ plus4_expansion_slot_device *m_slot;
+
+ UINT8 *m_c1l;
+ UINT8 *m_c1h;
+ UINT8 *m_c2l;
+ UINT8 *m_c2h;
+ UINT8 *m_ram;
+ UINT8 *m_nvram;
+
+ size_t m_nvram_size;
+
+ size_t m_c1l_mask;
+ size_t m_c1h_mask;
+ size_t m_c2l_mask;
+ size_t m_c2h_mask;
+ size_t m_ram_mask;
+ size_t m_nvram_mask;
+};
+
+
+// device type definition
+extern const device_type PLUS4_EXPANSION_SLOT;
+
+
+
+#endif
diff --git a/src/mess/machine/plus4user.c b/src/mess/machine/plus4user.c
new file mode 100644
index 00000000000..ebdfa4b99be
--- /dev/null
+++ b/src/mess/machine/plus4user.c
@@ -0,0 +1,104 @@
+/**********************************************************************
+
+ Commodore Plus/4 User Port emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "machine/plus4user.h"
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type PLUS4_USER_PORT = &device_creator<plus4_user_port_device>;
+
+
+
+//**************************************************************************
+// CARD INTERFACE
+//**************************************************************************
+
+//-------------------------------------------------
+// device_plus4_user_port_interface - constructor
+//-------------------------------------------------
+
+device_plus4_user_port_interface::device_plus4_user_port_interface(const machine_config &mconfig, device_t &device)
+ : device_slot_card_interface(mconfig,device)
+{
+ m_slot = dynamic_cast<plus4_user_port_device *>(device.owner());
+}
+
+
+//-------------------------------------------------
+// ~device_plus4_user_port_interface - destructor
+//-------------------------------------------------
+
+device_plus4_user_port_interface::~device_plus4_user_port_interface()
+{
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// plus4_user_port_device - constructor
+//-------------------------------------------------
+
+plus4_user_port_device::plus4_user_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, PLUS4_USER_PORT, "User Port", tag, owner, clock),
+ device_slot_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// plus4_user_port_device - destructor
+//-------------------------------------------------
+
+plus4_user_port_device::~plus4_user_port_device()
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void plus4_user_port_device::device_start()
+{
+ m_cart = dynamic_cast<device_plus4_user_port_interface *>(get_card_device());
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void plus4_user_port_device::device_reset()
+{
+ breset_w(ASSERT_LINE);
+ breset_w(CLEAR_LINE);
+}
+
+
+READ8_MEMBER( plus4_user_port_device::p_r ) { UINT8 data = 0xff; if (m_cart != NULL) data = m_cart->plus4_p_r(); return data; }
+WRITE8_MEMBER( plus4_user_port_device::p_w ) { if (m_cart != NULL) m_cart->plus4_p_w(data); }
+
+READ_LINE_MEMBER( plus4_user_port_device::rxd_r ) { int state = 1; if (m_cart != NULL) state = m_cart->plus4_rxd_r(); return state; }
+READ_LINE_MEMBER( plus4_user_port_device::dcd_r ) { int state = 1; if (m_cart != NULL) state = m_cart->plus4_dcd_r(); return state; }
+READ_LINE_MEMBER( plus4_user_port_device::dsr_r ) { int state = 1; if (m_cart != NULL) state = m_cart->plus4_dsr_r(); return state; }
+
+WRITE_LINE_MEMBER( plus4_user_port_device::txd_w ) { if (m_cart != NULL) m_cart->plus4_txd_w(state); }
+WRITE_LINE_MEMBER( plus4_user_port_device::dtr_w ) { if (m_cart != NULL) m_cart->plus4_dtr_w(state); }
+WRITE_LINE_MEMBER( plus4_user_port_device::rts_w ) { if (m_cart != NULL) m_cart->plus4_rts_w(state); }
+WRITE_LINE_MEMBER( plus4_user_port_device::rxc_w ) { if (m_cart != NULL) m_cart->plus4_rxc_w(state); }
+WRITE_LINE_MEMBER( plus4_user_port_device::atn_w ) { if (m_cart != NULL) m_cart->plus4_atn_w(state); }
+WRITE_LINE_MEMBER( plus4_user_port_device::breset_w ) { if (m_cart != NULL) m_cart->plus4_breset_w(state); }
diff --git a/src/mess/machine/plus4user.h b/src/mess/machine/plus4user.h
new file mode 100644
index 00000000000..9cece222f35
--- /dev/null
+++ b/src/mess/machine/plus4user.h
@@ -0,0 +1,126 @@
+/**********************************************************************
+
+ Commodore Plus/4 User Port emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+
+ 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
+ P0 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 "emu.h"
+
+
+
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
+
+#define PLUS4_USER_PORT_TAG "user"
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_PLUS4_USER_PORT_ADD(_tag, _slot_intf, _def_slot, _def_inp) \
+ MCFG_DEVICE_ADD(_tag, PLUS4_USER_PORT, 0) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false)
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> plus4_user_port_device
+
+class device_plus4_user_port_interface;
+
+class plus4_user_port_device : public device_t,
+ public device_slot_interface
+{
+public:
+ // construction/destruction
+ plus4_user_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ virtual ~plus4_user_port_device();
+
+ // computer interface
+ DECLARE_READ8_MEMBER( p_r );
+ DECLARE_WRITE8_MEMBER( p_w );
+ DECLARE_READ_LINE_MEMBER( rxd_r );
+ DECLARE_READ_LINE_MEMBER( dcd_r );
+ DECLARE_READ_LINE_MEMBER( dsr_r );
+ DECLARE_WRITE_LINE_MEMBER( txd_w );
+ DECLARE_WRITE_LINE_MEMBER( dtr_w );
+ DECLARE_WRITE_LINE_MEMBER( rts_w );
+ DECLARE_WRITE_LINE_MEMBER( rxc_w );
+ DECLARE_WRITE_LINE_MEMBER( atn_w );
+ DECLARE_WRITE_LINE_MEMBER( breset_w );
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete() { };
+ virtual void device_start();
+ virtual void device_reset();
+
+ device_plus4_user_port_interface *m_cart;
+};
+
+
+// ======================> device_plus4_user_port_interface
+
+// class representing interface-specific live plus4_expansion card
+class device_plus4_user_port_interface : public device_slot_card_interface
+{
+public:
+ // construction/destruction
+ device_plus4_user_port_interface(const machine_config &mconfig, device_t &device);
+ virtual ~device_plus4_user_port_interface();
+
+ virtual UINT8 plus4_p_r() { return 0xff; };
+ virtual void plus4_p_w(UINT8 data) { };
+
+ virtual int plus4_rxd_r() { return 1; };
+ virtual int plus4_dcd_r() { return 0; };
+ virtual int plus4_dsr_r() { return 0; };
+ virtual void plus4_txd_w(int level) { };
+ virtual void plus4_dtr_w(int level) { };
+ virtual void plus4_rts_w(int level) { };
+ virtual void plus4_rxc_w(int level) { };
+ virtual void plus4_atn_w(int level) { };
+
+ // reset
+ virtual void plus4_breset_w(int level) { };
+
+protected:
+ plus4_user_port_device *m_slot;
+};
+
+
+// device type definition
+extern const device_type PLUS4_USER_PORT;
+
+
+
+#endif
diff --git a/src/mess/machine/pmd85.c b/src/mess/machine/pmd85.c
new file mode 100644
index 00000000000..fe4da215e02
--- /dev/null
+++ b/src/mess/machine/pmd85.c
@@ -0,0 +1,966 @@
+/***************************************************************************
+
+ machine.c
+
+ Functions to emulate general aspects of PMD-85 (RAM, ROM, interrupts,
+ I/O ports)
+
+ Krzysztof Strzecha
+
+***************************************************************************/
+
+#include "emu.h"
+#include "imagedev/cassette.h"
+#include "cpu/i8085/i8085.h"
+#include "machine/i8255.h"
+#include "includes/pmd85.h"
+#include "machine/i8251.h"
+#include "machine/pit8253.h"
+#include "machine/ram.h"
+
+
+
+enum {PMD85_LED_1, PMD85_LED_2, PMD85_LED_3};
+enum {PMD85_1, PMD85_2, PMD85_2A, PMD85_2B, PMD85_3, ALFA, MATO, C2717};
+
+
+
+static void pmd851_update_memory(running_machine &machine)
+{
+ pmd85_state *state = machine.driver_data<pmd85_state>();
+ address_space* space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ UINT8 *ram = machine.device<ram_device>(RAM_TAG)->pointer();
+
+ if (state->m_startup_mem_map)
+ {
+ UINT8 *mem = state->memregion("maincpu")->base();
+
+ space->unmap_write(0x0000, 0x0fff);
+ space->nop_write(0x1000, 0x1fff);
+ space->unmap_write(0x2000, 0x2fff);
+ space->nop_write(0x3000, 0x3fff);
+
+ space->nop_read(0x1000, 0x1fff);
+ space->nop_read(0x3000, 0x3fff);
+
+ state->membank("bank1")->set_base(mem + 0x010000);
+ state->membank("bank3")->set_base(mem + 0x010000);
+ state->membank("bank5")->set_base(ram + 0xc000);
+
+ state->membank("bank6")->set_base(mem + 0x010000);
+ state->membank("bank7")->set_base(mem + 0x010000);
+ state->membank("bank8")->set_base(ram + 0xc000);
+ }
+ else
+ {
+ space->install_write_bank(0x0000, 0x0fff, "bank1");
+ space->install_write_bank(0x1000, 0x1fff, "bank2");
+ space->install_write_bank(0x2000, 0x2fff, "bank3");
+ space->install_write_bank(0x3000, 0x3fff, "bank4");
+ space->install_write_bank(0x4000, 0x7fff, "bank5");
+
+ space->install_read_bank(0x1000, 0x1fff, "bank2");
+ space->install_read_bank(0x3000, 0x3fff, "bank4");
+
+ state->membank("bank1")->set_base(ram);
+ state->membank("bank2")->set_base(ram + 0x1000);
+ state->membank("bank3")->set_base(ram + 0x2000);
+ state->membank("bank4")->set_base(ram + 0x3000);
+ state->membank("bank5")->set_base(ram + 0x4000);
+ }
+}
+
+static void pmd852a_update_memory(running_machine &machine)
+{
+ pmd85_state *state = machine.driver_data<pmd85_state>();
+ address_space* space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ UINT8 *ram = machine.device<ram_device>(RAM_TAG)->pointer();
+
+ if (state->m_startup_mem_map)
+ {
+ UINT8 *mem = state->memregion("maincpu")->base();
+
+ space->unmap_write(0x0000, 0x0fff);
+ space->unmap_write(0x2000, 0x2fff);
+
+ state->membank("bank1")->set_base(mem + 0x010000);
+ state->membank("bank2")->set_base(ram + 0x9000);
+ state->membank("bank3")->set_base(mem + 0x010000);
+ state->membank("bank4")->set_base(ram + 0xb000);
+ state->membank("bank5")->set_base(ram + 0xc000);
+ state->membank("bank6")->set_base(mem + 0x010000);
+ state->membank("bank7")->set_base(ram + 0x9000);
+ state->membank("bank8")->set_base(mem + 0x010000);
+ state->membank("bank9")->set_base(ram + 0xb000);
+ state->membank("bank10")->set_base(ram + 0xc000);
+
+ }
+ else
+ {
+ space->install_write_bank(0x0000, 0x0fff, "bank1");
+ space->install_write_bank(0x2000, 0x2fff, "bank3");
+
+ state->membank("bank1")->set_base(ram);
+ state->membank("bank2")->set_base(ram + 0x1000);
+ state->membank("bank3")->set_base(ram + 0x2000);
+ state->membank("bank4")->set_base(ram + 0x5000);
+ state->membank("bank5")->set_base(ram + 0x4000);
+ }
+}
+
+static void pmd853_update_memory(running_machine &machine)
+{
+ pmd85_state *state = machine.driver_data<pmd85_state>();
+ UINT8 *mem = state->memregion("maincpu")->base();
+ UINT8 *ram = machine.device<ram_device>(RAM_TAG)->pointer();
+
+ if (state->m_startup_mem_map)
+ {
+ state->membank("bank1")->set_base(mem + 0x010000);
+ state->membank("bank2")->set_base(mem + 0x010000);
+ state->membank("bank3")->set_base(mem + 0x010000);
+ state->membank("bank4")->set_base(mem + 0x010000);
+ state->membank("bank5")->set_base(mem + 0x010000);
+ state->membank("bank6")->set_base(mem + 0x010000);
+ state->membank("bank7")->set_base(mem + 0x010000);
+ state->membank("bank8")->set_base(mem + 0x010000);
+ state->membank("bank9")->set_base(ram);
+ state->membank("bank10")->set_base(ram + 0x2000);
+ state->membank("bank11")->set_base(ram + 0x4000);
+ state->membank("bank12")->set_base(ram + 0x6000);
+ state->membank("bank13")->set_base(ram + 0x8000);
+ state->membank("bank14")->set_base(ram + 0xa000);
+ state->membank("bank15")->set_base(ram + 0xc000);
+ state->membank("bank16")->set_base(ram + 0xe000);
+ }
+ else
+ {
+ state->membank("bank1")->set_base(ram);
+ state->membank("bank2")->set_base(ram + 0x2000);
+ state->membank("bank3")->set_base(ram + 0x4000);
+ state->membank("bank4")->set_base(ram + 0x6000);
+ state->membank("bank5")->set_base(ram + 0x8000);
+ state->membank("bank6")->set_base(ram + 0xa000);
+ state->membank("bank7")->set_base(ram + 0xc000);
+ state->membank("bank8")->set_base(state->m_pmd853_memory_mapping ? mem + 0x010000 : ram + 0xe000);
+ }
+}
+
+static void alfa_update_memory(running_machine &machine)
+{
+ pmd85_state *state = machine.driver_data<pmd85_state>();
+ address_space* space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ UINT8 *ram = machine.device<ram_device>(RAM_TAG)->pointer();
+
+ if (state->m_startup_mem_map)
+ {
+ UINT8 *mem = state->memregion("maincpu")->base();
+
+ space->unmap_write(0x0000, 0x0fff);
+ space->unmap_write(0x1000, 0x33ff);
+ space->nop_write(0x3400, 0x3fff);
+
+ state->membank("bank1")->set_base(mem + 0x010000);
+ state->membank("bank2")->set_base(mem + 0x011000);
+ state->membank("bank4")->set_base(ram + 0xc000);
+ state->membank("bank5")->set_base(mem + 0x010000);
+ state->membank("bank6")->set_base(mem + 0x011000);
+ state->membank("bank7")->set_base(ram + 0xc000);
+ }
+ else
+ {
+ space->install_write_bank(0x0000, 0x0fff, "bank1");
+ space->install_write_bank(0x1000, 0x33ff, "bank2");
+ space->install_write_bank(0x3400, 0x3fff, "bank3");
+
+ state->membank("bank1")->set_base(ram);
+ state->membank("bank2")->set_base(ram + 0x1000);
+ state->membank("bank3")->set_base(ram + 0x3400);
+ state->membank("bank4")->set_base(ram + 0x4000);
+ }
+}
+
+static void mato_update_memory(running_machine &machine)
+{
+ pmd85_state *state = machine.driver_data<pmd85_state>();
+ address_space* space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ UINT8 *ram = machine.device<ram_device>(RAM_TAG)->pointer();
+
+ if (state->m_startup_mem_map)
+ {
+ UINT8 *mem = state->memregion("maincpu")->base();
+
+ space->unmap_write(0x0000, 0x3fff);
+
+ state->membank("bank1")->set_base(mem + 0x010000);
+ state->membank("bank2")->set_base(ram + 0xc000);
+ state->membank("bank3")->set_base(mem + 0x010000);
+ state->membank("bank4")->set_base(ram + 0xc000);
+ }
+ else
+ {
+ space->install_write_bank(0x0000, 0x3fff, "bank1");
+
+ state->membank("bank1")->set_base(ram);
+ state->membank("bank2")->set_base(ram + 0x4000);
+ }
+}
+
+static void c2717_update_memory(running_machine &machine)
+{
+ pmd85_state *state = machine.driver_data<pmd85_state>();
+ address_space* space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ UINT8 *mem = state->memregion("maincpu")->base();
+ UINT8 *ram = machine.device<ram_device>(RAM_TAG)->pointer();
+
+ if (state->m_startup_mem_map)
+ {
+ space->unmap_write(0x0000, 0x3fff);
+
+ state->membank("bank1")->set_base(mem + 0x010000);
+ state->membank("bank2")->set_base(ram + 0x4000);
+ state->membank("bank3")->set_base(mem + 0x010000);
+ state->membank("bank4")->set_base(ram + 0xc000);
+ }
+ else
+ {
+ space->install_write_bank(0x0000, 0x3fff, "bank1");
+ state->membank("bank1")->set_base(ram);
+ state->membank("bank2")->set_base(ram + 0x4000);
+ }
+}
+
+/*******************************************************************************
+
+ Motherboard 8255 (PMD-85.1, PMD-85.2, PMD-85.3, Didaktik Alfa)
+ --------------------------------------------------------------
+ keyboard, speaker, LEDs
+
+*******************************************************************************/
+
+static READ8_DEVICE_HANDLER ( pmd85_ppi_0_porta_r )
+{
+ return 0xff;
+}
+
+static READ8_DEVICE_HANDLER ( pmd85_ppi_0_portb_r )
+{
+ pmd85_state *state = device->machine().driver_data<pmd85_state>();
+ static const char *const keynames[] = {
+ "KEY0", "KEY1", "KEY2", "KEY3", "KEY4", "KEY5", "KEY6", "KEY7",
+ "KEY8", "KEY9", "KEY10", "KEY11", "KEY12", "KEY13", "KEY14", "KEY15"
+ };
+
+ return device->machine().root_device().ioport(keynames[(state->m_ppi_port_outputs[0][0] & 0x0f)])->read() & device->machine().root_device().ioport("KEY15")->read();
+}
+
+static READ8_DEVICE_HANDLER ( pmd85_ppi_0_portc_r )
+{
+ return 0xff;
+}
+
+static WRITE8_DEVICE_HANDLER ( pmd85_ppi_0_porta_w )
+{
+ pmd85_state *state = device->machine().driver_data<pmd85_state>();
+ state->m_ppi_port_outputs[0][0] = data;
+}
+
+static WRITE8_DEVICE_HANDLER ( pmd85_ppi_0_portb_w )
+{
+ pmd85_state *state = device->machine().driver_data<pmd85_state>();
+ state->m_ppi_port_outputs[0][1] = data;
+}
+
+static WRITE8_DEVICE_HANDLER ( pmd85_ppi_0_portc_w )
+{
+ pmd85_state *state = device->machine().driver_data<pmd85_state>();
+ state->m_ppi_port_outputs[0][2] = data;
+ set_led_status(device->machine(), PMD85_LED_2, (data & 0x08) ? 1 : 0);
+ set_led_status(device->machine(), PMD85_LED_3, (data & 0x04) ? 1 : 0);
+}
+
+/*******************************************************************************
+
+ Motherboard 8255 (Mato)
+ -----------------------
+ keyboard, speaker, LEDs, tape
+
+*******************************************************************************/
+
+static READ8_DEVICE_HANDLER ( mato_ppi_0_portb_r )
+{
+ pmd85_state *state = device->machine().driver_data<pmd85_state>();
+ int i;
+ UINT8 data = 0xff;
+ static const char *const keynames[] = { "KEY0", "KEY1", "KEY2", "KEY3", "KEY4", "KEY5", "KEY6", "KEY7" };
+
+ for (i = 0; i < 8; i++)
+ {
+ if (!BIT(state->m_ppi_port_outputs[0][0], i))
+ data &= device->machine().root_device().ioport(keynames[i])->read();
+ }
+ return data;
+}
+
+static READ8_DEVICE_HANDLER ( mato_ppi_0_portc_r )
+{
+ return device->machine().root_device().ioport("KEY8")->read() | 0x8f;
+}
+
+static WRITE8_DEVICE_HANDLER ( mato_ppi_0_portc_w )
+{
+ pmd85_state *state = device->machine().driver_data<pmd85_state>();
+ state->m_ppi_port_outputs[0][2] = data;
+ set_led_status(device->machine(), PMD85_LED_2, BIT(data, 3));
+ set_led_status(device->machine(), PMD85_LED_3, BIT(data, 2));
+}
+
+/*******************************************************************************
+
+ I/O board 8255
+ --------------
+ GPIO/0 (K3 connector), GPIO/1 (K4 connector)
+
+*******************************************************************************/
+
+static READ8_DEVICE_HANDLER ( pmd85_ppi_1_porta_r )
+{
+ return 0xff;
+}
+
+static READ8_DEVICE_HANDLER ( pmd85_ppi_1_portb_r )
+{
+ return 0xff;
+}
+
+static READ8_DEVICE_HANDLER ( pmd85_ppi_1_portc_r )
+{
+ return 0xff;
+}
+
+static WRITE8_DEVICE_HANDLER ( pmd85_ppi_1_porta_w )
+{
+ pmd85_state *state = device->machine().driver_data<pmd85_state>();
+ state->m_ppi_port_outputs[1][0] = data;
+}
+
+static WRITE8_DEVICE_HANDLER ( pmd85_ppi_1_portb_w )
+{
+ pmd85_state *state = device->machine().driver_data<pmd85_state>();
+ state->m_ppi_port_outputs[1][1] = data;
+}
+
+static WRITE8_DEVICE_HANDLER ( pmd85_ppi_1_portc_w )
+{
+ pmd85_state *state = device->machine().driver_data<pmd85_state>();
+ state->m_ppi_port_outputs[1][2] = data;
+}
+
+/*******************************************************************************
+
+ I/O board 8255
+ --------------
+ IMS-2 (K5 connector)
+
+ - 8251 - cassette recorder and V.24/IFSS (selectable by switch)
+
+ - external interfaces connector (K2)
+
+*******************************************************************************/
+
+static READ8_DEVICE_HANDLER ( pmd85_ppi_2_porta_r )
+{
+ return 0xff;
+}
+
+static READ8_DEVICE_HANDLER ( pmd85_ppi_2_portb_r )
+{
+ return 0xff;
+}
+
+static READ8_DEVICE_HANDLER ( pmd85_ppi_2_portc_r )
+{
+ return 0xff;
+}
+
+static WRITE8_DEVICE_HANDLER ( pmd85_ppi_2_porta_w )
+{
+ pmd85_state *state = device->machine().driver_data<pmd85_state>();
+ state->m_ppi_port_outputs[2][0] = data;
+}
+
+static WRITE8_DEVICE_HANDLER ( pmd85_ppi_2_portb_w )
+{
+ pmd85_state *state = device->machine().driver_data<pmd85_state>();
+ state->m_ppi_port_outputs[2][1] = data;
+}
+
+static WRITE8_DEVICE_HANDLER ( pmd85_ppi_2_portc_w )
+{
+ pmd85_state *state = device->machine().driver_data<pmd85_state>();
+ state->m_ppi_port_outputs[2][2] = data;
+}
+
+/*******************************************************************************
+
+ I/O board 8251
+ --------------
+ cassette recorder and V.24/IFSS (selectable by switch)
+
+*******************************************************************************/
+
+/*******************************************************************************
+
+ I/O board 8253
+ --------------
+
+ Timer 0:
+ OUT0 - external interfaces connector (K2)
+ CLK0 - external interfaces connector (K2)
+ GATE0 - external interfaces connector (K2), default = 1
+ Timer 1:
+ OUT0 - external interfaces connector (K2), i8251 (for V24 only)
+ CLK0 - hardwired to 2 MHz system clock
+ GATE0 - external interfaces connector (K2), default = 1
+ Timer 2:
+ OUT0 - unused
+ CLK0 - hardwired to 1HZ signal generator
+ GATE0 - hardwired to 5V, default = 1
+
+*******************************************************************************/
+
+const struct pit8253_config pmd85_pit8253_interface =
+{
+ {
+ { 0, DEVCB_NULL, DEVCB_NULL },
+ { 2000000, DEVCB_NULL, DEVCB_NULL },
+ { 1, DEVCB_LINE_VCC, DEVCB_NULL }
+ }
+};
+
+/*******************************************************************************
+
+ I/O board external interfaces connector (K2)
+ --------------------------------------------
+
+*******************************************************************************/
+
+
+
+/*******************************************************************************
+
+ ROM Module 8255
+ ---------------
+ port A - data read
+ ports B, C - address select
+
+*******************************************************************************/
+
+static READ8_DEVICE_HANDLER ( pmd85_ppi_3_porta_r )
+{
+ pmd85_state *state = device->machine().driver_data<pmd85_state>();
+ if (state->memregion("user1")->base() != NULL)
+ return state->memregion("user1")->base()[state->m_ppi_port_outputs[3][1] | (state->m_ppi_port_outputs[3][2] << 8)];
+ else
+ return 0;
+}
+
+static READ8_DEVICE_HANDLER ( pmd85_ppi_3_portb_r )
+{
+ return 0xff;
+}
+
+static READ8_DEVICE_HANDLER ( pmd85_ppi_3_portc_r )
+{
+ return 0xff;
+}
+
+static WRITE8_DEVICE_HANDLER ( pmd85_ppi_3_porta_w )
+{
+ pmd85_state *state = device->machine().driver_data<pmd85_state>();
+ state->m_ppi_port_outputs[3][0] = data;
+}
+
+static WRITE8_DEVICE_HANDLER ( pmd85_ppi_3_portb_w )
+{
+ pmd85_state *state = device->machine().driver_data<pmd85_state>();
+ state->m_ppi_port_outputs[3][1] = data;
+}
+
+static WRITE8_DEVICE_HANDLER ( pmd85_ppi_3_portc_w )
+{
+ pmd85_state *state = device->machine().driver_data<pmd85_state>();
+ state->m_ppi_port_outputs[3][2] = data;
+}
+
+/*******************************************************************************
+
+ I/O ports (PMD-85.1, PMD-85.2, PMD-85.3, Didaktik Alfa)
+ -------------------------------------------------------
+
+ I/O board
+ 1xxx11aa external interfaces connector (K2)
+
+ 0xxx11aa I/O board interfaces
+ 000111aa 8251 (casette recorder, V24)
+ 010011aa 8255 (GPIO/0, GPIO/1)
+ 010111aa 8253
+ 011111aa 8255 (IMS-2)
+
+ Motherboard
+ 1xxx01aa 8255 (keyboard, speaker, LEDs)
+ PMD-85.3 memory banking
+
+ ROM Module
+ 1xxx10aa 8255 (ROM reading)
+
+*******************************************************************************/
+
+READ8_MEMBER(pmd85_state::pmd85_io_r)
+{
+ i8251_device *uart = machine().device<i8251_device>("uart");
+ if (m_startup_mem_map)
+ {
+ return 0xff;
+ }
+
+ switch (offset & 0x0c)
+ {
+ case 0x04: /* Motherboard */
+ switch (offset & 0x80)
+ {
+ case 0x80: /* Motherboard 8255 */
+ return machine().device<i8255_device>("ppi8255_0")->read(space, offset & 0x03);
+ }
+ break;
+ case 0x08: /* ROM module connector */
+ switch (m_model)
+ {
+ case PMD85_1:
+ case PMD85_2:
+ case PMD85_2A:
+ case C2717:
+ case PMD85_3:
+ if (m_rom_module_present)
+ {
+ switch (offset & 0x80)
+ {
+ case 0x80: /* ROM module 8255 */
+ return machine().device<i8255_device>("ppi8255_3")->read(space, offset & 0x03);
+ }
+ }
+ break;
+ }
+ break;
+ case 0x0c: /* I/O board */
+ switch (offset & 0x80)
+ {
+ case 0x00: /* I/O board interfaces */
+ switch (offset & 0x70)
+ {
+ case 0x10: /* 8251 (casette recorder, V24) */
+ switch (offset & 0x01)
+ {
+ case 0x00: return uart->data_r(space, offset & 0x01);
+ case 0x01: return uart->status_r(space, offset & 0x01);
+ }
+ break;
+ case 0x40: /* 8255 (GPIO/0, GPIO/1) */
+ return machine().device<i8255_device>("ppi8255_1")->read(space, offset & 0x03);
+ case 0x50: /* 8253 */
+ return pit8253_r( machine().device("pit8253"), offset & 0x03);
+ case 0x70: /* 8255 (IMS-2) */
+ return machine().device<i8255_device>("ppi8255_2")->read(space, offset & 0x03);
+ }
+ break;
+ case 0x80: /* external interfaces */
+ break;
+ }
+ break;
+ }
+
+ logerror ("Reading from unmapped port: %02x\n", offset);
+ return 0xff;
+}
+
+WRITE8_MEMBER(pmd85_state::pmd85_io_w)
+{
+ i8251_device *uart = machine().device<i8251_device>("uart");
+ if (m_startup_mem_map)
+ {
+ m_startup_mem_map = 0;
+ (*update_memory)(machine());
+ }
+
+ switch (offset & 0x0c)
+ {
+ case 0x04: /* Motherboard */
+ switch (offset & 0x80)
+ {
+ case 0x80: /* Motherboard 8255 */
+ machine().device<i8255_device>("ppi8255_0")->write(space, offset & 0x03, data);
+ /* PMD-85.3 memory banking */
+ if ((offset & 0x03) == 0x03)
+ {
+ m_pmd853_memory_mapping = data & 0x01;
+ (*update_memory)(machine());
+ }
+ break;
+ }
+ break;
+ case 0x08: /* ROM module connector */
+ switch (m_model)
+ {
+ case PMD85_1:
+ case PMD85_2:
+ case PMD85_2A:
+ case C2717:
+ case PMD85_3:
+ if (m_rom_module_present)
+ {
+ switch (offset & 0x80)
+ {
+ case 0x80: /* ROM module 8255 */
+ machine().device<i8255_device>("ppi8255_3")->write(space, offset & 0x03, data);
+ break;
+ }
+ }
+ break;
+ }
+ break;
+ case 0x0c: /* I/O board */
+ switch (offset & 0x80)
+ {
+ case 0x00: /* I/O board interfaces */
+ switch (offset & 0x70)
+ {
+ case 0x10: /* 8251 (casette recorder, V24) */
+ switch (offset & 0x01)
+ {
+ case 0x00: uart->data_w(space, offset & 0x01, data); break;
+ case 0x01: uart->control_w(space, offset & 0x01, data); break;
+ }
+ break;
+ case 0x40: /* 8255 (GPIO/0, GPIO/0) */
+ machine().device<i8255_device>("ppi8255_1")->write(space, offset & 0x03, data);
+ break;
+ case 0x50: /* 8253 */
+ pit8253_w(machine().device("pit8253"), offset & 0x03, data);
+ logerror ("8253 writing. Address: %02x, Data: %02x\n", offset, data);
+ break;
+ case 0x70: /* 8255 (IMS-2) */
+ machine().device<i8255_device>("ppi8255_2")->write(space, offset & 0x03, data);
+ break;
+ }
+ break;
+ case 0x80: /* external interfaces */
+ break;
+ }
+ break;
+ }
+}
+
+/*******************************************************************************
+
+ I/O ports (Mato)
+ ----------------
+
+ Motherboard
+ 1xxx01aa 8255 (keyboard, speaker, LEDs, tape)
+
+*******************************************************************************/
+
+READ8_MEMBER(pmd85_state::mato_io_r)
+{
+ if (m_startup_mem_map)
+ {
+ return 0xff;
+ }
+
+ switch (offset & 0x0c)
+ {
+ case 0x04: /* Motherboard */
+ switch (offset & 0x80)
+ {
+ case 0x80: /* Motherboard 8255 */
+ return machine().device<i8255_device>("ppi8255_0")->read(space, offset & 0x03);
+ }
+ break;
+ }
+
+ logerror ("Reading from unmapped port: %02x\n", offset);
+ return 0xff;
+}
+
+WRITE8_MEMBER(pmd85_state::mato_io_w)
+{
+ if (m_startup_mem_map)
+ {
+ m_startup_mem_map = 0;
+ (*update_memory)(machine());
+ }
+
+ switch (offset & 0x0c)
+ {
+ case 0x04: /* Motherboard */
+ switch (offset & 0x80)
+ {
+ case 0x80: /* Motherboard 8255 */
+ return machine().device<i8255_device>("ppi8255_0")->write(space, offset & 0x03, data);
+ break;
+ }
+ break;
+ }
+}
+
+const i8255_interface pmd85_ppi8255_interface[4] =
+{
+ {
+ DEVCB_HANDLER(pmd85_ppi_0_porta_r),
+ DEVCB_HANDLER(pmd85_ppi_0_porta_w),
+ DEVCB_HANDLER(pmd85_ppi_0_portb_r),
+ DEVCB_HANDLER(pmd85_ppi_0_portb_w),
+ DEVCB_HANDLER(pmd85_ppi_0_portc_r),
+ DEVCB_HANDLER(pmd85_ppi_0_portc_w)
+ },
+ {
+ DEVCB_HANDLER(pmd85_ppi_1_porta_r),
+ DEVCB_HANDLER(pmd85_ppi_1_porta_w),
+ DEVCB_HANDLER(pmd85_ppi_1_portb_r),
+ DEVCB_HANDLER(pmd85_ppi_1_portb_w),
+ DEVCB_HANDLER(pmd85_ppi_1_portc_r),
+ DEVCB_HANDLER(pmd85_ppi_1_portc_w)
+ },
+ {
+ DEVCB_HANDLER(pmd85_ppi_2_porta_r),
+ DEVCB_HANDLER(pmd85_ppi_2_porta_w),
+ DEVCB_HANDLER(pmd85_ppi_2_portb_r),
+ DEVCB_HANDLER(pmd85_ppi_2_portb_w),
+ DEVCB_HANDLER(pmd85_ppi_2_portc_r),
+ DEVCB_HANDLER(pmd85_ppi_2_portc_w)
+ },
+ {
+ DEVCB_HANDLER(pmd85_ppi_3_porta_r),
+ DEVCB_HANDLER(pmd85_ppi_3_porta_w),
+ DEVCB_HANDLER(pmd85_ppi_3_portb_r),
+ DEVCB_HANDLER(pmd85_ppi_3_portb_w),
+ DEVCB_HANDLER(pmd85_ppi_3_portc_r),
+ DEVCB_HANDLER(pmd85_ppi_3_portc_w)
+ }
+};
+
+const i8255_interface alfa_ppi8255_interface[3] =
+{
+ {
+ DEVCB_HANDLER(pmd85_ppi_0_porta_r),
+ DEVCB_HANDLER(pmd85_ppi_0_porta_w),
+ DEVCB_HANDLER(pmd85_ppi_0_portb_r),
+ DEVCB_HANDLER(pmd85_ppi_0_portb_w),
+ DEVCB_HANDLER(pmd85_ppi_0_portc_r),
+ DEVCB_HANDLER(pmd85_ppi_0_portc_w)
+ },
+ {
+ DEVCB_HANDLER(pmd85_ppi_1_porta_r),
+ DEVCB_HANDLER(pmd85_ppi_1_porta_w),
+ DEVCB_HANDLER(pmd85_ppi_1_portb_r),
+ DEVCB_HANDLER(pmd85_ppi_1_portb_w),
+ DEVCB_HANDLER(pmd85_ppi_1_portc_r),
+ DEVCB_HANDLER(pmd85_ppi_1_portc_w)
+ },
+ {
+ DEVCB_HANDLER(pmd85_ppi_2_porta_r),
+ DEVCB_HANDLER(pmd85_ppi_2_porta_w),
+ DEVCB_HANDLER(pmd85_ppi_2_portb_r),
+ DEVCB_HANDLER(pmd85_ppi_2_portb_w),
+ DEVCB_HANDLER(pmd85_ppi_2_portc_r),
+ DEVCB_HANDLER(pmd85_ppi_2_portc_w)
+ }
+};
+
+I8255_INTERFACE( mato_ppi8255_interface )
+{
+ DEVCB_HANDLER(pmd85_ppi_0_porta_r),
+ DEVCB_HANDLER(pmd85_ppi_0_porta_w),
+ DEVCB_HANDLER(mato_ppi_0_portb_r),
+ DEVCB_HANDLER(pmd85_ppi_0_portb_w),
+ DEVCB_HANDLER(mato_ppi_0_portc_r),
+ DEVCB_HANDLER(mato_ppi_0_portc_w)
+};
+
+
+static TIMER_CALLBACK(pmd85_cassette_timer_callback)
+{
+ pmd85_state *state = machine.driver_data<pmd85_state>();
+ i8251_device *uart = machine.device<i8251_device>("uart");
+ serial_source_device *ser = machine.device<serial_source_device>("sercas");
+ int data;
+ int current_level;
+
+ if (!(machine.root_device().ioport("DSW0")->read() & 0x02)) /* V.24 / Tape Switch */
+ {
+ /* tape reading */
+ if (machine.device<cassette_image_device>(CASSETTE_TAG)->get_state()&CASSETTE_PLAY)
+ {
+ switch (state->m_model)
+ {
+ case PMD85_1:
+ if (state->m_clk_level_tape)
+ {
+ state->m_previous_level = ((machine.device<cassette_image_device>(CASSETTE_TAG))->input() > 0.038) ? 1 : 0;
+ state->m_clk_level_tape = 0;
+ }
+ else
+ {
+ current_level = ((machine.device<cassette_image_device>(CASSETTE_TAG))->input() > 0.038) ? 1 : 0;
+
+ if (state->m_previous_level!=current_level)
+ {
+ data = (!state->m_previous_level && current_level) ? 1 : 0;
+
+ ser->send_bit(data);
+ uart->receive_clock();
+
+ state->m_clk_level_tape = 1;
+ }
+ }
+ return;
+ case PMD85_2:
+ case PMD85_2A:
+ case C2717:
+ case PMD85_3:
+ case ALFA:
+ /* not hardware data decoding */
+ return;
+ }
+ }
+
+ /* tape writing */
+ if (machine.device<cassette_image_device>(CASSETTE_TAG)->get_state()&CASSETTE_RECORD)
+ {
+ data = ser->get_in_data_bit();
+ data ^= state->m_clk_level_tape;
+ machine.device<cassette_image_device>(CASSETTE_TAG)->output(data&0x01 ? 1 : -1);
+
+ if (!state->m_clk_level_tape)
+ uart->transmit_clock();
+
+ state->m_clk_level_tape = state->m_clk_level_tape ? 0 : 1;
+
+ return;
+ }
+
+ state->m_clk_level_tape = 1;
+
+ if (!state->m_clk_level)
+ uart->transmit_clock();
+ state->m_clk_level = state->m_clk_level ? 0 : 1;
+ }
+}
+
+static TIMER_CALLBACK( pmd_reset )
+{
+ machine.schedule_soft_reset();
+}
+
+DIRECT_UPDATE_MEMBER(pmd85_state::pmd85_opbaseoverride)
+{
+ if (ioport("RESET")->read() & 0x01)
+ machine().scheduler().timer_set(attotime::from_usec(10), FUNC(pmd_reset));
+ return address;
+}
+
+static void pmd85_common_driver_init (running_machine &machine)
+{
+ pmd85_state *state = machine.driver_data<pmd85_state>();
+ state->m_previous_level = 0;
+ state->m_clk_level = state->m_clk_level_tape = 1;
+ state->m_cassette_timer = machine.scheduler().timer_alloc(FUNC(pmd85_cassette_timer_callback));
+ state->m_cassette_timer->adjust(attotime::zero, 0, attotime::from_hz(2400));
+}
+
+DRIVER_INIT_MEMBER(pmd85_state,pmd851)
+{
+ m_model = PMD85_1;
+ update_memory = pmd851_update_memory;
+ pmd85_common_driver_init(machine());
+}
+
+DRIVER_INIT_MEMBER(pmd85_state,pmd852a)
+{
+ m_model = PMD85_2A;
+ update_memory = pmd852a_update_memory;
+ pmd85_common_driver_init(machine());
+}
+
+DRIVER_INIT_MEMBER(pmd85_state,pmd853)
+{
+ m_model = PMD85_3;
+ update_memory = pmd853_update_memory;
+ pmd85_common_driver_init(machine());
+}
+
+DRIVER_INIT_MEMBER(pmd85_state,alfa)
+{
+ m_model = ALFA;
+ update_memory = alfa_update_memory;
+ pmd85_common_driver_init(machine());
+}
+
+DRIVER_INIT_MEMBER(pmd85_state,mato)
+{
+ m_model = MATO;
+ update_memory = mato_update_memory;
+}
+
+DRIVER_INIT_MEMBER(pmd85_state,c2717)
+{
+ m_model = C2717;
+ update_memory = c2717_update_memory;
+ pmd85_common_driver_init(machine());
+}
+
+static TIMER_CALLBACK( setup_machine_state )
+{
+ pmd85_state *state = machine.driver_data<pmd85_state>();
+ if (state->m_model != MATO)
+ {
+ i8251_device *uart = machine.device<i8251_device>("uart");
+ serial_source_device *ser = machine.device<serial_source_device>("sercas");
+ uart->connect(ser);
+ }
+}
+
+
+MACHINE_RESET( pmd85 )
+{
+ pmd85_state *state = machine.driver_data<pmd85_state>();
+ int i, j;
+
+ /* checking for Rom Module */
+ switch (state->m_model)
+ {
+ case PMD85_1:
+ case PMD85_2A:
+ case PMD85_3:
+ case C2717:
+ state->m_rom_module_present = (machine.root_device().ioport("DSW0")->read() & 0x01) ? 1 : 0;
+ break;
+ case ALFA:
+ case MATO:
+ break;
+ }
+
+ for (i = 0; i < 4; i++)
+ for (j = 0; j < 3; j++)
+ state->m_ppi_port_outputs[i][j] = 0;
+
+ /* memory initialization */
+ memset(machine.device<ram_device>(RAM_TAG)->pointer(), 0, sizeof(unsigned char)*0x10000);
+ state->m_pmd853_memory_mapping = 1;
+ state->m_startup_mem_map = 1;
+ state->update_memory(machine);
+
+ machine.scheduler().timer_set(attotime::zero, FUNC(setup_machine_state));
+
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->set_direct_update_handler(direct_update_delegate(FUNC(pmd85_state::pmd85_opbaseoverride), state));
+}
diff --git a/src/mess/machine/pokemini.c b/src/mess/machine/pokemini.c
new file mode 100644
index 00000000000..82117f54b0d
--- /dev/null
+++ b/src/mess/machine/pokemini.c
@@ -0,0 +1,1585 @@
+/**********************************************************************
+
+ Pokemini machine emulation.
+
+
+**********************************************************************/
+
+
+#include "emu.h"
+#include "includes/pokemini.h"
+
+
+static void pokemini_check_irqs( running_machine &machine )
+{
+ pokemini_state *state = machine.driver_data<pokemini_state>();
+ int irq_set[4] = { 1, 0, 0, 0 };
+ int prio, vector;
+
+ /* Check IRQ $03-$04 */
+ prio = ( state->m_pm_reg[0x20] >> 6 ) & 0x03;
+ if ( ! irq_set[prio] )
+ {
+ if ( state->m_pm_reg[0x23] & state->m_pm_reg[0x27] & 0x40 )
+ irq_set[prio] = 0x04;
+
+ if ( state->m_pm_reg[0x23] & state->m_pm_reg[0x27] & 0x80 )
+ irq_set[prio] = 0x03;
+ }
+
+ /* Check IRQ $05-$06 */
+ prio = ( state->m_pm_reg[0x20] >> 4 ) & 0x03;
+ if ( ! irq_set[prio] )
+ {
+ if ( state->m_pm_reg[0x23] & state->m_pm_reg[0x27] & 0x10 )
+ irq_set[prio] = 0x06;
+
+ if ( state->m_pm_reg[0x23] & state->m_pm_reg[0x27] & 0x20 )
+ irq_set[prio] = 0x05;
+ }
+
+ /* Check IRQ $07-$08 */
+ prio = ( state->m_pm_reg[0x20] >> 2 ) & 0x03;
+ if ( ! irq_set[prio] )
+ {
+ if ( state->m_pm_reg[0x23] & state->m_pm_reg[0x27] & 0x04 )
+ irq_set[prio] = 0x08;
+
+ if ( state->m_pm_reg[0x23] & state->m_pm_reg[0x27] & 0x08 )
+ irq_set[prio] = 0x07;
+ }
+
+ /* Check IRQ $09-$0A */
+ prio = ( state->m_pm_reg[0x20] >> 0 ) & 0x03;
+ if ( ! irq_set[prio] )
+ {
+ if ( state->m_pm_reg[0x23] & state->m_pm_reg[0x27] & 0x01 )
+ irq_set[prio] = 0x0A;
+
+ if ( state->m_pm_reg[0x23] & state->m_pm_reg[0x27] & 0x02 )
+ irq_set[prio] = 0x09;
+ }
+
+ /* Check IRQ $0B-$0E */
+ prio = ( state->m_pm_reg[0x21] >> 6 ) & 0x03;
+ if ( ! irq_set[prio] )
+ {
+ if ( state->m_pm_reg[0x24] & state->m_pm_reg[0x28] & 0x04 )
+ irq_set[prio] = 0x0E;
+
+ if ( state->m_pm_reg[0x24] & state->m_pm_reg[0x28] & 0x08 )
+ irq_set[prio] = 0x0D;
+
+ if ( state->m_pm_reg[0x24] & state->m_pm_reg[0x28] & 0x10 )
+ irq_set[prio] = 0x0C;
+
+ if ( state->m_pm_reg[0x24] & state->m_pm_reg[0x28] & 0x20 )
+ irq_set[prio] = 0x0B;
+ }
+
+ /* Check IRQ $0F-$10 */
+ prio = ( state->m_pm_reg[0x22] >> 0 ) & 0x03;
+ if ( ! irq_set[prio] )
+ {
+ if ( state->m_pm_reg[0x26] & state->m_pm_reg[0x2A] & 0x40 )
+ irq_set[prio] = 0x10;
+
+ if ( state->m_pm_reg[0x26] & state->m_pm_reg[0x2A] & 0x80 )
+ irq_set[prio] = 0x0F;
+ }
+
+ /* Check IRQ $13-$14 */
+ prio = ( state->m_pm_reg[0x21] >> 4 ) & 0x03;
+ if ( ! irq_set[prio] )
+ {
+ if ( state->m_pm_reg[0x24] & state->m_pm_reg[0x28] & 0x01 )
+ irq_set[prio] = 0x14;
+
+ if ( state->m_pm_reg[0x24] & state->m_pm_reg[0x28] & 0x02 )
+ irq_set[prio] = 0x13;
+ }
+
+ /* Check IRQ $15-$1C */
+ prio = ( state->m_pm_reg[0x21] >> 2 ) & 0x03;
+ if ( ! irq_set[prio] )
+ {
+ if ( state->m_pm_reg[0x25] & state->m_pm_reg[0x29] & 0x01 )
+ irq_set[prio] = 0x1C;
+
+ if ( state->m_pm_reg[0x25] & state->m_pm_reg[0x29] & 0x02 )
+ irq_set[prio] = 0x1B;
+
+ if ( state->m_pm_reg[0x25] & state->m_pm_reg[0x29] & 0x04 )
+ irq_set[prio] = 0x1A;
+
+ if ( state->m_pm_reg[0x25] & state->m_pm_reg[0x29] & 0x08 )
+ irq_set[prio] = 0x19;
+
+ if ( state->m_pm_reg[0x25] & state->m_pm_reg[0x29] & 0x10 )
+ irq_set[prio] = 0x18;
+
+ if ( state->m_pm_reg[0x25] & state->m_pm_reg[0x29] & 0x20 )
+ irq_set[prio] = 0x17;
+
+ if ( state->m_pm_reg[0x25] & state->m_pm_reg[0x29] & 0x40 )
+ irq_set[prio] = 0x16;
+
+ if ( state->m_pm_reg[0x25] & state->m_pm_reg[0x29] & 0x80 )
+ irq_set[prio] = 0x15;
+ }
+
+ /* Check IRQ $1D-$1F */
+ prio = ( state->m_pm_reg[0x21] >> 0 ) & 0x03;
+ if ( ! irq_set[prio] && ( state->m_pm_reg[0x26] & state->m_pm_reg[0x2A] & 0x07 ) )
+ {
+ if ( state->m_pm_reg[0x26] & state->m_pm_reg[0x2A] & 0x01 )
+ irq_set[prio] = 0x1F;
+
+ if ( state->m_pm_reg[0x26] & state->m_pm_reg[0x2A] & 0x02 )
+ irq_set[prio] = 0x1E;
+
+ if ( state->m_pm_reg[0x26] & state->m_pm_reg[0x2A] & 0x04 )
+ irq_set[prio] = 0x1D;
+ }
+
+ /* Determine vector */
+ vector = 0;
+ if ( irq_set[1] )
+ vector = irq_set[1];
+ if ( irq_set[2] )
+ vector = irq_set[2];
+ if ( irq_set[3] )
+ vector = irq_set[3];
+
+ if ( vector )
+ {
+ //logerror("Triggering IRQ with vector %02x\n", vector );
+ /* Trigger interrupt and set vector */
+ cputag_set_input_line_and_vector( machine, "maincpu", 0, ASSERT_LINE, vector );
+ }
+ else
+ {
+ cputag_set_input_line( machine, "maincpu", 0, CLEAR_LINE );
+ }
+}
+
+
+static void pokemini_update_sound( running_machine &machine )
+{
+ pokemini_state *state = machine.driver_data<pokemini_state>();
+ device_t *speaker = machine.device(SPEAKER_TAG);
+ /* Check if sound should be muted */
+ if ( state->m_pm_reg[0x70] & 0x03 )
+ {
+ speaker_level_w( speaker, 0 );
+ }
+ else
+ {
+ ///static const int levels[4] = { 0, 1, 1, 2 };
+ int level; /// silence clang warning/// = levels[ state->m_pm_reg[0x71] & 0x03 ];
+
+// if ( ( ( state->m_pm_reg[0x48] & 0x80 ) && ( state->m_pm_reg[0x4E] | ( state->m_pm_reg[0x4F] << 8 ) ) > ( state->m_pm_reg[0x4C] | ( state->m_pm_reg[0x4D] << 8 ) ) )
+// || ( ( state->m_pm_reg[0x48] & 0x80 ) && state->m_pm_reg[0x4F] > state->m_pm_reg[0x4D] ) )
+// {
+ level = 0;
+// }
+
+ speaker_level_w( speaker, level );
+ }
+}
+
+
+static TIMER_CALLBACK(pokemini_seconds_timer_callback)
+{
+ pokemini_state *state = machine.driver_data<pokemini_state>();
+ if ( state->m_pm_reg[0x08] & 0x01 )
+ {
+ state->m_pm_reg[0x09] += 1;
+ if ( ! state->m_pm_reg[0x09] )
+ {
+ state->m_pm_reg[0x0A] += 1;
+ if ( ! state->m_pm_reg[0x0A] )
+ {
+ state->m_pm_reg[0x0B] += 1;
+ }
+ }
+ }
+}
+
+
+static TIMER_CALLBACK(pokemini_256hz_timer_callback)
+{
+ pokemini_state *state = machine.driver_data<pokemini_state>();
+ if ( state->m_pm_reg[0x40] & 0x01 )
+ {
+ state->m_pm_reg[0x41] += 1;
+ /* Check if the 32Hz IRQ should be triggered */
+ if ( ! ( state->m_pm_reg[0x41] & 0x07 ) )
+ {
+ state->m_pm_reg[0x28] |= 0x20;
+
+ /* Check if the 8Hz IRQ should be triggered */
+ if ( ! ( state->m_pm_reg[0x41] & 0x1F ) )
+ {
+ state->m_pm_reg[0x28] |= 0x10;
+
+ /* Check if the 2Hz IRQ should be triggered */
+ if ( ! ( state->m_pm_reg[0x41] & 0x7F ) )
+ {
+ state->m_pm_reg[0x28] |= 0x08;
+
+ /* Check if the 1Hz IRQ should be triggered */
+ if ( ! state->m_pm_reg[0x41] )
+ {
+ state->m_pm_reg[0x28] |= 0x04;
+ }
+ }
+ }
+
+ pokemini_check_irqs( machine );
+ }
+ }
+}
+
+
+static TIMER_CALLBACK(pokemini_timer1_callback)
+{
+ pokemini_state *state = machine.driver_data<pokemini_state>();
+ state->m_pm_reg[0x36] -= 1;
+ /* Check for underflow of timer */
+ if ( state->m_pm_reg[0x36] == 0xFF )
+ {
+ /* Check if timer1 is running in 16bit mode */
+ if ( state->m_pm_reg[0x30] & 0x80 )
+ {
+ state->m_pm_reg[0x37] -= 1;
+ if ( state->m_pm_reg[0x37] == 0xFF )
+ {
+ state->m_pm_reg[0x27] |= 0x08;
+ pokemini_check_irqs( machine );
+ state->m_pm_reg[0x36] = state->m_pm_reg[0x32];
+ state->m_pm_reg[0x37] = state->m_pm_reg[0x33];
+ }
+ }
+ else
+ {
+ state->m_pm_reg[0x27] |= 0x04;
+ pokemini_check_irqs( machine );
+ state->m_pm_reg[0x36] = state->m_pm_reg[0x32];
+ }
+ }
+}
+
+
+static TIMER_CALLBACK(pokemini_timer1_hi_callback)
+{
+ pokemini_state *state = machine.driver_data<pokemini_state>();
+ state->m_pm_reg[0x37] -= 1;
+ /* Check for underflow of timer */
+ if ( state->m_pm_reg[0x37] == 0xFF )
+ {
+ state->m_pm_reg[0x27] |= 0x08;
+ pokemini_check_irqs( machine );
+ state->m_pm_reg[0x37] = state->m_pm_reg[0x33];
+ }
+}
+
+
+static TIMER_CALLBACK(pokemini_timer2_callback)
+{
+ pokemini_state *state = machine.driver_data<pokemini_state>();
+ state->m_pm_reg[0x3E] -= 1;
+ /* Check for underflow of timer */
+ if ( state->m_pm_reg[0x3E] == 0xFF )
+ {
+ /* Check if timer2 is running in 16bit mode */
+ if ( state->m_pm_reg[0x38] & 0x80 )
+ {
+ state->m_pm_reg[0x3F] -= 1;
+ if ( state->m_pm_reg[0x3F] == 0xFF )
+ {
+ state->m_pm_reg[0x27] |= 0x20;
+ pokemini_check_irqs( machine );
+ state->m_pm_reg[0x3E] = state->m_pm_reg[0x3A];
+ state->m_pm_reg[0x3F] = state->m_pm_reg[0x3B];
+ }
+ }
+ else
+ {
+ state->m_pm_reg[0x27] |= 0x10;
+ pokemini_check_irqs( machine );
+ state->m_pm_reg[0x3E] = state->m_pm_reg[0x3A];
+ }
+ }
+}
+
+
+static TIMER_CALLBACK(pokemini_timer2_hi_callback)
+{
+ pokemini_state *state = machine.driver_data<pokemini_state>();
+ state->m_pm_reg[0x3F] -= 1;
+ /* Check for underfow of timer */
+ if ( state->m_pm_reg[0x3F] == 0xFF )
+ {
+ state->m_pm_reg[0x27] |= 0x20;
+ pokemini_check_irqs( machine );
+ state->m_pm_reg[0x3F] = state->m_pm_reg[0x3B];
+ }
+}
+
+
+static TIMER_CALLBACK(pokemini_timer3_callback)
+{
+ pokemini_state *state = machine.driver_data<pokemini_state>();
+ state->m_pm_reg[0x4E] -= 1;
+ /* Check for underflow of timer */
+ if ( state->m_pm_reg[0x4E] == 0xFF )
+ {
+ /* Check if timer3 is running in 16bit mode */
+ if ( state->m_pm_reg[0x48] & 0x80 )
+ {
+ state->m_pm_reg[0x4F] -= 1;
+ if ( state->m_pm_reg[0x4F] == 0xFF )
+ {
+ state->m_pm_reg[0x27] |= 0x02;
+ pokemini_check_irqs( machine );
+ state->m_pm_reg[0x4E] = state->m_pm_reg[0x4A];
+ state->m_pm_reg[0x4F] = state->m_pm_reg[0x4B];
+ }
+ }
+ else
+ {
+ state->m_pm_reg[0x4E] = state->m_pm_reg[0x4A];
+ }
+ }
+
+ if ( state->m_pm_reg[0x48] & 0x80 )
+ {
+ if ( ( state->m_pm_reg[0x4E] == state->m_pm_reg[0x4C] ) && ( state->m_pm_reg[0x4F] == state->m_pm_reg[0x4D] ) )
+ {
+ state->m_pm_reg[0x27] |= 0x01;
+ pokemini_check_irqs( machine );
+ }
+ pokemini_update_sound( machine );
+ }
+}
+
+
+static TIMER_CALLBACK(pokemini_timer3_hi_callback)
+{
+ pokemini_state *state = machine.driver_data<pokemini_state>();
+ state->m_pm_reg[0x4F] -= 1;
+ /* Check for underflow of timer */
+ if ( state->m_pm_reg[0x4F] == 0xFF )
+ {
+ state->m_pm_reg[0x27] |= 0x02;
+ pokemini_check_irqs( machine );
+ state->m_pm_reg[0x4F] = state->m_pm_reg[0x4B];
+ }
+
+ if ( ! ( state->m_pm_reg[0x48] & 0x80 ) )
+ {
+ if( state->m_pm_reg[0x4F] == state->m_pm_reg[0x4D] )
+ {
+ state->m_pm_reg[0x27] |= 0x01;
+ pokemini_check_irqs( machine );
+ }
+ pokemini_update_sound( machine );
+ }
+}
+
+
+WRITE8_DEVICE_HANDLER( pokemini_hwreg_w )
+{
+ pokemini_state *state = device->machine().driver_data<pokemini_state>();
+ static const int timer_to_cycles_fast[8] = { 2, 8, 32, 64, 128, 256, 1024, 4096 };
+ static const int timer_to_cycles_slow[8] = { 128, 256, 512, 1024, 2048, 4096, 8192, 16384 };
+
+ //logerror( "%0X: Write to hardware address: %02X, %02X\n", cpu_get_pc( &space->device() ), offset, data );
+
+ switch( offset )
+ {
+ case 0x00: /* start-up contrast
+ Bit 0-1 R/W Must be 1(?)
+ Bit 2-7 R/W Start up contrast (doesn't affect contrast until after reboot)
+ */
+ case 0x01: /* CPU related?
+ Bit 0-7 R/W Unknown
+ */
+ case 0x02: /* CPU related?
+ Bit 0-7 R/W Unknown
+ */
+ logerror( "%0X: Write to unknown hardware address: %02X, %02X\n", cpu_get_pc( device->machine().firstcpu ), offset, data );
+ break;
+ case 0x08: /* Seconds-timer control
+ Bit 0 R/W Timer enable
+ Bit 1 W Timer reset
+ Bit 2-7 Unused
+ */
+ if ( data & 0x02 )
+ {
+ state->m_pm_reg[0x09] = 0x00;
+ state->m_pm_reg[0x0A] = 0x00;
+ state->m_pm_reg[0x0B] = 0x00;
+ data &= ~0x02;
+ }
+ break;
+ case 0x09: /* Seconds-timer (low), read only
+ Bit 0-7 R Seconds timer bit 0-7
+ */
+ return;
+ case 0x0A: /* Seconds-timer (mid), read only
+ Bit 0-7 R Seconds timer bit 8-15
+ */
+ return;
+ case 0x0B: /* Seconds-timer (high), read only
+ Bit 0-7 R Seconds timer bit 16-23
+ */
+ return;
+ case 0x10: /* Low power detector
+ Bit 0-4 R/W Unknown
+ Bit 5 R Battery status: 0 - battery OK, 1 - battery low
+ Bit 6-7 Unused
+ */
+ logerror( "%0X: Write to unknown hardware address: %02X, %02X\n", cpu_get_pc( device->machine().firstcpu ), offset, data );
+ break;
+ case 0x18: /* Timer 1 pre-scale + enable
+ Bit 0-2 R/W low timer 1 prescaler select
+ 000 - 2 or 128 cycles
+ 001 - 8 or 256 cycles
+ 010 - 32 or 512 cycles
+ 011 - 64 or 1024 cycles
+ 100 - 128 or 2048 cycles
+ 101 - 256 or 4096 cycles
+ 110 - 1024 or 8192 cycles
+ 111 - 4096 or 16384 cycles
+ Bit 3 R/W Enable low counting
+ Bit 4-6 R/W high timer 1 prescaler select
+ Bit 7 R/W Enable high counting
+ */
+ /* Check for prescaler change for the low counter */
+ if ( ( data & 0x07 ) != ( state->m_pm_reg[0x18] & 0x07 ) )
+ {
+ int index = data & 0x07;
+ int cycles = ( state->m_pm_reg[0x19] & 0x01 ) ? timer_to_cycles_slow[index] : timer_to_cycles_fast[index];
+
+ state->m_timers.timer1->adjust(attotime::zero, 0, device->machine().device<cpu_device>("maincpu")->cycles_to_attotime(cycles));
+ }
+
+ /* Check for prescaler change for the high counter */
+ if ( ( data & 0x70 ) != ( state->m_pm_reg[0x18] & 0x70 ) )
+ {
+ int index = ( data >> 4 ) & 0x07;
+ int cycles = ( state->m_pm_reg[0x19] & 0x02 ) ? timer_to_cycles_slow[index] : timer_to_cycles_fast[index];
+
+ state->m_timers.timer1_hi->adjust(attotime::zero, 0, device->machine().device<cpu_device>("maincpu")->cycles_to_attotime(cycles));
+ }
+
+ /* Check if timer1 low should be enabled */
+ if ( ( data & 0x08 ) && ( state->m_pm_reg[0x30] & 0x04 ) &&
+ ( ( ( state->m_pm_reg[0x19] & 0x10 ) && ( state->m_pm_reg[0x19] & 0x01 ) ) ||
+ ( ( state->m_pm_reg[0x19] & 0x20 ) && ! ( state->m_pm_reg[0x19] & 0x01 ) ) ) )
+ {
+ state->m_timers.timer1->enable( 1 );
+ }
+ else
+ {
+ state->m_timers.timer1->enable( 0 );
+ }
+
+ /* Check if timer1 high should be enabled */
+ if ( ( data & 0x80 ) && ( state->m_pm_reg[0x31] & 0x04 ) && ! ( state->m_pm_reg[0x30] & 0x80 ) &&
+ ( ( ( state->m_pm_reg[0x19] & 0x10 ) && ( state->m_pm_reg[0x19] & 0x02 ) ) ||
+ ( ( state->m_pm_reg[0x19] & 0x20 ) && ! ( state->m_pm_reg[0x19] & 0x02 ) ) ) )
+ {
+ state->m_timers.timer1_hi->enable( 1 );
+ }
+ else
+ {
+ state->m_timers.timer1_hi->enable( 0 );
+ }
+ break;
+ case 0x19: /* Timers 1 speed
+ Bit 0 R/W Select slow timer for timer 1 lo
+ Bit 1 R/W Select slow timer for timer 1 hi
+ Bit 2-3 Unused
+ Bit 4 R/W Enable slow timers
+ Bit 5 R/W Enable fast timers
+ Bit 6-7 Unused
+ */
+ /* Check for prescaler change for the high counter */
+ if ( ( data & 0x01 ) != ( state->m_pm_reg[0x19] & 0x01 ) )
+ {
+ int index = state->m_pm_reg[0x18] & 0x07;
+ int cycles = ( data & 0x01 ) ? timer_to_cycles_slow[index] : timer_to_cycles_fast[index];
+
+ state->m_timers.timer1->adjust(attotime::zero, 0, device->machine().device<cpu_device>("maincpu")->cycles_to_attotime(cycles));
+ }
+
+ /* Check for prescaler change for the low counter */
+ if ( ( data & 0x02 ) != ( state->m_pm_reg[0x19] & 0x02 ) )
+ {
+ int index = ( state->m_pm_reg[0x18] >> 4 ) & 0x07;
+ int cycles = ( data & 0x02 ) ? timer_to_cycles_slow[index] : timer_to_cycles_fast[index];
+
+ state->m_timers.timer1_hi->adjust(attotime::zero, 0, device->machine().device<cpu_device>("maincpu")->cycles_to_attotime(cycles));
+ }
+
+ {
+ int timer1_enable = 0, timer1_hi_enable = 0;
+ int timer2_enable = 0, timer2_hi_enable = 0;
+ int timer3_enable = 0, timer3_hi_enable = 0;
+
+ /* Check which fast timers should be enabled */
+ if ( data & 0x20 )
+ {
+ if ( ( state->m_pm_reg[0x18] & 0x08 ) && ( state->m_pm_reg[0x30] & 0x04 ) && ! ( data & 0x01 ) )
+ timer1_enable = 1;
+
+ if ( ( state->m_pm_reg[0x18] & 0x80 ) && ( state->m_pm_reg[0x31] & 0x04 ) && ! ( state->m_pm_reg[0x30] & 0x80 ) && ! ( data & 0x02 ) )
+ timer1_hi_enable = 1;
+
+ if ( ( state->m_pm_reg[0x1A] & 0x08 ) && ( state->m_pm_reg[0x38] & 0x04 ) && ! ( state->m_pm_reg[0x1B] & 0x01 ) )
+ timer2_enable = 1;
+
+ if ( ( state->m_pm_reg[0x1A] & 0x80 ) && ( state->m_pm_reg[0x39] & 0x04 ) && ! ( state->m_pm_reg[0x38] & 0x80 ) && ! ( state->m_pm_reg[0x1B] & 0x02 ) )
+ timer2_hi_enable = 1;
+
+ if ( ( state->m_pm_reg[0x1C] & 0x08 ) && ( state->m_pm_reg[0x48] & 0x04 ) && ! ( state->m_pm_reg[0x1D] & 0x01 ) )
+ timer3_enable = 1;
+
+ if ( ( state->m_pm_reg[0x1C] & 0x80 ) && ( state->m_pm_reg[0x49] & 0x04 ) && ! ( state->m_pm_reg[0x48] & 0x80 ) && ! ( state->m_pm_reg[0x1D] & 0x02 ) )
+ timer3_hi_enable = 1;
+ }
+
+ /* Check which slow timers should be enabled */
+ if ( data & 0x10 )
+ {
+ if ( ( state->m_pm_reg[0x18] & 0x08 ) && ( data & 0x01 ) )
+ timer1_enable = 1;
+
+ if ( ( state->m_pm_reg[0x1A] & 0x08 ) && ( state->m_pm_reg[0x1B] & 0x01 ) )
+ timer2_enable = 1;
+
+ if ( ( state->m_pm_reg[0x1C] & 0x08 ) && ( state->m_pm_reg[0x1D] & 0x01 ) )
+ timer3_enable = 1;
+ }
+ state->m_timers.timer1->enable( timer1_enable );
+ state->m_timers.timer1_hi->enable( timer1_hi_enable );
+ state->m_timers.timer2->enable( timer2_enable );
+ state->m_timers.timer2_hi->enable( timer2_hi_enable );
+ state->m_timers.timer3->enable( timer3_enable );
+ state->m_timers.timer3_hi->enable( timer3_hi_enable );
+ }
+ break;
+ case 0x1A: /* Timer 2 pre-scale + enable
+ Bit 0-2 R/W low timer 2 prescaler select
+ 000 - 2 or 128 cycles
+ 001 - 8 or 256 cycles
+ 010 - 32 or 512 cycles
+ 011 - 64 or 1024 cycles
+ 100 - 128 or 2048 cycles
+ 101 - 256 or 4096 cycles
+ 110 - 1024 or 8192 cycles
+ 111 - 4096 or 16384 cycles
+ Bit 3 R/W Enable low counting
+ Bit 4-6 R/W high timer 2 prescaler select
+ Bit 7 R/W Enable high counting
+ */
+ /* Check for prescaler change for the low counter */
+ if ( ( data & 0x07 ) != ( state->m_pm_reg[0x1A] & 0x07 ) )
+ {
+ int index = data & 0x07;
+ int cycles = ( state->m_pm_reg[0x1B] & 0x01 ) ? timer_to_cycles_slow[index] : timer_to_cycles_fast[index];
+
+ state->m_timers.timer2->adjust(attotime::zero, 0, device->machine().device<cpu_device>("maincpu")->cycles_to_attotime(cycles));
+ }
+
+ /* Check for prescaler change for the high counter */
+ if ( ( data & 0x70 ) != ( state->m_pm_reg[0x1A] & 0x70 ) )
+ {
+ int index = ( data >> 4 ) & 0x07;
+ int cycles = ( state->m_pm_reg[0x1B] & 0x02 ) ? timer_to_cycles_slow[index] : timer_to_cycles_fast[index];
+
+ state->m_timers.timer2_hi->adjust(attotime::zero, 0, device->machine().device<cpu_device>("maincpu")->cycles_to_attotime(cycles));
+ }
+
+ /* Check if timer2 low should be enabled */
+ if ( ( data & 0x08 ) && ( state->m_pm_reg[0x38] & 0x04 ) &&
+ ( ( ( state->m_pm_reg[0x19] & 0x10 ) && ( state->m_pm_reg[0x1B] & 0x01 ) ) ||
+ ( ( state->m_pm_reg[0x19] & 0x20 ) && ! ( state->m_pm_reg[0x1B] & 0x01 ) ) ) )
+ {
+ state->m_timers.timer2->enable( 1 );
+ }
+ else
+ {
+ state->m_timers.timer2->enable( 0 );
+ }
+
+ /* Check if timer2 high should be enabled */
+ if ( ( data & 0x80 ) && ( state->m_pm_reg[0x39] & 0x04 ) && ! ( state->m_pm_reg[0x38] & 0x80 ) &&
+ ( ( ( state->m_pm_reg[0x19] & 0x10 ) && ( state->m_pm_reg[0x1B] & 0x02 ) ) ||
+ ( ( state->m_pm_reg[0x19] & 0x20 ) && ! ( state->m_pm_reg[0x1B] & 0x02 ) ) ) )
+ {
+ state->m_timers.timer2_hi->enable( 1 );
+ }
+ else
+ {
+ state->m_timers.timer2_hi->enable( 0 );
+ }
+ break;
+ case 0x1B: /* Timer 2 speeds
+ Bit 0 R/W Select slow timer for timer 2 lo
+ Bit 1 R/W Select slow timer for timer 2 hi
+ */
+ /* Check for prescaler change for the high counter */
+ if ( ( data & 0x01 ) != ( state->m_pm_reg[0x1B] & 0x01 ) )
+ {
+ int index = state->m_pm_reg[0x1A] & 0x07;
+ int cycles = ( data & 0x01 ) ? timer_to_cycles_slow[index] : timer_to_cycles_fast[index];
+
+ state->m_timers.timer2->adjust(attotime::zero, 0, device->machine().device<cpu_device>("maincpu")->cycles_to_attotime(cycles));
+
+ if ( ( state->m_pm_reg[0x1A] & 0x08 ) && ( state->m_pm_reg[0x38] & 0x04 ) &&
+ ( ( ( state->m_pm_reg[0x19] & 0x10 ) && ( data & 0x01 ) ) ||
+ ( ( state->m_pm_reg[0x19] & 0x20 ) && ! ( data & 0x01 ) ) ) )
+ {
+ state->m_timers.timer2->enable( 1 );
+ }
+ else
+ {
+ state->m_timers.timer2->enable( 0 );
+ }
+ }
+
+ /* Check for prescaler change for the low counter */
+ if ( ( data & 0x02 ) != ( state->m_pm_reg[0x1B] & 0x02 ) )
+ {
+ int index = ( state->m_pm_reg[0x1A] >> 4 ) & 0x07;
+ int cycles = ( data & 0x02 ) ? timer_to_cycles_slow[index] : timer_to_cycles_fast[index];
+
+ state->m_timers.timer2_hi->adjust(attotime::zero, 0, device->machine().device<cpu_device>("maincpu")->cycles_to_attotime(cycles));
+
+ if ( ( state->m_pm_reg[0x1A] & 0x80 ) && ( state->m_pm_reg[0x39] & 0x04 ) && ! ( state->m_pm_reg[0x38] & 0x80 ) &&
+ ( ( ( state->m_pm_reg[0x19] & 0x10 ) && ( data & 0x02 ) ) ||
+ ( ( state->m_pm_reg[0x19] & 0x20 ) && ! ( data & 0x02 ) ) ) )
+ {
+ state->m_timers.timer2_hi->enable( 1 );
+ }
+ else
+ {
+ state->m_timers.timer2_hi->enable( 0 );
+ }
+ }
+ break;
+ case 0x1C: /* Timer 3 pre-scale + enable
+ Bit 0-2 R/W low timer 3 prescaler select
+ 000 - 2 or 128 cycles
+ 001 - 8 or 256 cycles
+ 010 - 32 or 512 cycles
+ 011 - 64 or 1024 cycles
+ 100 - 128 or 2048 cycles
+ 101 - 256 or 4096 cycles
+ 110 - 1024 or 8192 cycles
+ 111 - 4096 or 16384 cycles
+ Bit 3 R/W Enable low counting
+ Bit 4-6 R/W high timer 3 prescaler select
+ Bit 7 R/W Enable high counting
+ */
+ /* Check for prescaler change for the low counter */
+ if ( ( data & 0x07 ) != ( state->m_pm_reg[0x1C] & 0x07 ) )
+ {
+ int index = data & 0x07;
+ int cycles = ( state->m_pm_reg[0x1D] & 0x01 ) ? timer_to_cycles_slow[index] : timer_to_cycles_fast[index];
+
+ state->m_timers.timer3->adjust(attotime::zero, 0, device->machine().device<cpu_device>("maincpu")->cycles_to_attotime(cycles));
+ }
+
+ /* Check for prescaler change for the high counter */
+ if ( ( data & 0x70 ) != ( state->m_pm_reg[0x1C] & 0x70 ) )
+ {
+ int index = ( data >> 4 ) & 0x07;
+ int cycles = ( state->m_pm_reg[0x1D] & 0x02 ) ? timer_to_cycles_slow[index] : timer_to_cycles_fast[index];
+
+ state->m_timers.timer3_hi->adjust(attotime::zero, 0, device->machine().device<cpu_device>("maincpu")->cycles_to_attotime(cycles));
+ }
+
+ /* Check if timer2 low should be enabled */
+ if ( ( data & 0x08 ) && ( state->m_pm_reg[0x48] & 0x04 ) &&
+ ( ( ( state->m_pm_reg[0x19] & 0x10 ) && ( state->m_pm_reg[0x1D] & 0x01 ) ) ||
+ ( ( state->m_pm_reg[0x19] & 0x20 ) && ! ( state->m_pm_reg[0x1D] & 0x01 ) ) ) )
+ {
+ state->m_timers.timer3->enable( 1 );
+ }
+ else
+ {
+ state->m_timers.timer3->enable( 0 );
+ }
+
+ /* Check if timer2 high should be enabled */
+ if ( ( data & 0x80 ) && ( state->m_pm_reg[0x49] & 0x04 ) && ! ( state->m_pm_reg[0x48] & 0x80 ) &&
+ ( ( ( state->m_pm_reg[0x19] & 0x10 ) && ( state->m_pm_reg[0x1D] & 0x02 ) ) ||
+ ( ( state->m_pm_reg[0x19] & 0x20 ) && ! ( state->m_pm_reg[0x1D] & 0x02 ) ) ) )
+ {
+ state->m_timers.timer3_hi->enable( 1 );
+ }
+ else
+ {
+ state->m_timers.timer3_hi->enable( 0 );
+ }
+ break;
+ case 0x1D: /* Timer 3 speeds
+ Bit 0 R/W Select slow timer for timer 3 lo
+ Bit 1 R/W Select slow timer for timer 3 hi
+ */
+ /* Check for prescaler change for the high counter */
+ if ( ( data & 0x01 ) != ( state->m_pm_reg[0x1D] & 0x01 ) )
+ {
+ int index = state->m_pm_reg[0x1C] & 0x07;
+ int cycles = ( data & 0x01 ) ? timer_to_cycles_slow[index] : timer_to_cycles_fast[index];
+
+ state->m_timers.timer3->adjust(attotime::zero, 0, device->machine().device<cpu_device>("maincpu")->cycles_to_attotime(cycles));
+
+ if ( ( state->m_pm_reg[0x1C] & 0x08 ) && ( state->m_pm_reg[0x48] & 0x04 ) &&
+ ( ( ( state->m_pm_reg[0x19] & 0x10 ) && ( data & 0x01 ) ) ||
+ ( ( state->m_pm_reg[0x19] & 0x20 ) && ! ( data & 0x01 ) ) ) )
+ {
+ state->m_timers.timer3->enable( 1 );
+ }
+ else
+ {
+ state->m_timers.timer3->enable( 0 );
+ }
+ }
+
+ /* Check for prescaler change for the low counter */
+ if ( ( data & 0x02 ) != ( state->m_pm_reg[0x1D] & 0x02 ) )
+ {
+ int index = ( state->m_pm_reg[0x1C] >> 4 ) & 0x07;
+ int cycles = ( data & 0x02 ) ? timer_to_cycles_slow[index] : timer_to_cycles_fast[index];
+
+ state->m_timers.timer3_hi->adjust(attotime::zero, 0, device->machine().device<cpu_device>("maincpu")->cycles_to_attotime(cycles));
+
+ if ( ( state->m_pm_reg[0x1C] & 0x80 ) && ( state->m_pm_reg[0x49] & 0x04 ) && ! ( state->m_pm_reg[0x48] & 0x80 ) &&
+ ( ( ( state->m_pm_reg[0x19] & 0x10 ) && ( data & 0x02 ) ) ||
+ ( ( state->m_pm_reg[0x19] & 0x20 ) && ! ( data & 0x02 ) ) ) )
+ {
+ state->m_timers.timer3_hi->enable( 1 );
+ }
+ else
+ {
+ state->m_timers.timer3_hi->enable( 0 );
+ }
+ }
+ break;
+ case 0x20: /* Event #1-#8 priority
+ Bit 0-1 R/W Timer 3 overflow Interrupt #7-#8
+ Bit 2-3 R/W Timer 1 overflow Interrupt #5-#6
+ Bit 4-5 R/W Timer 2 overflow Interrupt #3-#4
+ Bit 6-7 R/W VDraw/VBlank trigger Interrupt #1-#2
+ */
+ state->m_pm_reg[0x20] = data;
+ pokemini_check_irqs(device->machine());
+ break;
+ case 0x21: /* Event #15-#22 priority
+ Bit 0-1 R/W Unknown
+ Bit 2-3 R/W All keypad interrupts - Interrupt #15-#22
+ Bit 4-7 R/W Unknown
+ */
+ state->m_pm_reg[0x21] = data;
+ pokemini_check_irqs(device->machine());
+ break;
+ case 0x22: /* Event #9-#14 priority
+ Bit 0-1 R/W All #9 - #14 events - Interrupt #9-#14
+ Bit 2-7 Unused
+ */
+ state->m_pm_reg[0x22] = data;
+ pokemini_check_irqs(device->machine());
+ break;
+ case 0x23: /* Event #1-#8 enable
+ Bit 0 R/W Timer 3 overflow (mirror) - Enable Interrupt #8
+ Bit 1 R/W Timer 3 overflow - Enable Interrupt #7
+ Bit 2 R/W Not called... - Enable Interrupt #6
+ Bit 3 R/W Timer 1 overflow - Enable Interrupt #5
+ Bit 4 R/W Not called... - Enable Interrupt #4
+ Bit 5 R/W Timer 2 overflow - Enable Interrupt #3
+ Bit 6 R/W V-Draw trigger - Enable Interrupt #2
+ Bit 7 R/W V-Blank trigger - Enable Interrupt #1
+ */
+ state->m_pm_reg[0x23] = data;
+ pokemini_check_irqs(device->machine());
+ break;
+ case 0x24: /* Event #9-#12 enable
+ Bit 0-5 R/W Unknown
+ Bit 6-7 Unused
+ */
+ state->m_pm_reg[0x24] = data;
+ pokemini_check_irqs(device->machine());
+ break;
+ case 0x25: /* Event #15-#22 enable
+ Bit 0 R/W Press key "A" event - Enable interrupt #22
+ Bit 1 R/W Press key "B" event - Enable interrupt #21
+ Bit 2 R/W Press key "C" event - Enable interrupt #20
+ Bit 3 R/W Press D-pad up key event - Enable interrupt #19
+ Bit 4 R/W Press D-pad down key event - Enable interrupt #18
+ Bit 5 R/W Press D-pad left key event - Enable interrupt #17
+ Bit 6 R/W Press D-pad right key event - Enable interrupt #16
+ Bit 7 R/W Press power button event - Enable interrupt #15
+ */
+ state->m_pm_reg[0x25] = data;
+ pokemini_check_irqs(device->machine());
+ break;
+ case 0x26: /* Event #13-#14 enable
+ Bit 0-2 R/W Unknown
+ Bit 3 Unused
+ Bit 4-5 R/W Unknown
+ Bit 6 R/W Shock detector trigger - Enable interrupt #14
+ Bit 7 R/W IR receiver - low to high trigger - Enable interrupt #13
+ */
+ state->m_pm_reg[0x26] = data;
+ pokemini_check_irqs(device->machine());
+ break;
+ case 0x27: /* Interrupt active flag #1-#8
+ Bit 0 Timer 3 overflow (mirror) / Clear interrupt #8
+ Bit 1 Timer 3 overflow / Clear interrupt #7
+ Bit 2 Not called ... / Clear interrupt #6
+ Bit 3 Timer 1 overflow / Clear interrupt #5
+ Bit 4 Not called ... / Clear interrupt #4
+ Bit 5 Timer 2 overflow / Clear interrupt #3
+ Bit 6 VDraw trigger / Clear interrupt #2
+ Bit 7 VBlank trigger / Clear interrupt #1
+ */
+ state->m_pm_reg[0x27] &= ~data;
+ pokemini_check_irqs(device->machine());
+ return;
+ case 0x28: /* Interrupt active flag #9-#12
+ Bit 0-1 Unknown
+ Bit 2 Unknown / Clear interrupt #12
+ Bit 3 Unknown / Clear interrupt #11
+ Bit 4 Unknown / Clear interrupt #10
+ Bit 5 Unknown / Clear interrupt #9
+ Bit 6-7 Unknown
+ */
+ state->m_pm_reg[0x28] &= ~data;
+ pokemini_check_irqs(device->machine());
+ return;
+ case 0x29: /* Interrupt active flag #15-#22
+ Bit 0 Press key "A" event / Clear interrupt #22
+ Bit 1 Press key "B" event / Clear interrupt #21
+ Bit 2 Press key "C" event / Clear interrupt #20
+ Bit 3 Press D-pad up key event / Clear interrupt #19
+ Bit 4 Press D-pad down key event / Clear interrupt #18
+ Bit 5 Press D-pad left key event / Clear interrupt #17
+ Bit 6 Press D-pad right key event / Clear interrupt #16
+ Bit 7 Press power button event / Clear interrupt #15
+ */
+ state->m_pm_reg[0x29] &= ~data;
+ pokemini_check_irqs(device->machine());
+ return;
+ case 0x2A: /* Interrupt active flag #13-#14
+ Bit 0-5 Unknown
+ Bit 6 Shock detector trigger / Clear interrupt #14
+ Bit 7 Unknown / Clear interrupt #13
+ */
+ state->m_pm_reg[0x2A] &= ~data;
+ pokemini_check_irqs(device->machine());
+ return;
+ case 0x30: /* Timer 1 control 1
+ Bit 0 R/W Unknown
+ Bit 1 W Reset low counter
+ Bit 2 R/W Enable high counter
+ Bit 3 R/W Unknown
+ Bit 4-6 Unused
+ Bit 7 R/W Enable 16bit mode
+ */
+ if ( data & 0x02 )
+ {
+ state->m_pm_reg[0x36] = state->m_pm_reg[0x32];
+ data &= ~0x02;
+ }
+
+ if ( ( data & 0x04 ) && ( state->m_pm_reg[0x18] & 0x08 ) &&
+ ( ( ( state->m_pm_reg[0x19] & 0x20 ) && ! ( state->m_pm_reg[0x19] & 0x01 ) ) ||
+ ( ( state->m_pm_reg[0x19] & 0x10 ) && ( state->m_pm_reg[0x19] & 0x01 ) ) ) )
+ {
+ state->m_timers.timer1->enable( 1 );
+ }
+ else
+ {
+ state->m_timers.timer1->enable( 0 );
+ }
+
+ if ( ( state->m_pm_reg[0x31] & 0x04 ) && ! ( data & 0x80 ) && ( state->m_pm_reg[0x18] & 0x80 ) &&
+ ( ( ( state->m_pm_reg[0x19] & 0x20 ) && ! ( state->m_pm_reg[0x19] & 0x02 ) ) ||
+ ( ( state->m_pm_reg[0x19] & 0x10 ) && ( state->m_pm_reg[0x19] & 0x02 ) ) ) )
+ {
+ state->m_timers.timer1_hi->enable( 1 );
+ }
+ else
+ {
+ state->m_timers.timer1_hi->enable( 0 );
+ }
+ break;
+ case 0x31: /* Timer 1 control 2
+ Bit 0 R/W Unknown
+ Bit 1 W Reset hi counter
+ Bit 2 R/W Enable high counter
+ Bit 3 R/W Unknown
+ Bit 4-7 Unused
+ */
+ if ( data & 0x02 )
+ {
+ state->m_pm_reg[0x37] = state->m_pm_reg[0x33];
+ data &= ~0x02;
+ }
+
+ if ( ( data & 0x04 ) && ! ( state->m_pm_reg[0x30] & 0x80 ) && ( state->m_pm_reg[0x18] & 0x80 ) &&
+ ( ( ( state->m_pm_reg[0x19] & 0x20 ) && ! ( state->m_pm_reg[0x19] & 0x02 ) ) ||
+ ( ( state->m_pm_reg[0x19] & 0x10 ) && ( state->m_pm_reg[0x19] & 0x02 ) ) ) )
+ {
+ state->m_timers.timer1_hi->enable( 1 );
+ }
+ else
+ {
+ state->m_timers.timer1_hi->enable( 0 );
+ }
+ break;
+ case 0x32: /* Timer 1 preset value (low)
+ Bit 0-7 R/W Timer 1 preset value bit 0-7
+ */
+ break;
+ case 0x33: /* Timer 1 preset value (high)
+ Bit 0-7 R/W Timer 1 preset value bit 8-15
+ */
+ break;
+ case 0x34: /* Timer 1 sound-pivot (low, unused)
+ */
+ case 0x35: /* Timer 1 sound-pivot (high, unused)
+ */
+ logerror( "%0X: Write to unknown hardware address: %02X, %02X\n", cpu_get_pc( device->machine().firstcpu ), offset, data );
+ break;
+ case 0x36: /* Timer 1 counter (low), read only
+ */
+ return;
+ case 0x37: /* Timer 1 counter (high), read only
+ */
+ return;
+ case 0x38: /* Timer 2 control 1
+ Bit 0 R/W Unknown
+ Bit 1 W Reset low counter
+ Bit 2 R/W Enable high counter
+ Bit 3 R/W Unknown
+ Bit 4-6 Unused
+ Bit 7 R/W Enable 16bit mode
+ */
+ if ( data & 0x02 )
+ {
+ state->m_pm_reg[0x3E] = state->m_pm_reg[0x3A];
+ data &= ~0x02;
+ }
+
+ if ( ( data & 0x04 ) && ( state->m_pm_reg[0x1A] & 0x08 ) &&
+ ( ( ( state->m_pm_reg[0x19] & 0x20 ) && ! ( state->m_pm_reg[0x1A] & 0x01 ) ) ||
+ ( ( state->m_pm_reg[0x19] & 0x10 ) && ( state->m_pm_reg[0x1A] & 0x01 ) ) ) )
+ {
+ state->m_timers.timer2->enable( 1 );
+ }
+ else
+ {
+ state->m_timers.timer2->enable( 0 );
+ }
+ if ( ( state->m_pm_reg[0x39] & 0x04 ) && ! ( data & 0x80 ) && ( state->m_pm_reg[0x1A] & 0x80 ) &&
+ ( ( ( state->m_pm_reg[0x19] & 0x20 ) && ! ( state->m_pm_reg[0x1B] & 0x02 ) ) ||
+ ( ( state->m_pm_reg[0x19] & 0x10 ) && ( state->m_pm_reg[0x1B] & 0x02 ) ) ) )
+ {
+ state->m_timers.timer2_hi->enable( 1 );
+ }
+ else
+ {
+ state->m_timers.timer2_hi->enable( 0 );
+ }
+ break;
+ case 0x39: /* Timer 2 control 2
+ Bit 0 R/W Unknown
+ Bit 1 W Reset hi counter
+ Bit 2 R/W Enable high counter
+ Bit 3 R/W Unknown
+ Bit 4-7 Unused
+ */
+ if ( data & 0x02 )
+ {
+ state->m_pm_reg[0x3F] = state->m_pm_reg[0x3A];
+ data &= ~0x02;
+ }
+
+ if ( ( data & 0x04 ) && ! ( state->m_pm_reg[0x38] & 0x80 ) && ( state->m_pm_reg[0x1A] & 0x80 ) &&
+ ( ( ( state->m_pm_reg[0x19] & 0x20 ) && ! ( state->m_pm_reg[0x1B] & 0x02 ) ) ||
+ ( ( state->m_pm_reg[0x19] & 0x10 ) && ( state->m_pm_reg[0x1B] & 0x02 ) ) ) )
+ {
+ state->m_timers.timer2_hi->enable( 1 );
+ }
+ else
+ {
+ state->m_timers.timer2_hi->enable( 0 );
+ }
+ break;
+ case 0x3A: /* Timer 2 preset value (low)
+ Bit 0-7 R/W Timer 2 preset value bit 0-7
+ */
+ break;
+ case 0x3B: /* Timer 2 preset value (high)
+ Bit 0-7 R/W Timer 2 preset value bit 8-15
+ */
+ break;
+ case 0x3C: /* Timer 2 sound-pivot (low, unused)
+ */
+ case 0x3D: /* Timer 2 sound-pivot (high, unused)
+ */
+ logerror( "%0X: Write to unknown hardware address: %02X, %02X\n", cpu_get_pc( device->machine().firstcpu ), offset, data );
+ break;
+ case 0x3E: /* Timer 2 counter (low), read only
+ Bit 0-7 R/W Timer 2 counter value bit 0-7
+ */
+ return;
+ case 0x3F: /* Timer 2 counter (high), read only
+ Bit 0-7 R/W Timer 2 counter value bit 8-15
+ */
+ return;
+ case 0x40: /* 256Hz timer control
+ Bit 0 R/W Enable Timer
+ Bit 1 W Reset Timer
+ Bit 2-7 Unused
+ */
+ if ( data & 0x02 )
+ {
+ state->m_pm_reg[0x41] = 0;
+ data &= ~0x02;
+ }
+ break;
+ case 0x41: /* 256Hz timer counter
+ Bit 0-7 R 256Hz timer counter
+ */
+ return;
+ case 0x48: /* Timer 3 control 1
+ Bit 0 R/W Unknown
+ Bit 1 W Reset low counter
+ Bit 2 R/W Enable high counter
+ Bit 3 R/W Unknown
+ Bit 4-6 Unused
+ Bit 7 R/W Enable 16bit mode
+ */
+ if ( data & 0x02 )
+ {
+ state->m_pm_reg[0x4E] = state->m_pm_reg[0x4A];
+ data &= ~0x02;
+ }
+
+ if ( ( data & 0x04 ) && ( state->m_pm_reg[0x1C] & 0x08 ) &&
+ ( ( ( state->m_pm_reg[0x19] & 0x20 ) && ! ( state->m_pm_reg[0x1D] & 0x01 ) ) ||
+ ( ( state->m_pm_reg[0x19] & 0x10 ) && ( state->m_pm_reg[0x1D] & 0x01 ) ) ) )
+ {
+ state->m_timers.timer3->enable( 1 );
+ }
+ else
+ {
+ state->m_timers.timer3->enable( 0 );
+ }
+ if ( ( state->m_pm_reg[0x49] & 0x04 ) && ! ( data & 0x80 ) && ( state->m_pm_reg[0x1C] & 0x80 ) &&
+ ( ( ( state->m_pm_reg[0x19] & 0x20 ) && ! ( state->m_pm_reg[0x1D] & 0x02 ) ) ||
+ ( ( state->m_pm_reg[0x19] & 0x10 ) && ( state->m_pm_reg[0x1D] & 0x02 ) ) ) )
+ {
+ state->m_timers.timer3_hi->enable( 1 );
+ }
+ else
+ {
+ state->m_timers.timer3_hi->enable( 0 );
+ }
+ state->m_pm_reg[0x48] = data;
+ pokemini_update_sound(device->machine());
+ break;
+ case 0x49: /* Timer 3 control 2
+ Bit 0 R/W Unknown
+ Bit 1 W Reset hi counter
+ Bit 2 R/W Enable high counter
+ Bit 3 R/W Unknown
+ Bit 4-7 Unused
+ */
+ if ( data & 0x02 )
+ {
+ state->m_pm_reg[0x4F] = state->m_pm_reg[0x4B];
+ data &= ~0x02;
+ }
+
+ if ( ( data & 0x04 ) && ! ( state->m_pm_reg[0x48] & 0x80 ) && ( state->m_pm_reg[0x1C] & 0x80 ) &&
+ ( ( ( state->m_pm_reg[0x19] & 0x20 ) && ! ( state->m_pm_reg[0x1D] & 0x02 ) ) ||
+ ( ( state->m_pm_reg[0x19] & 0x10 ) && ( state->m_pm_reg[0x1D] & 0x02 ) ) ) )
+ {
+ state->m_timers.timer3_hi->enable( 1 );
+ }
+ else
+ {
+ state->m_timers.timer3_hi->enable( 0 );
+ }
+ state->m_pm_reg[0x49] = data;
+ pokemini_update_sound(device->machine());
+ break;
+ case 0x4A: /* Timer 3 preset value (low)
+ Bit 0-7 R/W Timer 3 preset value bit 0-7
+ */
+ state->m_pm_reg[0x4A] = data;
+ pokemini_update_sound(device->machine());
+ break;
+ case 0x4B: /* Timer 3 preset value (high)
+ Bit 0-7 R/W Timer 3 preset value bit 8-15
+ */
+ state->m_pm_reg[0x4B] = data;
+ pokemini_update_sound(device->machine());
+ break;
+ case 0x4C: /* Timer 3 sound-pivot (low)
+ Bit 0-7 R/W Timer 3 sound-pivot value bit 0-7
+ */
+ state->m_pm_reg[0x4C] = data;
+ pokemini_update_sound(device->machine());
+ break;
+ case 0x4D: /* Timer 3 sound-pivot (high)
+ Bit 0-7 R/W Timer 3 sound-pivot value bit 8-15
+
+ Sound-pivot location:
+ Pulse-Width of 0% = 0x0000
+ Pulse-Width of 50% = Half of preset-value
+ Pulse-Width of 100% = Same as preset-value
+ */
+ state->m_pm_reg[0x4D] = data;
+ pokemini_update_sound(device->machine());
+ break;
+ case 0x4E: /* Timer 3 counter (low), read only
+ Bit 0-7 R/W Timer 3 counter value bit 0-7
+ */
+ return;
+ case 0x4F: /* Timer 3 counter (high), read only
+ Bit 0-7 R/W Timer 3 counter value bit 8-15
+ */
+ return;
+ case 0x52: /* Keypad status
+ Bit 0 R Key "A"
+ Bit 1 R Key "B"
+ Bit 2 R Key "C"
+ Bit 3 R D-pad up
+ Bit 4 R D-pad down
+ Bit 5 R D-pad left
+ Bit 6 R D-pad right
+ Bit 7 R Power button
+ */
+ return;
+ case 0x60: /* I/O peripheral circuit select
+ Bit 0 R/W Unknown
+ bit 1 R/W IR receive / transmit
+ Bit 2 R/W EEPROM / RTC data
+ Bit 3 R/W EEPROM / RTC clock
+ Bit 4 R/W Rumble controller
+ Bit 5 R/W IR enable/disable
+ Bit 6 R/W Unknown
+ Bit 7 R/W Unknown
+ */
+ break;
+ case 0x61: /* I/O peripheral status control
+ Bit 0 R/W IR received bit (if device not selected: 0)
+ Bit 1 R/W IR transmit (if device not selected: 0)
+ Bit 2 R/W EEPROM / RTC data (if device not selected: 1)
+ Bit 3 R/W EEPROM / RTC clock (if device not selected: 0)
+ Bit 4 R/W Rumble on/off (if device not selected: 0)
+ Bit 5 R/W IR disable (receive & transmit) (if device not selected: 1)
+ Bit 6 Always 1
+ Bit 7 R/W IR received bit (mirror, if device not selected: 0)
+ */
+ if ( state->m_pm_reg[0x60] & 0x04 )
+ i2cmem_sda_write(device, ( data & 0x04 ) ? 1 : 0 );
+
+ if ( state->m_pm_reg[0x60] & 0x08 )
+ i2cmem_scl_write(device, ( data & 0x08 ) ? 1 : 0 );
+ break;
+ case 0x70: /* Sound related */
+ state->m_pm_reg[0x70] = data;
+ pokemini_update_sound(device->machine());
+ break;
+ case 0x71: /* Sound volume
+ Bit 0-1 R/W Sound volume
+ 00 - 0%
+ 01 - 50%
+ 10 - 50%
+ 11 - 100%
+ Bit 2 R/W Always set to 0
+ Bit 3-7 Unused
+ */
+ state->m_pm_reg[0x71] = data;
+ pokemini_update_sound(device->machine());
+ break;
+ case 0x80: /* LCD control
+ Bit 0 R/W Invert colors; 0 - normal, 1 - inverted
+ Bit 1 R/W Enable rendering of background
+ Bit 2 R/W Enable rendering of sprites
+ Bit 3 R/W Enable copy to LCD ram
+ Bit 4-5 R/W Map size
+ 00 - 12x16
+ 01 - 16x12
+ 10 - 24x8
+ 11 - 24x8 (prohibited code)
+ Bit 6-7 Unused
+ */
+ state->m_prc.colors_inverted = ( data & 0x01 ) ? 1 : 0;
+ state->m_prc.background_enabled = ( data & 0x02 ) ? 1 : 0;
+ state->m_prc.sprites_enabled = ( data & 0x04 ) ? 1 : 0;
+ state->m_prc.copy_enabled = ( data & 0x08 ) ? 1 : 0;
+ state->m_prc.map_size = ( data >> 4 ) & 0x03;
+ switch( state->m_prc.map_size )
+ {
+ case 0:
+ state->m_prc.map_size_x = 12; break;
+ case 1:
+ state->m_prc.map_size_x = 16; break;
+ case 2:
+ case 3:
+ state->m_prc.map_size_x = 24; break;
+ }
+ break;
+ case 0x81: /* LCD render refresh rate
+ Bit 0 R/W Unknown
+ Bit 1-3 R/W LCD refresh rate divider
+ 000 - 60Hz / 3 = 20Hz (0 - 2)
+ 001 - 60Hz / 6 = 10Hz (0 - 5)
+ 010 - 60Hz / 9 = 6,6Hz (0 - 8)
+ 011 - 60Hz / 12 = 5Hz (0 - B)
+ 100 - 60Hz / 2 = 30Hz (0 - 1)
+ 101 - 60Hz / 4 = 15Hz (0 - 3)
+ 110 - 60Hz / 6 = 10Hz (0 - 5)
+ 111 - 60Hz / 8 = 7,5Hz (0 - 7)
+ Bit 4-7 R Divider position, when overflow the LCD is updated
+ */
+ switch ( data & 0x0E )
+ {
+ case 0x00: state->m_prc.max_frame_count = 3; break;
+ case 0x02: state->m_prc.max_frame_count = 6; break;
+ case 0x04: state->m_prc.max_frame_count = 9; break;
+ case 0x06: state->m_prc.max_frame_count = 12; break;
+ case 0x08: state->m_prc.max_frame_count = 2; break;
+ case 0x0A: state->m_prc.max_frame_count = 4; break;
+ case 0x0C: state->m_prc.max_frame_count = 6; break;
+ case 0x0E: state->m_prc.max_frame_count = 8; break;
+ }
+ break;
+ case 0x82: /* BG tile data memory offset (low)
+ Bit 0-2 Always "0"
+ Bit 3-7 R/W BG tile data memory offset bit 3-7
+ */
+ data &= 0xF8;
+ state->m_prc.bg_tiles = ( state->m_prc.bg_tiles & 0xFFFF00 ) | data;
+ break;
+ case 0x83: /* BG tile data memory offset (mid)
+ Bit 0-7 R/W BG tile data memory offset bit 8-15
+ */
+ state->m_prc.bg_tiles = ( state->m_prc.bg_tiles & 0xFF00FF ) | ( data << 8 );
+ break;
+ case 0x84: /* BG tile data memory offset (high)
+ Bit 0-4 R/W BG tile data memory offset bit 16-20
+ Bit 5-7 Unused
+ */
+ data &= 0x1F;
+ state->m_prc.bg_tiles = ( state->m_prc.bg_tiles & 0x00FFFF ) | ( data << 16 );
+ break;
+ case 0x85: /* BG vertical move
+ Bit 0-6 R/W Move the background up, move range:
+ Map size 0: 0x00 to 0x40
+ Map size 1: 0x00 to 0x20
+ Map size 2: move ignored
+ Bit 7 Unused
+ */
+ case 0x86: /* BG horizontal move
+ Bit 0-6 R/W Move the background left, move range:
+ Map size 0: move ignored
+ Map size 1: 0x00 to 0x20
+ Map size 2: 0x00 to 0x60
+ Bit 7 Unused
+ */
+ logerror( "%0X: Write to unknown hardware address: %02X, %02X\n", cpu_get_pc( device->machine().firstcpu ), offset, data );
+ break;
+ case 0x87: /* Sprite tile data memory offset (low)
+ Bit 0-5 Always "0"
+ Bit 6-7 R/W Sprite tile data memory offset bit 6-7
+ */
+ data &= 0xC0;
+ state->m_prc.spr_tiles = ( state->m_prc.spr_tiles & 0xFFFF00 ) | data;
+ break;
+ case 0x88: /* Sprite tile data memory offset (med)
+ Bit 0-7 R/W Sprite tile data memory offset bit 8-15
+ */
+ state->m_prc.spr_tiles = ( state->m_prc.spr_tiles & 0xFF00FF ) | ( data << 8 );
+ break;
+ case 0x89: /* Sprite tile data memory offset (high)
+ Bit 0-4 R/W Sprite tile data memory offset bit 16-20
+ Bit 5-7 Unused
+ */
+ data &= 0x1F;
+ state->m_prc.spr_tiles = ( state->m_prc.spr_tiles & 0x00FFFF ) | ( data << 16 );
+ break;
+ case 0x8A: /* LCD status
+ Bit 0 R Unknown
+ Bit 1 R Unknown
+ Bit 2 R Unknown
+ Bit 3 R Unknown
+ Bit 4 R LCD during V-Sync / Rendering circuitry active or not ( 1 = not active)
+ Bit 5 R Unknown
+ Bit 6-7 Unused
+ */
+ case 0xFE: /* Direct LCD control / data
+ Bit 0-7 R/W Direct LCD command or data
+ */
+// lcd_command_w( data );
+ break;
+ case 0xFF: /* Direct LCD data
+ Bit 0-7 R/W Direct LCD data
+ */
+// lcd_data_w( data );
+ break;
+ default:
+ logerror( "%0X: Write to unknown hardware address: %02X, %02X\n", cpu_get_pc( device->machine().firstcpu ), offset, data );
+ break;
+ }
+ state->m_pm_reg[offset] = data;
+}
+
+READ8_DEVICE_HANDLER( pokemini_hwreg_r )
+{
+ pokemini_state *state = device->machine().driver_data<pokemini_state>();
+ UINT8 data = state->m_pm_reg[offset];
+
+ switch( offset )
+ {
+ case 0x52: return state->ioport("INPUTS")->read();
+ case 0x61:
+ if ( ! ( state->m_pm_reg[0x60] & 0x04 ) )
+ {
+ data = ( data & ~ 0x04 ) | ( i2cmem_sda_read( device) ? 0x04 : 0x00 );
+ }
+
+ if ( ! ( state->m_pm_reg[0x60] & 0x08 ) )
+ {
+ data &= ~0x08;
+ }
+ break;
+ case 0x81: return ( state->m_pm_reg[offset] & 0x0F ) | ( state->m_prc.frame_count << 4 );
+ case 0x8A: return state->m_prc.count;
+ }
+ return data;
+}
+
+DEVICE_IMAGE_LOAD( pokemini_cart )
+{
+ if (image.software_entry() == NULL)
+ {
+ int size = image.length();
+
+ /* Verify that the image is big enough */
+ if (size <= 0x2100)
+ {
+ image.seterror(IMAGE_ERROR_UNSPECIFIED, "Invalid ROM image: ROM image is too small");
+ return IMAGE_INIT_FAIL;
+ }
+
+ /* Verify that the image is not too big */
+ if (size > 0x1FFFFF)
+ {
+ image.seterror(IMAGE_ERROR_UNSPECIFIED, "Invalid ROM image: ROM image is too big");
+ return IMAGE_INIT_FAIL;
+ }
+
+ /* Skip the first 0x2100 bytes */
+ image.fseek(0x2100, SEEK_SET);
+ size -= 0x2100;
+
+ if (size != image.fread( image.device().machine().root_device().memregion("maincpu")->base() + 0x2100, size))
+ {
+ image.seterror(IMAGE_ERROR_UNSPECIFIED, "Error occurred while reading ROM image");
+ return IMAGE_INIT_FAIL;
+ }
+ }
+ else
+ {
+ UINT8 *cart_rom = image.get_software_region("rom");
+ UINT32 cart_rom_size = image.get_software_region_length("rom");
+ memcpy(image.device().machine().root_device().memregion("maincpu")->base() + 0x2100, cart_rom + 0x2100, cart_rom_size - 0x2100);
+ }
+
+ return IMAGE_INIT_PASS;
+}
+
+
+static TIMER_CALLBACK( pokemini_prc_counter_callback )
+{
+ pokemini_state *state = machine.driver_data<pokemini_state>();
+ address_space *space = machine.device( "maincpu")->memory().space( AS_PROGRAM );
+ state->m_prc.count++;
+
+ /* Check for overflow */
+ if ( state->m_prc.count >= 0x42 )
+ {
+ state->m_prc.count = 0;
+ state->m_prc.frame_count++;
+ }
+ else
+ {
+ if ( state->m_prc.count == 0x18 && state->m_prc.frame_count >= state->m_prc.max_frame_count )
+ {
+ state->m_prc.frame_count = 0;
+
+ /* Check if the background should be drawn */
+ if ( state->m_prc.background_enabled )
+ {
+ int x, y;
+ for ( y = 0; y < 8; y++ ) {
+ for ( x = 0; x < 12; x++ ) {
+ UINT8 tile = state->m_p_ram[ 0x360 + ( y * state->m_prc.map_size_x ) + x ];
+ int i;
+ for( i = 0; i < 8; i++ ) {
+ state->m_p_ram[ ( y * 96 ) + ( x * 8 ) + i ] = space->read_byte( state->m_prc.bg_tiles + ( tile * 8 ) + i );
+ }
+ }
+ }
+ }
+
+ /* Check if the sprites should be drawn */
+ if ( state->m_prc.sprites_enabled )
+ {
+ UINT16 spr;
+
+ for ( spr = 0x35C; spr >= 0x300; spr -= 4 )
+ {
+ int spr_x = ( state->m_p_ram[ spr + 0 ] & 0x7F ) - 16;
+ int spr_y = ( state->m_p_ram[ spr + 1 ] & 0x7F ) - 16;
+ UINT8 spr_tile = state->m_p_ram[ spr + 2 ];
+ UINT8 spr_flag = state->m_p_ram[ spr + 3 ];
+
+ if ( spr_flag & 0x08 )
+ {
+ UINT16 gfx, mask;
+ UINT32 spr_base = state->m_prc.spr_tiles + spr_tile * 64;
+ int i, j;
+
+ for ( i = 0; i < 16; i++ )
+ {
+ if ( spr_x + i >= 0 && spr_x + i < 96 )
+ {
+ int rel_x = ( spr_flag & 0x01 ) ? 15 - i : i;
+ UINT32 s = spr_base + ( ( rel_x & 0x08 ) << 2 ) + ( rel_x & 0x07 );
+
+ mask = ~ ( space->read_byte( s ) | ( space->read_byte( s + 8 ) << 8 ) );
+ gfx = space->read_byte( s + 16 ) | ( space->read_byte( s + 24 ) << 8 );
+
+ /* Are the colors inverted? */
+ if ( spr_flag & 0x04 )
+ {
+ gfx = ~gfx;
+ }
+
+ for ( j = 0; j < 16; j++ )
+ {
+ if ( spr_y + j >= 0 && spr_y + j < 64 )
+ {
+ UINT16 ram_addr = ( ( ( spr_y + j ) >> 3 ) * 96 ) + spr_x + i;
+
+ if ( spr_flag & 0x02 )
+ {
+ if ( mask & 0x8000 )
+ {
+ state->m_p_ram[ ram_addr ] &= ~ ( 1 << ( ( spr_y + j ) & 0x07 ) );
+ if ( gfx & 0x8000 )
+ {
+ state->m_p_ram[ ram_addr ] |= ( 1 << ( ( spr_y + j ) & 0x07 ) );
+ }
+ }
+ mask <<= 1;
+ gfx <<= 1;
+ }
+ else
+ {
+ if ( mask & 0x0001 )
+ {
+ state->m_p_ram[ ram_addr ] &= ~ ( 1 << ( ( spr_y + j ) & 0x07 ) );
+ if ( gfx & 0x0001 )
+ {
+ state->m_p_ram[ ram_addr ] |= ( 1 << ( ( spr_y + j ) & 0x07 ) );
+ }
+ }
+ mask >>= 1;
+ gfx >>= 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Set PRC Render interrupt */
+ state->m_pm_reg[0x27] |= 0x40;
+ pokemini_check_irqs( machine );
+
+ /* Check if the rendered data should be copied to the LCD */
+ if ( state->m_prc.copy_enabled )
+ {
+ int x, y;
+
+ for( y = 0; y < 64; y += 8 ) {
+ for( x = 0; x < 96; x++ ) {
+ UINT8 data = state->m_p_ram[ ( y * 12 ) + x ];
+
+ state->m_bitmap.pix16(y + 0, x) = ( data & 0x01 ) ? 3 : 0;
+ state->m_bitmap.pix16(y + 1, x) = ( data & 0x02 ) ? 3 : 0;
+ state->m_bitmap.pix16(y + 2, x) = ( data & 0x04 ) ? 3 : 0;
+ state->m_bitmap.pix16(y + 3, x) = ( data & 0x08 ) ? 3 : 0;
+ state->m_bitmap.pix16(y + 4, x) = ( data & 0x10 ) ? 3 : 0;
+ state->m_bitmap.pix16(y + 5, x) = ( data & 0x20 ) ? 3 : 0;
+ state->m_bitmap.pix16(y + 6, x) = ( data & 0x40 ) ? 3 : 0;
+ state->m_bitmap.pix16(y + 7, x) = ( data & 0x80 ) ? 3 : 0;
+ }
+ }
+
+ /* Set PRC Copy interrupt */
+ state->m_pm_reg[0x27] |= 0x80;
+ pokemini_check_irqs( machine );
+ }
+ }
+
+ /* Set possible input irqs */
+ state->m_pm_reg[0x29] |= ~ machine.root_device().ioport( "INPUTS" )->read();
+ }
+}
+
+
+MACHINE_START_MEMBER( pokemini_state )
+{
+ /* Clear internal structures */
+ memset( &m_prc, 0, sizeof(m_prc) );
+ memset( &m_timers, 0, sizeof(m_timers) );
+ memset( m_pm_reg, 0, sizeof(m_pm_reg) );
+
+ /* Set up timers */
+ m_timers.seconds_timer = machine().scheduler().timer_alloc(FUNC(pokemini_seconds_timer_callback));
+ m_timers.seconds_timer->adjust( attotime::zero, 0, attotime::from_seconds( 1 ) );
+
+ m_timers.hz256_timer = machine().scheduler().timer_alloc(FUNC(pokemini_256hz_timer_callback));
+ m_timers.hz256_timer->adjust( attotime::zero, 0, attotime::from_hz( 256 ) );
+
+ m_timers.timer1 = machine().scheduler().timer_alloc(FUNC(pokemini_timer1_callback));
+ m_timers.timer1_hi = machine().scheduler().timer_alloc(FUNC(pokemini_timer1_hi_callback));
+ m_timers.timer2 = machine().scheduler().timer_alloc(FUNC(pokemini_timer2_callback));
+ m_timers.timer2_hi = machine().scheduler().timer_alloc(FUNC(pokemini_timer2_hi_callback));
+ m_timers.timer3 = machine().scheduler().timer_alloc(FUNC(pokemini_timer3_callback));
+ m_timers.timer3_hi = machine().scheduler().timer_alloc(FUNC(pokemini_timer3_hi_callback));
+
+ /* Set up the PRC */
+ m_prc.max_frame_count = 2;
+ m_prc.count_timer = machine().scheduler().timer_alloc(FUNC(pokemini_prc_counter_callback));
+ m_prc.count_timer->adjust( attotime::zero, 0, m_maincpu->cycles_to_attotime(55640 / 65) );
+}
+
diff --git a/src/mess/machine/poly88.c b/src/mess/machine/poly88.c
new file mode 100644
index 00000000000..d29ba6bc22f
--- /dev/null
+++ b/src/mess/machine/poly88.c
@@ -0,0 +1,332 @@
+/***************************************************************************
+
+ Poly-88 machine by Miodrag Milanovic
+
+ 18/05/2009 Initial implementation
+
+****************************************************************************/
+
+#include "emu.h"
+#include "cpu/i8085/i8085.h"
+#include "imagedev/cassette.h"
+#include "includes/poly88.h"
+
+
+static TIMER_CALLBACK(poly88_usart_timer_callback)
+{
+ poly88_state *state = machine.driver_data<poly88_state>();
+ state->m_int_vector = 0xe7;
+ device_set_input_line(machine.device("maincpu"), 0, HOLD_LINE);
+}
+
+WRITE8_MEMBER(poly88_state::poly88_baud_rate_w)
+{
+ logerror("poly88_baud_rate_w %02x\n",data);
+ m_usart_timer = machine().scheduler().timer_alloc(FUNC(poly88_usart_timer_callback));
+ m_usart_timer->adjust(attotime::zero, 0, attotime::from_hz(300));
+
+}
+
+static UINT8 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;
+}
+
+static TIMER_CALLBACK(keyboard_callback)
+{
+ poly88_state *state = machine.driver_data<poly88_state>();
+ static const char *const keynames[] = { "LINE0", "LINE1", "LINE2", "LINE3", "LINE4", "LINE5", "LINE6" };
+
+ int i;
+ UINT8 code;
+ UINT8 key_code = 0;
+ UINT8 shift = machine.root_device().ioport("LINEC")->read() & 0x02 ? 1 : 0;
+ UINT8 ctrl = machine.root_device().ioport("LINEC")->read() & 0x01 ? 1 : 0;
+
+ for(i = 0; i < 7; i++)
+ {
+
+ code = machine.root_device().ioport(keynames[i])->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==1 && ctrl==0) {
+ key_code = 0x60 + row_number(code) + (i-2)*8; // for small letters
+ }
+ if (i>=2 && i<=4 && shift==0 && ctrl==0) {
+ key_code = 0x40 + row_number(code) + (i-2)*8; // for big letters
+ }
+ if (i>=2 && i<=4 && 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) {
+ key_code = 0x60 + row_number(code) + (i-2)*8; // for small letters
+ } else {
+ key_code = 0x40 + row_number(code) + (i-2)*8; // for signs it is switched
+ }
+ }
+ if (i==5 && shift==0 && ctrl==0) {
+ if (row_number(code)<7) {
+ key_code = 0x40 + row_number(code) + (i-2)*8; // for small letters
+ } else {
+ key_code = 0x60 + row_number(code) + (i-2)*8; // for signs it is switched
+ }
+ }
+ if (i==5 && shift==0 && ctrl==1) {
+ key_code = 0x00 + row_number(code) + (i-2)*8; // for letters + ctrl
+ }
+ 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 = 0x0D; break; // Enter
+ case 6: key_code = 0x09; break; // TAB
+ case 7: key_code = 0x0A; break; // LF
+ }
+ }
+ }
+ }
+ if (key_code==0 && state->m_last_code !=0){
+ state->m_int_vector = 0xef;
+ cputag_set_input_line(machine, "maincpu", 0, HOLD_LINE);
+ } else {
+ state->m_last_code = key_code;
+ }
+}
+
+static IRQ_CALLBACK (poly88_irq_callback)
+{
+ poly88_state *state = device->machine().driver_data<poly88_state>();
+ return state->m_int_vector;
+}
+
+static TIMER_CALLBACK(poly88_cassette_timer_callback)
+{
+ poly88_state *state = machine.driver_data<poly88_state>();
+ int data;
+ int current_level;
+ i8251_device *uart = machine.device<i8251_device>("uart");
+ serial_source_device *ser = machine.device<serial_source_device>("sercas");
+
+// if (!(machine.root_device().ioport("DSW0")->read() & 0x02)) /* V.24 / Tape Switch */
+ //{
+ /* tape reading */
+ if (machine.device<cassette_image_device>(CASSETTE_TAG)->get_state()&CASSETTE_PLAY)
+ {
+ if (state->m_clk_level_tape)
+ {
+ state->m_previous_level = ((machine.device<cassette_image_device>(CASSETTE_TAG))->input() > 0.038) ? 1 : 0;
+ state->m_clk_level_tape = 0;
+ }
+ else
+ {
+ current_level = ((machine.device<cassette_image_device>(CASSETTE_TAG))->input() > 0.038) ? 1 : 0;
+
+ if (state->m_previous_level!=current_level)
+ {
+ data = (!state->m_previous_level && current_level) ? 1 : 0;
+//data = current_level;
+ ser->send_bit(data);
+ uart->receive_clock();
+
+ state->m_clk_level_tape = 1;
+ }
+ }
+ }
+
+ /* tape writing */
+ if (machine.device<cassette_image_device>(CASSETTE_TAG)->get_state()&CASSETTE_RECORD)
+ {
+ data = ser->get_in_data_bit();
+ data ^= state->m_clk_level_tape;
+ machine.device<cassette_image_device>(CASSETTE_TAG)->output(data&0x01 ? 1 : -1);
+
+ if (!state->m_clk_level_tape)
+ uart->transmit_clock();
+
+ state->m_clk_level_tape = state->m_clk_level_tape ? 0 : 1;
+
+ return;
+ }
+
+ state->m_clk_level_tape = 1;
+
+ if (!state->m_clk_level)
+ uart->transmit_clock();
+ state->m_clk_level = state->m_clk_level ? 0 : 1;
+// }
+}
+
+
+static TIMER_CALLBACK( setup_machine_state )
+{
+// poly88_state *state = machine.driver_data<poly88_state>();
+ i8251_device *uart = machine.device<i8251_device>("uart");
+ serial_source_device *ser = machine.device<serial_source_device>("sercas");
+ uart->connect(ser);
+}
+
+DRIVER_INIT_MEMBER(poly88_state,poly88)
+{
+ m_previous_level = 0;
+ m_clk_level = m_clk_level_tape = 1;
+ m_cassette_timer = machine().scheduler().timer_alloc(FUNC(poly88_cassette_timer_callback));
+ m_cassette_timer->adjust(attotime::zero, 0, attotime::from_hz(600));
+
+ machine().scheduler().timer_pulse(attotime::from_hz(24000), FUNC(keyboard_callback));
+}
+
+MACHINE_RESET(poly88)
+{
+ poly88_state *state = machine.driver_data<poly88_state>();
+ device_set_irq_callback(machine.device("maincpu"), poly88_irq_callback);
+ state->m_intr = 0;
+ state->m_last_code = 0;
+
+ machine.scheduler().timer_set(attotime::zero, FUNC(setup_machine_state));
+}
+
+INTERRUPT_GEN( poly88_interrupt )
+{
+ poly88_state *state = device->machine().driver_data<poly88_state>();
+ state->m_int_vector = 0xf7;
+ device_set_input_line(device, 0, HOLD_LINE);
+}
+
+static WRITE_LINE_DEVICE_HANDLER( poly88_usart_rxready )
+{
+ //poly88_state *drvstate = device->machine().driver_data<poly88_state>();
+ //drvstate->m_int_vector = 0xe7;
+ //device_set_input_line(device, 0, HOLD_LINE);
+}
+
+const i8251_interface poly88_usart_interface=
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_LINE(poly88_usart_rxready),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+READ8_MEMBER(poly88_state::poly88_keyboard_r)
+{
+ UINT8 retVal = m_last_code;
+ cputag_set_input_line(machine(), "maincpu", 0, CLEAR_LINE);
+ m_last_code = 0x00;
+ return retVal;
+}
+
+WRITE8_MEMBER(poly88_state::poly88_intr_w)
+{
+ cputag_set_input_line(machine(), "maincpu", 0, CLEAR_LINE);
+}
+
+SNAPSHOT_LOAD( poly88 )
+{
+ address_space *space = image.device().machine().device("maincpu")->memory().space(AS_PROGRAM);
+ UINT8* data= auto_alloc_array(image.device().machine(), UINT8, snapshot_size);
+ UINT16 recordNum;
+ UINT16 recordLen;
+ UINT16 address;
+ UINT8 recordType;
+
+ int pos = 0x300;
+ char name[9];
+ int i = 0;
+ int theend = 0;
+
+ image.fread( data, snapshot_size);
+
+ while (pos<snapshot_size) {
+ for(i=0;i<9;i++) {
+ name[i] = (char) data[pos + i];
+ }
+ pos+=8;
+ name[8] = 0;
+
+
+ recordNum = data[pos]+ data[pos+1]*256; pos+=2;
+ recordLen = data[pos]; pos++;
+ if (recordLen==0) recordLen=0x100;
+ address = data[pos] + data[pos+1]*256; pos+=2;
+ recordType = data[pos]; pos++;
+
+ logerror("Block :%s number:%d length: %d address=%04x type:%d\n",name,recordNum,recordLen,address, recordType);
+ switch(recordType) {
+ case 0 :
+ /* 00 Absolute */
+ memcpy(space->get_read_ptr(address ), data + pos ,recordLen);
+ break;
+ case 1 :
+ /* 01 Comment */
+ break;
+ case 2 :
+ /* 02 End */
+ theend = 1;
+ break;
+ case 3 :
+ /* 03 Auto Start @ Address */
+ cpu_set_reg(image.device().machine().device("maincpu"), I8085_PC, address);
+ theend = 1;
+ break;
+ case 4 :
+ /* 04 Data ( used by Assembler ) */
+ logerror("ASM load unsupported\n");
+ theend = 1;
+ break;
+ case 5 :
+ /* 05 BASIC program file */
+ logerror("BASIC load unsupported\n");
+ theend = 1;
+ break;
+ case 6 :
+ /* 06 End ( used by Assembler? ) */
+ theend = 1;
+ break;
+ default: break;
+ }
+
+ if (theend) {
+ break;
+ }
+ pos+=recordLen;
+ }
+ image.device().machine().device("uart")->reset();
+ return IMAGE_INIT_PASS;
+}
diff --git a/src/mess/machine/pp01.c b/src/mess/machine/pp01.c
new file mode 100644
index 00000000000..98eceb40384
--- /dev/null
+++ b/src/mess/machine/pp01.c
@@ -0,0 +1,238 @@
+/***************************************************************************
+
+ PP-01 driver by Miodrag Milanovic
+
+ 08/09/2008 Preliminary driver.
+
+****************************************************************************/
+
+
+#include "emu.h"
+#include "cpu/i8085/i8085.h"
+#include "includes/pp01.h"
+#include "machine/ram.h"
+
+
+WRITE8_MEMBER(pp01_state::pp01_video_write_mode_w)
+{
+ m_video_write_mode = data & 0x0f;
+}
+
+static void pp01_video_w(running_machine &machine,UINT8 block,UINT16 offset,UINT8 data,UINT8 part)
+{
+ pp01_state *state = machine.driver_data<pp01_state>();
+ UINT16 addroffset = part ? 0x1000 : 0x0000;
+ UINT8 *ram = machine.device<ram_device>(RAM_TAG)->pointer();
+
+ if (BIT(state->m_video_write_mode,3)) {
+ // Copy mode
+ if(BIT(state->m_video_write_mode,0)) {
+ ram[0x6000+offset+addroffset] = data;
+ } else {
+ ram[0x6000+offset+addroffset] = 0;
+ }
+ if(BIT(state->m_video_write_mode,1)) {
+ ram[0xa000+offset+addroffset] = data;
+ } else {
+ ram[0xa000+offset+addroffset] = 0;
+ }
+ if(BIT(state->m_video_write_mode,2)) {
+ ram[0xe000+offset+addroffset] = data;
+ } else {
+ ram[0xe000+offset+addroffset] = 0;
+ }
+ } else {
+ if (block==0) {
+ ram[0x6000+offset+addroffset] = data;
+ }
+ if (block==1) {
+ ram[0xa000+offset+addroffset] = data;
+ }
+ if (block==2) {
+ ram[0xe000+offset+addroffset] = data;
+ }
+ }
+}
+
+WRITE8_MEMBER(pp01_state::pp01_video_r_1_w)
+{
+ pp01_video_w(machine(),0,offset,data,0);
+}
+WRITE8_MEMBER(pp01_state::pp01_video_g_1_w)
+{
+ pp01_video_w(machine(),1,offset,data,0);
+}
+WRITE8_MEMBER(pp01_state::pp01_video_b_1_w)
+{
+ pp01_video_w(machine(),2,offset,data,0);
+}
+
+WRITE8_MEMBER(pp01_state::pp01_video_r_2_w)
+{
+ pp01_video_w(machine(),0,offset,data,1);
+}
+WRITE8_MEMBER(pp01_state::pp01_video_g_2_w)
+{
+ pp01_video_w(machine(),1,offset,data,1);
+}
+WRITE8_MEMBER(pp01_state::pp01_video_b_2_w)
+{
+ pp01_video_w(machine(),2,offset,data,1);
+}
+
+
+static void pp01_set_memory(running_machine &machine,UINT8 block, UINT8 data)
+{
+ pp01_state *state = machine.driver_data<pp01_state>();
+ UINT8 *mem = state->memregion("maincpu")->base();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ UINT16 startaddr = block*0x1000;
+ UINT16 endaddr = ((block+1)*0x1000)-1;
+ UINT8 blocknum = block + 1;
+ char bank[10];
+ sprintf(bank,"bank%d",blocknum);
+ if (data>=0xE0 && data<=0xEF) {
+ // This is RAM
+ space->install_read_bank (startaddr, endaddr, bank);
+ switch(data) {
+ case 0xe6 :
+ space->install_write_handler(startaddr, endaddr, write8_delegate(FUNC(pp01_state::pp01_video_r_1_w),state));
+ break;
+ case 0xe7 :
+ space->install_write_handler(startaddr, endaddr, write8_delegate(FUNC(pp01_state::pp01_video_r_2_w),state));
+ break;
+ case 0xea :
+ space->install_write_handler(startaddr, endaddr, write8_delegate(FUNC(pp01_state::pp01_video_g_1_w),state));
+ break;
+ case 0xeb :
+ space->install_write_handler(startaddr, endaddr, write8_delegate(FUNC(pp01_state::pp01_video_g_2_w),state));
+ break;
+ case 0xee :
+ space->install_write_handler(startaddr, endaddr, write8_delegate(FUNC(pp01_state::pp01_video_b_1_w),state));
+ break;
+ case 0xef :
+ space->install_write_handler(startaddr, endaddr, write8_delegate(FUNC(pp01_state::pp01_video_b_2_w),state));
+ break;
+
+ default :
+ space->install_write_bank(startaddr, endaddr, bank);
+ break;
+ }
+
+ state->membank(bank)->set_base(machine.device<ram_device>(RAM_TAG)->pointer() + (data & 0x0F)* 0x1000);
+ } else if (data>=0xF8) {
+ space->install_read_bank (startaddr, endaddr, bank);
+ space->unmap_write(startaddr, endaddr);
+ state->membank(bank)->set_base(mem + ((data & 0x0F)-8)* 0x1000+0x10000);
+ } else {
+ logerror("%02x %02x\n",block,data);
+ space->unmap_readwrite (startaddr, endaddr);
+ }
+}
+
+MACHINE_RESET( pp01 )
+{
+ pp01_state *state = machine.driver_data<pp01_state>();
+ int i;
+ memset(state->m_memory_block,0xff,16);
+ for(i=0;i<16;i++) {
+ state->m_memory_block[i] = 0xff;
+ pp01_set_memory(machine, i, 0xff);
+ }
+}
+
+WRITE8_MEMBER(pp01_state::pp01_mem_block_w)
+{
+ m_memory_block[offset] = data;
+ pp01_set_memory(machine(), offset, data);
+}
+
+READ8_MEMBER(pp01_state::pp01_mem_block_r)
+{
+ return m_memory_block[offset];
+}
+
+MACHINE_START(pp01)
+{
+}
+
+
+static WRITE_LINE_DEVICE_HANDLER( pp01_pit_out0 )
+{
+}
+
+static WRITE_LINE_DEVICE_HANDLER( pp01_pit_out1 )
+{
+}
+
+const struct pit8253_config pp01_pit8253_intf =
+{
+ {
+ {
+ 0,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE("pit8253", pp01_pit_out0)
+ },
+ {
+ 2000000,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE("pit8253", pp01_pit_out1)
+ },
+ {
+ 2000000,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE("pit8253", pit8253_clk0_w)
+ }
+ }
+};
+
+static READ8_DEVICE_HANDLER (pp01_8255_porta_r )
+{
+ pp01_state *state = device->machine().driver_data<pp01_state>();
+ return state->m_video_scroll;
+}
+static WRITE8_DEVICE_HANDLER (pp01_8255_porta_w )
+{
+ pp01_state *state = device->machine().driver_data<pp01_state>();
+ state->m_video_scroll = data;
+}
+
+static READ8_DEVICE_HANDLER (pp01_8255_portb_r )
+{
+ pp01_state *state = device->machine().driver_data<pp01_state>();
+ static const char *const keynames[] = {
+ "LINE0", "LINE1", "LINE2", "LINE3", "LINE4", "LINE5", "LINE6", "LINE7",
+ "LINE8", "LINE9", "LINEA", "LINEB", "LINEC", "LINED", "LINEE", "LINEF"
+ };
+
+ return (device->machine().root_device().ioport(keynames[state->m_key_line])->read() & 0x3F) | (device->machine().root_device().ioport("LINEALL")->read() & 0xC0);
+}
+static WRITE8_DEVICE_HANDLER (pp01_8255_portb_w )
+{
+ //logerror("pp01_8255_portb_w %02x\n",data);
+
+}
+
+static WRITE8_DEVICE_HANDLER (pp01_8255_portc_w )
+{
+ pp01_state *state = device->machine().driver_data<pp01_state>();
+ state->m_key_line = data & 0x0f;
+}
+
+static READ8_DEVICE_HANDLER (pp01_8255_portc_r )
+{
+ return 0xff;
+}
+
+
+
+I8255A_INTERFACE( pp01_ppi8255_interface )
+{
+ DEVCB_DEVICE_HANDLER("ppi8255", pp01_8255_porta_r),
+ DEVCB_DEVICE_HANDLER("ppi8255", pp01_8255_porta_w),
+ DEVCB_DEVICE_HANDLER("ppi8255", pp01_8255_portb_r),
+ DEVCB_DEVICE_HANDLER("ppi8255", pp01_8255_portb_w),
+ DEVCB_DEVICE_HANDLER("ppi8255", pp01_8255_portc_r),
+ DEVCB_DEVICE_HANDLER("ppi8255", pp01_8255_portc_w)
+};
+
diff --git a/src/mess/machine/primo.c b/src/mess/machine/primo.c
new file mode 100644
index 00000000000..ec5a70c6c41
--- /dev/null
+++ b/src/mess/machine/primo.c
@@ -0,0 +1,374 @@
+/*******************************************************************************
+
+ primo.c
+
+ Functions to emulate general aspects of Microkey Primo computers
+ (RAM, ROM, interrupts, I/O ports)
+
+ Krzysztof Strzecha
+
+*******************************************************************************/
+
+/* Core includes */
+#include "emu.h"
+#include "includes/primo.h"
+
+/* Components */
+#include "cpu/z80/z80.h"
+#include "machine/cbmiec.h"
+#include "sound/speaker.h"
+
+/* Devices */
+#include "imagedev/cassette.h"
+#include "imagedev/snapquik.h"
+#include "imagedev/cartslot.h"
+
+
+
+/*******************************************************************************
+
+ Interrupt callback
+
+*******************************************************************************/
+
+INTERRUPT_GEN( primo_vblank_interrupt )
+{
+ primo_state *state = device->machine().driver_data<primo_state>();
+ if (state->m_nmi)
+ device_set_input_line(device, INPUT_LINE_NMI, PULSE_LINE);
+}
+
+/*******************************************************************************
+
+ Memory banking
+
+*******************************************************************************/
+
+static void primo_update_memory(running_machine &machine)
+{
+ primo_state *state = machine.driver_data<primo_state>();
+ address_space* space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ switch (state->m_port_FD & 0x03)
+ {
+ case 0x00: /* Original ROM */
+ space->unmap_write(0x0000, 0x3fff);
+ state->membank("bank1")->set_base(machine.root_device().memregion("maincpu")->base()+0x10000);
+ break;
+ case 0x01: /* EPROM extension 1 */
+ space->unmap_write(0x0000, 0x3fff);
+ state->membank("bank1")->set_base(machine.root_device().memregion("maincpu")->base()+0x14000);
+ break;
+ case 0x02: /* RAM */
+ space->install_write_bank(0x0000, 0x3fff, "bank1");
+ state->membank("bank1")->set_base(machine.root_device().memregion("maincpu")->base());
+ break;
+ case 0x03: /* EPROM extension 2 */
+ space->unmap_write(0x0000, 0x3fff);
+ state->membank("bank1")->set_base(state->memregion("maincpu")->base()+0x18000);
+ break;
+ }
+ logerror ("Memory update: %02x\n", state->m_port_FD);
+}
+
+/*******************************************************************************
+
+ IO read/write handlers
+
+*******************************************************************************/
+
+READ8_MEMBER(primo_state::primo_be_1_r)
+{
+ UINT8 data = 0x00;
+ static const char *const portnames[] = { "IN0", "IN1", "IN2", "IN3" };
+
+ // bit 7, 6 - not used
+
+ // bit 5 - VBLANK
+ data |= (machine().primary_screen->vblank()) ? 0x20 : 0x00;
+
+ // bit 4 - I4 (external bus)
+
+ // bit 3 - I3 (external bus)
+
+ // bit 2 - cassette
+ data |= ((machine().device<cassette_image_device>(CASSETTE_TAG))->input() < 0.1) ? 0x04 : 0x00;
+
+ // bit 1 - reset button
+ data |= (ioport("RESET")->read()) ? 0x02 : 0x00;
+
+ // bit 0 - keyboard
+ data |= (ioport(portnames[(offset & 0x0030) >> 4])->read() >> (offset&0x000f)) & 0x0001 ? 0x01 : 0x00;
+
+ return data;
+}
+
+READ8_MEMBER(primo_state::primo_be_2_r)
+{
+ UINT8 data = 0xff;
+
+ // bit 7, 6 - not used
+
+ // bit 5 - SCLK
+ if (!m_iec->clk_r())
+ data &= ~0x20;
+
+ // bit 4 - SDATA
+ if (!m_iec->data_r())
+ data &= ~0x10;
+
+ // bit 3 - SRQ
+ if (!m_iec->srq_r())
+ data &= ~0x08;
+
+ // bit 2 - joystic 2 (not implemeted yet)
+
+ // bit 1 - ATN
+ if (!m_iec->atn_r())
+ data &= ~0x02;
+
+ // bit 0 - joystic 1 (not implemeted yet)
+
+ logerror ("IOR BE-2 data:%02x\n", data);
+ return data;
+}
+
+WRITE8_MEMBER(primo_state::primo_ki_1_w)
+{
+ device_t *speaker = machine().device(SPEAKER_TAG);
+ // bit 7 - NMI generator enable/disable
+ m_nmi = (data & 0x80) ? 1 : 0;
+
+ // bit 6 - joystick register shift (not emulated)
+
+ // bit 5 - V.24 (2) / tape control (not emulated)
+
+ // bit 4 - speaker
+ speaker_level_w(speaker, (data&0x10)>>4);
+
+ // bit 3 - display buffer
+ if (data & 0x08)
+ m_video_memory_base |= 0x2000;
+ else
+ m_video_memory_base &= 0xdfff;
+
+ // bit 2 - V.24 (1) / tape control (not emulated)
+
+ // bit 1, 0 - cassette output
+ switch (data & 0x03)
+ {
+ case 0:
+ machine().device<cassette_image_device>(CASSETTE_TAG)->output(-1.0);
+ break;
+ case 1:
+ case 2:
+ machine().device<cassette_image_device>(CASSETTE_TAG)->output(0.0);
+ break;
+ case 3:
+ machine().device<cassette_image_device>(CASSETTE_TAG)->output(1.0);
+ break;
+ }
+}
+
+WRITE8_MEMBER(primo_state::primo_ki_2_w)
+{
+
+ // bit 7, 6 - not used
+
+ // bit 5 - SCLK
+ m_iec->clk_w(!BIT(data, 5));
+
+ // bit 4 - SDATA
+ m_iec->data_w(!BIT(data, 4));
+
+ // bit 3 - not used
+
+ // bit 2 - SRQ
+ m_iec->srq_w(!BIT(data, 2));
+
+ // bit 1 - ATN
+ m_iec->atn_w(!BIT(data, 1));
+
+ // bit 0 - not used
+
+// logerror ("IOW KI-2 data:%02x\n", data);
+}
+
+WRITE8_MEMBER(primo_state::primo_FD_w)
+{
+ if (!ioport("MEMORY_EXPANSION")->read())
+ {
+ m_port_FD = data;
+ primo_update_memory(machine());
+ }
+}
+
+/*******************************************************************************
+
+ Driver initialization
+
+*******************************************************************************/
+
+static void primo_common_driver_init (primo_state *state)
+{
+ state->m_port_FD = 0x00;
+}
+
+DRIVER_INIT_MEMBER(primo_state,primo32)
+{
+ primo_common_driver_init(this);
+ m_video_memory_base = 0x6800;
+}
+
+DRIVER_INIT_MEMBER(primo_state,primo48)
+{
+ primo_common_driver_init(this);
+ m_video_memory_base = 0xa800;
+}
+
+DRIVER_INIT_MEMBER(primo_state,primo64)
+{
+ primo_common_driver_init(this);
+ m_video_memory_base = 0xe800;
+}
+
+/*******************************************************************************
+
+ Machine initialization
+
+*******************************************************************************/
+
+static void primo_common_machine_init (running_machine &machine)
+{
+ primo_state *state = machine.driver_data<primo_state>();
+ if (machine.root_device().ioport("MEMORY_EXPANSION")->read())
+ state->m_port_FD = 0x00;
+ primo_update_memory(machine);
+ machine.device("maincpu")->set_clock_scale(machine.root_device().ioport("CPU_CLOCK")->read() ? 1.5 : 1.0);
+}
+
+MACHINE_RESET( primoa )
+{
+ primo_common_machine_init(machine);
+}
+
+MACHINE_RESET( primob )
+{
+ primo_common_machine_init(machine);
+
+//removed cbm_drive_0_config(SERIAL, 8);
+//removed cbm_drive_1_config(SERIAL, 9);
+}
+
+/*******************************************************************************
+
+ Snapshot files (.pss)
+
+*******************************************************************************/
+
+static void primo_setup_pss (running_machine &machine, UINT8* snapshot_data, UINT32 snapshot_size)
+{
+ primo_state *state = machine.driver_data<primo_state>();
+ int i;
+ device_t *speaker = machine.device(SPEAKER_TAG);
+
+ /* Z80 registers */
+
+ cpu_set_reg(machine.device("maincpu"), Z80_BC, snapshot_data[4] + snapshot_data[5]*256);
+ cpu_set_reg(machine.device("maincpu"), Z80_DE, snapshot_data[6] + snapshot_data[7]*256);
+ cpu_set_reg(machine.device("maincpu"), Z80_HL, snapshot_data[8] + snapshot_data[9]*256);
+ cpu_set_reg(machine.device("maincpu"), Z80_AF, snapshot_data[10] + snapshot_data[11]*256);
+ cpu_set_reg(machine.device("maincpu"), Z80_BC2, snapshot_data[12] + snapshot_data[13]*256);
+ cpu_set_reg(machine.device("maincpu"), Z80_DE2, snapshot_data[14] + snapshot_data[15]*256);
+ cpu_set_reg(machine.device("maincpu"), Z80_HL2, snapshot_data[16] + snapshot_data[17]*256);
+ cpu_set_reg(machine.device("maincpu"), Z80_AF2, snapshot_data[18] + snapshot_data[19]*256);
+ cpu_set_reg(machine.device("maincpu"), Z80_PC, snapshot_data[20] + snapshot_data[21]*256);
+ cpu_set_reg(machine.device("maincpu"), Z80_SP, snapshot_data[22] + snapshot_data[23]*256);
+ cpu_set_reg(machine.device("maincpu"), Z80_I, snapshot_data[24]);
+ cpu_set_reg(machine.device("maincpu"), Z80_R, snapshot_data[25]);
+ cpu_set_reg(machine.device("maincpu"), Z80_IX, snapshot_data[26] + snapshot_data[27]*256);
+ cpu_set_reg(machine.device("maincpu"), Z80_IY, snapshot_data[28] + snapshot_data[29]*256);
+
+
+ /* IO ports */
+
+ // KI-1 bit 7 - NMI generator enable/disable
+ state->m_nmi = (snapshot_data[30] & 0x80) ? 1 : 0;
+
+ // KI-1 bit 4 - speaker
+ speaker_level_w(speaker, (snapshot_data[30]&0x10)>>4);
+
+
+ /* memory */
+
+ for (i=0; i<0xc000; i++)
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->write_byte( i+0x4000, snapshot_data[i+38]);
+}
+
+SNAPSHOT_LOAD( primo )
+{
+ UINT8 *snapshot_data;
+
+ if (!(snapshot_data = (UINT8*) malloc(snapshot_size)))
+ return IMAGE_INIT_FAIL;
+
+ if (image.fread( snapshot_data, snapshot_size) != snapshot_size)
+ {
+ free(snapshot_data);
+ return IMAGE_INIT_FAIL;
+ }
+
+ if (strncmp((char *)snapshot_data, "PS01", 4))
+ {
+ free(snapshot_data);
+ return IMAGE_INIT_FAIL;
+ }
+
+ primo_setup_pss(image.device().machine(),snapshot_data, snapshot_size);
+
+ free(snapshot_data);
+ return IMAGE_INIT_PASS;
+}
+
+/*******************************************************************************
+
+ Quicload files (.pp)
+
+*******************************************************************************/
+
+
+static void primo_setup_pp (running_machine &machine,UINT8* quickload_data, UINT32 quickload_size)
+{
+ int i;
+
+ UINT16 load_addr;
+ UINT16 start_addr;
+
+ load_addr = quickload_data[0] + quickload_data[1]*256;
+ start_addr = quickload_data[2] + quickload_data[3]*256;
+
+ for (i=4; i<quickload_size; i++)
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->write_byte(start_addr+i-4, quickload_data[i]);
+
+ cpu_set_reg(machine.device("maincpu"), Z80_PC, start_addr);
+
+ logerror ("Quickload .pp l: %04x r: %04x s: %04x\n", load_addr, start_addr, quickload_size-4);
+}
+
+QUICKLOAD_LOAD( primo )
+{
+ UINT8 *quickload_data;
+
+ if (!(quickload_data = (UINT8*) malloc(quickload_size)))
+ return IMAGE_INIT_FAIL;
+
+ if (image.fread( quickload_data, quickload_size) != quickload_size)
+ {
+ free(quickload_data);
+ return IMAGE_INIT_FAIL;
+ }
+
+ primo_setup_pp(image.device().machine(), quickload_data, quickload_size);
+
+ free(quickload_data);
+ return IMAGE_INIT_PASS;
+}
diff --git a/src/mess/machine/ps2.c b/src/mess/machine/ps2.c
new file mode 100644
index 00000000000..ae06f06f275
--- /dev/null
+++ b/src/mess/machine/ps2.c
@@ -0,0 +1,96 @@
+/*****************************************************************************
+ *
+ * machine/ps2.c
+ *
+ * IBM Personal System 2
+ *
+ ****************************************************************************/
+
+#include "emu.h"
+#include "includes/ps2.h"
+
+
+/*
+ibm ps2 model 30
+----------------
+(postcode at 0x0190!)
+f008a
+f0112 "real mode switchback"
+f0147
+f0204 03
+f02a5 04
+f03b8 07
+f0413 08
+f0470 0a
+f04a2 0b
+f04e9 0e
+f0525 0f
+f088f
+ f215c
+f0928 12
+f0bbf
+f0c27
+f0c96 24
+f0e01 40
+ e1cf0
+ e2b2c
+ e1d48
+f0e45
+ beep code
+f0e8e 43
+f0ec9 45
+f0f19 48
+f0f62 4a
+f0f97 4c
+f0ff7 4e
+f1050 51
+f118c 52
+f11e3 53
+f2393 f0
+f23eb f2
+f241f f3 task register usage!
+f2468 f4
+f24d2 f5
+f2524 f6
+f2574 f7
+f25be f9
+f264c 3e
+f137e 55
+f13a8 output of keyboard problem
+f152b 5b
+f1543 5c
+f15c6 60
+f16c9 65
+ various error outputs
+f176a 66
+f1827 6a
+f18ec 6c
+f1a1e 6e
+f2bf7 6f
+
+f2dcc
+
+f1db9 write byte to nvram
+*/
+
+static struct {
+ UINT8 data[8];
+} pos={
+ { 0 }
+};
+
+ READ8_HANDLER(ps2_pos_r)
+{
+ UINT8 data=pos.data[offset];
+ switch (offset) {
+ case 2:
+ data|=8;
+ break;
+ }
+ return data;
+}
+
+WRITE8_HANDLER(ps2_pos_w)
+{
+ pos.data[offset]=data;
+}
diff --git a/src/mess/machine/psion_pack.c b/src/mess/machine/psion_pack.c
new file mode 100644
index 00000000000..681d812c46e
--- /dev/null
+++ b/src/mess/machine/psion_pack.c
@@ -0,0 +1,330 @@
+/****************************************************************************
+
+ psion_pack.c
+
+ Psion Organiser II Datapack emulation
+
+
+ Datapack pinout from Psion's documentation
+ __ __
+ SD1 1 | \/ | 2 SD0
+ SD3 3 | | 4 SD2
+ SD5 5 | | 6 SD4
+ SD7 7 | | 8 SD6
+ SMR 9 | | 10 SCLK
+ SOE_B 11 | | 12 SS_B
+ GND 13 | | 14 SPGM_B
+ SVCC 15 |______| 16 SVPP
+
+****************************************************************************/
+
+#include "emu.h"
+#include "psion_pack.h"
+
+// Datapack control lines
+#define DP_LINE_CLOCK 0x01
+#define DP_LINE_RESET 0x02
+#define DP_LINE_PROGRAM 0x04
+#define DP_LINE_OUTPUT_ENABLE 0x08
+#define DP_LINE_SLOT_SELECT 0x10
+
+// Datapack ID
+#define DP_ID_EPROM 0x02
+#define DP_ID_PAGED 0x04
+#define DP_ID_WRITE 0x08
+#define DP_ID_BOOT 0x10
+#define DP_ID_COPY 0x20
+
+#define OPK_HEAD_SIZE 6
+
+
+static OPTION_GUIDE_START( datapack_option_guide )
+ OPTION_INT('S', "size", "Datapack size" )
+ OPTION_INT('R', "ram", "RAM/EPROM" )
+ OPTION_INT('P', "paged", "Paged" )
+ OPTION_INT('W', "protect", "Write-protected" )
+ OPTION_INT('B', "boot", "Bootable" )
+ OPTION_INT('C', "copy", "Copyable" )
+OPTION_GUIDE_END
+
+static const char *datapack_option_spec =
+ "S1/2/4/[8]/16;R0/[1];P[0]/1;W[0]/1;B[0]/1;C0/[1]";
+
+
+// device type definition
+const device_type PSION_DATAPACK = &device_creator<datapack_device>;
+
+//-------------------------------------------------
+// datapack_device - constructor
+//-------------------------------------------------
+
+datapack_device::datapack_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, PSION_DATAPACK, "Psion Datapack", tag, owner, clock),
+ device_image_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// datapack_device - destructor
+//-------------------------------------------------
+
+datapack_device::~datapack_device()
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void datapack_device::device_start()
+{
+ call_unload();
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void datapack_device::device_config_complete()
+{
+ image_device_format *format = global_alloc_clear(image_device_format);
+
+ format->m_index = 0;
+ format->m_name = "opk";
+ format->m_description = "Psion Datapack image";
+ format->m_extensions = "opk";
+ format->m_optspec = datapack_option_spec;
+ format->m_next = NULL;
+
+ m_formatlist = format;
+
+ // set brief and instance name
+ update_names();
+}
+
+
+//-------------------------------------------------
+// option_guide for create new image
+//-------------------------------------------------
+
+const option_guide *datapack_device::create_option_guide() const
+{
+ return datapack_option_guide;
+}
+
+
+/*-------------------------------------------------
+ update the internal state
+-------------------------------------------------*/
+
+void datapack_device::update()
+{
+ UINT32 pack_addr = m_counter + ((m_id & DP_ID_PAGED) ? (m_page << 8) : 0);
+
+ // if the datapack is 128k or more is treated as segmented
+ if (m_size >= 0x10)
+ pack_addr += (m_segment << 14);
+
+ if (pack_addr < (m_size << 13))
+ {
+ if ((m_control & DP_LINE_OUTPUT_ENABLE) && !(m_control & DP_LINE_RESET))
+ {
+ // write data
+ if (software_entry() == NULL && (m_id & DP_ID_WRITE))
+ {
+ fseek(pack_addr + OPK_HEAD_SIZE, SEEK_SET);
+ fwrite(&m_data, 1);
+ }
+ }
+ else if ((m_control & DP_LINE_OUTPUT_ENABLE) && (m_control & DP_LINE_RESET))
+ {
+ // write datapack segment
+ if (m_size <= 0x10)
+ m_segment = m_data & 0x07;
+ else if (m_size <= 0x20)
+ m_segment = m_data & 0x0f;
+ else if (m_size <= 0x40)
+ m_segment = m_data & 0x1f;
+ else if (m_size <= 0x80)
+ m_segment = m_data & 0x3f;
+ else
+ m_segment = m_data;
+ }
+ else if (!(m_control & DP_LINE_OUTPUT_ENABLE) && !(m_control & DP_LINE_RESET))
+ {
+ // read data
+ if ((pack_addr + OPK_HEAD_SIZE) < length())
+ {
+ fseek(pack_addr + OPK_HEAD_SIZE, SEEK_SET);
+ fread(&m_data, 1);
+ }
+ else
+ {
+ m_data = 0xff;
+ }
+ }
+ else if (!(m_control & DP_LINE_OUTPUT_ENABLE) && (m_control & DP_LINE_RESET))
+ {
+ // read datapack ID
+ if (m_id & DP_ID_EPROM)
+ m_data = m_id;
+ else
+ m_data = 0x01; // for identify RAM pack
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ read datapack data lines
+-------------------------------------------------*/
+
+UINT8 datapack_device::data_r()
+{
+ return (!(m_control & DP_LINE_SLOT_SELECT)) ? m_data : 0;
+}
+
+
+/*-------------------------------------------------
+ write datapack data lines
+-------------------------------------------------*/
+
+void datapack_device::data_w(UINT8 data)
+{
+ if (is_loaded())
+ {
+ m_data = data;
+
+ // updates the internal state
+ if (!(data & DP_LINE_SLOT_SELECT))
+ update();
+ }
+}
+
+
+/*-------------------------------------------------
+ read datapack control lines
+-------------------------------------------------*/
+
+UINT8 datapack_device::control_r()
+{
+ return m_control;
+}
+
+
+/*-------------------------------------------------
+ write datapack control lines
+-------------------------------------------------*/
+
+void datapack_device::control_w(UINT8 data)
+{
+ if (is_loaded())
+ {
+ if ((m_control & DP_LINE_CLOCK) != (data & DP_LINE_CLOCK))
+ {
+ // increments the counter
+ m_counter++;
+
+ if (m_counter >= ((m_id & DP_ID_PAGED) ? 0x100 : (m_size << 13)))
+ m_counter = 0;
+ }
+
+ if ((m_control & DP_LINE_PROGRAM) && !(data & DP_LINE_PROGRAM))
+ {
+ // increments the page
+ m_page++;
+
+ if (m_page >= (m_size << 5))
+ m_page = 0;
+ }
+
+ if (data & DP_LINE_RESET)
+ {
+ // reset counter and page
+ m_counter = 0;
+ m_page = 0;
+ }
+
+ m_control = data;
+
+ // updates the internal state
+ if (!(data & DP_LINE_SLOT_SELECT))
+ update();
+ }
+}
+
+
+/*-------------------------------------------------
+ DEVICE_IMAGE_LOAD( datapack )
+-------------------------------------------------*/
+
+bool datapack_device::call_load()
+{
+ UINT8 data[0x10];
+
+ fread(data, 0x10);
+
+ // check the OPK head
+ if(strncmp((const char*)data, "OPK", 3))
+ return IMAGE_INIT_FAIL;
+
+ // get datapack ID and size
+ m_id = data[OPK_HEAD_SIZE + 0];
+ m_size = data[OPK_HEAD_SIZE + 1];
+
+ return IMAGE_INIT_PASS;
+}
+
+
+/*-------------------------------------------------
+ DEVICE_IMAGE_CREATE( datapack )
+-------------------------------------------------*/
+
+bool datapack_device::call_create(int format_type, option_resolution *create_args)
+{
+ static const UINT8 opk_head[6] = {'O', 'P', 'K', 0x00, 0x00, 0x00};
+
+ if (create_args != NULL)
+ {
+ m_id = 0x40;
+ m_id |= (option_resolution_lookup_int(create_args, 'R')) ? 0x00 : 0x02;
+ m_id |= (option_resolution_lookup_int(create_args, 'P')) ? 0x04 : 0x00;
+ m_id |= (option_resolution_lookup_int(create_args, 'W')) ? 0x00 : 0x08;
+ m_id |= (option_resolution_lookup_int(create_args, 'B')) ? 0x00 : 0x10;
+ m_id |= (option_resolution_lookup_int(create_args, 'C')) ? 0x20 : 0x00;
+ m_size = option_resolution_lookup_int(create_args, 'S');
+ }
+ else
+ {
+ // 64k RAM datapack by default
+ m_id = 0x7c;
+ m_size = 0x08;
+ }
+
+ fwrite(opk_head, 6);
+ fwrite(&m_id, 1);
+ fwrite(&m_size, 1);
+
+ return IMAGE_INIT_PASS;
+}
+
+
+/*-------------------------------------------------
+ DEVICE_IMAGE_UNLOAD( datapack )
+-------------------------------------------------*/
+
+void datapack_device::call_unload()
+{
+ m_id = 0;
+ m_size = 0;
+ m_counter = 0;
+ m_page = 0;
+ m_segment = 0;
+ m_control = 0;
+ m_data = 0;
+}
diff --git a/src/mess/machine/psion_pack.h b/src/mess/machine/psion_pack.h
new file mode 100644
index 00000000000..2987be6d5f1
--- /dev/null
+++ b/src/mess/machine/psion_pack.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+
+ psion_pack.h
+
+****************************************************************************/
+
+#ifndef __PSION_PACK_H__
+#define __PSION_PACK_H__
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+// ======================> datapack_device
+
+class datapack_device : public device_t,
+ public device_image_interface
+{
+public:
+ // construction/destruction
+ datapack_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ virtual ~datapack_device();
+
+ // image-level overrides
+ virtual bool call_load();
+ virtual void call_unload();
+ virtual bool call_create(int format_type, option_resolution *create_args);
+ virtual bool call_softlist_load(char *swlist, char *swname, rom_entry *start_entry) { return load_software(swlist, swname, 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 "psion_pack"; }
+ virtual const char *file_extensions() const { return "opk"; }
+ virtual const option_guide *create_option_guide() const;
+
+ // specific implementation
+ UINT8 data_r();
+ void data_w(UINT8 data);
+ UINT8 control_r();
+ void control_w(UINT8 data);
+
+protected:
+ // internal helper
+ void update();
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_config_complete();
+
+private:
+ // internal device state
+ UINT8 m_id; //datapack ID
+ UINT8 m_size; //size in 8k blocks
+ UINT8 m_data; //data lines
+ UINT8 m_control; //control lines
+ UINT16 m_counter; //address counter
+ UINT8 m_page; //active page (only for paged Datapack)
+ UINT8 m_segment; //active segment (only for segmented Datapack)
+};
+
+
+// device type definition
+extern const device_type PSION_DATAPACK;
+
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+#define MCFG_PSION_DATAPACK_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, PSION_DATAPACK, 0) \
+
+#endif /* __PSION_PACK_H__ */
diff --git a/src/mess/machine/psxcard.c b/src/mess/machine/psxcard.c
new file mode 100644
index 00000000000..fa380a01abe
--- /dev/null
+++ b/src/mess/machine/psxcard.c
@@ -0,0 +1,258 @@
+/*
+ psxcard.c - Sony PlayStation memory card device
+
+ by pSXAuthor
+ MESS conversion by R. Belmont
+*/
+
+#include "emu.h"
+#include "psxcard.h"
+#include "includes/psx.h"
+
+//
+//
+//
+
+//#define debug_card
+
+//
+//
+//
+
+const device_type PSXCARD = &device_creator<psxcard_device>;
+
+enum transfer_states
+{
+ state_illegal=0,
+ state_command,
+ state_cmdack_1,
+ state_cmdack_2,
+ state_addr_hi,
+ state_addr_lo,
+ state_read,
+ state_write,
+ state_writeack_1,
+ state_writeack_2,
+ state_writechk
+};
+
+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)
+{
+}
+
+void psxcard_device::device_start()
+{
+ cache=new unsigned char [128*1024];
+
+ memset(cache, 0, 128*1024);
+
+ // save state registrations
+/* save_item(NAME(pkt));
+ save_item(NAME(pkt_ptr));
+ save_item(NAME(pkt_sz));
+ save_item(NAME(pkt));
+ save_item(NAME(cache));
+ save_item(NAME(addr));
+ save_item(NAME(state));*/
+}
+
+void psxcard_device::device_reset()
+{
+ state = state_illegal;
+ addr = 0;
+}
+
+//
+//
+//
+
+bool psxcard_device::transfer(UINT8 to, UINT8 *from)
+{
+ bool ret=true;
+
+ switch (state)
+ {
+ case state_illegal:
+ if (to == 0x81)
+ {
+// printf("CARD: begin\n");
+ state = state_command;
+ *from = 0x00;
+ }
+ else
+ {
+ ret = false;
+ }
+ break;
+
+ case state_command:
+ cmd=to;
+ *from=0x00;
+ state=state_cmdack_1;
+ break;
+
+ case state_cmdack_1:
+ //assert(to==0);
+ *from=0x5a;
+ state=state_cmdack_2;
+ break;
+
+ case state_cmdack_2:
+ //assert(to==0);
+ *from=0x5d;
+ state=state_addr_hi;
+ break;
+
+ case state_addr_hi:
+ addr=(to<<8);
+// printf("addr_hi: %02x, addr = %x\n", to, addr);
+ *from=0;
+ state=state_addr_lo;
+ break;
+
+ case state_addr_lo:
+ addr|=(to&0xff);
+// printf("addr_lo: %02x, addr = %x, cmd = %x\n", to, addr, cmd);
+ *from=(addr>>8);
+
+ switch (cmd)
+ {
+ case 'R': // 0x52
+ {
+ pkt[0]=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=0;
+ 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;
+ 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_illegal;
+ ret=false;
+ }
+ break;
+
+ case state_write:
+ *from=(pkt_ptr==0)?(addr&0xff):pkt[pkt_ptr-1];
+ pkt[pkt_ptr++]=to;
+ if (pkt_ptr==pkt_sz)
+ state=state_writeack_1;
+ break;
+
+ case state_writeack_1:
+ *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_illegal;
+ ret=false;
+ 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<1024)
+ {
+ memcpy(buf,cache+(addr*128),128);
+ } else
+ {
+ memset(buf,0,128);
+ }
+}
+
+//
+//
+//
+
+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<1024)
+ {
+ memcpy(cache+(addr*128),buf,128);
+ }
+}
+
+//
+//
+//
+
+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;
+}
diff --git a/src/mess/machine/psxcard.h b/src/mess/machine/psxcard.h
new file mode 100644
index 00000000000..970820f055f
--- /dev/null
+++ b/src/mess/machine/psxcard.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#ifndef _PSXCARD_
+#define _PSXCARD_
+
+#include "emu.h"
+
+#define MCFG_PSXCARD_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, PSXCARD, 0)
+
+struct psxcard_interface
+{
+};
+
+class psxcard_device : public device_t,
+ public psxcard_interface
+{
+public:
+ psxcard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+private:
+ unsigned char pkt[0x8b], pkt_ptr, pkt_sz, cmd, *cache;
+ unsigned short addr;
+ int state;
+
+ 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);
+
+public:
+ virtual void device_start();
+ virtual void device_reset();
+
+ bool transfer(UINT8 to, UINT8 *from);
+ void mess_io(running_machine *machine, UINT8 n_data);
+private:
+};
+
+// device type definition
+extern const device_type PSXCARD;
+
+#endif
diff --git a/src/mess/machine/psxcd.c b/src/mess/machine/psxcd.c
new file mode 100644
index 00000000000..e1d8eeb2e3f
--- /dev/null
+++ b/src/mess/machine/psxcd.c
@@ -0,0 +1,1686 @@
+#include "emu.h"
+#include "includes/psx.h"
+#include "psxcd.h"
+#include "machine/devhelpr.h"
+#include "sound/spu.h"
+#include "debugger.h"
+
+//
+//
+//
+
+//#define debug_cdrom
+//#define debug_cdrom_registers
+//#define skip_reads
+//#define dump_subheader
+//#define disable_xa_prefetch
+//#define disable_cdda_prefetch
+
+//
+//
+//
+
+enum cdrom_events
+{
+ event_cmd_complete=0,
+ event_preread_sector,
+ event_read_sector,
+ event_play_sector
+};
+
+//
+//
+//
+
+enum intr_status
+{
+ intr_nointr=0,
+ intr_dataready,
+ intr_acknowledge,
+ intr_complete,
+ intr_dataend,
+ intr_diskerror
+};
+
+enum mode_flags
+{
+ mode_double_speed=0x80,
+ mode_adpcm=0x40,
+ mode_size=0x20,
+ mode_size2=0x10,
+ mode_size_shift=4,
+ mode_size_mask=(3<<mode_size_shift),
+ mode_channel=0x08,
+ mode_report=0x04,
+ mode_autopause=0x02,
+ mode_cdda=0x01
+};
+
+enum status_f
+{
+ status_playing=0x80,
+ status_seeking=0x40,
+ status_reading=0x20,
+ status_shellopen=0x10,
+ status_seekerror=0x04,
+ status_standby=0x02,
+ status_error=0x01
+};
+
+struct subheader
+{
+ unsigned char file,
+ channel,
+ submode,
+ coding;
+};
+
+enum submode_flags
+{
+ submode_eof=0x80,
+ submode_realtime=0x40,
+ submode_form=0x20,
+ submode_trigger=0x10,
+ submode_data=0x08,
+ submode_audio=0x04,
+ submode_video=0x02,
+ submode_eor=0x01
+};
+
+//
+//
+//
+
+static const unsigned int max_xa_prefetch_distance=32,
+ max_cdda_prefetch_distance=32;
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type PSXCD = &device_creator<psxcd_device>;
+
+void psxcd_device::static_set_devname(device_t &device, const char *devname)
+{
+ psxcd_device &psxcd = downcast<psxcd_device &>(device);
+ psxcd.m_devname = devname;
+}
+
+psxcd_device::psxcd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, PSXCD, "PSXCD", tag, owner, clock)
+{
+}
+
+void psxcd_device::device_start()
+{
+ unsigned int sysclk=machine().device<cpu_device>("maincpu")->clock()/2;
+ start_read_delay=(sysclk/60);
+ read_sector_cycles=(sysclk/75);
+ preread_delay=(read_sector_cycles>>2)-500;
+
+ m_sysclock = sysclk;
+
+ secleft = 0;
+ secsize = 2048;
+ res_queue = NULL;
+ cur_res = NULL;
+ open = false;
+ streaming = false;
+ sechead = 0;
+ sectail = 0;
+ secin = 0;
+ secskip = 0;
+ next_read_event = NULL;
+ cbp = cmdbuf;
+ first_open = true;
+
+ status=status_standby;
+ sr=8|1;
+ res=0;
+ ir=0;
+ mode=0;
+
+ driver = NULL;
+
+ for (int i = 0; i < MAX_PSXCD_TIMERS; i++)
+ {
+ m_timers[i] = timer_alloc(i, NULL);
+ m_timerinuse[i] = false;
+ }
+}
+
+//
+//
+//
+
+void psxcd_device::device_reset()
+{
+ stop_read();
+ open=false;
+
+ for (int i = 0; i < MAX_PSXCD_TIMERS; i++)
+ {
+ m_timerinuse[i] = false;
+ }
+
+ m_cddevice = machine().device<cdrom_image_device>(m_devname);
+ if (m_cddevice)
+ {
+ m_cd = m_cddevice->get_cdrom_file();
+
+ if (m_cd)
+ {
+// printf("psxcd: found disc!\n");
+ driver = open_mess_drv();
+ driver->set_machine(machine());
+ driver->set_cdrom_file(m_cd);
+ }
+ else
+ {
+ driver = NULL;
+// printf("psxcd: Found device, but no disc\n");
+ }
+ }
+ else
+ {
+ driver = NULL;
+// printf("psxcd: Device [%s] not found!\n", m_devname);
+ }
+
+}
+
+//
+//
+//
+
+unsigned char psxcd_device::read_byte(const unsigned int addr)
+{
+ unsigned char ret = 0;
+
+ switch (addr&3)
+ {
+ case 0: ret=sr; break;
+ case 1:
+ ret=res;
+ if ((cur_res) && (rdp<cur_res->sz))
+ {
+ res=cur_res->data[rdp++];
+ sr|=(1<<5);
+ } else
+ {
+ if ((cur_res) && (cur_res->res&0x10))
+ {
+ global_free(cur_res);
+ cur_res=NULL;
+ }
+
+ sr&=~(1<<5);
+ }
+ break;
+ case 2: ret=0; break;
+ case 3: ret=ir; break;
+ }
+
+ #ifdef debug_cdrom_registers
+ printf("cdrom: read byte %08x = %02x (PC=%x)\n",addr,ret,cpu_get_pc(machine().device("maincpu")));
+ #endif
+
+ return ret;
+}
+
+//
+//
+//
+
+void psxcd_device::write_byte(const unsigned int addr, const unsigned char byte)
+{
+ #ifdef debug_cdrom_registers
+ printf("cdrom: write byte %08x = %02x (PC=%x)\n",addr,byte,cpu_get_pc(machine().device("maincpu")));
+ #endif
+
+ switch (addr&3)
+ {
+ case 0:
+ cmdmode=byte&1;
+ if (cmdmode==0)
+ {
+ cbp=cmdbuf;
+ } else
+ {
+ if (! cur_res)
+ {
+ if (cur_res) global_free(cur_res);
+
+ if (res_queue)
+ {
+ #ifdef debug_cdrom_registers
+ printf("cdrom: nextres\n");
+ #endif
+
+ cur_res=res_queue;
+ res_queue=res_queue->next;
+ ir=cur_res->res&0xf;
+ rdp=0;
+
+ if (cur_res->sz)
+ {
+ res=cur_res->data[rdp++];
+ sr|=(1<<5);
+ } else
+ {
+ sr&=~(1<<5);
+ }
+ } else
+ {
+ //ir=0;
+ cur_res=NULL;
+ }
+ }
+ /*else
+ {
+ if (rdp>=cur_res->sz)
+ {
+ sr&=~(1<<5);
+ } else
+ {
+ sr|=~(1<<5);
+ res=cur_res->data[rdp++];
+ }
+ }
+ */
+ }
+ break;
+
+ case 1:
+ if (cmdmode==0)
+ {
+ write_command(byte);
+ }
+ break;
+
+ case 2:
+ if (cmdmode==0)
+ {
+ *cbp++=byte;
+ } else
+ {
+ // ?flush buffer?
+ }
+ break;
+
+ case 3:
+ if (byte==0x07)
+ {
+ if (cur_res)
+ {
+ global_free(cur_res);
+ cur_res=NULL;
+ sr&=~(1<<5);
+ }
+ ir=0;
+ }
+ break;
+ }
+}
+
+psxcd_device::command_info psxcd_device::cmd_table[num_commands]=
+{
+ { &psxcd_device::cdcmd_sync, "sync" }, // 00
+ { &psxcd_device::cdcmd_nop, "nop" }, // 01
+ { &psxcd_device::cdcmd_setloc, "setloc" }, // 02
+ { &psxcd_device::cdcmd_play, "play" }, // 03
+ { &psxcd_device::cdcmd_forward, "forward" }, // 04
+ { &psxcd_device::cdcmd_backward, "backward" }, // 05
+ { &psxcd_device::cdcmd_readn, "readn" }, // 06
+ { &psxcd_device::cdcmd_standby, "standby" }, // 07
+ { &psxcd_device::cdcmd_stop, "stop" }, // 08
+ { &psxcd_device::cdcmd_pause, "pause" }, // 09
+ { &psxcd_device::cdcmd_init, "init" }, // 0a
+ { &psxcd_device::cdcmd_mute, "mute" }, // 0b
+ { &psxcd_device::cdcmd_demute, "demute" }, // 0c
+ { &psxcd_device::cdcmd_setfilter, "setfilter" }, // 0d
+ { &psxcd_device::cdcmd_setmode, "setmode" }, // 0e
+ { &psxcd_device::cdcmd_getparam, "getparam" }, // 0f
+ { &psxcd_device::cdcmd_getlocl, "getlocl" }, // 10
+ { &psxcd_device::cdcmd_getlocp, "getlocp" }, // 11
+ { &psxcd_device::cdcmd_illegal, "illegal" }, // 12
+ { &psxcd_device::cdcmd_gettn, "gettn" }, // 13
+ { &psxcd_device::cdcmd_gettd, "gettd" }, // 14
+ { &psxcd_device::cdcmd_seekl, "seekl" }, // 15
+ { &psxcd_device::cdcmd_seekp, "seekp" }, // 16
+ { &psxcd_device::cdcmd_illegal, "illegal" }, // 17
+ { &psxcd_device::cdcmd_illegal, "illegal" }, // 18
+ { &psxcd_device::cdcmd_test, "test" }, // 19
+ { &psxcd_device::cdcmd_id, "id" }, // 1a
+ { &psxcd_device::cdcmd_reads, "reads" }, // 1b
+ { &psxcd_device::cdcmd_reset, "reset" }, // 1c
+ { &psxcd_device::cdcmd_illegal, "illegal" }, // 1d
+ { &psxcd_device::cdcmd_readtoc, "readtoc" }, // 1e
+};
+
+//
+//
+//
+
+void psxcd_device::write_command(const unsigned char byte)
+{
+ assert(byte<num_commands);
+ (this->*cmd_table[byte].func)();
+}
+
+//
+//
+//
+
+void psxcd_device::cdcmd_sync()
+{
+ #ifdef debug_cdrom
+ printf("cdrom: sync\n");
+ #endif
+
+ stop_read();
+ send_result(intr_acknowledge);
+}
+
+static int open_nops=0;
+
+void psxcd_device::cdcmd_nop()
+{
+ #ifdef debug_cdrom
+ printf("cdrom: nop\n");
+ #endif
+
+ //stop_read();
+
+ if ((! open) && (driver))
+ {
+ if (open_nops==0)
+ {
+ open=driver->read_toc();
+ } else
+ {
+ open_nops--;
+ }
+ }
+
+ send_result(intr_complete);
+}
+
+void psxcd_device::cdcmd_setloc()
+{
+ #ifdef debug_cdrom
+ printf("cdrom: setloc %08x:%08x:%08x\n",
+ cmdbuf[0],
+ cmdbuf[1],
+ cmdbuf[2]);
+ #endif
+
+ stop_read();
+
+ unsigned char l[3];
+ l[0]=bcd_to_decimal(cmdbuf[0]);
+ l[1]=bcd_to_decimal(cmdbuf[1]);
+ l[2]=bcd_to_decimal(cmdbuf[2]);
+
+ if ((l[0]>0) || (l[1]>=2))
+ {
+ loc[0]=l[0];
+ loc[1]=l[1];
+ loc[2]=l[2];
+ } else
+ {
+ printf("setloc out of range: %02d:%02d:%02d\n",
+ l[0],l[1],l[2]);
+ }
+
+ send_result(intr_complete);
+}
+
+void psxcd_device::cdcmd_play()
+{
+ #ifdef debug_cdrom
+ printf("cdrom: play %02x %02x %02x => %d\n", loc[0], loc[1], loc[2], msf_to_sector(loc));
+ #endif
+
+ curpos[0]=loc[0];
+ curpos[1]=loc[1];
+ curpos[2]=loc[2];
+
+ if ((curpos[0]==0) &&
+ (curpos[1]==0) &&
+ (curpos[2]==0))
+ {
+ send_result(intr_acknowledge);
+ } else
+ {
+ stop_read();
+ start_play();
+ send_result(intr_acknowledge);
+ }
+}
+
+void psxcd_device::cdcmd_forward()
+{
+ #ifdef debug_cdrom
+ printf("cdrom: forward\n");
+ #endif
+}
+
+void psxcd_device::cdcmd_backward()
+{
+ #ifdef debug_cdrom
+ printf("cdrom: backward\n");
+ #endif
+}
+
+void psxcd_device::cdcmd_readn()
+{
+ if (driver)
+ {
+ #ifdef debug_cdrom
+ printf("cdrom: readn\n");
+ #endif
+
+ curpos[0]=loc[0];
+ curpos[1]=loc[1];
+ curpos[2]=loc[2];
+
+ stop_read();
+ start_read();
+ send_result(intr_complete);
+ } else
+ {
+ printf("read without driver\n");
+ send_result(intr_diskerror);
+ }
+}
+
+void psxcd_device::cdcmd_standby()
+{
+ #ifdef debug_cdrom
+ printf("cdrom: standby\n");
+ #endif
+
+ stop_read();
+ send_result(intr_acknowledge);
+}
+
+void psxcd_device::cdcmd_stop()
+{
+ #ifdef debug_cdrom
+ printf("cdrom: stop\n");
+ #endif
+
+ stop_read();
+ send_result(intr_acknowledge);
+}
+
+void psxcd_device::cdcmd_pause()
+{
+ #ifdef debug_cdrom
+ printf("cdrom: pause\n");
+ #endif
+
+ stop_read();
+
+ send_result(intr_acknowledge);
+}
+
+void psxcd_device::cdcmd_init()
+{
+ #ifdef debug_cdrom
+ printf("cdrom: init\n");
+ #endif
+
+ stop_read();
+ mode=0;
+ sr|=0x10;
+
+ send_result(intr_acknowledge);
+}
+
+void psxcd_device::cdcmd_mute()
+{
+ #ifdef debug_cdrom
+ printf("cdrom: mute\n");
+ #endif
+
+ send_result(intr_acknowledge);
+}
+
+void psxcd_device::cdcmd_demute()
+{
+ #ifdef debug_cdrom
+ printf("cdrom: demute\n");
+ #endif
+
+ send_result(intr_acknowledge);
+}
+
+void psxcd_device::cdcmd_setfilter()
+{
+ #ifdef debug_cdrom
+ printf("cdrom: setfilter %08x,%08x\n",cmdbuf[0],cmdbuf[1]);
+ #endif
+
+ filter_file=cmdbuf[0];
+ filter_channel=cmdbuf[1];
+
+ send_result(intr_acknowledge);
+}
+
+void psxcd_device::cdcmd_setmode()
+{
+ #ifdef debug_cdrom
+ printf("cdrom: setmode %08x\n",cmdbuf[0]);
+ #endif
+
+ mode=cmdbuf[0];
+
+ switch ((mode&mode_size_mask)>>mode_size_shift)
+ {
+ case 1:
+ secsize=2328;
+ secskip=24;
+ break;
+
+ case 2:
+ secsize=2340;
+ secskip=12;
+ break;
+
+ default:
+ secsize=2048;
+ secskip=24;
+ break;
+ }
+
+ send_result(intr_complete);
+}
+
+void psxcd_device::cdcmd_getparam()
+{
+ unsigned char data[6]=
+ {
+ status,
+ mode,
+ filter_file,
+ filter_channel,
+ 0,
+ 0
+ };
+
+ #ifdef debug_cdrom
+ printf("cdrom: getparam [%02x %02x %02x %02x %02x %02x]\n",
+ data[0],
+ data[1],
+ data[2],
+ data[3],
+ data[4],
+ data[5]);
+ #endif
+
+ send_result(intr_complete,data,6);
+}
+
+#if 0
+static void add_loc(unsigned char *dst, const unsigned char *src1, const unsigned char *src2)
+{
+ int f=src1[2]+src2[2],
+ s=src1[1]+src2[1],
+ m=src1[0]+src2[0];
+ while (f>=75) { s++; f-=75; }
+ while (s>=60) { m++; s-=60; }
+
+ dst[0]=m;
+ dst[1]=s;
+ dst[2]=f;
+}
+#endif
+static void sub_loc(unsigned char *dst, const unsigned char *src1, const unsigned char *src2)
+{
+ int f=src1[2]-src2[2],
+ s=src1[1]-src2[1],
+ m=src1[0]-src2[0];
+ while (f<0) { s--; f+=75; }
+ while (s<0) { m--; s+=60; }
+
+ if (m<0)
+ m=s=f=0;
+
+ dst[0]=m;
+ dst[1]=s;
+ dst[2]=f;
+}
+
+void psxcd_device::cdcmd_getlocl()
+{
+ #ifdef debug_cdrom
+ printf("cdrom: getlocl\n");
+ #endif
+
+ #ifdef debug_cdrom
+ printf("cdrom: getlocl [%02x %02x %02x %02x %02x %02x %02x %02x]\n",
+ lastsechdr[0],
+ lastsechdr[1],
+ lastsechdr[2],
+ lastsechdr[3],
+ lastsechdr[4],
+ lastsechdr[5],
+ lastsechdr[6],
+ lastsechdr[7]);
+ #endif
+
+ send_result(intr_complete,lastsechdr,8);
+}
+
+void psxcd_device::cdcmd_getlocp()
+{
+ unsigned char tloc[3],
+ twosec[3]={ 0,2,0 };
+ sub_loc(tloc,loc,twosec);
+
+ unsigned char data[8]=
+ {
+ 0x01, // track
+ 0x01, // index
+ decimal_to_bcd(tloc[0]), // min
+ decimal_to_bcd(tloc[1]), // sec
+ decimal_to_bcd(tloc[2]), // frame
+ decimal_to_bcd(loc[0]), // amin
+ decimal_to_bcd(loc[1]), // asec
+ decimal_to_bcd(loc[2]) // aframe
+ };
+
+ //unsigned char data[8]={ 2,1,0,0xff,0xff,0xff,0xff,0xff };
+
+ #ifdef debug_cdrom
+ printf("cdrom: getlocp [%02x %02x %02x %02x %02x %02x %02x %02x]\n",
+ data[0],
+ data[1],
+ data[2],
+ data[3],
+ data[4],
+ data[5],
+ data[6],
+ data[7]);
+ #endif
+
+ send_result(intr_complete,data,8);
+}
+
+void psxcd_device::cdcmd_illegal()
+{
+ assert(0);
+}
+
+void psxcd_device::cdcmd_gettn()
+{
+ #ifdef debug_cdrom
+ printf("cdrom: gettn\n");
+ #endif
+
+ assert(driver);
+
+ unsigned char data[3]=
+ {
+ status,
+ decimal_to_bcd(driver->get_first_track()),
+ decimal_to_bcd(driver->get_num_tracks())
+ };
+
+ //stop_read();
+ send_result(intr_acknowledge,data,3);
+}
+
+void psxcd_device::cdcmd_gettd()
+{
+ unsigned char addr[3];
+ driver->get_track_address(bcd_to_decimal(cmdbuf[0]), addr);
+
+ unsigned char data[3]=
+ {
+ status,
+ decimal_to_bcd(addr[0]),
+ decimal_to_bcd(addr[1])
+ };
+
+ #ifdef debug_cdrom
+ printf("cdrom: gettd %02x [%02x %02x %02x]\n",
+ cmdbuf[0],
+ data[0],
+ data[1],
+ data[2]);
+ #endif
+
+ //stop_read();
+ send_result(intr_acknowledge,data,3);
+}
+
+void psxcd_device::cdcmd_seekl()
+{
+ #ifdef debug_cdrom
+ printf("cdrom: seekl [%02d:%02d:%02d]\n",loc[0],loc[1],loc[2]);
+ #endif
+
+ curpos[0]=loc[0];
+ curpos[1]=loc[1];
+ curpos[2]=loc[2];
+
+ send_result(intr_acknowledge);
+}
+
+void psxcd_device::cdcmd_seekp()
+{
+ #ifdef debug_cdrom
+ printf("cdrom: seekp\n");
+ #endif
+
+ curpos[0]=loc[0];
+ curpos[1]=loc[1];
+ curpos[2]=loc[2];
+
+ send_result(intr_acknowledge);
+}
+
+void psxcd_device::cdcmd_test()
+{
+ #ifdef debug_cdrom
+ printf("cdrom: test %08x\n",cmdbuf[0]);
+ #endif
+
+ static unsigned char data[4]=
+ {
+ 0x95,
+ 0x07,
+ 0x06,
+ 0xff
+ };
+
+ send_result(intr_complete,data,4);
+}
+
+void psxcd_device::cdcmd_id()
+{
+ #ifdef debug_cdrom
+ printf("cdrom: id\n");
+ #endif
+
+ if (! open)
+ {
+ if (driver)
+ open=driver->read_toc();
+ }
+
+ if (open)
+ {
+ static unsigned char gamedata[8] = { 0x08, 0x00, 0x00, 0x00, 'S', 'C', 'E', 'A' };
+ static unsigned char audiodata[8] = { 0x08, 0x90, 0x00, 0x00, 'S', 'C', 'E', 'A' }; // drops into the audio CD player. 08 80 goes to the menu.
+
+ if (cdrom_get_track_type(m_cd, 0) == CD_TRACK_AUDIO)
+ {
+ send_result(intr_acknowledge,audiodata,8);
+ }
+ else
+ {
+ send_result(intr_acknowledge,gamedata,8);
+ }
+ } else
+ {
+ status=status_error|status_shellopen;
+ send_result(intr_diskerror);
+ }
+}
+
+void psxcd_device::cdcmd_reads()
+{
+ curpos[0]=loc[0];
+ curpos[1]=loc[1];
+ curpos[2]=loc[2];
+
+ #ifdef skip_reads
+ #ifdef debug_cdrom
+ log("cdrom: reads [SKIPPING - RETURN COMPLETE]\n");
+ #endif
+
+ send_result(intr_complete);
+ #else
+ #ifdef debug_cdrom
+ printf("cdrom: reads\n");
+ #endif
+
+ stop_read();
+ start_streaming();
+ #endif
+}
+
+void psxcd_device::cdcmd_reset()
+{
+ #ifdef debug_cdrom
+ printf("cdrom: reset\n");
+ #endif
+}
+
+void psxcd_device::cdcmd_readtoc()
+{
+ #ifdef debug_cdrom
+ printf("cdrom: readtoc\n");
+ #endif
+
+ static unsigned char data[4]=
+ {
+ 0x00,
+ 0x00,
+ 0xff,
+ 0xfe
+ };
+
+ send_result(intr_complete|0x10,data,2);
+}
+
+//
+//
+//
+
+void psxcd_device::cmd_complete(command_result *res)
+{
+ bool doint=((res->res&0x10)==0);
+ #ifdef debug_cdrom
+ command_result *rf;
+ #endif
+
+ if (doint)
+ {
+ psx_irq_set(machine(), 0x0004);
+ }
+
+ add_result(res);
+
+ #ifdef debug_cdrom
+ if (doint)
+ {
+ printf("cdrom: irq [");
+ for (rf=res_queue; ((rf) && (rf->next)); rf=rf->next);
+ printf("%d ",rf->res);
+ printf("]\n");
+ }
+ #endif
+}
+
+//
+//
+//
+
+void psxcd_device::add_result(command_result *res)
+{
+ command_result *rf;
+
+ if (res_queue)
+ {
+ for (rf=res_queue; rf->next; rf=rf->next);
+ rf->next=res;
+ } else
+ {
+ res_queue=res;
+ }
+
+ res->next=NULL;
+}
+
+//
+//
+//
+
+event *psxcd_device::send_result(const unsigned int res,
+ const unsigned char *data,
+ const unsigned int sz,
+ const unsigned int delay)
+{
+ // Update shell open status
+
+ if (! open)
+ {
+ status=status_error|status_shellopen;
+ }
+ else
+ {
+ if (status&status_shellopen)
+ status=status_standby;
+ }
+
+ // Prepare event
+
+ event *ev=new event;
+ ev->t=delay;
+ ev->type=event_cmd_complete;
+
+ command_result *cr=(command_result *)ev->data;
+
+ cr->res=res;
+ if (sz)
+ {
+ assert(sz<sizeof(cr->data));
+ memcpy(cr->data,data,sz);
+ cr->sz=sz;
+ } else
+ {
+ cr->data[0]=status;
+ cr->sz=1;
+ }
+
+ // Avoid returning results after sector read results -
+ // delay the sector read slightly if necessary
+
+ UINT64 systime = machine().device<cpu_device>("maincpu")->total_cycles();
+ if ((next_read_event) && ((systime+ev->t)>(next_sector_t)))
+ {
+ UINT32 hz = m_sysclock / (delay + 2000);
+ next_read_event->timer->adjust(attotime::from_hz(hz), 0, attotime::never);
+
+ for (int i = 0; i < MAX_PSXCD_TIMERS; i++)
+ {
+ if (m_eventfortimer[i] == next_read_event)
+ {
+ printf("Adjusting timer %d to %d hz]n", i, hz);
+ }
+ }
+ }
+
+ add_system_event(ev);
+ return ev;
+}
+
+//
+//
+//
+
+void psxcd_device::start_dma(UINT8 *mainram, UINT32 size)
+{
+ if ((int)size>secleft)
+ {
+ printf("cdrom: dma past end of sector (secleft=%d sz=%d)\n",secleft,size);
+ }
+
+// printf("cdrom: start dma %d bytes, %d remaining, secptr %p\n", size, secleft, secptr);
+ #ifdef debug_cdrom
+ if (size==12)
+ {
+ char poo[1024],*pp=poo;
+ for (unsigned int i=0; i<12; i++)
+ {
+ sprintf(pp,"%02x ",secptr[i]);
+ pp+=3;
+ }
+ printf("cdrom: data=%s\n",poo);
+ }
+ #endif
+
+ memcpy(mainram, secptr, size);
+ memset(secptr, 0xff, size);
+
+ secptr += size;
+ secleft -= size;
+
+ if (secleft<0) secleft=0;
+ if (secleft==0) sr&=~0x40;
+}
+
+//
+//
+//
+
+void psxcd_device::prefetch_next_sector()
+{
+ unsigned int pos=msf_to_sector(curpos);
+ assert(driver);
+ driver->prefetch_sector(pos);
+}
+
+//
+//
+//
+
+bool psxcd_device::read_next_sector(const bool block)
+{
+ unsigned int pos=msf_to_sector(curpos);
+ unsigned char *buf=&secbuf[sechead*raw_sector_size];
+ assert(driver);
+ assert(secin<sector_buffer_size);
+
+// printf("read_next_sector: sec %d, sechead %d, raw_sector_size %d\n", pos, sechead, raw_sector_size);
+ if (driver->read_sector(pos, buf, block))
+ {
+// printf("buf contents = %02x %02x | %02x %02x\n", buf[0], buf[1], buf[0x20], buf[0x21]);
+
+ sechead=(sechead+1)&(sector_buffer_size-1);
+ secin++;
+
+ memcpy(lastsechdr,&secbuf[raw_sector_size*sectail]+12,8);
+
+ return true;
+ } else
+ {
+ return false;
+ }
+}
+
+//
+//
+//
+
+void psxcd_device::read_sector()
+{
+ next_read_event=NULL;
+
+ if (status & status_reading)
+ {
+ bool isend=false;
+
+ if (read_next_sector(false))
+ {
+ unsigned char *rawsec;
+
+ if ((mode&mode_adpcm) && (streaming))
+ {
+ rawsec=&secbuf[raw_sector_size*sectail];
+ secptr=rawsec+24;
+ secleft=2048;
+ }
+ else
+ {
+ rawsec=&secbuf[raw_sector_size*sectail];
+ secptr=rawsec+secskip;
+ secleft=secsize;
+ }
+
+ secin--;
+ sectail=(sectail+1)&(sector_buffer_size-1);
+
+ //
+
+ bool isxa=false;
+
+ subheader *sub=(subheader *)(rawsec+16);
+
+ #ifdef dump_subheader
+ printf("cdrom: subheader file=%02x chan=%02x submode=%02x coding=%02x [%02x%02x%02x%02x]\n",
+ sub->file,
+ sub->channel,
+ sub->submode,
+ sub->coding,
+ rawsec[0xc],
+ rawsec[0xd],
+ rawsec[0xe],
+ rawsec[0xf]);
+ #endif
+
+ status&=~status_playing;
+ isxa=((mode&mode_adpcm) && (sub->submode&submode_audio));
+
+ if (((mode&mode_channel)==0) ||
+ ((sub->file==filter_file) && (sub->channel==filter_channel)))
+ {
+ if (isxa)
+ {
+ if (sub->submode&submode_eof)
+ {
+ isend=true;
+ //printf("end of file\n");
+ }
+
+ #ifndef disable_xa_prefetch
+ unsigned int cursec=msf_to_sector(curpos);
+
+ if (xa_prefetch_sector==-1)
+ {
+ xa_prefetch_sector=cursec;
+ machine().device<spu_device>("spu")->flush_xa();
+ }
+
+ unsigned char *xaptr;
+ unsigned int xasecsz;
+
+ while (1)
+ {
+ int dist=xa_prefetch_sector-cursec;
+ if (dist>max_xa_prefetch_distance) break;
+
+ xaptr=driver->get_prefetch_sector(xa_prefetch_sector,&xasecsz);
+ if (! xaptr) break;
+
+ switch (xasecsz)
+ {
+ case 2336:
+ break;
+
+ default:
+ xaptr+=16;
+ break;
+ }
+
+ subheader *xasub=(subheader *)xaptr;
+
+ if ((xasub->submode&submode_audio) &&
+ (((mode&mode_channel)==0) ||
+ ((xasub->file==sub->file) &&
+ (xasub->channel==sub->channel))))
+ {
+ if (! machine().device<spu_device>("spu")->play_xa(xa_prefetch_sector,xaptr))
+ break;
+ }
+ xa_prefetch_sector++;
+ }
+ #else
+ machine().device<spu_device>("spu")->play_xa(0,rawsec+16);
+ #endif
+
+ status|=status_playing;
+ }
+ }
+
+ if ((mode&mode_autopause)==0)
+ isend=false;
+
+ //
+
+ curpos[2]++;
+ if (curpos[2]==75)
+ {
+ curpos[2]=0;
+ curpos[1]++;
+ if (curpos[1]==60)
+ {
+ curpos[1]=0;
+ curpos[0]++;
+ }
+ }
+
+ loc[0]=curpos[0];
+ loc[1]=curpos[1];
+ loc[2]=curpos[2];
+
+ //
+
+ command_result *res=new command_result;
+ res->res=isend?intr_dataend:intr_dataready;
+ res->data[0]=status;
+ res->sz=1;
+
+ sr|=0x40;
+
+ if ((streaming) && (isxa))
+ {
+ global_free(res);
+ res=NULL;
+ }
+
+ if (res)
+ {
+ #ifdef debug_cdrom
+ printf("cdrom:: data ready\n");
+ #endif
+
+ cmd_complete(res);
+ }
+ }
+
+ if (! isend)
+ {
+ unsigned int cyc=read_sector_cycles;
+ if (mode&mode_double_speed) cyc>>=1;
+
+ next_sector_t+=cyc;
+
+ event *ev=new event;
+ ev->t=cyc;
+ ev->type=event_read_sector;
+ next_read_event=ev;
+ add_system_event(ev);
+
+ //read_next_sector();
+ } else
+ {
+ printf("autopause xa\n");
+ stop_read();
+ }
+ }
+}
+
+//
+//
+//
+
+bool psxcd_device::play_cdda_sector(const unsigned int sector,
+ unsigned char *rawsec)
+{
+ bool isdata=true;
+
+ if (rawsec[0]!=0)
+ {
+ isdata=false;
+ } else
+ {
+ for (int i=0; i<10; i++)
+ if (rawsec[i+1]!=0xff)
+ {
+ isdata=false;
+ break;
+ }
+ }
+
+ if (! isdata)
+ {
+ return machine().device<spu_device>("spu")->play_cdda(sector,rawsec);
+ } else
+ {
+ return true;
+ }
+}
+
+//
+//
+//
+
+void psxcd_device::play_sector()
+{
+ next_read_event=NULL;
+
+ if (status&status_playing)
+ {
+ #ifdef disable_cdda_prefetch
+ unsigned char *rawsec=&secbuf[raw_sector_size*sectail];
+ #endif
+ secin--;
+ sectail=(sectail+1)&(sector_buffer_size-1);
+
+ //
+
+ #ifndef disable_cdda_prefetch
+ unsigned int cursec=msf_to_sector(curpos);
+
+ if (cdda_prefetch_sector==-1)
+ {
+ cdda_prefetch_sector=cursec;
+ machine().device<spu_device>("spu")->flush_cdda();
+ }
+
+ unsigned char *cddaptr;
+// bool full=false;
+ unsigned int cddasecsz;
+
+ while (1)
+ {
+ int dist=cdda_prefetch_sector-cursec;
+ if (dist>max_cdda_prefetch_distance) break;
+
+ cddaptr=driver->get_prefetch_sector(cdda_prefetch_sector,&cddasecsz);
+ if (! cddaptr) break;
+
+ if (! play_cdda_sector(cdda_prefetch_sector,cddaptr))
+ break;
+
+ cdda_prefetch_sector++;
+ }
+ #else
+ play_cdda_sector(0,rawsec);
+ #endif
+
+ //
+
+ curpos[2]++;
+ if (curpos[2]==75)
+ {
+ curpos[2]=0;
+ curpos[1]++;
+ if (curpos[1]==60)
+ {
+ curpos[1]=0;
+ curpos[0]++;
+ }
+ }
+
+ loc[0]=curpos[0];
+ loc[1]=curpos[1];
+ loc[2]=curpos[2];
+
+ //
+
+ if (mode&mode_autopause)
+ {
+ if (msf_to_sector(loc)>=autopause_sector)
+ {
+ printf("autopause cdda\n");
+
+ command_result *res=new command_result;
+ res->res=intr_dataend;
+ res->data[0]=status_standby;
+ res->sz=1;
+ cmd_complete(res);
+ stop_read();
+ return;
+ }
+ }
+
+ if (mode&mode_report)
+ {
+ command_result *res=new command_result;
+ res->res=intr_complete; //dataready;
+
+ res->data[0]=status_playing|status_standby;
+ res->data[1]=0x01;
+ res->data[2]=0x80;
+ res->data[3]=decimal_to_bcd(loc[0]);
+ res->data[4]=decimal_to_bcd(loc[1])|0x80;
+ res->data[5]=decimal_to_bcd(loc[2]);
+
+ res->sz=8;
+
+ cmd_complete(res);
+ }
+
+ unsigned int cyc=read_sector_cycles;
+
+ event *ev=new event;
+ ev->t=next_sector_t - machine().device<cpu_device>("maincpu")->total_cycles();
+ ev->type=event_play_sector;
+
+ next_sector_t+=cyc;
+
+ next_read_event=ev;
+ add_system_event(ev);
+
+ read_next_sector();
+ }
+}
+
+
+//
+//
+//
+
+void psxcd_device::preread_sector()
+{
+ next_read_event=NULL;
+
+ //
+
+ event *ev=new event;
+
+ unsigned int pos=msf_to_sector(curpos);
+ unsigned char *buf=&secbuf[sechead*raw_sector_size];
+ if (! driver->read_sector(pos,buf,false))
+ {
+ ev->t=(m_sysclock/60);
+ ev->type=event_preread_sector;
+
+ unsigned int cyc=read_sector_cycles;
+ if (mode&mode_double_speed) cyc>>=1;
+ next_sector_t=ev->t+(cyc-preread_delay)+machine().device<cpu_device>("maincpu")->total_cycles();
+ } else
+ {
+ memcpy(lastsechdr,buf+12,8);
+
+ //
+
+ command_result *res=new command_result;
+ res->res=intr_complete;
+ res->data[0]=status;
+ res->sz=1;
+
+ #ifdef debug_cdrom
+ printf("cdrom: read acknowledge\n");
+ #endif
+
+ cmd_complete(res);
+
+ //
+
+ ev->t=next_sector_t - machine().device<cpu_device>("maincpu")->total_cycles();
+ ev->type=event_read_sector;
+
+ //read_next_sector();
+ }
+
+ next_read_event=ev;
+ add_system_event(ev);
+}
+
+//
+//
+//
+
+void psxcd_device::start_read()
+{
+ #ifdef debug_cdrom
+ printf("cdrom: start read\n");
+ #endif
+
+ assert((status&(status_reading|status_playing))==0);
+
+ status|=status_reading;
+
+ secin=sechead=sectail=0;
+ xa_prefetch_sector=-1;
+
+ unsigned int cyc=read_sector_cycles;
+ if (mode&mode_double_speed) cyc>>=1;
+
+ INT64 systime=machine().device<cpu_device>("maincpu")->total_cycles();
+
+ systime+=start_read_delay;
+
+ event *ev=new event;
+ ev->t=start_read_delay+preread_delay;
+ ev->type=event_preread_sector;
+
+ next_sector_t=systime+cyc;
+ next_read_event=ev;
+ add_system_event(ev);
+
+ prefetch_next_sector();
+}
+
+//
+//
+//
+
+void psxcd_device::start_streaming()
+{
+ assert(! streaming);
+
+ streaming=true;
+ start_read();
+}
+
+//
+//
+//
+
+void psxcd_device::start_play()
+{
+ #ifdef debug_cdrom
+ printf("cdrom: start play\n");
+ #endif
+
+ status|=status_playing;
+
+ secin=sechead=sectail=0;
+ cdda_prefetch_sector=-1;
+
+ if (mode&mode_autopause)
+ {
+ unsigned int pos=msf_to_sector(curpos);
+ driver->find_track(pos+150,NULL,&autopause_sector);
+// printf("pos=%d auto=%d\n",pos,autopause_sector);
+ }
+
+ unsigned int cyc=read_sector_cycles;
+
+ next_sector_t=machine().device<cpu_device>("maincpu")->total_cycles()+cyc;
+
+ event *ev=new event;
+ ev->t=next_sector_t - machine().device<cpu_device>("maincpu")->total_cycles();
+ ev->type=event_play_sector;
+
+ next_sector_t+=cyc;
+
+ next_read_event=ev;
+ add_system_event(ev);
+
+ read_next_sector();
+}
+
+//
+//
+//
+
+void psxcd_device::stop_read()
+{
+ #ifdef debug_cdrom
+ if (status&status_reading)
+ printf("cdrom: stop read\n");
+ #endif
+ status&=~(status_reading|status_playing);
+ streaming=false;
+
+ if (next_read_event)
+ {
+ next_read_event->timer->adjust(attotime::never, 0, attotime::never);
+ for (int i = 0; i < MAX_PSXCD_TIMERS; i++)
+ {
+ if (m_timers[i] == next_read_event->timer)
+ {
+ m_timerinuse[i] = false;
+ m_eventfortimer[i] = NULL;
+ break;
+ }
+ }
+ global_free(next_read_event);
+ next_read_event=NULL;
+ }
+
+ unsigned int sector=msf_to_sector(curpos);
+ machine().device<spu_device>("spu")->flush_xa(sector);
+ machine().device<spu_device>("spu")->flush_cdda(sector);
+}
+
+//
+//
+//
+
+void psxcd_device::set_driver(cdrom_driver *d)
+{
+ char err[1024];
+
+ if (d)
+ {
+ if (d->is_usable(err,1024))
+ {
+ driver=d;
+ open=false;
+
+ if (! first_open)
+ {
+ command_result *res=new command_result;
+ res->res=intr_acknowledge;
+ res->data[0]=status_standby;
+ res->sz=1;
+
+ cmd_complete(res);
+
+ open_nops=10;
+ }
+
+ first_open=false;
+ }
+ } else
+ {
+ driver=NULL;
+ open=false;
+
+ command_result *res=new command_result;
+ res->res=intr_acknowledge;
+ res->data[0]=status_shellopen;
+ res->sz=1;
+
+ cmd_complete(res);
+ }
+}
+
+//
+//
+//
+void psxcd_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr)
+{
+ event *ev = m_eventfortimer[tid];
+
+// printf("timer %d fired, performing event type %d\n", tid, ev->type);
+
+ switch (ev->type)
+ {
+ case event_cmd_complete:
+ {
+ #ifdef debug_cdrom
+ printf("cdrom:: event cmd complete\n");
+ #endif
+
+ command_result *res=new command_result;
+ memcpy(res,ev->data,sizeof(command_result));
+ cmd_complete(res);
+ break;
+ }
+
+ case event_preread_sector:
+ preread_sector();
+ break;
+
+ case event_read_sector:
+ read_sector();
+ break;
+
+ case event_play_sector:
+ play_sector();
+ break;
+ }
+
+ // free the timer
+// printf("Freeing timer %d\n", tid);
+ m_timers[tid]->adjust(attotime::never, 0, attotime::never);
+ m_timerinuse[tid] = false;
+ m_eventfortimer[tid] = NULL;
+
+ global_free(ev);
+}
+
+void psxcd_device::add_system_event(event *ev)
+{
+ emu_timer *timer = NULL;
+ int tnum = -1;
+
+ // allocate a timer for this event
+ for (int i = 0; i < MAX_PSXCD_TIMERS; i++)
+ {
+ if (!m_timerinuse[i])
+ {
+ tnum = i;
+ timer = m_timers[i];
+ m_timerinuse[i] = true;
+ m_eventfortimer[i] = ev;
+ break;
+ }
+ }
+
+ if (tnum == -1)
+ {
+ fatalerror("PSXCD: ran out of timers!\n");
+ }
+
+ // ev->t is in maincpu clock cycles
+ UINT32 hz = m_sysclock / ev->t;
+// printf("add_system_event: event type %d for %d hz (using timer %d)\n", ev->type, hz, tnum);
+ timer->adjust(attotime::from_hz(hz), tnum, attotime::never);
+
+ // back-reference the timer from the event
+ ev->timer = timer;
+}
+
diff --git a/src/mess/machine/psxcd.h b/src/mess/machine/psxcd.h
new file mode 100644
index 00000000000..937e7358c7f
--- /dev/null
+++ b/src/mess/machine/psxcd.h
@@ -0,0 +1,186 @@
+#ifndef _included_psxcdrom_
+#define _included_psxcdrom_
+
+#include "imagedev/chd_cd.h"
+#include "psxcddrv.h"
+
+#define MAX_PSXCD_TIMERS (4)
+
+class event;
+
+//
+//
+//
+
+const int num_commands=0x20;
+
+//
+//
+//
+
+#define PSXCD_TAG "psxcd"
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_PSXCD_ADD(_devname) \
+ MCFG_DEVICE_ADD(PSXCD_TAG, PSXCD, 0) \
+ MCFG_PSXCD_DEVNAME(_devname)
+
+#define MCFG_PSXCD_DEVNAME(_name) \
+ psxcd_device::static_set_devname(*device, _name); \
+
+struct psxcd_interface
+{
+};
+
+class psxcd_device : public device_t,
+ public psxcd_interface
+{
+public:
+
+ psxcd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ // inline configuration helpers
+ static void static_set_devname(device_t &device, const char *devname);
+private:
+ struct command_result
+ {
+ unsigned char data[32], sz, res;
+ command_result *next;
+ };
+
+ static const unsigned int sector_buffer_size=16, default_irq_delay=16000; //480; //8000; //2000<<2;
+
+ unsigned char sr,res,ir,cmdmode,
+ cmdbuf[64],*cbp,
+ mode,
+ loc[3],
+ curpos[3],
+ secbuf[raw_sector_size*sector_buffer_size],
+ *secptr,
+ filter_file,
+ filter_channel,
+ lastsechdr[8],
+ status;
+ int rdp,secsize,secleft,secskip,
+ sechead,sectail,
+ secin;
+ command_result *res_queue,
+ *cur_res;
+ bool open,
+ streaming,
+ first_open;
+ event *next_read_event;
+ INT64 next_sector_t;
+ unsigned int autopause_sector,
+ xa_prefetch_sector,
+ cdda_prefetch_sector;
+
+ cdrom_driver *driver;
+
+ unsigned int start_read_delay,
+ read_sector_cycles,
+ preread_delay;
+
+ void write_command(const unsigned char byte);
+
+ struct command_info
+ {
+ void (psxcd_device::*func)();
+ const char *name;
+ };
+
+ void cdcmd_sync();
+ void cdcmd_nop();
+ void cdcmd_setloc();
+ void cdcmd_play();
+ void cdcmd_forward();
+ void cdcmd_backward();
+ void cdcmd_readn();
+ void cdcmd_standby();
+ void cdcmd_stop();
+ void cdcmd_pause();
+ void cdcmd_init();
+ void cdcmd_mute();
+ void cdcmd_demute();
+ void cdcmd_setfilter();
+ void cdcmd_setmode();
+ void cdcmd_getparam();
+ void cdcmd_getlocl();
+ void cdcmd_getlocp();
+ void cdcmd_illegal();
+ void cdcmd_gettn();
+ void cdcmd_gettd();
+ void cdcmd_seekl();
+ void cdcmd_seekp();
+ void cdcmd_test();
+ void cdcmd_id();
+ void cdcmd_reads();
+ void cdcmd_reset();
+ void cdcmd_readtoc();
+
+ static command_info cmd_table[num_commands];
+
+ void cmd_complete(command_result *res);
+ void add_result(command_result *res);
+ event *send_result(const unsigned int res,
+ const unsigned char *data=NULL,
+ const unsigned int sz=0,
+ const unsigned int delay=default_irq_delay);
+
+ void start_read();
+ void start_play();
+ void start_streaming();
+ void stop_read();
+ void read_sector();
+ void prefetch_next_sector();
+ bool read_next_sector(const bool block=true);
+ bool play_cdda_sector(const unsigned int sector, unsigned char *rawsec);
+ void play_sector();
+ void preread_sector();
+
+public:
+ void set_driver(cdrom_driver *d);
+ cdrom_driver *get_driver() const { return driver; }
+
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+ void start_dma(UINT8 *mainram, UINT32 size);
+
+ unsigned char read_byte(const unsigned int addr);
+ void write_byte(const unsigned int addr, const unsigned char byte);
+
+private:
+ emu_timer *m_timer;
+ UINT32 m_sysclock;
+ const char *m_devname;
+ cdrom_image_device *m_cddevice;
+ cdrom_file *m_cd;
+ emu_timer *m_timers[MAX_PSXCD_TIMERS];
+ event *m_eventfortimer[MAX_PSXCD_TIMERS];
+ bool m_timerinuse[MAX_PSXCD_TIMERS];
+
+ void add_system_event(event *ev);
+};
+
+
+// miniature version of pSX's event class, which we emulate with device timers
+const int max_event_data=64;
+
+class event
+{
+public:
+ UINT64 t; // expire time
+ unsigned int type;
+ unsigned char data[max_event_data];
+ emu_timer *timer;
+};
+
+
+// device type definition
+extern const device_type PSXCD;
+
+#endif
diff --git a/src/mess/machine/psxcddrv.c b/src/mess/machine/psxcddrv.c
new file mode 100644
index 00000000000..bd39dbe345b
--- /dev/null
+++ b/src/mess/machine/psxcddrv.c
@@ -0,0 +1,533 @@
+#include "emu.h"
+#include "includes/psx.h"
+#include "psxcd.h"
+#include "psxcddrv.h"
+
+//#define debug_mess_driver
+
+//
+//
+//
+
+static const unsigned int num_pf_sectors=32, num_pf_buffers=16;
+
+//
+//
+//
+
+cdrom_driver::cdrom_driver()
+{
+ pf_head = 0;
+ pf_tail = 0;
+ num_pf = 0;
+ pf_head_sector = 0;
+ pf_status = NULL;
+ native_sector_size = raw_sector_size;
+ last_pf_status = NULL;
+ m_cd = NULL;
+ m_machine = NULL;
+
+// printf("cdrom_driver base class init, pf_buffer size is %d\n", num_pf_sectors*num_pf_buffers*raw_sector_size);
+
+ pf_buffer=new unsigned char [num_pf_sectors*num_pf_buffers*raw_sector_size];
+
+ timestamp_frequency = 1;
+}
+
+cdrom_driver::~cdrom_driver()
+{
+ global_free(pf_buffer);
+}
+
+//
+//
+//
+
+void cdrom_driver::set_native_sector_size(const unsigned int sz)
+{
+ native_sector_size=sz;
+}
+
+//
+//
+//
+
+void cdrom_driver::cancel_io()
+{
+ if (pf_status)
+ {
+ pf_status->cancel();
+ pf_status->release();
+ }
+
+ pf_status=NULL;
+}
+
+//
+//
+//
+
+void cdrom_driver::prefetch_sector(const unsigned int sec)
+{
+ int numpfsec=num_pf*num_pf_sectors,
+ pfsec=sec-pf_head_sector;
+
+// printf("prefetch_sector: %d\n", sec);
+
+ if ((pfsec<0) || (pfsec>numpfsec))
+ {
+ // Sector is not in prefetch buffer, abort current prefetch
+
+ if (pf_status)
+ {
+ pf_status->cancel();
+ pf_status->release();
+ }
+
+ // Reset the buffer and begin a new prefetch
+
+ pf_head=0;
+ pf_tail=0;
+ num_pf=1;
+ pf_head_sector=sec;
+
+ last_pf_status=NULL;
+ pf_status=read_sectors(sec, num_pf_sectors, pf_buffer);
+ }
+}
+
+//
+//
+//
+
+bool cdrom_driver::is_prefetch_sector_loaded(const unsigned int sec)
+{
+ int numpfsec=num_pf*num_pf_sectors,
+ pfsec=sec-pf_head_sector;
+
+ if ((pfsec<0) || (pfsec>=numpfsec))
+ {
+ // Requested sector is not in prefetch buffer, begin a new prefetch
+
+ prefetch_sector(sec);
+ pfsec=sec-pf_head_sector;
+ numpfsec=num_pf*num_pf_sectors;
+ }
+
+ int blk=pfsec/num_pf_sectors;
+
+ if (blk>0)
+ {
+ // Discard blocks below the prefetch point
+
+ pf_head=(pf_head+blk)%num_pf_buffers;
+ pf_head_sector+=num_pf_sectors*blk;
+ pfsec-=num_pf_sectors*blk;
+ num_pf-=blk;
+ blk=0;
+ }
+
+ bool comp=((! pf_status) || (pf_status->complete()));
+
+ if (! comp)
+ {
+ INT64 curtime=m_machine->device<cpu_device>("maincpu")->total_cycles();
+
+ if (last_pf_status!=pf_status)
+ {
+ last_pf_status=pf_status;
+ pf_timeout_begin=curtime;
+ }
+
+ INT64 timeout=curtime-pf_timeout_begin;
+ int timeout_sec=(int)(timeout/timestamp_frequency);
+ if (timeout_sec>20)
+ {
+ printf("cdrom: prefetch timed out, trying again...\n");
+ num_pf=0;
+ pf_head_sector=-1;
+ prefetch_sector(sec);
+ return is_prefetch_sector_loaded(sec);
+ }
+ }
+
+ if ((num_pf<num_pf_buffers) && (comp))
+ {
+ // The prefetch buffer is not full and we are not waiting on IO,
+ // prefetch the next block
+
+ pf_tail=(pf_tail+1)%num_pf_buffers;
+ num_pf++;
+
+ int nxtsec=pf_head_sector+((num_pf-1)*num_pf_sectors);
+ unsigned char *ptr=pf_buffer+((pf_tail*num_pf_sectors)*native_sector_size);
+
+ if (pf_status)
+ {
+ pf_status->release();
+ pf_status=last_pf_status=NULL;
+ }
+
+ pf_status=read_sectors(nxtsec, num_pf_sectors, ptr);
+ }
+
+ if (blk==(num_pf-1))
+ {
+ // The sector we want is in the last block in the prefetch buffer
+ // which might still be loading, check if the sector we want is loaded
+#if 0 // we do not load async in MESS
+ INT64 trans=pf_status->bytes_transferred();
+ unsigned int secmod=pfsec%num_pf_sectors,
+ needbytes=(secmod+1)*native_sector_size;
+
+ if (trans<needbytes)
+ {
+ // The sector is not loaded yet
+
+ return false;
+ } else
+#endif
+ {
+ // The sector is loaded
+
+ return true;
+ }
+ } else
+ {
+ // The sector is not in the last block so it must be loaded
+
+ return true;
+ }
+}
+
+//
+//
+//
+
+unsigned char *cdrom_driver::get_prefetch_sector(const unsigned int sec, unsigned int *sz)
+{
+ int numpfsec=num_pf*num_pf_sectors,
+ pfsec=sec-pf_head_sector;
+ if ((pfsec>=0) && (pfsec<numpfsec))
+ {
+ int blk=(pf_head+(pfsec/num_pf_sectors))%num_pf_buffers,
+ off=((blk*num_pf_sectors)+(pfsec%num_pf_sectors))*native_sector_size;
+ *sz=native_sector_size;
+ return pf_buffer+off;
+ } else
+ {
+ return NULL;
+ }
+}
+
+//
+//
+//
+
+bool cdrom_driver::read_sector(const unsigned int sec, unsigned char *buf, const bool block)
+{
+ bool loaded=is_prefetch_sector_loaded(sec);
+
+// printf("read_sector: %d (loaded=%c)\n", sec, loaded ? 'Y' : 'N');
+
+ if ((! loaded) && (block))
+ {
+ pf_status->block_until_complete();
+ loaded=true;
+ }
+
+ if (loaded)
+ {
+ unsigned int secsz=0;
+ unsigned char *ptr=get_prefetch_sector(sec,&secsz);
+ assert(ptr);
+
+// printf("got sector %d @ %p, size %d = %02x %02x | %02x %02x\n", sec, ptr, secsz, ptr[0], ptr[1], ptr[0x20], ptr[0x21]);
+
+ if (secsz<2352)
+ {
+ // Add sector header
+
+ buf[0]=0;
+ memset(buf+1,0xff,10);
+ buf[11]=0;
+ sector_to_msf(sec,buf+12);
+ buf[12]=decimal_to_bcd(buf[12]);
+ buf[13]=decimal_to_bcd(buf[13]);
+ buf[14]=decimal_to_bcd(buf[14]);
+ buf[15]=2;
+
+ if (secsz<2336)
+ {
+ memset(buf+16,0xff,8);
+ }
+ }
+
+ switch (secsz)
+ {
+ case 2048:
+ memcpy(buf+24,ptr,2048);
+ break;
+
+ case 2336:
+ memcpy(buf+16,ptr,2336);
+ break;
+
+ case 2352:
+ memcpy(buf,ptr,raw_sector_size);
+ break;
+ }
+
+ return true;
+ } else
+ {
+ return false;
+ }
+}
+
+void cdrom_driver::set_machine(const running_machine &machine)
+{
+ m_machine = (running_machine *)&machine;
+
+ timestamp_frequency = m_machine->device<cpu_device>("maincpu")->clock();
+
+// printf("cdrom_driver::set_machine: timestamp frequency = %d\n", timestamp_frequency);
+}
+
+/*
+ MAME/MESS driver implementation
+*/
+
+class mess_cdrom_driver : public cdrom_driver
+{
+ enum track_type
+ {
+ track_illegal=-1,
+ track_mode1_2048=0,
+ track_mode2_2352,
+ track_mode2_2336,
+ track_audio
+ };
+
+ struct toc_entry
+ {
+ unsigned int type;
+ unsigned char address[3];
+ };
+
+ int num_sectors, num_tracks;
+ toc_entry toc[100];
+ int bin_sector_size;
+ const char *err;
+
+ io_status *read_sectors(const unsigned int startsec, const unsigned int numsec, unsigned char *buf);
+
+public:
+ mess_cdrom_driver();
+ ~mess_cdrom_driver();
+
+ bool is_usable(char *error_msg, const int msglen) const
+ {
+ return true;
+ }
+
+ bool read_toc();
+ unsigned int get_first_track() const;
+ unsigned int get_num_tracks() const;
+ bool get_track_address(const unsigned int track,unsigned char *address) const;
+ tracktype get_track_type(const unsigned int track) const;
+ unsigned int find_track(const unsigned int sector, unsigned int *start_sector, unsigned int *end_sector) const;
+ cdromtype get_type() const;
+};
+
+mess_cdrom_driver::mess_cdrom_driver()
+ : err(NULL)
+{
+ for (int i=0; i<100; i++)
+ toc[i].type=track_illegal;
+ num_tracks=0;
+ num_sectors=0;
+}
+
+//
+//
+//
+
+mess_cdrom_driver::~mess_cdrom_driver()
+{
+ cancel_io();
+}
+
+//
+//
+//
+
+bool mess_cdrom_driver::read_toc()
+{
+ if (m_cd)
+ {
+ const cdrom_toc *toc = cdrom_get_toc(m_cd);
+
+ num_tracks = cdrom_get_last_track(m_cd);
+
+ switch (toc->tracks[0].trktype)
+ {
+ case CD_TRACK_MODE1: bin_sector_size=2048; break;
+ case CD_TRACK_MODE2_FORM1: bin_sector_size=2048; break;
+ case CD_TRACK_MODE2: bin_sector_size=2336; break;
+ case CD_TRACK_MODE2_FORM_MIX: bin_sector_size=2336; break;
+ default: bin_sector_size=2352; break;
+ }
+
+ set_native_sector_size(bin_sector_size);
+ num_sectors = cdrom_get_track_start(m_cd, num_tracks) + toc->tracks[num_tracks].frames;
+
+// printf("mess_cdrom_driver: %d sectors, native size %d\n",num_sectors, bin_sector_size);
+
+ return true;
+ }
+
+ return false;
+}
+
+//
+//
+//
+
+io_status *mess_cdrom_driver::read_sectors(const unsigned int startsec, const unsigned int numsec, unsigned char *buf)
+{
+ const cdrom_toc *toc = cdrom_get_toc(m_cd);
+ UINT32 track = cdrom_get_track(m_cd, startsec);
+ UINT32 secsize = toc->tracks[track].datasize;
+
+ #ifdef debug_mess_driver
+ printf("mess: read %d sectors from %d (secsize %d)\n",numsec,startsec,secsize);
+ #endif
+
+ if (1) // && ((int)startsec<num_sectors))
+ {
+// fin->seek((INT64)startsec*(INT64)bin_sector_size);
+
+// io_status *ios=fin->async_read(buf,numsec*bin_sector_size);
+// if (! ios)
+ for (int i = 0; i < numsec; i++)
+ {
+// printf("[%d/%d] Reading to pf_buffer %p at offset %d, size %d\n", i, numsec, &buf[secsize*i], secsize*i, secsize);
+ cdrom_read_data(m_cd, startsec+i, &buf[secsize*i], CD_TRACK_RAW_DONTCARE);
+ }
+
+ return NULL;
+
+// return ios;
+ }
+ else
+ {
+ printf("mess: read sector out of range (%d, max=%d)\n",
+ startsec,
+ num_sectors);
+
+ memset(buf,0xff,numsec*bin_sector_size);
+ return NULL;
+ }
+}
+
+//
+//
+//
+
+unsigned int mess_cdrom_driver::get_first_track() const
+{
+ return 1;
+}
+
+unsigned int mess_cdrom_driver::get_num_tracks() const
+{
+// printf("get_num_tracks = %d\n", num_tracks);
+ return num_tracks;
+}
+
+bool mess_cdrom_driver::get_track_address(const unsigned int track, unsigned char *address) const
+{
+ if ((track>=1) && ((int)track<=num_tracks))
+ {
+ UINT32 trkstart = cdrom_get_track_start(m_cd, track);
+
+ sector_to_msf(trkstart, address);
+
+ address[0] = address[0];
+ address[1] = address[1];
+ address[2] = address[2];
+
+// printf("get_track_address %d = %02x:%02x:%02x\n", track, address[0], address[1], address[2]);
+
+ return true;
+ }
+ else
+ {
+ address[0]=address[1]=address[2]=0;
+ return false;
+ }
+}
+
+unsigned int mess_cdrom_driver::find_track(const unsigned int sector, unsigned int *start_sector, unsigned int *end_sector) const
+{
+ const cdrom_toc *toc = cdrom_get_toc(m_cd);
+ UINT32 track = cdrom_get_track(m_cd, sector);
+ int start;
+
+ start = cdrom_get_track_start(m_cd, track);
+
+ if (start_sector != NULL)
+ {
+ *start_sector = start;
+ }
+
+ if (end_sector != NULL)
+ {
+ *end_sector = start + toc->tracks[track].frames;
+ }
+
+ printf("find_track: track %d start %d end %d\n", track, start, start + toc->tracks[track].frames);
+
+ return -1;
+}
+
+//
+//
+//
+
+cdromtype mess_cdrom_driver::get_type() const
+{
+// printf("get_type\n");
+ return cdromtype_cd;
+}
+
+//
+//
+//
+
+tracktype mess_cdrom_driver::get_track_type(const unsigned int track) const
+{
+ const cdrom_toc *toc = cdrom_get_toc(m_cd);
+
+// printf("get_track_type %d = %d\n", track, toc->tracks[track].trktype);
+
+ switch (toc->tracks[track].trktype)
+ {
+ case CD_TRACK_MODE1: return tracktype_mode1;
+ case CD_TRACK_MODE2_RAW: return tracktype_mode2;
+ case CD_TRACK_MODE2_FORM_MIX: return tracktype_mode2;
+ case CD_TRACK_AUDIO: return tracktype_audio;
+ default: return tracktype_unknown;
+ }
+}
+
+//
+//
+//
+
+cdrom_driver *open_mess_drv()
+{
+ return new mess_cdrom_driver();
+}
+
diff --git a/src/mess/machine/psxcddrv.h b/src/mess/machine/psxcddrv.h
new file mode 100644
index 00000000000..e4904198c63
--- /dev/null
+++ b/src/mess/machine/psxcddrv.h
@@ -0,0 +1,133 @@
+#ifndef _included_psxcddriver_
+#define _included_psxcddriver_
+
+const unsigned int raw_sector_size=2352;
+
+class io_status
+{
+protected:
+ virtual ~io_status() {}
+
+public:
+ io_status() { }
+
+ virtual void cancel()=0;
+ virtual void release()=0;
+ virtual bool complete() const=0;
+ virtual bool block_until_complete() const=0;
+ virtual INT64 bytes_transferred() const=0;
+};
+
+enum cdromtype
+{
+ cdromtype_cd=0,
+ cdromtype_dvd
+};
+
+enum tracktype
+{
+ tracktype_unknown=0,
+ tracktype_mode1,
+ tracktype_mode2,
+ tracktype_audio
+};
+
+class cdrom_driver
+{
+ int pf_head,
+ pf_tail,
+ num_pf,
+ pf_head_sector;
+ unsigned char *pf_buffer;
+ io_status *pf_status,
+ *last_pf_status;
+ INT64 pf_timeout_begin;
+
+ int native_sector_size;
+
+ virtual io_status *read_sectors(const unsigned int sec, const unsigned int numsec, unsigned char *buf)=0;
+
+ bool is_prefetch_sector_loaded(const unsigned int pfsec);
+
+protected:
+ void cancel_io();
+ void set_native_sector_size(const unsigned int sz);
+ UINT32 timestamp_frequency;
+ cdrom_file *m_cd;
+private:
+ running_machine *m_machine;
+
+public:
+ cdrom_driver();
+ virtual ~cdrom_driver();
+
+ void set_machine(const running_machine &machine);
+ void set_cdrom_file(cdrom_file *cdfile) { m_cd = cdfile; }
+
+ virtual bool is_usable(char *error_msg=NULL, const int msglen=0) const=0;
+ virtual bool read_toc()=0;
+
+ void prefetch_sector(const unsigned int sec);
+ bool read_sector(const unsigned int sec,
+ unsigned char *buf,
+ const bool block=true);
+ unsigned char *get_prefetch_sector(const unsigned int pfsec,
+ unsigned int *sz);
+
+ virtual unsigned int get_first_track() const=0;
+ virtual unsigned int get_num_tracks() const=0;
+ virtual bool get_track_address(const unsigned int track,
+ unsigned char *address) const=0;
+ virtual tracktype get_track_type(const unsigned int track) const=0;
+ virtual unsigned int find_track(const unsigned int sector,
+ unsigned int *start_sector=NULL,
+ unsigned int *end_sector=NULL) const=0;
+
+ virtual cdromtype get_type() const { return cdromtype_cd; }
+};
+
+//
+//
+//
+
+inline unsigned int msf_to_sector(const unsigned char *msf)
+{
+ unsigned int sec=msf[2]+(msf[1]*75)+(msf[0]*(60*75));
+ if (sec>=150)
+ {
+ return sec-150;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+inline void sector_to_msf(const unsigned int sec, unsigned char *msf)
+{
+ unsigned int s=sec+150;
+ msf[0]=s/(60*75);
+ s-=msf[0]*(60*75);
+ msf[1]=s/75;
+ s-=msf[1]*75;
+ msf[2]=s;
+}
+
+//
+//
+//
+
+inline unsigned char bcd_to_decimal(const unsigned char bcd)
+{
+ return ((bcd>>4)*10)+(bcd&0xf);
+}
+
+inline unsigned char decimal_to_bcd(const unsigned char dec)
+{
+ //assert(dec<100);
+ return ((dec/10)<<4)|(dec%10);
+}
+
+cdrom_driver *open_mess_drv();
+
+#endif
diff --git a/src/mess/machine/radio86.c b/src/mess/machine/radio86.c
new file mode 100644
index 00000000000..920a88a00a8
--- /dev/null
+++ b/src/mess/machine/radio86.c
@@ -0,0 +1,282 @@
+/***************************************************************************
+
+ Radio-86RK machine driver by Miodrag Milanovic
+
+ 06/03/2008 Preliminary driver.
+
+****************************************************************************/
+
+
+#include "emu.h"
+#include "cpu/i8085/i8085.h"
+#include "imagedev/cassette.h"
+#include "machine/i8255.h"
+#include "machine/8257dma.h"
+#include "video/i8275.h"
+#include "includes/radio86.h"
+
+
+
+void radio86_init_keyboard(running_machine &machine)
+{
+ radio86_state *state = machine.driver_data<radio86_state>();
+ state->m_keyboard_mask = 0;
+ state->m_tape_value = 0x10;
+}
+
+/* Driver initialization */
+DRIVER_INIT_MEMBER(radio86_state,radio86)
+{
+ /* set initialy ROM to be visible on first bank */
+ UINT8 *RAM = memregion("maincpu")->base();
+ memset(RAM,0x0000,0x1000); // make frist page empty by default
+ membank("bank1")->configure_entries(1, 2, RAM, 0x0000);
+ membank("bank1")->configure_entries(0, 2, RAM, 0xf800);
+ radio86_init_keyboard(machine());
+}
+
+DRIVER_INIT_MEMBER(radio86_state,radioram)
+{
+ DRIVER_INIT_CALL(radio86);
+ m_radio_ram_disk = auto_alloc_array(machine(), UINT8, 0x20000);
+ memset(m_radio_ram_disk,0,0x20000);
+}
+static READ8_DEVICE_HANDLER (radio86_8255_portb_r2 )
+{
+ radio86_state *state = device->machine().driver_data<radio86_state>();
+ UINT8 key = 0xff;
+ if ((state->m_keyboard_mask & 0x01)!=0) { key &= state->ioport("LINE0")->read(); }
+ if ((state->m_keyboard_mask & 0x02)!=0) { key &= device->machine().root_device().ioport("LINE1")->read(); }
+ if ((state->m_keyboard_mask & 0x04)!=0) { key &= device->machine().root_device().ioport("LINE2")->read(); }
+ if ((state->m_keyboard_mask & 0x08)!=0) { key &= device->machine().root_device().ioport("LINE3")->read(); }
+ if ((state->m_keyboard_mask & 0x10)!=0) { key &= device->machine().root_device().ioport("LINE4")->read(); }
+ if ((state->m_keyboard_mask & 0x20)!=0) { key &= device->machine().root_device().ioport("LINE5")->read(); }
+ if ((state->m_keyboard_mask & 0x40)!=0) { key &= device->machine().root_device().ioport("LINE6")->read(); }
+ if ((state->m_keyboard_mask & 0x80)!=0) { key &= device->machine().root_device().ioport("LINE7")->read(); }
+ return key;
+}
+
+static READ8_DEVICE_HANDLER (radio86_8255_portc_r2 )
+{
+ radio86_state *state = device->machine().driver_data<radio86_state>();
+ double level = (device->machine().device<cassette_image_device>(CASSETTE_TAG)->input());
+ UINT8 dat = state->ioport("LINE8")->read();
+ if (level < 0) {
+ dat ^= state->m_tape_value;
+ }
+ return dat;
+}
+
+static WRITE8_DEVICE_HANDLER (radio86_8255_porta_w2 )
+{
+ radio86_state *state = device->machine().driver_data<radio86_state>();
+ state->m_keyboard_mask = data ^ 0xff;
+}
+
+static WRITE8_DEVICE_HANDLER (radio86_8255_portc_w2 )
+{
+ device->machine().device<cassette_image_device>(CASSETTE_TAG)->output(data & 0x01 ? 1 : -1);
+}
+
+
+I8255A_INTERFACE( radio86_ppi8255_interface_1 )
+{
+ DEVCB_NULL,
+ DEVCB_HANDLER(radio86_8255_porta_w2),
+ DEVCB_HANDLER(radio86_8255_portb_r2),
+ DEVCB_NULL,
+ DEVCB_HANDLER(radio86_8255_portc_r2),
+ DEVCB_HANDLER(radio86_8255_portc_w2),
+};
+
+I8255A_INTERFACE( mikrosha_ppi8255_interface_1 )
+{
+ DEVCB_HANDLER(radio86_8255_portb_r2),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(radio86_8255_porta_w2),
+ DEVCB_HANDLER(radio86_8255_portc_r2),
+ DEVCB_HANDLER(radio86_8255_portc_w2),
+};
+
+
+
+static READ8_DEVICE_HANDLER (rk7007_8255_portc_r )
+{
+ radio86_state *state = device->machine().driver_data<radio86_state>();
+ double level = (device->machine().device<cassette_image_device>(CASSETTE_TAG)->input());
+ UINT8 key = 0xff;
+ if ((state->m_keyboard_mask & 0x01)!=0) { key &= state->ioport("CLINE0")->read(); }
+ if ((state->m_keyboard_mask & 0x02)!=0) { key &= device->machine().root_device().ioport("CLINE1")->read(); }
+ if ((state->m_keyboard_mask & 0x04)!=0) { key &= device->machine().root_device().ioport("CLINE2")->read(); }
+ if ((state->m_keyboard_mask & 0x08)!=0) { key &= device->machine().root_device().ioport("CLINE3")->read(); }
+ if ((state->m_keyboard_mask & 0x10)!=0) { key &= device->machine().root_device().ioport("CLINE4")->read(); }
+ if ((state->m_keyboard_mask & 0x20)!=0) { key &= device->machine().root_device().ioport("CLINE5")->read(); }
+ if ((state->m_keyboard_mask & 0x40)!=0) { key &= device->machine().root_device().ioport("CLINE6")->read(); }
+ if ((state->m_keyboard_mask & 0x80)!=0) { key &= device->machine().root_device().ioport("CLINE7")->read(); }
+ key &= 0xe0;
+ if (level < 0) {
+ key ^= state->m_tape_value;
+ }
+ return key;
+}
+
+I8255A_INTERFACE( rk7007_ppi8255_interface )
+{
+ DEVCB_NULL,
+ DEVCB_HANDLER(radio86_8255_porta_w2),
+ DEVCB_HANDLER(radio86_8255_portb_r2),
+ DEVCB_NULL,
+ DEVCB_HANDLER(rk7007_8255_portc_r),
+ DEVCB_HANDLER(radio86_8255_portc_w2),
+};
+
+static WRITE_LINE_DEVICE_HANDLER( hrq_w )
+{
+ /* HACK - this should be connected to the BUSREQ line of Z80 */
+ cputag_set_input_line(device->machine(), "maincpu", INPUT_LINE_HALT, state);
+
+ /* HACK - this should be connected to the BUSACK line of Z80 */
+ i8257_hlda_w(device, state);
+}
+
+static UINT8 memory_read_byte(address_space *space, offs_t address) { return space->read_byte(address); }
+static void memory_write_byte(address_space *space, offs_t address, UINT8 data) { space->write_byte(address, data); }
+
+I8257_INTERFACE( radio86_dma )
+{
+ DEVCB_LINE(hrq_w),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_MEMORY_HANDLER("maincpu", PROGRAM, memory_read_byte),
+ DEVCB_MEMORY_HANDLER("maincpu", PROGRAM, memory_write_byte),
+ { DEVCB_NULL, DEVCB_NULL, DEVCB_NULL, DEVCB_NULL },
+ { DEVCB_NULL, DEVCB_NULL, DEVCB_DEVICE_HANDLER("i8275", i8275_dack_w), DEVCB_NULL }
+};
+
+static TIMER_CALLBACK( radio86_reset )
+{
+ radio86_state *state = machine.driver_data<radio86_state>();
+ state->membank("bank1")->set_entry(0);
+}
+
+
+READ8_MEMBER(radio86_state::radio_cpu_state_r)
+{
+ return cpu_get_reg(&space.device(), I8085_STATUS);
+}
+
+READ8_MEMBER(radio86_state::radio_io_r)
+{
+ return machine().device("maincpu")->memory().space(AS_PROGRAM)->read_byte((offset << 8) + offset);
+}
+
+WRITE8_MEMBER(radio86_state::radio_io_w)
+{
+ machine().device("maincpu")->memory().space(AS_PROGRAM)->write_byte((offset << 8) + offset,data);
+}
+
+MACHINE_RESET( radio86 )
+{
+ radio86_state *state = machine.driver_data<radio86_state>();
+ machine.scheduler().timer_set(attotime::from_usec(10), FUNC(radio86_reset));
+ state->membank("bank1")->set_entry(1);
+
+ state->m_keyboard_mask = 0;
+ state->m_disk_sel = 0;
+}
+
+
+WRITE8_MEMBER(radio86_state::radio86_pagesel)
+{
+ m_disk_sel = data;
+}
+
+static READ8_DEVICE_HANDLER (radio86_romdisk_porta_r )
+{
+ radio86_state *state = device->machine().driver_data<radio86_state>();
+ UINT8 *romdisk = state->memregion("maincpu")->base() + 0x10000;
+ if ((state->m_disk_sel & 0x0f) ==0) {
+ return romdisk[state->m_romdisk_msb*256+state->m_romdisk_lsb];
+ } else {
+ if (state->m_disk_sel==0xdf) {
+ return state->m_radio_ram_disk[state->m_romdisk_msb*256+state->m_romdisk_lsb + 0x10000];
+ } else {
+ return state->m_radio_ram_disk[state->m_romdisk_msb*256+state->m_romdisk_lsb];
+ }
+ }
+}
+
+static WRITE8_DEVICE_HANDLER (radio86_romdisk_portb_w )
+{
+ radio86_state *state = device->machine().driver_data<radio86_state>();
+ state->m_romdisk_lsb = data;
+}
+
+static WRITE8_DEVICE_HANDLER (radio86_romdisk_portc_w )
+{
+ radio86_state *state = device->machine().driver_data<radio86_state>();
+ state->m_romdisk_msb = data;
+}
+
+I8255A_INTERFACE( radio86_ppi8255_interface_2 )
+{
+ DEVCB_HANDLER(radio86_romdisk_porta_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(radio86_romdisk_portb_w),
+ DEVCB_NULL,
+ DEVCB_HANDLER(radio86_romdisk_portc_w)
+};
+
+static WRITE8_DEVICE_HANDLER (mikrosha_8255_font_page_w )
+{
+ radio86_state *state = device->machine().driver_data<radio86_state>();
+ state->m_mikrosha_font_page = (data > 7) & 1;
+}
+
+I8255A_INTERFACE( mikrosha_ppi8255_interface_2 )
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(mikrosha_8255_font_page_w),
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+const i8275_interface radio86_i8275_interface = {
+ "screen",
+ 6,
+ 0,
+ DEVCB_DEVICE_LINE("dma8257", i8257_drq2_w),
+ DEVCB_NULL,
+ radio86_display_pixels
+};
+
+const i8275_interface mikrosha_i8275_interface = {
+ "screen",
+ 6,
+ 0,
+ DEVCB_DEVICE_LINE("dma8257", i8257_drq2_w),
+ DEVCB_NULL,
+ mikrosha_display_pixels
+};
+
+const i8275_interface apogee_i8275_interface = {
+ "screen",
+ 6,
+ 0,
+ DEVCB_DEVICE_LINE("dma8257", i8257_drq2_w),
+ DEVCB_NULL,
+ apogee_display_pixels
+};
+
+const i8275_interface partner_i8275_interface = {
+ "screen",
+ 6,
+ 1,
+ DEVCB_DEVICE_LINE("dma8257", i8257_drq2_w),
+ DEVCB_NULL,
+ partner_display_pixels
+};
diff --git a/src/mess/machine/rm380z.c b/src/mess/machine/rm380z.c
new file mode 100644
index 00000000000..fa7302eda9b
--- /dev/null
+++ b/src/mess/machine/rm380z.c
@@ -0,0 +1,300 @@
+
+/*
+
+RM 380Z machine
+
+*/
+
+
+#include "includes/rm380z.h"
+
+
+/*
+
+PORT0 write in COS 4.0B/M:
+
+bit0: 1=reset keyboard latch (?)
+bit1: ?
+bit2: ?
+bit3: ?
+bit4: ?
+bit5: 40/80 cols switch (?)
+bit6: 0=write to char RAM/1=write to attribute RAM
+bit7: 1=map ROM at 0000-0fff/0=RAM
+
+*/
+
+WRITE8_MEMBER( rm380z_state::port_write )
+{
+ switch ( offset )
+ {
+ case 0xFC: // PORT0
+ //printf("FBFCw[%2.2x] FBFD [%2.2x] FBFE [%2.2x] PC [%4.4x] writenum [%4.4x]\n",data,m_fbfd,m_fbfe,cpu_get_pc(machine().device("maincpu")),writenum);
+ m_port0 = data;
+ if (data&0x01)
+ {
+ //printf("WARNING: bit0 of port0 reset\n");
+ m_port0_kbd=0;
+ }
+ m_port1&=~0x01; //?
+
+ config_videomode();
+ config_memory_map();
+ break;
+
+ case 0xFD: // screen line counter (?)
+ //printf("FBFC [%2.2x] FBFDw[%2.2x] FBFE [%2.2x] PC [%4.4x] writenum [%4.4x]\n",m_port0,data,m_fbfe,cpu_get_pc(machine().device("maincpu")),writenum);
+
+ m_old_old_fbfd=m_old_fbfd;
+ m_old_fbfd=m_fbfd;
+ m_fbfd=data;
+
+ writenum++;
+
+ check_scroll_register();
+
+ break;
+
+ case 0xFE: // line on screen to write to divided by 2
+ //printf("FBFC [%2.2x] FBFD [%2.2x] FBFEw[%2.2x] PC [%4.4x] writenum [%4.4x]\n",m_port0,m_fbfd,data,cpu_get_pc(machine().device("maincpu")),writenum);
+ m_fbfe=data;
+ break;
+
+ case 0xFF: // user I/O port
+ //printf("write of [%x] to FBFF\n",data);
+ //logerror("%s: Write %02X to user I/O port\n", machine().describe_context(), data );
+ break;
+
+ default:
+ printf("unknown port [%2.2x] write of [%2.2x]\n",offset,data);
+ }
+}
+
+READ8_MEMBER( rm380z_state::port_read )
+{
+ UINT8 data = 0xFF;
+
+ switch ( offset )
+ {
+ case 0xFC: // PORT0
+ //m_port0_kbd=getKeyboard();
+ data = m_port0_kbd;
+ //if (m_port0_kbd!=0) m_port0_kbd=0;
+ //m_port0_kbd=0;
+ //printf("read of port0 (kbd) from PC [%x]\n",cpu_get_pc(machine().device("maincpu")));
+ break;
+
+ case 0xFD: // "counter" (?)
+ //printf("%s: Read from counter FBFD\n", machine().describe_context());
+ data = 0x00;
+ break;
+
+ case 0xFE: // PORT1
+ data = m_port1;
+ //printf("read of port1 from PC [%x]\n",cpu_get_pc(machine().device("maincpu")));
+ break;
+
+ case 0xFF: // user port
+ //printf("%s: Read from user port\n", machine().describe_context());
+ break;
+
+ default:
+ printf("read from unknown port [%2.2x]\n",offset);
+ }
+
+ return data;
+}
+
+WRITE8_MEMBER( rm380z_state::port_write_1b00 )
+{
+ address_space *program = m_maincpu->space(AS_PROGRAM);
+ port_write(*program,offset+0xfc,data);
+}
+
+READ8_MEMBER( rm380z_state::port_read_1b00 )
+{
+ address_space *program = m_maincpu->space(AS_PROGRAM);
+ return port_read(*program,offset+0xfc);
+}
+
+READ8_MEMBER( rm380z_state::hiram_read )
+{
+ return hiram[offset];
+}
+
+WRITE8_MEMBER( rm380z_state::hiram_write )
+{
+ hiram[offset]=data;
+}
+
+READ8_MEMBER( rm380z_state::rm380z_portlow_r )
+{
+ return 0xff;
+}
+
+WRITE8_MEMBER( rm380z_state::rm380z_portlow_w )
+{
+ //printf("port write [%x] [%x] at PC [%x]\n",offset,data,cpu_get_pc(machine().device("maincpu")));
+}
+
+READ8_MEMBER( rm380z_state::rm380z_porthi_r )
+{
+ return 0xff;
+}
+
+WRITE8_MEMBER( rm380z_state::rm380z_porthi_w )
+{
+ //printf("port write [%x] [%x]\n",offset+0xc5,data);
+}
+
+
+#define LINE_SUBDIVISION 82
+#define HORZ_LINES 100
+#define TIMER_SPEED 50*HORZ_LINES*LINE_SUBDIVISION
+
+//
+// this simulates line+frame blanking
+// according to the System manual, "frame blanking bit (bit 6) of port1 becomes high
+// for about 4.5 milliseconds every 20 milliseconds"
+//
+
+static TIMER_CALLBACK(static_vblank_timer)
+{
+ //printf("timer callback called at [%f]\n",machine.time().as_double());
+
+ rm380z_state *state = machine.driver_data<rm380z_state>();
+
+ state->m_rasterlineCtr++;
+ state->m_rasterlineCtr%=(HORZ_LINES*LINE_SUBDIVISION);
+
+ // frame blanking
+ if (state->m_rasterlineCtr>=((HORZ_LINES-22)*LINE_SUBDIVISION))
+ {
+ state->m_port1|=0x40;
+ }
+ else
+ {
+ state->m_port1&=~0x40;
+ }
+
+ // line blanking
+ if ((state->m_rasterlineCtr%LINE_SUBDIVISION)>80)
+ {
+ state->m_port1|=0x80;
+ }
+ else
+ {
+ state->m_port1&=~0x80;
+ }
+}
+
+WRITE8_MEMBER( rm380z_state::keyboard_put )
+{
+ if (data)
+ {
+ m_port0_kbd = data;
+ m_port1 |= 1;
+ }
+}
+
+//
+// ports c0-cf are related to the floppy disc controller
+// c0-c3: wd1771
+// c4-c8: disk drive port0
+//
+// CP/M booting:
+// from the service manual: "the B command reads a sector from drive 0, track 0, sector 1 into memory
+// at 0x0080 to 0x00FF, then jumps to it if there is no error."
+//
+
+WRITE8_MEMBER( rm380z_state::disk_0_control )
+{
+ device_t *fdc = machine().device("wd1771");
+
+ //printf("disk drive port0 write [%x]\n",data);
+
+ // drive port0
+ if (data&0x01)
+ {
+ // drive select bit 0
+ wd17xx_set_drive(fdc,0);
+ }
+
+ if (data&0x02)
+ {
+ // drive select bit 1
+ wd17xx_set_drive(fdc,1);
+ }
+
+ if (data&0x08)
+ {
+ // motor on
+ }
+
+ // "MSEL (dir/side select bit)"
+ if (data&0x20)
+ {
+ wd17xx_set_side(fdc,1);
+ }
+ else
+ {
+ wd17xx_set_side(fdc,0);
+ }
+
+ // set drive en- (?)
+ if (data&0x40)
+ {
+ }
+}
+
+void rm380z_state::machine_start()
+{
+ machine().scheduler().timer_pulse(attotime::from_hz(TIMER_SPEED), FUNC(static_vblank_timer));
+}
+
+void rm380z_state::machine_reset()
+{
+ m_port0=0x00;
+ m_port0_kbd=0x00;
+ m_port1=0x00;
+ m_fbfd=0x00;
+ m_fbfe=0x00;
+ m_old_fbfd=0x00;
+ m_old_old_fbfd=0x00;
+ writenum=0;
+
+ m_videomode=RM380Z_VIDEOMODE_80COL;
+ m_old_videomode=m_videomode;
+ m_rasterlineCtr=0;
+
+ // note: from COS 4.0 videos, screen seems to show garbage at the beginning
+ memset(m_mainVideoram,0,RM380Z_VIDEORAM_SIZE);
+
+ memset(m_vramattribs,0,RM380Z_SCREENSIZE);
+ memset(m_vramchars,0,RM380Z_SCREENSIZE);
+ memset(m_vram,0,RM380Z_SCREENSIZE);
+
+ config_memory_map();
+ wd17xx_reset(machine().device("wd1771"));
+
+ init_graphic_chars();
+}
+
+void rm380z_state::config_memory_map()
+{
+ address_space *program = m_maincpu->space(AS_PROGRAM);
+ UINT8 *rom = memregion(RM380Z_MAINCPU_TAG)->base();
+ UINT8* m_ram_p = m_messram->pointer();
+
+ if ( RM380Z_PORTS_ENABLED_HIGH )
+ {
+ program->install_ram( 0x0000, 0xDFFF, m_ram_p );
+ }
+ else
+ {
+ program->install_rom( 0x0000, 0x0FFF, rom );
+ program->install_readwrite_handler(0x1BFC, 0x1BFF,read8_delegate(FUNC(rm380z_state::port_read_1b00), this),write8_delegate(FUNC(rm380z_state::port_write_1b00), this) );
+ program->install_rom( 0x1C00, 0x1DFF, rom + 0x1400 );
+ program->install_ram( 0x4000, 0xDFFF, m_ram_p );
+ }
+}
diff --git a/src/mess/machine/rmnimbus.c b/src/mess/machine/rmnimbus.c
new file mode 100644
index 00000000000..b69ca34b846
--- /dev/null
+++ b/src/mess/machine/rmnimbus.c
@@ -0,0 +1,3055 @@
+/*
+ machine/rmnimbus.c
+
+ Machine driver for the Research Machines Nimbus.
+
+ Phill Harvey-Smith
+ 2009-11-29.
+
+ 80186 internal DMA/Timer/PIC code borrowed from Compis driver.
+ Perhaps this needs merging into the 80186 core.....
+*/
+
+/*
+
+ SCSI/SASI drives supported by RM Nimbus machines
+
+Native SCSI - format with HDFORM.EXE
+
+Drive Capacity Tracks Heads Sec/Track Blocks
+RO652-20 20MB 306 4 34 41616
+ST225N 20MB 615 4 17 41721
+ST125N 20MB 407 4 26 41921
+8425S-30 20MB 41004
+CP3020 20MB 623 2 33 41118
+ST225NP 20MB 615 4 17 41720
+CP3040 40MB 1026 2 40 82080
+
+Via Xibec S1410 SASI to MFM bridge board - format with WINFORM.EXE
+NP05-10S 8MB 160 6 17 16320
+NP04-20T 16MB 320 6 17 32640
+NP03-20 15MB 306 6 17 31212
+R352-10 10MB 306 4 17 20808
+NP04-50 40MB 699 7 17 83181
+NP04-55 44MB 754 7 17 89726
+
+Via Adaptec ACB4070 SCSI to RLL bridge board - format with ADAPT.EXE
+NEC D5147 60MB 615 8 26 127920
+ST227R 60MB 820 6 26 127920
+
+After formating, the drives need to have a partition table put on them with
+STAMP.EXE and then formatted in the normal way for a dos system drive with
+Format /s.
+
+The tracks, heads and sectors/track can be used with chdman -createblank
+to create a blank hard disk which can then be formatted with the RM tools.
+The important thing when doing this is to make sure that if using the Native
+SCSI tools, that the disk has the same number of blocks as specified above,
+even if you have to use unusual geometry to do so !
+*/
+
+
+#include "emu.h"
+#include "debugger.h"
+#include "cpu/i86/i86.h"
+#include "debug/debugcpu.h"
+#include "debug/debugcon.h"
+#include "imagedev/flopdrv.h"
+#include "machine/ram.h"
+#include "machine/er59256.h"
+#include "machine/pic8259.h"
+#include "machine/pit8253.h"
+#include "machine/i8251.h"
+#include "machine/ctronics.h"
+#include "machine/6522via.h"
+#include "machine/scsi.h"
+#include "sound/ay8910.h"
+#include "sound/msm5205.h"
+
+#include "includes/rmnimbus.h"
+
+static void sio_interrupt(device_t *device, int state);
+//static WRITE8_DEVICE_HANDLER( sio_dtr_w );
+static WRITE8_DEVICE_HANDLER( sio_serial_transmit );
+static int sio_serial_receive( device_t *device, int channel );
+
+
+/*-------------------------------------------------------------------------*/
+/* Defines, constants, and global variables */
+/*-------------------------------------------------------------------------*/
+
+/* CPU 80186 */
+#define LATCH_INTS 1
+#define LOG_PORTS 0
+#define LOG_INTERRUPTS 0
+#define LOG_INTERRUPTS_EXT 0
+#define LOG_TIMER 0
+#define LOG_OPTIMIZATION 0
+#define LOG_DMA 0
+#define CPU_RESUME_TRIGGER 7123
+#define LOG_KEYBOARD 0
+#define LOG_SIO 0
+#define LOG_DISK_FDD 0
+#define LOG_DISK_HDD 0
+#define LOG_DISK 0
+#define LOG_PC8031 0
+#define LOG_PC8031_186 0
+#define LOG_PC8031_PORT 0
+#define LOG_IOU 0
+#define LOG_SOUND 0
+#define LOG_RAM 0
+
+/* Debugging */
+
+#define DEBUG_SET(flags) ((state->m_debug_machine & (flags))==(flags))
+
+#define DEBUG_NONE 0x0000000
+#define DMA_BREAK 0x0000001
+#define DECODE_BIOS 0x0000002
+#define DECODE_BIOS_RAW 0x0000004
+#define DECODE_DOS21 0x0000008
+
+
+/* Z80 SIO */
+
+const z80sio_interface nimbus_sio_intf =
+{
+ sio_interrupt, /* interrupt handler */
+ 0, //sio_dtr_w, /* DTR changed handler */
+ 0, /* RTS changed handler */
+ 0, /* BREAK changed handler */
+ sio_serial_transmit, /* transmit handler */
+ sio_serial_receive /* receive handler */
+};
+
+/* Floppy drives WD2793 */
+
+static WRITE_LINE_DEVICE_HANDLER( nimbus_fdc_intrq_w );
+static WRITE_LINE_DEVICE_HANDLER( nimbus_fdc_drq_w );
+
+const wd17xx_interface nimbus_wd17xx_interface =
+{
+ DEVCB_LINE_GND,
+ DEVCB_LINE(nimbus_fdc_intrq_w),
+ DEVCB_LINE(nimbus_fdc_drq_w),
+ {FLOPPY_0, FLOPPY_1, FLOPPY_2, FLOPPY_3}
+};
+
+
+static const UINT16 def_config[16] =
+{
+ 0x0280, 0x017F, 0xE822, 0x8129,
+ 0x0329, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x8796, 0x2025, 0xB9E6
+};
+
+/* Memory controler */
+
+/* IO Unit */
+
+/* Sound */
+
+
+static void drq_callback(running_machine &machine, int which);
+static void nimbus_recalculate_ints(running_machine &machine);
+
+static void execute_debug_irq(running_machine &machine, int ref, int params, const char *param[]);
+static void execute_debug_intmasks(running_machine &machine, int ref, int params, const char *param[]);
+static void nimbus_debug(running_machine &machine, int ref, int params, const char *param[]);
+
+static int instruction_hook(device_t &device, offs_t curpc);
+static void decode_subbios(device_t *device,offs_t pc, UINT8 raw_flag);
+static void decode_dos21(device_t *device,offs_t pc);
+static void decode_dssi_generic(device_t *device,UINT16 ds, UINT16 si, UINT8 raw_flag);
+static void decode_dssi_f_fill_area(device_t *device,UINT16 ds, UINT16 si, UINT8 raw_flag);
+static void decode_dssi_f_plot_character_string(device_t *device,UINT16 ds, UINT16 si, UINT8 raw_flag);
+static void decode_dssi_f_set_new_clt(device_t *device,UINT16 ds, UINT16 si, UINT8 raw_flag);
+static void decode_dssi_f_plonk_char(device_t *device,UINT16 ds, UINT16 si, UINT8 raw_flag);
+static void decode_dssi_f_rw_sectors(device_t *device,UINT16 ds, UINT16 si, UINT8 raw_flag);
+
+static void nimbus_bank_memory(running_machine &machine);
+static void memory_reset(running_machine &machine);
+static void fdc_reset(running_machine &machine);
+static void set_disk_int(running_machine &machine, int state);
+static void hdc_reset(running_machine &machine);
+static void hdc_ctrl_write(running_machine &machine, UINT8 data);
+static void hdc_post_rw(running_machine &machine);
+static void hdc_drq(running_machine &machine);
+
+static void keyboard_reset(running_machine &machine);
+static TIMER_CALLBACK(keyscan_callback);
+
+static void pc8031_reset(running_machine &machine);
+static void iou_reset(running_machine &machine);
+static void sound_reset(running_machine &machine);
+
+static void mouse_js_reset(running_machine &machine);
+static TIMER_CALLBACK(mouse_callback);
+
+
+/*************************************
+ *
+ * 80186 interrupt controller
+ *
+ *************************************/
+static IRQ_CALLBACK(int_callback)
+{
+ rmnimbus_state *state = device->machine().driver_data<rmnimbus_state>();
+ UINT8 vector;
+ UINT16 old;
+ UINT16 oldreq;
+
+ if (LOG_INTERRUPTS)
+ logerror("(%f) **** Acknowledged interrupt vector %02X\n", device->machine().time().as_double(), state->m_i186.intr.poll_status & 0x1f);
+
+ /* clear the interrupt */
+ device_set_input_line(device, 0, CLEAR_LINE);
+ state->m_i186.intr.pending = 0;
+
+ oldreq=state->m_i186.intr.request;
+
+ /* clear the request and set the in-service bit */
+#if LATCH_INTS
+ state->m_i186.intr.request &= ~state->m_i186.intr.ack_mask;
+#else
+ state->m_i186.intr.request &= ~(state->m_i186.intr.ack_mask & 0x0f);
+#endif
+
+ if((LOG_INTERRUPTS) && (state->m_i186.intr.request!=oldreq))
+ logerror("i186.intr.request changed from %02X to %02X\n",oldreq,state->m_i186.intr.request);
+
+ old=state->m_i186.intr.in_service;
+
+ state->m_i186.intr.in_service |= state->m_i186.intr.ack_mask;
+
+ if((LOG_INTERRUPTS) && (state->m_i186.intr.in_service!=old))
+ logerror("i186.intr.in_service changed from %02X to %02X\n",old,state->m_i186.intr.in_service);
+
+ if (state->m_i186.intr.ack_mask == 0x0001)
+ {
+ switch (state->m_i186.intr.poll_status & 0x1f)
+ {
+ case 0x08: state->m_i186.intr.status &= ~0x01; break;
+ case 0x12: state->m_i186.intr.status &= ~0x02; break;
+ case 0x13: state->m_i186.intr.status &= ~0x04; break;
+ }
+ }
+ state->m_i186.intr.ack_mask = 0;
+
+ /* a request no longer pending */
+ state->m_i186.intr.poll_status &= ~0x8000;
+
+ /* return the vector */
+ switch(state->m_i186.intr.poll_status & 0x1F)
+ {
+ case 0x0C : vector=(state->m_i186.intr.ext[0] & EXTINT_CTRL_CASCADE) ? state->m_i186.intr.ext_vector[0] : (state->m_i186.intr.poll_status & 0x1f); break;
+ case 0x0D : vector=(state->m_i186.intr.ext[1] & EXTINT_CTRL_CASCADE) ? state->m_i186.intr.ext_vector[1] : (state->m_i186.intr.poll_status & 0x1f); break;
+ default :
+ vector=state->m_i186.intr.poll_status & 0x1f; break;
+ }
+
+ if (LOG_INTERRUPTS)
+ {
+ logerror("i186.intr.ext[0]=%04X i186.intr.ext[1]=%04X\n",state->m_i186.intr.ext[0],state->m_i186.intr.ext[1]);
+ logerror("Ext vectors : %02X %02X\n",state->m_i186.intr.ext_vector[0],state->m_i186.intr.ext_vector[1]);
+ logerror("Int %02X Calling vector %02X\n",state->m_i186.intr.poll_status,vector);
+ }
+
+ return vector;
+}
+
+
+static void update_interrupt_state(running_machine &machine)
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_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", state->m_i186.intr.request, state->m_i186.intr.status, state->m_i186.intr.in_service, state->m_i186.intr.priority_mask);
+
+ /* loop over priorities */
+ for (Priority = 0; Priority <= state->m_i186.intr.priority_mask; Priority++)
+ {
+ /* note: by checking 4 bits, we also verify that the mask is off */
+ if ((state->m_i186.intr.timer & 0x0F) == Priority)
+ {
+ /* if we're already servicing something at this level, don't generate anything new */
+ if (state->m_i186.intr.in_service & 0x01)
+ return;
+
+ /* if there's something pending, generate an interrupt */
+ if (state->m_i186.intr.status & 0x07)
+ {
+ if (state->m_i186.intr.status & 1)
+ new_vector = 0x08;
+ else if (state->m_i186.intr.status & 2)
+ new_vector = 0x12;
+ else if (state->m_i186.intr.status & 4)
+ new_vector = 0x13;
+ else
+ popmessage("Invalid timer interrupt!");
+
+ /* set the clear mask and generate the int */
+ state->m_i186.intr.ack_mask = 0x0001;
+ goto generate_int;
+ }
+ }
+
+ /* check DMA interrupts */
+ for (IntNo = 0; IntNo < 2; IntNo++)
+ if ((state->m_i186.intr.dma[IntNo] & 0x0F) == Priority)
+ {
+ /* if we're already servicing something at this level, don't generate anything new */
+ if (state->m_i186.intr.in_service & (0x04 << IntNo))
+ return;
+
+ /* if there's something pending, generate an interrupt */
+ if (state->m_i186.intr.request & (0x04 << IntNo))
+ {
+ new_vector = 0x0a + IntNo;
+
+ /* set the clear mask and generate the int */
+ state->m_i186.intr.ack_mask = 0x0004 << IntNo;
+ goto generate_int;
+ }
+ }
+
+ /* check external interrupts */
+ for (IntNo = 0; IntNo < 4; IntNo++)
+ if ((state->m_i186.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 (state->m_i186.intr.in_service & (0x10 << IntNo))
+ return;
+
+ /* if there's something pending, generate an interrupt */
+ if (state->m_i186.intr.request & (0x10 << IntNo))
+ {
+ /* otherwise, generate an interrupt for this request */
+ new_vector = 0x0c + IntNo;
+
+ /* set the clear mask and generate the int */
+ state->m_i186.intr.ack_mask = 0x0010 << IntNo;
+ goto generate_int;
+ }
+ }
+ }
+ return;
+
+generate_int:
+ /* generate the appropriate interrupt */
+ state->m_i186.intr.poll_status = 0x8000 | new_vector;
+ if (!state->m_i186.intr.pending)
+ cputag_set_input_line(machine, MAINCPU_TAG, 0, ASSERT_LINE);
+ state->m_i186.intr.pending = 1;
+ machine.scheduler().trigger(CPU_RESUME_TRIGGER);
+ if (LOG_OPTIMIZATION) logerror(" - trigger due to interrupt pending\n");
+ if (LOG_INTERRUPTS) logerror("(%f) **** Requesting interrupt vector %02X\n", machine.time().as_double(), new_vector);
+}
+
+
+static void handle_eoi(running_machine &machine,int data)
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ int Priority;
+ int IntNo;
+ int handled=0;
+
+ /* specific case */
+ if (!(data & 0x8000))
+ {
+ /* turn off the appropriate in-service bit */
+ switch (data & 0x1f)
+ {
+ case 0x08: state->m_i186.intr.in_service &= ~0x01; break;
+ case 0x12: state->m_i186.intr.in_service &= ~0x01; break;
+ case 0x13: state->m_i186.intr.in_service &= ~0x01; break;
+ case 0x0a: state->m_i186.intr.in_service &= ~0x04; break;
+ case 0x0b: state->m_i186.intr.in_service &= ~0x08; break;
+ case 0x0c: state->m_i186.intr.in_service &= ~0x10; break;
+ case 0x0d: state->m_i186.intr.in_service &= ~0x20; break;
+ case 0x0e: state->m_i186.intr.in_service &= ~0x40; break;
+ case 0x0f: state->m_i186.intr.in_service &= ~0x80; break;
+ default: logerror("%05X:ERROR - 80186 EOI with unknown vector %02X\n", cpu_get_pc(machine.device(MAINCPU_TAG)), 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 ((state->m_i186.intr.timer & 0x07) == Priority && (state->m_i186.intr.in_service & 0x01))
+ {
+ state->m_i186.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 ((state->m_i186.intr.dma[IntNo] & 0x07) == Priority && (state->m_i186.intr.in_service & (0x04 << IntNo)))
+ {
+ state->m_i186.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 ((state->m_i186.intr.ext[IntNo] & 0x07) == Priority && (state->m_i186.intr.in_service & (0x10 << IntNo)))
+ {
+ state->m_i186.intr.in_service &= ~(0x10 << IntNo);
+ if (LOG_INTERRUPTS) logerror("(%f) **** Got EOI for INT%d\n", machine.time().as_double(), IntNo);
+ handled=1;
+ }
+ }
+ }
+ nimbus_recalculate_ints(machine);
+}
+
+/* Trigger an external interupt, optionally supplying the vector to take */
+static void external_int(running_machine &machine, UINT16 intno, UINT8 vector)
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ if (LOG_INTERRUPTS_EXT) logerror("generating external int %02X, vector %02X\n",intno,vector);
+
+ // Only 4 external ints
+ if(intno>3)
+ {
+ logerror("external_int() invalid external interupt no : 0x%02X (can only be 0..3)\n",intno);
+ return;
+ }
+
+ // Only set external vector if cascade mode enabled, only valid for
+ // int 0 & int 1
+ if (intno<2)
+ {
+ if(state->m_i186.intr.ext[intno] & EXTINT_CTRL_CASCADE)
+ state->m_i186.intr.ext_vector[intno]=vector;
+ }
+
+ // Turn on the requested request bit and handle interrupt
+ state->m_i186.intr.request |= (0x010 << intno);
+ update_interrupt_state(machine);
+}
+
+static void nimbus_recalculate_ints(running_machine &machine)
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ if((state->m_iou_reg092 & DISK_INT_ENABLE) && state->m_nimbus_drives.int_ff)
+ {
+ state->m_nimbus_drives.int_ff=0;
+ external_int(machine,0,EXTERNAL_INT_DISK);
+ }
+}
+
+/*************************************
+ *
+ * 80186 internal timers
+ *
+ *************************************/
+
+static TIMER_CALLBACK(internal_timer_int)
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ int which = param;
+ struct timer_state *t = &state->m_i186.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)
+ {
+ state->m_i186.intr.status |= 0x01 << which;
+ update_interrupt_state(machine);
+ if (LOG_TIMER) logerror(" Generating timer interrupt\n");
+ }
+
+ /* if we're continuous, reset */
+ if (t->control & 0x0001)
+ {
+ int count = t->maxA ? t->maxA : 0x10000;
+ t->int_timer->adjust((attotime::from_hz(2000000) * count), which);
+ if (LOG_TIMER) logerror(" Repriming interrupt\n");
+ }
+ else
+ t->int_timer->adjust(attotime::never, which);
+}
+
+
+static void internal_timer_sync(running_machine &machine, int which)
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ struct timer_state *t = &state->m_i186.timer[which];
+
+ /* if we have a timing timer running, adjust the count */
+ if (t->time_timer_active)
+ {
+ attotime current_time = t->time_timer->elapsed();
+ int net_clocks = ((current_time - t->last_time) * 2000000).seconds;
+ t->last_time = current_time;
+
+ /* set the max count bit if we passed the max */
+ if ((int)t->count + net_clocks >= t->maxA)
+ t->control |= 0x0020;
+
+ /* set the new count */
+ if (t->maxA != 0)
+ t->count = (t->count + net_clocks) % t->maxA;
+ else
+ t->count = t->count + net_clocks;
+ }
+}
+
+
+static void internal_timer_update(running_machine &machine,
+ int which,
+ int new_count,
+ int new_maxA,
+ int new_maxB,
+ int new_control)
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ struct timer_state *t = &state->m_i186.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(machine, 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(machine, 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(machine, 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;
+
+ /* merge back in the bits we don't modify */
+ new_control = (new_control & ~0x1fc0) | (t->control & 0x1fc0);
+
+ /* 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 & 0x001c)
+ logerror("%05X:ERROR! -unsupported timer mode %04X\n",
+ cpu_get_pc(machine.device(MAINCPU_TAG)), 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(machine, which);
+
+ /* nuke the timer and force the interrupt timer to be recomputed */
+ t->time_timer->adjust(attotime::never, which);
+ t->time_timer_active = 0;
+ update_int_timer = 1;
+ }
+
+ /* if we're going on, start the timers running */
+ else if ((diff & 0x8000) && (new_control & 0x8000))
+ {
+ /* start the timing */
+ t->time_timer->adjust(attotime::never, which);
+ t->time_timer_active = 1;
+ update_int_timer = 1;
+ }
+
+ /* if something about the interrupt timer changed, force an update */
+ if (!(diff & 0x8000) && (diff & 0x2000))
+ {
+ internal_timer_sync(machine, which);
+ update_int_timer = 1;
+ }
+ }
+
+ /* set the new control register */
+ t->control = new_control;
+ }
+
+ /* update the interrupt timer */
+ if (update_int_timer)
+ {
+ if ((t->control & 0x8000) && (t->control & 0x2000))
+ {
+ int diff = t->maxA - t->count;
+ if (diff <= 0)
+ diff += 0x10000;
+ t->int_timer->adjust(attotime::from_hz(2000000) * diff, which);
+ if (LOG_TIMER) logerror("Set interrupt timer for %d\n", which);
+ }
+ else
+ {
+ t->int_timer->adjust(attotime::never, which);
+ }
+ }
+}
+
+
+
+/*************************************
+ *
+ * 80186 internal DMA
+ *
+ *************************************/
+
+static TIMER_CALLBACK(dma_timer_callback)
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ int which = param;
+ struct dma_state *d = &state->m_i186.dma[which];
+
+ /* complete the status update */
+ d->control &= ~0x0002;
+ d->source += d->count;
+ d->count = 0;
+
+ /* check for interrupt generation */
+ if (d->control & 0x0100)
+ {
+ if (LOG_DMA>1) logerror("DMA%d timer callback - requesting interrupt: count = %04X, source = %04X\n", which, d->count, d->source);
+ state->m_i186.intr.request |= 0x04 << which;
+ update_interrupt_state(machine);
+ }
+}
+
+
+static void update_dma_control(running_machine &machine, int which, int new_control)
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ struct dma_state *d = &state->m_i186.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",
+ cpu_get_pc(machine.device(MAINCPU_TAG)), new_control);
+#if 0
+ /* if we're going live, set a timer */
+ if ((diff & 0x0002) && (new_control & 0x0002))
+ {
+ /* make sure the parameters meet our expectations */
+ if ((new_control & 0xfe00) != 0x1600)
+ {
+ if (LOG_DMA) logerror("Unexpected DMA control %02X\n", new_control);
+ }
+ else if (/*!is_redline &&*/ ((d->dest & 1) || (d->dest & 0x3f) > 0x0b))
+ {
+ if (LOG_DMA) logerror("Unexpected DMA destination %02X\n", d->dest);
+ }
+ else if (/*is_redline && */ (d->dest & 0xf000) != 0x4000 && (d->dest & 0xf000) != 0x5000)
+ {
+ if (LOG_DMA) logerror("Unexpected DMA destination %02X\n", d->dest);
+ }
+
+ /* otherwise, set a timer */
+ else
+ {
+ d->finished = 0;
+ }
+ }
+#endif
+
+ if (LOG_DMA) logerror("Initiated DMA %d - count = %04X, source = %04X, dest = %04X\n", which, d->count, d->source, d->dest);
+ if (DEBUG_SET(DMA_BREAK))
+ debugger_break(machine);
+
+ /* set the new control register */
+ d->control = new_control;
+}
+
+static void drq_callback(running_machine &machine, int which)
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ struct dma_state *dma = &state->m_i186.dma[which];
+ address_space *memory_space = machine.device(MAINCPU_TAG)->memory().space(AS_PROGRAM);
+ address_space *io_space = machine.device(MAINCPU_TAG)->memory().space(AS_IO);
+
+ address_space *src_space;
+ address_space *dest_space;
+
+ 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))
+ {
+ logerror("%05X:ERROR! - drq%d with dma channel stopped\n",
+ cpu_get_pc(machine.device(MAINCPU_TAG)), which);
+
+ return;
+ }
+
+ if(dma->control & DEST_MIO)
+ dest_space=memory_space;
+ else
+ dest_space=io_space;
+
+ if(dma->control & SRC_MIO)
+ src_space=memory_space;
+ else
+ src_space=io_space;
+
+ // Do the transfer
+ if(dma->control & BYTE_WORD)
+ {
+ dma_word=src_space->read_word(dma->source);
+ dest_space->write_word(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 ans source pointers as needed
+ switch (dma->control & DEST_INCDEC_MASK)
+ {
+ case DEST_DECREMENT : dma->dest -= incdec_size;
+ case DEST_INCREMENT : dma->dest += incdec_size;
+ }
+
+ switch (dma->control & SRC_INCDEC_MASK)
+ {
+ case SRC_DECREMENT : dma->source -= incdec_size;
+ case SRC_INCREMENT : dma->source += incdec_size;
+ }
+
+ // decrement count
+ dma->count -= 1;
+
+ // Terminate if count is zero, and terminate flag set
+ if((dma->control & TERMINATE_ON_ZERO) && (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);
+ state->m_i186.intr.request |= 0x04 << which;
+ update_interrupt_state(machine);
+ }
+}
+
+/*-------------------------------------------------------------------------*/
+/* Name: rmnimbus */
+/* Desc: CPU - Initialize the 80186 CPU */
+/*-------------------------------------------------------------------------*/
+static void nimbus_cpu_init(running_machine &machine)
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ logerror("Machine reset\n");
+
+ /* create timers here so they stick around */
+ state->m_i186.timer[0].int_timer = machine.scheduler().timer_alloc(FUNC(internal_timer_int));
+ state->m_i186.timer[1].int_timer = machine.scheduler().timer_alloc(FUNC(internal_timer_int));
+ state->m_i186.timer[2].int_timer = machine.scheduler().timer_alloc(FUNC(internal_timer_int));
+ state->m_i186.timer[0].time_timer = machine.scheduler().timer_alloc(FUNC_NULL);
+ state->m_i186.timer[1].time_timer = machine.scheduler().timer_alloc(FUNC_NULL);
+ state->m_i186.timer[2].time_timer = machine.scheduler().timer_alloc(FUNC_NULL);
+ state->m_i186.dma[0].finish_timer = machine.scheduler().timer_alloc(FUNC(dma_timer_callback));
+ state->m_i186.dma[1].finish_timer = machine.scheduler().timer_alloc(FUNC(dma_timer_callback));
+}
+
+static void nimbus_cpu_reset(running_machine &machine)
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ /* reset the interrupt state */
+ state->m_i186.intr.priority_mask = 0x0007;
+ state->m_i186.intr.timer = 0x000f;
+ state->m_i186.intr.dma[0] = 0x000f;
+ state->m_i186.intr.dma[1] = 0x000f;
+ state->m_i186.intr.ext[0] = 0x000f;
+ state->m_i186.intr.ext[1] = 0x000f;
+ state->m_i186.intr.ext[2] = 0x000f;
+ state->m_i186.intr.ext[3] = 0x000f;
+ state->m_i186.intr.in_service = 0x0000;
+
+ /* External vectors by default to internal int 0/1 vectors */
+ state->m_i186.intr.ext_vector[0] = 0x000C;
+ state->m_i186.intr.ext_vector[1] = 0x000D;
+
+ state->m_i186.intr.pending = 0x0000;
+ state->m_i186.intr.ack_mask = 0x0000;
+ state->m_i186.intr.request = 0x0000;
+ state->m_i186.intr.status = 0x0000;
+ state->m_i186.intr.poll_status = 0x0000;
+
+ logerror("CPU reset done\n");
+}
+
+READ16_MEMBER(rmnimbus_state::nimbus_i186_internal_port_r)
+{
+ int temp, which;
+
+ switch (offset)
+ {
+ case 0x11:
+ logerror("%05X:ERROR - read from 80186 EOI\n", cpu_get_pc(&space.device()));
+ break;
+
+ case 0x12:
+ if (LOG_PORTS) logerror("%05X:read 80186 interrupt poll\n", cpu_get_pc(&space.device()));
+ if (m_i186.intr.poll_status & 0x8000)
+ int_callback(machine().device(MAINCPU_TAG), 0);
+ return m_i186.intr.poll_status;
+
+ case 0x13:
+ if (LOG_PORTS) logerror("%05X:read 80186 interrupt poll status\n", cpu_get_pc(&space.device()));
+ return m_i186.intr.poll_status;
+
+ case 0x14:
+ if (LOG_PORTS) logerror("%05X:read 80186 interrupt mask\n", cpu_get_pc(&space.device()));
+ temp = (m_i186.intr.timer >> 3) & 0x01;
+ temp |= (m_i186.intr.dma[0] >> 1) & 0x04;
+ temp |= (m_i186.intr.dma[1] >> 0) & 0x08;
+ temp |= (m_i186.intr.ext[0] << 1) & 0x10;
+ temp |= (m_i186.intr.ext[1] << 2) & 0x20;
+ temp |= (m_i186.intr.ext[2] << 3) & 0x40;
+ temp |= (m_i186.intr.ext[3] << 4) & 0x80;
+ return temp;
+
+ case 0x15:
+ if (LOG_PORTS) logerror("%05X:read 80186 interrupt priority mask\n", cpu_get_pc(&space.device()));
+ return m_i186.intr.priority_mask;
+
+ case 0x16:
+ if (LOG_PORTS) logerror("%05X:read 80186 interrupt in-service\n", cpu_get_pc(&space.device()));
+ return m_i186.intr.in_service;
+
+ case 0x17:
+ if (LOG_PORTS) logerror("%05X:read 80186 interrupt request\n", cpu_get_pc(&space.device()));
+ temp = m_i186.intr.request & ~0x0001;
+ if (m_i186.intr.status & 0x0007)
+ temp |= 1;
+ return temp;
+
+ case 0x18:
+ if (LOG_PORTS) logerror("%05X:read 80186 interrupt status\n", cpu_get_pc(&space.device()));
+ return m_i186.intr.status;
+
+ case 0x19:
+ if (LOG_PORTS) logerror("%05X:read 80186 timer interrupt control\n", cpu_get_pc(&space.device()));
+ return m_i186.intr.timer;
+
+ case 0x1a:
+ if (LOG_PORTS) logerror("%05X:read 80186 DMA 0 interrupt control\n", cpu_get_pc(&space.device()));
+ return m_i186.intr.dma[0];
+
+ case 0x1b:
+ if (LOG_PORTS) logerror("%05X:read 80186 DMA 1 interrupt control\n", cpu_get_pc(&space.device()));
+ return m_i186.intr.dma[1];
+
+ case 0x1c:
+ if (LOG_PORTS) logerror("%05X:read 80186 INT 0 interrupt control\n", cpu_get_pc(&space.device()));
+ return m_i186.intr.ext[0];
+
+ case 0x1d:
+ if (LOG_PORTS) logerror("%05X:read 80186 INT 1 interrupt control\n", cpu_get_pc(&space.device()));
+ return m_i186.intr.ext[1];
+
+ case 0x1e:
+ if (LOG_PORTS) logerror("%05X:read 80186 INT 2 interrupt control\n", cpu_get_pc(&space.device()));
+ return m_i186.intr.ext[2];
+
+ case 0x1f:
+ if (LOG_PORTS) logerror("%05X:read 80186 INT 3 interrupt control\n", cpu_get_pc(&space.device()));
+ return m_i186.intr.ext[3];
+
+ case 0x28:
+ case 0x2c:
+ case 0x30:
+ if (LOG_PORTS) logerror("%05X:read 80186 Timer %d count\n", cpu_get_pc(&space.device()), (offset - 0x28) / 4);
+ which = (offset - 0x28) / 4;
+ if (!(offset & 1))
+ internal_timer_sync(machine(), which);
+ return m_i186.timer[which].count;
+
+ case 0x29:
+ case 0x2d:
+ case 0x31:
+ if (LOG_PORTS) logerror("%05X:read 80186 Timer %d max A\n", cpu_get_pc(&space.device()), (offset - 0x29) / 4);
+ which = (offset - 0x29) / 4;
+ return m_i186.timer[which].maxA;
+
+ case 0x2a:
+ case 0x2e:
+ logerror("%05X:read 80186 Timer %d max B\n", cpu_get_pc(&space.device()), (offset - 0x2a) / 4);
+ which = (offset - 0x2a) / 4;
+ return m_i186.timer[which].maxB;
+
+ case 0x2b:
+ case 0x2f:
+ case 0x33:
+ if (LOG_PORTS) logerror("%05X:read 80186 Timer %d control\n", cpu_get_pc(&space.device()), (offset - 0x2b) / 4);
+ which = (offset - 0x2b) / 4;
+ return m_i186.timer[which].control;
+
+ case 0x50:
+ if (LOG_PORTS) logerror("%05X:read 80186 upper chip select\n", cpu_get_pc(&space.device()));
+ return m_i186.mem.upper;
+
+ case 0x51:
+ if (LOG_PORTS) logerror("%05X:read 80186 lower chip select\n", cpu_get_pc(&space.device()));
+ return m_i186.mem.lower;
+
+ case 0x52:
+ if (LOG_PORTS) logerror("%05X:read 80186 peripheral chip select\n", cpu_get_pc(&space.device()));
+ return m_i186.mem.peripheral;
+
+ case 0x53:
+ if (LOG_PORTS) logerror("%05X:read 80186 middle chip select\n", cpu_get_pc(&space.device()));
+ return m_i186.mem.middle;
+
+ case 0x54:
+ if (LOG_PORTS) logerror("%05X:read 80186 middle P chip select\n", cpu_get_pc(&space.device()));
+ return m_i186.mem.middle_size;
+
+ case 0x60:
+ case 0x68:
+ if (LOG_PORTS) logerror("%05X:read 80186 DMA%d lower source address\n", cpu_get_pc(&space.device()), (offset - 0x60) / 8);
+ which = (offset - 0x60) / 8;
+ return m_i186.dma[which].source;
+
+ case 0x61:
+ case 0x69:
+ if (LOG_PORTS) logerror("%05X:read 80186 DMA%d upper source address\n", cpu_get_pc(&space.device()), (offset - 0x61) / 8);
+ which = (offset - 0x61) / 8;
+ return m_i186.dma[which].source >> 16;
+
+ case 0x62:
+ case 0x6a:
+ if (LOG_PORTS) logerror("%05X:read 80186 DMA%d lower dest address\n", cpu_get_pc(&space.device()), (offset - 0x62) / 8);
+ which = (offset - 0x62) / 8;
+ return m_i186.dma[which].dest;
+
+ case 0x63:
+ case 0x6b:
+ if (LOG_PORTS) logerror("%05X:read 80186 DMA%d upper dest address\n", cpu_get_pc(&space.device()), (offset - 0x63) / 8);
+ which = (offset - 0x63) / 8;
+ return m_i186.dma[which].dest >> 16;
+
+ case 0x64:
+ case 0x6c:
+ if (LOG_PORTS) logerror("%05X:read 80186 DMA%d transfer count\n", cpu_get_pc(&space.device()), (offset - 0x64) / 8);
+ which = (offset - 0x64) / 8;
+ return m_i186.dma[which].count;
+
+ case 0x65:
+ case 0x6d:
+ if (LOG_PORTS) logerror("%05X:read 80186 DMA%d control\n", cpu_get_pc(&space.device()), (offset - 0x65) / 8);
+ which = (offset - 0x65) / 8;
+ return m_i186.dma[which].control;
+
+ default:
+ logerror("%05X:read 80186 port %02X\n", cpu_get_pc(&space.device()), offset);
+ break;
+ }
+ return 0x00;
+}
+
+/*************************************
+ *
+ * 80186 internal I/O writes
+ *
+ *************************************/
+
+WRITE16_MEMBER(rmnimbus_state::nimbus_i186_internal_port_w)
+{
+ int temp, which, data16 = data;
+
+ switch (offset)
+ {
+ case 0x11:
+ if (LOG_PORTS) logerror("%05X:80186 EOI = %04X\n", cpu_get_pc(&space.device()), data16);
+ handle_eoi(machine(),0x8000);
+ update_interrupt_state(machine());
+ break;
+
+ case 0x12:
+ logerror("%05X:ERROR - write to 80186 interrupt poll = %04X\n", cpu_get_pc(&space.device()), data16);
+ break;
+
+ case 0x13:
+ logerror("%05X:ERROR - write to 80186 interrupt poll status = %04X\n", cpu_get_pc(&space.device()), data16);
+ break;
+
+ case 0x14:
+ if (LOG_PORTS) logerror("%05X:80186 interrupt mask = %04X\n", cpu_get_pc(&space.device()), data16);
+ m_i186.intr.timer = (m_i186.intr.timer & ~0x08) | ((data16 << 3) & 0x08);
+ m_i186.intr.dma[0] = (m_i186.intr.dma[0] & ~0x08) | ((data16 << 1) & 0x08);
+ m_i186.intr.dma[1] = (m_i186.intr.dma[1] & ~0x08) | ((data16 << 0) & 0x08);
+ m_i186.intr.ext[0] = (m_i186.intr.ext[0] & ~0x08) | ((data16 >> 1) & 0x08);
+ m_i186.intr.ext[1] = (m_i186.intr.ext[1] & ~0x08) | ((data16 >> 2) & 0x08);
+ m_i186.intr.ext[2] = (m_i186.intr.ext[2] & ~0x08) | ((data16 >> 3) & 0x08);
+ m_i186.intr.ext[3] = (m_i186.intr.ext[3] & ~0x08) | ((data16 >> 4) & 0x08);
+ update_interrupt_state(machine());
+ break;
+
+ case 0x15:
+ if (LOG_PORTS) logerror("%05X:80186 interrupt priority mask = %04X\n", cpu_get_pc(&space.device()), data16);
+ m_i186.intr.priority_mask = data16 & 0x0007;
+ update_interrupt_state(machine());
+ break;
+
+ case 0x16:
+ if (LOG_PORTS) logerror("%05X:80186 interrupt in-service = %04X\n", cpu_get_pc(&space.device()), data16);
+ m_i186.intr.in_service = data16 & 0x00ff;
+ update_interrupt_state(machine());
+ break;
+
+ case 0x17:
+ if (LOG_PORTS) logerror("%05X:80186 interrupt request = %04X\n", cpu_get_pc(&space.device()), data16);
+ m_i186.intr.request = (m_i186.intr.request & ~0x00c0) | (data16 & 0x00c0);
+ update_interrupt_state(machine());
+ break;
+
+ case 0x18:
+ if (LOG_PORTS) logerror("%05X:WARNING - wrote to 80186 interrupt status = %04X\n", cpu_get_pc(&space.device()), data16);
+ m_i186.intr.status = (m_i186.intr.status & ~0x8007) | (data16 & 0x8007);
+ update_interrupt_state(machine());
+ break;
+
+ case 0x19:
+ if (LOG_PORTS) logerror("%05X:80186 timer interrupt contol = %04X\n", cpu_get_pc(&space.device()), data16);
+ m_i186.intr.timer = data16 & 0x000f;
+ break;
+
+ case 0x1a:
+ if (LOG_PORTS) logerror("%05X:80186 DMA 0 interrupt control = %04X\n", cpu_get_pc(&space.device()), data16);
+ m_i186.intr.dma[0] = data16 & 0x000f;
+ break;
+
+ case 0x1b:
+ if (LOG_PORTS) logerror("%05X:80186 DMA 1 interrupt control = %04X\n", cpu_get_pc(&space.device()), data16);
+ m_i186.intr.dma[1] = data16 & 0x000f;
+ break;
+
+ case 0x1c:
+ if (LOG_PORTS) logerror("%05X:80186 INT 0 interrupt control = %04X\n", cpu_get_pc(&space.device()), data16);
+ m_i186.intr.ext[0] = data16 & 0x007f;
+ break;
+
+ case 0x1d:
+ if (LOG_PORTS) logerror("%05X:80186 INT 1 interrupt control = %04X\n", cpu_get_pc(&space.device()), data16);
+ m_i186.intr.ext[1] = data16 & 0x007f;
+ break;
+
+ case 0x1e:
+ if (LOG_PORTS) logerror("%05X:80186 INT 2 interrupt control = %04X\n", cpu_get_pc(&space.device()), data16);
+ m_i186.intr.ext[2] = data16 & 0x001f;
+ break;
+
+ case 0x1f:
+ if (LOG_PORTS) logerror("%05X:80186 INT 3 interrupt control = %04X\n", cpu_get_pc(&space.device()), data16);
+ m_i186.intr.ext[3] = data16 & 0x001f;
+ break;
+
+ case 0x28:
+ case 0x2c:
+ case 0x30:
+ if (LOG_PORTS) logerror("%05X:80186 Timer %d count = %04X\n", cpu_get_pc(&space.device()), (offset - 0x28) / 4, data16);
+ which = (offset - 0x28) / 4;
+ internal_timer_update(machine(),which, data16, -1, -1, -1);
+ break;
+
+ case 0x29:
+ case 0x2d:
+ case 0x31:
+ if (LOG_PORTS) logerror("%05X:80186 Timer %d max A = %04X\n", cpu_get_pc(&space.device()), (offset - 0x29) / 4, data16);
+ which = (offset - 0x29) / 4;
+ internal_timer_update(machine(),which, -1, data16, -1, -1);
+ break;
+
+ case 0x2a:
+ case 0x2e:
+ if (LOG_PORTS) logerror("%05X:80186 Timer %d max B = %04X\n", cpu_get_pc(&space.device()), (offset - 0x2a) / 4, data16);
+ which = (offset - 0x2a) / 4;
+ internal_timer_update(machine(),which, -1, -1, data16, -1);
+ break;
+
+ case 0x2b:
+ case 0x2f:
+ case 0x33:
+ if (LOG_PORTS) logerror("%05X:80186 Timer %d control = %04X\n", cpu_get_pc(&space.device()), (offset - 0x2b) / 4, data16);
+ which = (offset - 0x2b) / 4;
+ internal_timer_update(machine(),which, -1, -1, -1, data16);
+ break;
+
+ case 0x50:
+ if (LOG_PORTS) logerror("%05X:80186 upper chip select = %04X\n", cpu_get_pc(&space.device()), data16);
+ m_i186.mem.upper = data16 | 0xc038;
+ break;
+
+ case 0x51:
+ if (LOG_PORTS) logerror("%05X:80186 lower chip select = %04X\n", cpu_get_pc(&space.device()), data16);
+ m_i186.mem.lower = (data16 & 0x3fff) | 0x0038; printf("%X",m_i186.mem.lower);
+ break;
+
+ case 0x52:
+ if (LOG_PORTS) logerror("%05X:80186 peripheral chip select = %04X\n", cpu_get_pc(&space.device()), data16);
+ m_i186.mem.peripheral = data16 | 0x0038;
+ break;
+
+ case 0x53:
+ if (LOG_PORTS) logerror("%05X:80186 middle chip select = %04X\n", cpu_get_pc(&space.device()), data16);
+ m_i186.mem.middle = data16 | 0x01f8;
+ break;
+
+ case 0x54:
+ if (LOG_PORTS) logerror("%05X:80186 middle P chip select = %04X\n", cpu_get_pc(&space.device()), data16);
+ m_i186.mem.middle_size = data16 | 0x8038;
+
+ /* we need to do this at a time when the I86 context is swapped in */
+ /* this register is generally set once at startup and never again, so it's a good */
+ /* time to set it up */
+ device_set_irq_callback(&space.device(), int_callback);
+ break;
+
+ case 0x60:
+ case 0x68:
+ if (LOG_PORTS) logerror("%05X:80186 DMA%d lower source address = %04X\n", cpu_get_pc(&space.device()), (offset - 0x60) / 8, data16);
+ which = (offset - 0x60) / 8;
+ m_i186.dma[which].source = (m_i186.dma[which].source & ~0x0ffff) | (data16 & 0x0ffff);
+ break;
+
+ case 0x61:
+ case 0x69:
+ if (LOG_PORTS) logerror("%05X:80186 DMA%d upper source address = %04X\n", cpu_get_pc(&space.device()), (offset - 0x61) / 8, data16);
+ which = (offset - 0x61) / 8;
+ m_i186.dma[which].source = (m_i186.dma[which].source & ~0xf0000) | ((data16 << 16) & 0xf0000);
+ break;
+
+ case 0x62:
+ case 0x6a:
+ if (LOG_PORTS) logerror("%05X:80186 DMA%d lower dest address = %04X\n", cpu_get_pc(&space.device()), (offset - 0x62) / 8, data16);
+ which = (offset - 0x62) / 8;
+ m_i186.dma[which].dest = (m_i186.dma[which].dest & ~0x0ffff) | (data16 & 0x0ffff);
+ break;
+
+ case 0x63:
+ case 0x6b:
+ if (LOG_PORTS) logerror("%05X:80186 DMA%d upper dest address = %04X\n", cpu_get_pc(&space.device()), (offset - 0x63) / 8, data16);
+ which = (offset - 0x63) / 8;
+ m_i186.dma[which].dest = (m_i186.dma[which].dest & ~0xf0000) | ((data16 << 16) & 0xf0000);
+ break;
+
+ case 0x64:
+ case 0x6c:
+ if (LOG_PORTS) logerror("%05X:80186 DMA%d transfer count = %04X\n", cpu_get_pc(&space.device()), (offset - 0x64) / 8, data16);
+ which = (offset - 0x64) / 8;
+ m_i186.dma[which].count = data16;
+ break;
+
+ case 0x65:
+ case 0x6d:
+ if (LOG_PORTS) logerror("%05X:80186 DMA%d control = %04X\n", cpu_get_pc(&space.device()), (offset - 0x65) / 8, data16);
+ which = (offset - 0x65) / 8;
+ update_dma_control(machine(), which, data16);
+ break;
+
+ case 0x7f:
+ if (LOG_PORTS) logerror("%05X:80186 relocation register = %04X\n", cpu_get_pc(&space.device()), data16);
+
+ /* we assume here there that this doesn't happen too often */
+ /* plus, we can't really remove the old memory range, so we also assume that it's */
+ /* okay to leave us mapped where we were */
+ temp = (data16 & 0x0fff) << 8;
+ if (data16 & 0x1000)
+ {
+ machine().device(MAINCPU_TAG)->memory().space(AS_PROGRAM)->install_read_handler(temp, temp + 0xff, read16_delegate(FUNC(rmnimbus_state::nimbus_i186_internal_port_r),this));
+ machine().device(MAINCPU_TAG)->memory().space(AS_PROGRAM)->install_write_handler(temp, temp + 0xff, write16_delegate(FUNC(rmnimbus_state::nimbus_i186_internal_port_w),this));
+ }
+ else
+ {
+ temp &= 0xffff;
+ machine().device(MAINCPU_TAG)->memory().space(AS_IO)->install_read_handler(temp, temp + 0xff, read16_delegate(FUNC(rmnimbus_state::nimbus_i186_internal_port_r),this));
+ machine().device(MAINCPU_TAG)->memory().space(AS_IO)->install_write_handler(temp, temp + 0xff, write16_delegate(FUNC(rmnimbus_state::nimbus_i186_internal_port_w),this));
+ }
+ break;
+
+ default:
+ logerror("%05X:80186 port %02X = %04X\n", cpu_get_pc(&space.device()), offset, data16);
+ break;
+ }
+}
+
+MACHINE_RESET(nimbus)
+{
+ /* CPU */
+ nimbus_cpu_reset(machine);
+ iou_reset(machine);
+ fdc_reset(machine);
+ hdc_reset(machine);
+ keyboard_reset(machine);
+ pc8031_reset(machine);
+ sound_reset(machine);
+ memory_reset(machine);
+ mouse_js_reset(machine);
+}
+
+DRIVER_INIT_MEMBER(rmnimbus_state,nimbus)
+{
+}
+
+MACHINE_START( nimbus )
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ /* init cpu */
+ nimbus_cpu_init(machine);
+
+ state->m_keyboard.keyscan_timer=machine.scheduler().timer_alloc(FUNC(keyscan_callback));
+ state->m_nimbus_mouse.m_mouse_timer=machine.scheduler().timer_alloc(FUNC(mouse_callback));
+
+ /* setup debug commands */
+ if (machine.debug_flags & DEBUG_FLAG_ENABLED)
+ {
+ debug_console_register_command(machine, "nimbus_irq", CMDFLAG_NONE, 0, 0, 2, execute_debug_irq);
+ debug_console_register_command(machine, "nimbus_intmasks", CMDFLAG_NONE, 0, 0, 0, execute_debug_intmasks);
+ debug_console_register_command(machine, "nimbus_debug", CMDFLAG_NONE, 0, 0, 1, nimbus_debug);
+
+ /* set up the instruction hook */
+ machine.device(MAINCPU_TAG)->debug()->set_instruction_hook(instruction_hook);
+ }
+
+ state->m_debug_machine=DEBUG_NONE;
+}
+
+static void execute_debug_irq(running_machine &machine, int ref, int params, const char *param[])
+{
+ int IntNo;
+ int Vector;
+
+ if(params>1)
+ {
+ sscanf(param[0],"%X",&IntNo);
+ sscanf(param[1],"%X",&Vector);
+
+ debug_console_printf(machine,"triggering IRQ%d, Vector=%02X\n",IntNo,Vector);
+ external_int(machine,IntNo,Vector);
+ }
+ else
+ {
+ debug_console_printf(machine,"Error, you must supply an intno and vector to trigger\n");
+ }
+}
+
+
+static void execute_debug_intmasks(running_machine &machine, int ref, int params, const char *param[])
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ int IntNo;
+
+ debug_console_printf(machine,"i186.intr.priority_mask=%4X\n",state->m_i186.intr.priority_mask);
+ for(IntNo=0; IntNo<4; IntNo++)
+ {
+ debug_console_printf(machine,"extInt%d mask=%4X\n",IntNo,state->m_i186.intr.ext[IntNo]);
+ }
+
+ debug_console_printf(machine,"i186.intr.request = %04X\n",state->m_i186.intr.request);
+ debug_console_printf(machine,"i186.intr.ack_mask = %04X\n",state->m_i186.intr.ack_mask);
+ debug_console_printf(machine,"i186.intr.in_service= %04X\n",state->m_i186.intr.in_service);
+}
+
+static void nimbus_debug(running_machine &machine, int ref, int params, const char *param[])
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ if(params>0)
+ {
+ sscanf(param[0],"%d",&state->m_debug_machine);
+ }
+ else
+ {
+ debug_console_printf(machine,"Error usage : nimbus_debug <debuglevel>\n");
+ debug_console_printf(machine,"Current debuglevel=%02X\n",state->m_debug_machine);
+ }
+}
+
+/*-----------------------------------------------
+ instruction_hook - per-instruction hook
+-----------------------------------------------*/
+
+static int instruction_hook(device_t &device, offs_t curpc)
+{
+ rmnimbus_state *state = device.machine().driver_data<rmnimbus_state>();
+ address_space *space = device.memory().space(AS_PROGRAM);
+ UINT8 *addr_ptr;
+
+ addr_ptr = (UINT8*)space->get_read_ptr(curpc);
+
+ if ((addr_ptr !=NULL) && (addr_ptr[0]==0xCD))
+ {
+ if(DEBUG_SET(DECODE_BIOS) && (addr_ptr[1]==0xF0))
+ {
+ if(DEBUG_SET(DECODE_BIOS_RAW))
+ decode_subbios(&device,curpc,1);
+ else
+ decode_subbios(&device,curpc,0);
+ }
+
+ if(DEBUG_SET(DECODE_DOS21) && (addr_ptr[1]==0x21))
+ decode_dos21(&device,curpc);
+ }
+
+ return 0;
+}
+
+#define set_type(type_name) sprintf(type_str,type_name)
+#define set_drv(drv_name) sprintf(drv_str,drv_name)
+#define set_func(func_name) sprintf(func_str,func_name)
+
+static void decode_subbios(device_t *device,offs_t pc, UINT8 raw_flag)
+{
+ char type_str[80];
+ char drv_str[80];
+ char func_str[80];
+
+ void (*dump_dssi)(device_t *,UINT16, UINT16 ,UINT8) = NULL;
+
+ device_t *cpu = device->machine().device(MAINCPU_TAG);
+
+ UINT16 ax = cpu_get_reg(cpu,I8086_AX);
+ UINT16 bx = cpu_get_reg(cpu,I8086_BX);
+ UINT16 cx = cpu_get_reg(cpu,I8086_CX);
+ UINT16 ds = cpu_get_reg(cpu,I8086_DS);
+ UINT16 si = cpu_get_reg(cpu,I8086_SI);
+
+ // *** TEMP Don't show f_enquire_display_line calls !
+ if((cx==6) && (ax==43))
+ return;
+ // *** END TEMP
+
+ if(!raw_flag)
+ {
+ logerror("=======================================================================\n");
+ logerror("Sub-bios call at %08X, AX=%04X, BX=%04X, CX=%04X, DS:SI=%04X:%04X\n",pc,ax,bx,cx,ds,si);
+ }
+
+ set_type("invalid");
+ set_drv("invalid");
+ set_func("invalid");
+
+ switch (cx)
+ {
+ case 0 :
+ {
+ set_type("t_mummu");
+ set_drv("d_mummu");
+
+ switch (ax)
+ {
+ case 0 : set_func("f_get_version_number"); break;
+ case 1 : set_func("f_add_type_code"); break;
+ case 2 : set_func("f_del_typc_code"); break;
+ case 3 : set_func("f_get_TCB"); break;
+ case 4 : set_func("f_add_driver_code"); break;
+ case 5 : set_func("f_del_driver_code"); break;
+ case 6 : set_func("f_get_DCB"); break;
+ case 7 : set_func("f_get_copyright"); break;
+ }
+ }; break;
+
+ case 1 :
+ {
+ set_type("t_character");
+ set_drv("d_printer");
+
+ switch(ax)
+ {
+ case 0 : set_func("f_get_version_number"); break;
+ case 1 : set_func("f_get_output_status"); break;
+ case 2 : set_func("f_output_character"); break;
+ case 3 : set_func("f_get_input_status"); break;
+ case 4 : set_func("f_get_and_remove"); break;
+ case 5 : set_func("f_get_no_remove"); break;
+ case 6 : set_func("f_get_last_and_remove"); break;
+ case 7 : set_func("f_get_last_no_remove"); break;
+ case 8 : set_func("f_set_IO_parameters"); break;
+ }
+ }; break;
+
+ case 2 :
+ {
+ set_type("t_disk");
+
+ switch(bx)
+ {
+ case 0 : set_drv("d_floppy"); break;
+ case 1 : set_drv("d_winchester"); break;
+ case 2 : set_drv("d_tape"); break;
+ case 3 : set_drv("d_rompack"); break;
+ case 4 : set_drv("d_eeprom"); break;
+ }
+
+ switch(ax)
+ {
+ case 0 : set_func("f_get_version_number"); break;
+ case 1 : set_func("f_initialise_unit"); break;
+ case 2 : set_func("f_pseudo_init_unit"); break;
+ case 3 : set_func("f_get_device_status"); break;
+ case 4 : set_func("f_read_n_sectors"); dump_dssi=&decode_dssi_f_rw_sectors; break;
+ case 5 : set_func("f_write_n_sectors"); dump_dssi=&decode_dssi_f_rw_sectors; break;
+ case 6 : set_func("f_verify_n_sectors"); break;
+ case 7 : set_func("f_media_check"); break;
+ case 8 : set_func("f_recalibrate"); break;
+ case 9 : set_func("f_motors_off"); break;
+ }
+ dump_dssi=&decode_dssi_f_rw_sectors;
+
+ }; break;
+
+ case 3 :
+ {
+ set_type("t_piconet");
+ set_drv("d_piconet");
+
+ switch(ax)
+ {
+ case 0 : set_func("f_get_version_number"); break;
+ case 1 : set_func("f_get_slave_status"); break;
+ case 2 : set_func("f_get_slave_map"); break;
+ case 3 : set_func("f_change_slave_addr"); break;
+ case 4 : set_func("f_read_slave_control"); break;
+ case 5 : set_func("f_write_slave_control"); break;
+ case 6 : set_func("f_send_data_byte"); break;
+ case 7 : set_func("f_request_data_byte"); break;
+ case 8 : set_func("f_send_data_block"); break;
+ case 9 : set_func("f_request_data_block"); break;
+ case 10 : set_func("f_reset_slave"); break;
+
+ }
+ }; break;
+
+ case 4 :
+ {
+ set_type("t_tick");
+ set_drv("d_tick");
+
+ switch(ax)
+ {
+ case 0 : set_func("f_get_version_number"); break;
+ case 1 : set_func("f_ticks_per_second"); break;
+ case 2 : set_func("f_link_tick_routine"); break;
+ case 3 : set_func("f_unlink_tick_routine"); break;
+ }
+ }; break;
+
+ case 5 :
+ {
+ set_type("t_graphics_input");
+
+ switch(bx)
+ {
+ case 0 : set_drv("d_mouse"); break;
+ case 1 : set_drv("d_joystick_1"); break;
+ case 2 : set_drv("d_joystick_2"); break;
+ }
+
+
+ switch(ax)
+ {
+ case 0 : set_func("f_get_version_number"); break;
+ case 1 : set_func("f_graphics_input_cold_start"); break;
+ case 2 : set_func("f_graphics_input_device_off"); break;
+ case 3 : set_func("f_return_button_status"); break;
+ case 4 : set_func("f_return_switch_and_button_stat"); break;
+ case 5 : set_func("f_start_tracking"); break;
+ case 6 : set_func("f_stop_tracking"); break;
+ case 7 : set_func("f_enquire_position"); break;
+ case 8 : set_func("f_set_position"); break;
+
+ case 10 : set_func("f_return_button_press_info"); break;
+ case 11 : set_func("f_return_button_release_info"); break;
+ case 12 : set_func("f_set_gain/f_set_squeaks_per_pixel_ratio"); break;
+ case 13 : set_func("f_enquire_graphics_in_misc_data"); break;
+ }
+ }; break;
+
+ case 6 :
+ {
+ set_type("t_graphics_output");
+ set_drv("d_ngc_screen");
+
+ switch(ax)
+ {
+ case 0 : set_func("f_get_version_number"); break;
+ case 1 : set_func("f_graphics_output_cold_start"); break;
+ case 2 : set_func("f_graphics_output_warm_start"); break;
+ case 3 : set_func("f_graphics_output_off"); break;
+ case 4 : set_func("f_reinit_graphics_output"); break;
+ case 5 : set_func("f_polymarker"); break;
+ case 6 : set_func("f_polyline"); dump_dssi=&decode_dssi_f_fill_area; break;
+ case 7 : set_func("f_fill_area"); dump_dssi=&decode_dssi_f_fill_area; break;
+ case 8 : set_func("f_flood_fill_area"); break;
+ case 9 : set_func("f_plot_character_string"); dump_dssi=&decode_dssi_f_plot_character_string; break;
+ case 10 : set_func("f_define_graphics_clipping_area"); break;
+ case 11 : set_func("f_enquire_clipping_area_limits"); break;
+ case 12 : set_func("f_select_graphics_clipping_area"); break;
+ case 13 : set_func("f_enq_selctd_graphics_clip_area"); break;
+ case 14 : set_func("f_set_clt_element"); break;
+ case 15 : set_func("f_enquire_clt_element"); break;
+ case 16 : set_func("f_set_new_clt"); dump_dssi=&decode_dssi_f_set_new_clt; break;
+ case 17 : set_func("f_enquire_clt_contents"); break;
+ case 18 : set_func("f_define_dithering_pattern"); break;
+ case 19 : set_func("f_enquire_dithering_pattern"); break;
+ case 20 : set_func("f_draw_sprite"); break;
+ case 21 : set_func("f_move_sprite"); break;
+ case 22 : set_func("f_erase_sprite"); break;
+ case 23 : set_func("f_read_pixel"); break;
+ case 24 : set_func("f_read_to_limit"); break;
+ case 25 : set_func("f_read_area_pixel"); break;
+ case 26 : set_func("f_write_area_pixel"); break;
+ case 27 : set_func("f_copy_area_pixel"); break;
+
+ case 29 : set_func("f_read_area_word"); break;
+ case 30 : set_func("f_write_area_word"); break;
+ case 31 : set_func("f_copy_area_word"); break;
+ case 32 : set_func("f_swap_area_word"); break;
+ case 33 : set_func("f_set_border_colour"); break;
+ case 34 : set_func("f_enquire_border_colour"); break;
+ case 35 : set_func("f_enquire_miscellaneous_data"); break;
+ case 36 : set_func("f_circle"); break;
+
+ case 38 : set_func("f_arc_of_ellipse"); break;
+ case 39 : set_func("f_isin"); break;
+ case 40 : set_func("f_icos"); break;
+ case 41 : set_func("f_define_hatching_pattern"); break;
+ case 42 : set_func("f_enquire_hatching_pattern"); break;
+ case 43 : set_func("f_enquire_display_line"); break;
+ case 44 : set_func("f_plonk_logo"); break;
+ }
+ }; break;
+
+ case 7 :
+ {
+ set_type("t_zend");
+ switch(ax)
+ {
+ case 0 : set_func("f_get_version_number"); break;
+ }
+ }; break;
+
+ case 8 :
+ {
+ set_type("t_zep");
+ switch(ax)
+ {
+ case 0 : set_func("f_get_version_number"); break;
+ }
+ }; break;
+
+ case 9 :
+ {
+ set_type("t_raw_console");
+
+ switch(bx)
+ {
+ case 0 :
+ {
+ set_drv("d_screen");
+
+ switch(ax)
+ {
+ case 0 : set_func("f_get_version_number"); break;
+ case 1 : set_func("f_plonk_char"); dump_dssi=decode_dssi_f_plonk_char; break;
+ case 2 : set_func("f_plonk_cursor"); break;
+ case 3 : set_func("f_kill_cursor"); break;
+ case 4 : set_func("f_scroll"); break;
+ case 5 : set_func("f_width"); dump_dssi=decode_dssi_generic;break;
+ case 6 : set_func("f_get_char_set"); break;
+ case 7 : set_func("f_set_char_set"); break;
+ case 8 : set_func("f_reset_char_set"); break;
+ case 9 : set_func("f_set_plonk_parameters"); break;
+ case 10 : set_func("f_set_cursor_flash_rate"); break;
+ }
+ }; break;
+
+ case 1 :
+ {
+ set_drv("d_keyboard");
+
+ switch(ax)
+ {
+ case 0 : set_func("f_get_version_number"); break;
+ case 1 : set_func("f_init_keyboard"); break;
+ case 2 : set_func("f_get_last_key_code"); break;
+ case 3 : set_func("f_get_bitmap"); break;
+ }
+ }; break;
+ }
+ }; break;
+
+ case 10 :
+ {
+
+ set_type("t_acoustics");
+
+ switch(bx)
+ {
+ case 0 :
+ {
+ set_drv("d_sound");
+
+ switch(ax)
+ {
+ case 0 : set_func("f_get_version_number"); break;
+ case 1 : set_func("f_sound_enable"); break;
+ case 2 : set_func("f_play_note"); break;
+ case 3 : set_func("f_get_queue_status"); break;
+ }
+ }; break;
+
+ case 1 :
+ {
+ set_drv("d_voice");
+
+ switch(ax)
+ {
+ case 0 : set_func("f_get_version_number"); break;
+ case 1 : set_func("f_talk"); break;
+ case 2 : set_func("f_wait_and_talk"); break;
+ case 3 : set_func("f_test_talking"); break;
+ }
+ }
+ }
+ }; break;
+
+ case 11 :
+ {
+ set_type("t_hard_sums");
+ switch(ax)
+ {
+ case 0 : set_func("f_get_version_number"); break;
+ }
+ }; break;
+ }
+
+ if(raw_flag)
+ {
+ if(dump_dssi!=NULL)
+ dump_dssi(device,ds,si,raw_flag);
+ }
+ else
+ {
+ logerror("Type=%s, Driver=%s, Function=%s\n",type_str,drv_str,func_str);
+
+ if(dump_dssi!=NULL)
+ dump_dssi(device,ds,si,raw_flag);
+ logerror("=======================================================================\n");
+ }
+}
+
+static void *get_dssi_ptr(address_space *space, UINT16 ds, UINT16 si)
+{
+ int addr;
+
+ addr=((ds<<4)+si);
+// OUTPUT_SEGOFS("DS:SI",ds,si);
+
+ return space->get_read_ptr(addr);
+}
+
+static void decode_dssi_generic(device_t *device,UINT16 ds, UINT16 si, UINT8 raw_flag)
+{
+ address_space *space = device->machine().device(MAINCPU_TAG)->memory().space(AS_PROGRAM);
+ UINT16 *params;
+ int count;
+
+ if(raw_flag)
+ return;
+
+ params=(UINT16 *)get_dssi_ptr(space,ds,si);
+
+ for(count=0; count<10; count++)
+ logerror("%04X ",params[count]);
+
+ logerror("\n");
+}
+
+
+static void decode_dssi_f_fill_area(device_t *device,UINT16 ds, UINT16 si, UINT8 raw_flag)
+{
+ address_space *space = device->machine().device(MAINCPU_TAG)->memory().space(AS_PROGRAM);
+
+ UINT16 *addr_ptr;
+ t_area_params *area_params;
+ t_nimbus_brush *brush;
+ int cocount;
+
+ area_params = (t_area_params *)get_dssi_ptr(space,ds,si);
+
+ if (!raw_flag)
+ OUTPUT_SEGOFS("SegBrush:OfsBrush",area_params->seg_brush,area_params->ofs_brush);
+
+ brush=(t_nimbus_brush *)space->get_read_ptr(LINEAR_ADDR(area_params->seg_brush,area_params->ofs_brush));
+
+ if(raw_flag)
+ {
+ logerror("\tdw\t%04X, %04X, %04X, %04X, %04X, %04X, %04X, %04X, %04X, ",
+ brush->style,brush->style_index,brush->colour1,brush->colour2,
+ brush->transparency,brush->boundary_spec,brush->boundary_colour,brush->save_colour,
+ area_params->count);
+ }
+ else
+ {
+ logerror("Brush params\n");
+ logerror("Style=%04X, StyleIndex=%04X\n",brush->style,brush->style_index);
+ logerror("Colour1=%04X, Colour2=%04X\n",brush->colour1,brush->colour2);
+ logerror("transparency=%04X, boundry_spec=%04X\n",brush->transparency,brush->boundary_spec);
+ logerror("boundry colour=%04X, save colour=%04X\n",brush->boundary_colour,brush->save_colour);
+
+
+ OUTPUT_SEGOFS("SegData:OfsData",area_params->seg_data,area_params->ofs_data);
+ }
+
+ addr_ptr = (UINT16 *)space->get_read_ptr(LINEAR_ADDR(area_params->seg_data,area_params->ofs_data));
+ for(cocount=0; cocount < area_params->count; cocount++)
+ {
+ if(raw_flag)
+ {
+ if(cocount!=(area_params->count-1))
+ logerror("%04X, %04X, ",addr_ptr[cocount*2],addr_ptr[(cocount*2)+1]);
+ else
+ logerror("%04X, %04X ",addr_ptr[cocount*2],addr_ptr[(cocount*2)+1]);
+ }
+ else
+ logerror("x=%d y=%d\n",addr_ptr[cocount*2],addr_ptr[(cocount*2)+1]);
+ }
+
+ if(raw_flag)
+ logerror("\n");
+}
+
+static void decode_dssi_f_plot_character_string(device_t *device,UINT16 ds, UINT16 si, UINT8 raw_flag)
+{
+ address_space *space = device->machine().device(MAINCPU_TAG)->memory().space(AS_PROGRAM);
+
+ UINT8 *char_ptr;
+ t_plot_string_params *plot_string_params;
+ int charno;
+
+ if(raw_flag)
+ return;
+
+ plot_string_params=(t_plot_string_params *)get_dssi_ptr(space,ds,si);
+
+ OUTPUT_SEGOFS("SegFont:OfsFont",plot_string_params->seg_font,plot_string_params->ofs_font);
+ OUTPUT_SEGOFS("SegData:OfsData",plot_string_params->seg_data,plot_string_params->ofs_data);
+
+ logerror("x=%d, y=%d, length=%d\n",plot_string_params->x,plot_string_params->y,plot_string_params->length);
+
+ char_ptr=(UINT8*)space->get_read_ptr(LINEAR_ADDR(plot_string_params->seg_data,plot_string_params->ofs_data));
+
+ if (plot_string_params->length==0xFFFF)
+ logerror("%s",char_ptr);
+ else
+ for(charno=0;charno<plot_string_params->length;charno++)
+ logerror("%c",char_ptr[charno]);
+
+ logerror("\n");
+}
+
+static void decode_dssi_f_set_new_clt(device_t *device,UINT16 ds, UINT16 si, UINT8 raw_flag)
+{
+ address_space *space = device->machine().device(MAINCPU_TAG)->memory().space(AS_PROGRAM);
+ UINT16 *new_colours;
+ int colour;
+ new_colours=(UINT16 *)get_dssi_ptr(space,ds,si);
+
+ if(raw_flag)
+ return;
+
+ OUTPUT_SEGOFS("SegColours:OfsColours",ds,si);
+
+ for(colour=0;colour<16;colour++)
+ logerror("colour #%02X=%04X\n",colour,new_colours[colour]);
+
+}
+
+static void decode_dssi_f_plonk_char(device_t *device,UINT16 ds, UINT16 si, UINT8 raw_flag)
+{
+ address_space *space = device->machine().device(MAINCPU_TAG)->memory().space(AS_PROGRAM);
+ UINT16 *params;
+ params=(UINT16 *)get_dssi_ptr(space,ds,si);
+
+ if(raw_flag)
+ return;
+
+ OUTPUT_SEGOFS("SegParams:OfsParams",ds,si);
+
+ logerror("plonked_char=%c\n",params[0]);
+}
+
+static void decode_dssi_f_rw_sectors(device_t *device,UINT16 ds, UINT16 si, UINT8 raw_flag)
+{
+ address_space *space = device->machine().device(MAINCPU_TAG)->memory().space(AS_PROGRAM);
+ UINT16 *params;
+ int param_no;
+
+ if(raw_flag)
+ return;
+
+ params=(UINT16 *)get_dssi_ptr(space,ds,si);
+
+ for(param_no=0;param_no<16;param_no++)
+ logerror("%04X ",params[param_no]);
+
+ logerror("\n");
+}
+
+static void decode_dos21(device_t *device,offs_t pc)
+{
+ device_t *cpu = device->machine().device(MAINCPU_TAG);
+
+ UINT16 ax = cpu_get_reg(cpu,I8086_AX);
+ UINT16 bx = cpu_get_reg(cpu,I8086_BX);
+ UINT16 cx = cpu_get_reg(cpu,I8086_CX);
+ UINT16 dx = cpu_get_reg(cpu,I8086_DX);
+ UINT16 cs = cpu_get_reg(cpu,I8086_CS);
+ UINT16 ds = cpu_get_reg(cpu,I8086_DS);
+ UINT16 es = cpu_get_reg(cpu,I8086_ES);
+ UINT16 ss = cpu_get_reg(cpu,I8086_SS);
+
+ UINT16 si = cpu_get_reg(cpu,I8086_SI);
+ UINT16 di = cpu_get_reg(cpu,I8086_DI);
+ UINT16 bp = cpu_get_reg(cpu,I8086_BP);
+
+ logerror("=======================================================================\n");
+ logerror("DOS Int 0x21 call at %05X\n",pc);
+ logerror("AX=%04X, BX=%04X, CX=%04X, DX=%04X\n",ax,bx,cx,dx);
+ logerror("CS=%04X, DS=%04X, ES=%04X, SS=%04X\n",cs,ds,es,ss);
+ logerror("SI=%04X, DI=%04X, BP=%04X\n",si,di,bp);
+ logerror("=======================================================================\n");
+
+ if((ax & 0xff00)==0x0900)
+ debugger_break(device->machine());
+}
+
+
+/*
+ The Nimbus has 3 banks of memory each of which can be either 16x4164 or 16x41256 giving
+ 128K or 512K per bank. These banks are as follows :
+
+ bank0 on nimbus motherboard.
+ bank1 first half of expansion card.
+ bank2 second half of expansion card.
+
+ The valid combinations are :
+
+ bank0 bank1 bank2 total
+ 128K 128K
+ 128K 128K 256K
+ 128K 128K 128K 384K
+ 128K 512K 640K (1)
+ 512K 128K 640K (2)
+ 512K 512K 1024K
+ 512K 512K 512K 1536K
+
+ It will be noted that there are two possible ways of getting 640K, we emulate method 2
+ (above).
+
+ To allow for the greatest flexibility, the Nimbus allows 4 methods of mapping the
+ banks of ram into the 1M addressable by the 81086.
+
+ With only 128K banks present, they are mapped into the first 3 blocks of 128K in
+ the memory map giving a total of up to 384K.
+
+ If any of the blocks are 512K, then the block size is set to 512K and the map arranged
+ so that the bottom block is a 512K block (if both 512K and 128K blocks are available).
+
+ This is all determined by the value written to port 80 :-
+
+ port80 = 0x07 start end
+ block0 0x00000 0x1FFFF
+ block1 0x20000 0x3FFFF
+ block2 0x40000 0x5FFFF
+
+ port80 = 0x1F
+ block0 0x00000 0x7FFFF
+ block1 0x80000 0xEFFFF (0x9FFFF if 128K (2))
+
+ port80 = 0x0F
+ block1 0x00000 0x7FFFF
+ block0 0x80000 0xEFFFF (0x9FFFF if 128K (1))
+
+ port80 = 0x17
+ block1 0x00000 0x7FFFF
+ block2 0x80000 0xEFFFF
+
+*/
+
+struct nimbus_meminfo
+{
+ offs_t start; /* start address of bank */
+ offs_t end; /* End address of bank */
+};
+
+static const struct nimbus_meminfo memmap[] =
+{
+ { 0x00000, 0x1FFFF },
+ { 0x20000, 0x3FFFF },
+ { 0x40000, 0x5FFFF },
+ { 0x60000, 0x7FFFF },
+ { 0x80000, 0x9FFFF },
+ { 0xA0000, 0xBFFFF },
+ { 0xC0000, 0xDFFFF },
+ { 0xE0000, 0xEFFFF }
+};
+
+typedef struct
+{
+ int blockbase;
+ int blocksize;
+} nimbus_block;
+
+typedef nimbus_block nimbus_blocks[3];
+
+static const nimbus_blocks ramblocks[] =
+{
+ {{ 0, 128 }, { 000, 000 }, { 000, 000 }} ,
+ {{ 0, 128 }, { 128, 128 }, { 000, 000 }} ,
+ {{ 0, 128 }, { 128, 128 }, { 256, 128 }} ,
+ {{ 0, 512 }, { 000, 000 }, { 000, 000 }} ,
+ {{ 0, 512 }, { 512, 128 }, { 000, 000 }} ,
+ {{ 0, 512 }, { 512, 512 }, { 000, 000 }} ,
+ {{ 0, 512 }, { 512, 512 }, { 1024, 512 } }
+};
+
+static void nimbus_bank_memory(running_machine &machine)
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ address_space *space = machine.device( MAINCPU_TAG)->memory().space( AS_PROGRAM );
+ int ramsize = machine.device<ram_device>(RAM_TAG)->size();
+ int ramblock = 0;
+ int blockno;
+ char bank[10];
+ UINT8 *ram = &machine.device<ram_device>(RAM_TAG)->pointer()[0];
+ UINT8 *map_blocks[3];
+ UINT8 *map_base;
+ int map_blockno;
+ int block_ofs;
+
+ UINT8 ramsel = (state->m_mcu_reg080 & 0x1F);
+
+ // Invalid ramsel, return.
+ if((ramsel & 0x07)!=0x07)
+ return;
+
+ switch (ramsize / 1024)
+ {
+ case 128 : ramblock=0; break;
+ case 256 : ramblock=1; break;
+ case 384 : ramblock=2; break;
+ case 512 : ramblock=3; break;
+ case 640 : ramblock=4; break;
+ case 1024 : ramblock=5; break;
+ case 1536 : ramblock=6; break;
+ }
+
+ map_blocks[0] = ram;
+ map_blocks[1] = (ramblocks[ramblock][1].blocksize==0) ? NULL : &ram[ramblocks[ramblock][1].blockbase*1024];
+ map_blocks[2] = (ramblocks[ramblock][2].blocksize==0) ? NULL : &ram[ramblocks[ramblock][2].blockbase*1024];
+
+ //if(LOG_RAM) logerror("\n\nmcu_reg080=%02X, ramblock=%d, map_blocks[0]=%X, map_blocks[1]=%X, map_blocks[2]=%X\n",state->m_mcu_reg080,ramblock,(int)map_blocks[0],(int)map_blocks[1],(int)map_blocks[2]);
+
+ for(blockno=0;blockno<8;blockno++)
+ {
+ sprintf(bank,"bank%d",blockno);
+
+ switch (ramsel)
+ {
+ case 0x07 : (blockno<3) ? map_blockno=blockno : map_blockno=-1; break;
+ case 0x1F : (blockno<4) ? map_blockno=0 : map_blockno=1; break;
+ case 0x0F : (blockno<4) ? map_blockno=1 : map_blockno=0; break;
+ case 0x17 : (blockno<4) ? map_blockno=1 : map_blockno=2; break;
+ default : map_blockno=-1;
+ }
+ block_ofs=(ramsel==0x07) ? 0 : ((blockno % 4)*128);
+
+
+ if(LOG_RAM) logerror("mapped %s",bank);
+
+ if((block_ofs < ramblocks[ramblock][map_blockno].blocksize) &&
+ (map_blocks[map_blockno]!=NULL) && (map_blockno>-1))
+ {
+ map_base=(ramsel==0x07) ? map_blocks[map_blockno] : &map_blocks[map_blockno][block_ofs*1024];
+
+ state->membank(bank)->set_base(map_base);
+ space->install_readwrite_bank(memmap[blockno].start, memmap[blockno].end, bank);
+ //if(LOG_RAM) logerror(", base=%X\n",(int)map_base);
+ }
+ else
+ {
+ space->nop_readwrite(memmap[blockno].start, memmap[blockno].end);
+ if(LOG_RAM) logerror("NOP\n");
+ }
+ }
+}
+
+READ8_MEMBER(rmnimbus_state::nimbus_mcu_r)
+{
+ return m_mcu_reg080;
+}
+
+WRITE8_MEMBER(rmnimbus_state::nimbus_mcu_w)
+{
+ m_mcu_reg080=data;
+
+ nimbus_bank_memory(machine());
+}
+
+static void memory_reset(running_machine &machine)
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ state->m_mcu_reg080=0x07;
+ nimbus_bank_memory(machine);
+}
+
+READ16_MEMBER(rmnimbus_state::nimbus_io_r)
+{
+ int pc=cpu_get_pc(&space.device());
+
+ logerror("Nimbus IOR at pc=%08X from %04X mask=%04X, data=%04X\n",pc,(offset*2)+0x30,mem_mask,m_IOPorts[offset]);
+
+ switch (offset*2)
+ {
+ default : return m_IOPorts[offset];
+ }
+ return 0;
+}
+
+WRITE16_MEMBER(rmnimbus_state::nimbus_io_w)
+{
+ int pc=cpu_get_pc(&space.device());
+
+ logerror("Nimbus IOW at %08X write of %04X to %04X mask=%04X\n",pc,data,(offset*2)+0x30,mem_mask);
+
+ switch (offset*2)
+ {
+ default : COMBINE_DATA(&m_IOPorts[offset]); break;
+ }
+}
+
+
+/*
+ Keyboard emulation
+
+*/
+
+static void keyboard_reset(running_machine &machine)
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ memset(state->m_keyboard.keyrows,0xFF,NIMBUS_KEYROWS);
+
+ // Setup timer to scan state->m_keyboard.
+ state->m_keyboard.keyscan_timer->adjust(attotime::zero, 0, attotime::from_hz(50));
+}
+
+static void queue_scancode(running_machine &machine, UINT8 scancode)
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ state->m_keyboard.queue[state->m_keyboard.head] = scancode;
+ state->m_keyboard.head++;
+ state->m_keyboard.head %= ARRAY_LENGTH(state->m_keyboard.queue);
+}
+
+static int keyboard_queue_read(running_machine &machine)
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ int data;
+ if (state->m_keyboard.tail == state->m_keyboard.head)
+ return -1;
+
+ data = state->m_keyboard.queue[state->m_keyboard.tail];
+
+ if (LOG_KEYBOARD)
+ logerror("keyboard_queue_read(): Keyboard Read 0x%02x\n",data);
+
+ state->m_keyboard.tail++;
+ state->m_keyboard.tail %= ARRAY_LENGTH(state->m_keyboard.queue);
+ return data;
+}
+
+static void scan_keyboard(running_machine &machine)
+
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ UINT8 keyrow;
+ UINT8 row;
+ UINT8 bitno;
+ UINT8 mask;
+ static const char *const keynames[] = {
+ "KEY0", "KEY1", "KEY2", "KEY3", "KEY4",
+ "KEY5", "KEY6", "KEY7", "KEY8", "KEY9",
+ "KEY10"
+ };
+
+ for(row=0;row<NIMBUS_KEYROWS;row++)
+ {
+ keyrow=machine.root_device().ioport(keynames[row])->read();
+
+ for(mask=0x80, bitno=7;mask>0;mask=mask>>1, bitno-=1)
+ {
+ if(!(keyrow & mask) && (state->m_keyboard.keyrows[row] & mask))
+ {
+ if (LOG_KEYBOARD) logerror("keypress %02X\n",(row<<3)+bitno);
+ queue_scancode(machine, (row<<3)+bitno);
+ }
+
+ if((keyrow & mask) && !(state->m_keyboard.keyrows[row] & mask))
+ {
+ if (LOG_KEYBOARD) logerror("keyrelease %02X\n",0x80+(row<<3)+bitno);
+ queue_scancode(machine, 0x80+(row<<3)+bitno);
+ }
+ }
+
+ state->m_keyboard.keyrows[row]=keyrow;
+ }
+}
+
+static TIMER_CALLBACK(keyscan_callback)
+{
+ scan_keyboard(machine);
+}
+
+/*
+
+Z80SIO, used for the keyboard interface
+
+*/
+
+/* Z80 SIO/2 */
+
+static void sio_interrupt(device_t *device, int state)
+{
+ rmnimbus_state *drvstate = device->machine().driver_data<rmnimbus_state>();
+ if(LOG_SIO)
+ logerror("SIO Interrupt state=%02X\n",state);
+
+ // Don't re-trigger if already active !
+ if(state!=drvstate->m_sio_int_state)
+ {
+ drvstate->m_sio_int_state=state;
+
+ if(state)
+ external_int(device->machine(),0,EXTERNAL_INT_Z80SIO);
+ }
+}
+
+#ifdef UNUSED_FUNCTION
+WRITE8_DEVICE_HANDLER( sio_dtr_w )
+{
+ if (offset == 1)
+ {
+ }
+}
+#endif
+
+static WRITE8_DEVICE_HANDLER( sio_serial_transmit )
+{
+}
+
+static int sio_serial_receive( device_t *device, int channel )
+{
+ if(channel==0)
+ {
+ return keyboard_queue_read(device->machine());
+ }
+ else
+ return -1;
+}
+
+/* Floppy disk */
+
+static void fdc_reset(running_machine &machine)
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ device_t *fdc = machine.device(FDC_TAG);
+
+ state->m_nimbus_drives.reg400=0;
+ state->m_nimbus_drives.reg410_in=0;
+ state->m_nimbus_drives.reg410_out=0;
+ state->m_nimbus_drives.int_ff=0;
+ wd17xx_set_pause_time(fdc,FDC_PAUSE);
+}
+
+static void set_disk_int(running_machine &machine, int state)
+{
+ rmnimbus_state *drvstate = machine.driver_data<rmnimbus_state>();
+ if(LOG_DISK)
+ logerror("nimbus_drives_intrq = %d\n",state);
+
+ if(drvstate->m_iou_reg092 & DISK_INT_ENABLE)
+ {
+ drvstate->m_nimbus_drives.int_ff=state;
+
+ if(state)
+ external_int(machine,0,EXTERNAL_INT_DISK);
+ }
+}
+
+static WRITE_LINE_DEVICE_HANDLER( nimbus_fdc_intrq_w )
+{
+ set_disk_int(device->machine(),state);
+}
+
+static WRITE_LINE_DEVICE_HANDLER( nimbus_fdc_drq_w )
+{
+ rmnimbus_state *drvstate = device->machine().driver_data<rmnimbus_state>();
+
+ if(LOG_DISK)
+ logerror("nimbus_drives_drq_w(%d)\n", state);
+
+ if(state && FDC_DRQ_ENABLED(drvstate))
+ drq_callback(device->machine(),1);
+}
+
+/*
+ 0x410 read bits
+
+ 0 Ready from floppy
+ 1 Index pulse from floppy
+ 2 Motor on from floppy
+ 3 MSG from HDD
+ 4 !BSY from HDD
+ 5 !I/O from HDD
+ 6 !C/D
+ 7 !REQ from HDD
+*/
+
+READ8_MEMBER(rmnimbus_state::nimbus_disk_r)
+{
+ int result = 0;
+ device_t *fdc = machine().device(FDC_TAG);
+ device_t *hdc = machine().device(SCSIBUS_TAG);
+
+ int pc=cpu_get_pc(&space.device());
+ rmnimbus_state *state = machine().driver_data<rmnimbus_state>();
+ device_t *drive = machine().device(nimbus_wd17xx_interface.floppy_drive_tags[FDC_DRIVE()]);
+
+ switch(offset*2)
+ {
+ case 0x08 :
+ result = wd17xx_status_r(fdc, 0);
+ if (LOG_DISK_FDD) logerror("Disk status=%2.2X\n",result);
+ break;
+ case 0x0A :
+ result = wd17xx_track_r(fdc, 0);
+ break;
+ case 0x0C :
+ result = wd17xx_sector_r(fdc, 0);
+ break;
+ case 0x0E :
+ result = wd17xx_data_r(fdc, 0);
+ break;
+ case 0x10 :
+ m_nimbus_drives.reg410_in &= ~FDC_BITS_410;
+ m_nimbus_drives.reg410_in |= (FDC_MOTOR() ? FDC_MOTOR_MASKI : 0x00);
+ m_nimbus_drives.reg410_in |= (floppy_drive_get_flag_state(drive, FLOPPY_DRIVE_INDEX) ? 0x00 : FDC_INDEX_MASK);
+ m_nimbus_drives.reg410_in |= (floppy_drive_get_flag_state(drive, FLOPPY_DRIVE_READY) ? FDC_READY_MASK : 0x00);
+
+ // Flip inverted bits
+ result=m_nimbus_drives.reg410_in ^ INV_BITS_410;
+ break;
+ case 0x18 :
+ result = scsi_data_r(hdc);
+ hdc_post_rw(machine());
+ default:
+ break;
+ }
+
+ if(LOG_DISK_FDD && ((offset*2)<=0x10))
+ logerror("Nimbus FDCR at pc=%08X from %04X data=%02X\n",pc,(offset*2)+0x400,result);
+
+ if((LOG_DISK_HDD) && ((offset*2)>=0x10))
+ logerror("Nimbus HDCR at pc=%08X from %04X data=%02X\n",pc,(offset*2)+0x400,result);
+
+ return result;
+}
+
+/*
+ 0x400 write bits
+
+ 0 drive 0 select
+ 1 drive 1 select
+ 2 drive 2 select
+ 3 drive 3 select
+ 4 side select
+ 5 fdc motor on
+ 6 hdc drq enabled
+ 7 fdc drq enabled
+
+ 0x410 write bits
+
+ 0 SCSI reset
+ 1 SCSI SEL
+ 2 SCSI IRQ Enable
+*/
+
+WRITE8_MEMBER(rmnimbus_state::nimbus_disk_w)
+{
+ device_t *fdc = machine().device(FDC_TAG);
+ device_t *hdc = machine().device(SCSIBUS_TAG);
+ int pc=cpu_get_pc(&space.device());
+ UINT8 reg400_old = m_nimbus_drives.reg400;
+
+ if(LOG_DISK_FDD && ((offset*2)<=0x10))
+ logerror("Nimbus FDCW at %05X write of %02X to %04X\n",pc,data,(offset*2)+0x400);
+
+ if((LOG_DISK_HDD) && (((offset*2)>=0x10) || (offset==0)))
+ logerror("Nimbus HDCW at %05X write of %02X to %04X\n",pc,data,(offset*2)+0x400);
+
+ rmnimbus_state *state = machine().driver_data<rmnimbus_state>();
+ switch(offset*2)
+ {
+ case 0x00 :
+ m_nimbus_drives.reg400=data;
+ wd17xx_set_drive(fdc,FDC_DRIVE());
+ wd17xx_set_side(fdc, FDC_SIDE());
+
+ // Nimbus FDC is hard wired for double density
+ //wd17xx_set_density(fdc, DEN_MFM_LO);
+
+ // if we enable hdc drq with a pending condition, act on it
+ if((data & HDC_DRQ_MASK) && (~reg400_old & HDC_DRQ_MASK))
+ hdc_drq(machine());
+
+ break;
+ case 0x08 :
+ wd17xx_command_w(fdc, 0, data);
+ break;
+ case 0x0A :
+ wd17xx_track_w(fdc, 0, data);
+ break;
+ case 0x0C :
+ wd17xx_sector_w(fdc, 0, data);
+ break;
+ case 0x0E :
+ wd17xx_data_w(fdc, 0, data);
+ break;
+ case 0x10 :
+ hdc_ctrl_write(machine(),data);
+ break;
+
+ case 0x18 :
+ scsi_data_w(hdc, data);
+ hdc_post_rw(machine());
+ break;
+ }
+}
+
+static void hdc_reset(running_machine &machine)
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ device_t *hdc = machine.device(SCSIBUS_TAG);
+
+ init_scsibus(hdc, 512);
+
+ state->m_nimbus_drives.reg410_in=0;
+ state->m_nimbus_drives.reg410_in |= (get_scsi_line(hdc,SCSI_LINE_REQ) ? HDC_REQ_MASK : 0);
+ state->m_nimbus_drives.reg410_in |= (get_scsi_line(hdc,SCSI_LINE_CD) ? HDC_CD_MASK : 0);
+ state->m_nimbus_drives.reg410_in |= (get_scsi_line(hdc,SCSI_LINE_IO) ? HDC_IO_MASK : 0);
+ state->m_nimbus_drives.reg410_in |= (get_scsi_line(hdc,SCSI_LINE_BSY) ? HDC_BSY_MASK : 0);
+ state->m_nimbus_drives.reg410_in |= (get_scsi_line(hdc,SCSI_LINE_MSG) ? HDC_MSG_MASK : 0);
+
+ state->m_nimbus_drives.drq_ff=0;
+}
+
+static void hdc_ctrl_write(running_machine &machine, UINT8 data)
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ device_t *hdc = machine.device(SCSIBUS_TAG);
+
+ // If we enable the HDC interupt, and an interrupt is pending, go deal with it.
+ if(((data & HDC_IRQ_MASK) && (~state->m_nimbus_drives.reg410_out & HDC_IRQ_MASK)) &&
+ ((~state->m_nimbus_drives.reg410_in & HDC_INT_TRIGGER)==HDC_INT_TRIGGER))
+ set_disk_int(machine,1);
+
+ state->m_nimbus_drives.reg410_out=data;
+
+ set_scsi_line(hdc, SCSI_LINE_RESET, (data & HDC_RESET_MASK) ? 0 : 1);
+ set_scsi_line(hdc, SCSI_LINE_SEL, (data & HDC_SEL_MASK) ? 0 : 1);
+}
+
+static void hdc_post_rw(running_machine &machine)
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ device_t *hdc = machine.device(SCSIBUS_TAG);
+
+ if((state->m_nimbus_drives.reg410_in & HDC_REQ_MASK)==0)
+ set_scsi_line(hdc,SCSI_LINE_ACK,0);
+
+ state->m_nimbus_drives.drq_ff=0;
+}
+
+static void hdc_drq(running_machine &machine)
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ if(HDC_DRQ_ENABLED() && state->m_nimbus_drives.drq_ff)
+ {
+ drq_callback(machine,1);
+ }
+}
+
+void nimbus_scsi_linechange(device_t *device, UINT8 line, UINT8 state)
+{
+ rmnimbus_state *drvstate = device->machine().driver_data<rmnimbus_state>();
+ UINT8 mask = 0;
+ UINT8 last = 0;
+
+ switch (line)
+ {
+ case SCSI_LINE_REQ : mask=HDC_REQ_MASK; break;
+ case SCSI_LINE_CD : mask=HDC_CD_MASK; break;
+ case SCSI_LINE_IO : mask=HDC_IO_MASK; break;
+ case SCSI_LINE_BSY : mask=HDC_BSY_MASK; break;
+ case SCSI_LINE_MSG : mask=HDC_MSG_MASK; break;
+ }
+
+ last=drvstate->m_nimbus_drives.reg410_in & mask;
+
+ if(state)
+ drvstate->m_nimbus_drives.reg410_in|=mask;
+ else
+ drvstate->m_nimbus_drives.reg410_in&=~mask;
+
+
+ if(HDC_IRQ_ENABLED(drvstate) && ((~drvstate->m_nimbus_drives.reg410_in & HDC_INT_TRIGGER)==HDC_INT_TRIGGER))
+ set_disk_int(device->machine(),1);
+ else
+ set_disk_int(device->machine(),0);
+
+ if(line==SCSI_LINE_REQ)
+ {
+ if (state==0)
+ {
+ if(((drvstate->m_nimbus_drives.reg410_in & HDC_CD_MASK)==HDC_CD_MASK) && (last!=0))
+ {
+ drvstate->m_nimbus_drives.drq_ff=1;
+ hdc_drq(device->machine());
+ }
+ }
+ else
+ set_scsi_line(device,SCSI_LINE_ACK,1);
+ }
+}
+
+/* 8031/8051 Peripheral controler 80186 side */
+
+static void pc8031_reset(running_machine &machine)
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ device_t *er59256 = machine.device(ER59256_TAG);
+
+ logerror("peripheral controler reset\n");
+
+ memset(&state->m_ipc_interface,0,sizeof(state->m_ipc_interface));
+
+ if(!er59256_data_loaded(er59256))
+ er59256_preload_rom(er59256,def_config,ARRAY_LENGTH(def_config));
+}
+
+
+#if 0
+static void ipc_dumpregs()
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ logerror("in_data=%02X, in_status=%02X, out_data=%02X, out_status=%02X\n",
+ state->m_ipc_interface.ipc_in, state->m_ipc_interface.status_in,
+ state->m_ipc_interface.ipc_out, state->m_ipc_interface.status_out);
+
+}
+#endif
+
+READ8_MEMBER(rmnimbus_state::nimbus_pc8031_r)
+{
+ int pc=cpu_get_pc(&space.device());
+ UINT8 result;
+
+ switch(offset*2)
+ {
+ case 0x00 : result=m_ipc_interface.ipc_out;
+ m_ipc_interface.status_in &= ~IPC_IN_READ_PEND;
+ m_ipc_interface.status_out &= ~IPC_OUT_BYTE_AVAIL;
+ break;
+
+ case 0x02 : result=m_ipc_interface.status_out;
+ break;
+
+ default : result=0; break;
+ }
+
+ if(LOG_PC8031_186)
+ logerror("Nimbus PCIOR %08X read of %04X returns %02X\n",pc,(offset*2)+0xC0,result);
+
+ return result;
+}
+
+WRITE8_MEMBER(rmnimbus_state::nimbus_pc8031_w)
+{
+ int pc=cpu_get_pc(&space.device());
+
+ switch(offset*2)
+ {
+ case 0x00 : m_ipc_interface.ipc_in=data;
+ m_ipc_interface.status_in |= IPC_IN_BYTE_AVAIL;
+ m_ipc_interface.status_in &= ~IPC_IN_ADDR;
+ m_ipc_interface.status_out |= IPC_OUT_READ_PEND;
+ break;
+
+ case 0x02 : m_ipc_interface.ipc_in=data;
+ m_ipc_interface.status_in |= IPC_IN_BYTE_AVAIL;
+ m_ipc_interface.status_in |= IPC_IN_ADDR;
+ m_ipc_interface.status_out |= IPC_OUT_READ_PEND;
+ break;
+ }
+
+ if(LOG_PC8031_186)
+ logerror("Nimbus PCIOW %08X write of %02X to %04X\n",pc,data,(offset*2)+0xC0);
+
+}
+
+/* 8031/8051 Peripheral controler 8031/8051 side */
+
+READ8_MEMBER(rmnimbus_state::nimbus_pc8031_iou_r)
+{
+ int pc=cpu_get_pc(&space.device());
+ UINT8 result = 0;
+
+ switch (offset & 0x01)
+ {
+ case 0x00 : result=m_ipc_interface.ipc_in;
+ m_ipc_interface.status_out &= ~IPC_OUT_READ_PEND;
+ m_ipc_interface.status_in &= ~IPC_IN_BYTE_AVAIL;
+ break;
+
+ case 0x01 : result=m_ipc_interface.status_in;
+ break;
+ }
+
+ if(((offset==2) || (offset==3)) && (m_iou_reg092 & PC8031_INT_ENABLE))
+ external_int(machine(),0,EXTERNAL_INT_PC8031_8C);
+
+ if(LOG_PC8031)
+ logerror("8031: PCIOR %04X read of %04X returns %02X\n",pc,offset,result);
+
+ return result;
+}
+
+WRITE8_MEMBER(rmnimbus_state::nimbus_pc8031_iou_w)
+{
+ int pc=cpu_get_pc(&space.device());
+
+ if(LOG_PC8031)
+ logerror("8031 PCIOW %04X write of %02X to %04X\n",pc,data,offset);
+
+ switch(offset & 0x03)
+ {
+ case 0x00 : m_ipc_interface.ipc_out=data;
+ m_ipc_interface.status_out |= IPC_OUT_BYTE_AVAIL;
+ m_ipc_interface.status_out &= ~IPC_OUT_ADDR;
+ m_ipc_interface.status_in |= IPC_IN_READ_PEND;
+ break;
+
+ case 0x01 : m_ipc_interface.ipc_out=data;
+ m_ipc_interface.status_out |= IPC_OUT_BYTE_AVAIL;
+ m_ipc_interface.status_out |= IPC_OUT_ADDR;
+ m_ipc_interface.status_in |= IPC_IN_READ_PEND;
+ break;
+
+ case 0x02 : m_ipc_interface.ipc_out=data;
+ m_ipc_interface.status_out |= IPC_OUT_BYTE_AVAIL;
+ m_ipc_interface.status_out &= ~IPC_OUT_ADDR;
+ m_ipc_interface.status_in |= IPC_IN_READ_PEND;
+ if(m_iou_reg092 & PC8031_INT_ENABLE)
+ external_int(machine(),0,EXTERNAL_INT_PC8031_8F);
+ break;
+
+ case 0x03 : m_ipc_interface.ipc_out=data;
+ //m_ipc_interface.status_out |= IPC_OUT_BYTE_AVAIL;
+ m_ipc_interface.status_out |= IPC_OUT_ADDR;
+ m_ipc_interface.status_in |= IPC_IN_READ_PEND;
+ if(m_iou_reg092 & PC8031_INT_ENABLE)
+ external_int(machine(),0,EXTERNAL_INT_PC8031_8E);
+ break;
+ }
+}
+
+READ8_MEMBER(rmnimbus_state::nimbus_pc8031_port_r)
+{
+ device_t *er59256 = machine().device(ER59256_TAG);
+ int pc=cpu_get_pc(&space.device());
+ UINT8 result = 0;
+
+ if(LOG_PC8031_PORT)
+ logerror("8031: PCPORTR %04X read of %04X returns %02X\n",pc,offset,result);
+
+ switch(offset)
+ {
+ case 0x01 : result=er59256_get_iobits(er59256);
+ }
+
+ return result;
+}
+
+WRITE8_MEMBER(rmnimbus_state::nimbus_pc8031_port_w)
+{
+ device_t *er59256 = machine().device(ER59256_TAG);
+ int pc=cpu_get_pc(&space.device());
+
+ switch (offset)
+ {
+ case 0x01 : er59256_set_iobits(er59256,(data&0x0F));
+ }
+
+ if(LOG_PC8031_PORT)
+ logerror("8031 PCPORTW %04X write of %02X to %04X\n",pc,data,offset);
+}
+
+
+
+/* IO Unit */
+READ8_MEMBER(rmnimbus_state::nimbus_iou_r)
+{
+ int pc=cpu_get_pc(&space.device());
+ UINT8 result=0;
+
+ if(offset==0)
+ {
+ result=m_iou_reg092;
+ }
+
+ if(LOG_IOU)
+ logerror("Nimbus IOUR %08X read of %04X returns %02X\n",pc,(offset*2)+0x92,result);
+
+ return result;
+}
+
+WRITE8_MEMBER(rmnimbus_state::nimbus_iou_w)
+{
+ int pc=cpu_get_pc(&space.device());
+ device_t *msm5205 = machine().device(MSM5205_TAG);
+
+ if(LOG_IOU)
+ logerror("Nimbus IOUW %08X write of %02X to %04X\n",pc,data,(offset*2)+0x92);
+
+ if(offset==0)
+ {
+ m_iou_reg092=data;
+ msm5205_reset_w(msm5205, (data & MSM5205_INT_ENABLE) ? 0 : 1);
+ }
+}
+
+static void iou_reset(running_machine &machine)
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ state->m_iou_reg092=0x00;
+}
+
+/*
+ Sound hardware : AY8910
+
+ I believe that the IO ports of the 8910 are used to control the ROMPack ports, however
+ this is currently un-implemented (and may never be as I don't have any rompacks!).
+
+ The registers are mapped as so :
+
+ Address 0xE0 0xE2
+ Read Data ????
+ Write Register Address Data
+
+*/
+
+static void sound_reset(running_machine &machine)
+{
+ rmnimbus_state *state = machine.driver_data<rmnimbus_state>();
+ //device_t *ay8910 = machine.device(AY8910_TAG);
+ device_t *msm5205 = machine.device(MSM5205_TAG);
+
+ //ay8910_reset_ym(ay8910);
+ msm5205_reset_w(msm5205, 1);
+
+ state->m_last_playmode=MSM5205_S48_4B;
+ msm5205_playmode_w(msm5205,state->m_last_playmode);
+
+ state->m_ay8910_a=0;
+}
+
+READ8_MEMBER(rmnimbus_state::nimbus_sound_ay8910_r)
+{
+ device_t *ay8910 = machine().device(AY8910_TAG);
+ UINT8 result=0;
+
+ if ((offset*2)==0)
+ result=ay8910_r(ay8910,0);
+
+ return result;
+}
+
+WRITE8_MEMBER(rmnimbus_state::nimbus_sound_ay8910_w)
+{
+ int pc=cpu_get_pc(&space.device());
+ device_t *ay8910 = machine().device(AY8910_TAG);
+
+ if(LOG_SOUND)
+ logerror("Nimbus SoundW %05X write of %02X to %04X\n",pc,data,(offset*2)+0xE0);
+
+ switch (offset*2)
+ {
+ case 0x00 : ay8910_data_address_w(ay8910, 1, data); break;
+ case 0x02 : ay8910_data_address_w(ay8910, 0, data); break;
+ }
+
+}
+
+WRITE8_MEMBER(rmnimbus_state::nimbus_sound_ay8910_porta_w)
+{
+ device_t *msm5205 = machine().device(MSM5205_TAG);
+
+ msm5205_data_w(msm5205, data);
+
+ // Mouse code needs a copy of this.
+ m_ay8910_a=data;
+}
+
+WRITE8_MEMBER(rmnimbus_state::nimbus_sound_ay8910_portb_w)
+{
+ device_t *msm5205 = machine().device(MSM5205_TAG);
+
+ if((data & 0x07)!=m_last_playmode)
+ {
+ m_last_playmode=(data & 0x07);
+ msm5205_playmode_w(msm5205, m_last_playmode);
+ }
+}
+
+void nimbus_msm5205_vck(device_t *device)
+{
+ rmnimbus_state *state = device->machine().driver_data<rmnimbus_state>();
+ if(state->m_iou_reg092 & MSM5205_INT_ENABLE)
+ external_int(device->machine(),0,EXTERNAL_INT_MSM5205);
+}
+
+static const int MOUSE_XYA[3][4] = { { 0, 0, 0, 0 }, { 1, 1, 0, 0 }, { 0, 1, 1, 0 } };
+static const int MOUSE_XYB[3][4] = { { 0, 0, 0, 0 }, { 0, 1, 1, 0 }, { 1, 1, 0, 0 } };
+//static const int MOUSE_XYA[4] = { 1, 1, 0, 0 };
+//static const int MOUSE_XYB[4] = { 0, 1, 1, 0 };
+
+static void mouse_js_reset(running_machine &machine)
+{
+ rmnimbus_state *drvstate = machine.driver_data<rmnimbus_state>();
+ _mouse_joy_state *state = &drvstate->m_nimbus_mouse;
+
+ state->m_mouse_px=0;
+ state->m_mouse_py=0;
+ state->m_mouse_x=128;
+ state->m_mouse_y=128;
+ state->m_mouse_pc=0;
+ state->m_mouse_pcx=0;
+ state->m_mouse_pcy=0;
+ state->m_intstate_x=0;
+ state->m_intstate_y=0;
+ state->m_reg0a4=0xC0;
+
+ // Setup timer to poll the mouse
+ state->m_mouse_timer->adjust(attotime::zero, 0, attotime::from_hz(1000));
+}
+
+static TIMER_CALLBACK(mouse_callback)
+{
+ rmnimbus_state *drvstate = machine.driver_data<rmnimbus_state>();
+ UINT8 x = 0;
+ UINT8 y = 0;
+// int pc=cpu_get_pc(machine.device(MAINCPU_TAG));
+
+ UINT8 intstate_x;
+ UINT8 intstate_y;
+ int xint;
+ int yint;
+
+ _mouse_joy_state *state = &drvstate->m_nimbus_mouse;
+
+
+ state->m_reg0a4 = machine.root_device().ioport(MOUSE_BUTTON_TAG)->read() | 0xC0;
+ x = machine.root_device().ioport(MOUSEX_TAG)->read();
+ y = machine.root_device().ioport(MOUSEY_TAG)->read();
+
+ UINT8 mxa;
+ UINT8 mxb;
+ UINT8 mya;
+ UINT8 myb;
+
+ //logerror("poll_mouse()\n");
+
+ if (x == state->m_mouse_x)
+ {
+ state->m_mouse_px = MOUSE_PHASE_STATIC;
+ }
+ else if (x > state->m_mouse_x)
+ {
+ state->m_mouse_px = MOUSE_PHASE_POSITIVE;
+ }
+ else if (x < state->m_mouse_x)
+ {
+ state->m_mouse_px = MOUSE_PHASE_NEGATIVE;
+ }
+
+ if (y == state->m_mouse_y)
+ {
+ state->m_mouse_py = MOUSE_PHASE_STATIC;
+ }
+ else if (y > state->m_mouse_y)
+ {
+ state->m_mouse_py = MOUSE_PHASE_POSITIVE;
+ }
+ else if (y < state->m_mouse_y)
+ {
+ state->m_mouse_py = MOUSE_PHASE_NEGATIVE;
+ }
+
+ switch (state->m_mouse_px)
+ {
+ case MOUSE_PHASE_STATIC : break;
+ case MOUSE_PHASE_POSITIVE : state->m_mouse_pcx++; break;
+ case MOUSE_PHASE_NEGATIVE : state->m_mouse_pcx--; break;
+ }
+ state->m_mouse_pcx &= 0x03;
+
+ switch (state->m_mouse_py)
+ {
+ case MOUSE_PHASE_STATIC : break;
+ case MOUSE_PHASE_POSITIVE : state->m_mouse_pcy++; break;
+ case MOUSE_PHASE_NEGATIVE : state->m_mouse_pcy--; break;
+ }
+ state->m_mouse_pcy &= 0x03;
+
+// mxb = MOUSE_XYB[state->m_mouse_px][state->m_mouse_pcx]; // XB
+// mxa = MOUSE_XYA[state->m_mouse_px][state->m_mouse_pcx]; // XA
+// mya = MOUSE_XYA[state->m_mouse_py][state->m_mouse_pcy]; // YA
+// myb = MOUSE_XYB[state->m_mouse_py][state->m_mouse_pcy]; // YB
+
+ mxb = MOUSE_XYB[1][state->m_mouse_pcx]; // XB
+ mxa = MOUSE_XYA[1][state->m_mouse_pcx]; // XA
+ mya = MOUSE_XYA[1][state->m_mouse_pcy]; // YA
+ myb = MOUSE_XYB[1][state->m_mouse_pcy]; // YB
+
+ if ((state->m_mouse_py!=MOUSE_PHASE_STATIC) || (state->m_mouse_px!=MOUSE_PHASE_STATIC))
+ {
+// logerror("mouse_px=%02X, mouse_py=%02X, mouse_pcx=%02X, mouse_pcy=%02X\n",
+// state->m_mouse_px,state->m_mouse_py,state->m_mouse_pcx,state->m_mouse_pcy);
+
+// logerror("mxb=%02x, mxa=%02X (mxb ^ mxa)=%02X, (ay8910_a & 0xC0)=%02X, (mxb ^ mxa) ^ ((ay8910_a & 0x80) >> 7)=%02X\n",
+// mxb,mxa, (mxb ^ mxa) , (state->m_ay8910_a & 0xC0), (mxb ^ mxa) ^ ((state->m_ay8910_a & 0x40) >> 6));
+ }
+
+ intstate_x = (mxb ^ mxa) ^ ((drvstate->m_ay8910_a & 0x40) >> 6);
+ intstate_y = (myb ^ mya) ^ ((drvstate->m_ay8910_a & 0x80) >> 7);
+
+ if (MOUSE_INT_ENABLED(drvstate))
+ {
+ if ((intstate_x==1) && (state->m_intstate_x==0))
+// if (intstate_x!=state->m_intstate_x)
+ {
+
+ xint=mxa ? EXTERNAL_INT_MOUSE_XR : EXTERNAL_INT_MOUSE_XL;
+
+ external_int(machine,0,xint);
+
+// logerror("Xint:%02X, mxb=%02X\n",xint,mxb);
+ }
+
+ if ((intstate_y==1) && (state->m_intstate_y==0))
+// if (intstate_y!=state->m_intstate_y)
+ {
+ yint=myb ? EXTERNAL_INT_MOUSE_YU : EXTERNAL_INT_MOUSE_YD;
+
+ external_int(machine,0,yint);
+// logerror("Yint:%02X, myb=%02X\n",yint,myb);
+ }
+ }
+ else
+ {
+ state->m_reg0a4 &= 0xF0;
+ state->m_reg0a4 |= ( mxb & 0x01) << 3; // XB
+ state->m_reg0a4 |= (~mxb & 0x01) << 2; // XA
+ state->m_reg0a4 |= (~myb & 0x01) << 1; // YA
+ state->m_reg0a4 |= ( myb & 0x01) << 0; // YB
+ }
+
+ state->m_mouse_x = x;
+ state->m_mouse_y = y;
+
+ if ((state->m_mouse_py!=MOUSE_PHASE_STATIC) || (state->m_mouse_px!=MOUSE_PHASE_STATIC))
+ {
+// logerror("pc=%05X, reg0a4=%02X, reg092=%02X, ay_a=%02X, x=%02X, y=%02X, px=%02X, py=%02X, intstate_x=%02X, intstate_y=%02X\n",
+// pc,state->m_reg0a4,state->m_iou_reg092,state->m_ay8910_a,state->m_mouse_x,state->m_mouse_y,state->m_mouse_px,state->m_mouse_py,intstate_x,intstate_y);
+ }
+
+ state->m_intstate_x=intstate_x;
+ state->m_intstate_y=intstate_y;
+}
+
+READ8_MEMBER(rmnimbus_state::nimbus_mouse_js_r)
+{
+ /*
+
+ bit description
+
+ 0 JOY 0-Up or mouse XB
+ 1 JOY 0-Down or mouse XA
+ 2 JOY 0-Left or mouse YA
+ 3 JOY 0-Right or mouse YB
+ 4 JOY 0-b0 or mouse rbutton
+ 5 JOY 0-b1 or mouse lbutton
+ 6 ?? always reads 1
+ 7 ?? always reads 1
+
+ */
+ UINT8 result;
+ //int pc=cpu_get_pc(machine().device(MAINCPU_TAG));
+ _mouse_joy_state *state = &m_nimbus_mouse;
+
+ if (ioport("config")->read() & 0x01)
+ {
+ result=state->m_reg0a4;
+ //logerror("mouse_js_r: pc=%05X, result=%02X\n",pc,result);
+ }
+ else
+ {
+ result=ioport(JOYSTICK0_TAG)->read_safe(0xff);
+ }
+
+ return result;
+}
+
+WRITE8_MEMBER(rmnimbus_state::nimbus_mouse_js_w)
+{
+}
+
+/**********************************************************************
+Paralell printer / User port.
+The Nimbus paralell printer port card is almost identical to the circuit
+in the BBC micro, so I have borrowed the driver code from the BBC :)
+
+Port A output is buffered before being connected to the printer connector.
+This means that they can only be operated as output lines.
+CA1 is pulled high by a 4K7 resistor. CA1 normally acts as an acknowledge
+line when a printer is used. CA2 is buffered so that it has become an open
+collector output only. It usially acts as the printer strobe line.
+***********************************************************************/
+
+/* USER VIA 6522 port B is connected to the BBC user port */
+static READ8_DEVICE_HANDLER( nimbus_via_read_portb )
+{
+ return 0xff;
+}
+
+static WRITE8_DEVICE_HANDLER( nimbus_via_write_portb )
+{
+}
+
+static WRITE_LINE_DEVICE_HANDLER( nimbus_via_irq_w )
+{
+ if(state)
+ external_int(device->machine(),VIA_INT,0x00);
+}
+
+const via6522_interface nimbus_via =
+{
+ DEVCB_NULL, //via_user_read_porta,
+ DEVCB_HANDLER(nimbus_via_read_portb),
+ DEVCB_NULL, //via_user_read_ca1,
+ DEVCB_NULL, //via_user_read_cb1,
+ DEVCB_NULL, //via_user_read_ca2,
+ DEVCB_NULL, //via_user_read_cb2,
+ DEVCB_DEVICE_MEMBER(CENTRONICS_TAG, centronics_device, write),
+ DEVCB_HANDLER(nimbus_via_write_portb),
+ DEVCB_NULL, //via_user_write_ca1
+ DEVCB_NULL, //via_user_write_cb1
+ DEVCB_DEVICE_LINE_MEMBER(CENTRONICS_TAG, centronics_device, strobe_w),
+ DEVCB_NULL, //via_user_write_cb2,
+ DEVCB_LINE(nimbus_via_irq_w)
+};
+
+WRITE_LINE_DEVICE_HANDLER(nimbus_ack_w)
+{
+ via6522_device *via_1 = device->machine().device<via6522_device>(VIA_TAG);
+ via_1->write_ca1(!state); /* ack seems to be inverted? */
+}
+
diff --git a/src/mess/machine/rx01.c b/src/mess/machine/rx01.c
new file mode 100644
index 00000000000..940e3c977bb
--- /dev/null
+++ b/src/mess/machine/rx01.c
@@ -0,0 +1,263 @@
+/**********************************************************************
+
+ DEC RX01 floppy drive controller
+
+**********************************************************************/
+
+/*
+
+ TODO:
+ - Create also unibus and qbus devices that contain this controller on them
+*/
+
+#include "emu.h"
+#include "machine/rx01.h"
+#include "imagedev/flopdrv.h"
+#include "formats/basicdsk.h"
+
+static LEGACY_FLOPPY_OPTIONS_START( rx01 )
+ LEGACY_FLOPPY_OPTION(rx01, "img", "RX01 image", basicdsk_identify_default, basicdsk_construct_default, NULL,
+ HEADS([1])
+ TRACKS([77])
+ SECTORS([26])
+ SECTOR_LENGTH([128])
+ FIRST_SECTOR_ID([1]))
+LEGACY_FLOPPY_OPTIONS_END
+
+
+static const floppy_interface rx01_floppy_interface =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ FLOPPY_STANDARD_8_SSSD,
+ LEGACY_FLOPPY_OPTIONS_NAME(rx01),
+ "floppy_8",
+ NULL
+};
+
+
+MACHINE_CONFIG_FRAGMENT( rx01 )
+ MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(rx01_floppy_interface)
+MACHINE_CONFIG_END
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type RX01 = &device_creator<rx01_device>;
+
+//-------------------------------------------------
+// rx01_device - constructor
+//-------------------------------------------------
+
+rx01_device::rx01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, RX01, "RX01", tag, owner, clock)
+{
+}
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor rx01_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( rx01 );
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void rx01_device::device_start()
+{
+ m_image[0] = subdevice(FLOPPY_0);
+ m_image[1] = subdevice(FLOPPY_1);
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void rx01_device::device_reset()
+{
+ for(int i=0;i<2;i++)
+ {
+ floppy_mon_w(m_image[i], 0); // turn it on
+ floppy_drive_set_controller(m_image[i], this);
+ floppy_drive_set_rpm(m_image[i], 360.);
+ }
+}
+
+//-------------------------------------------------
+// read
+//-------------------------------------------------
+
+READ16_MEMBER( rx01_device::read )
+{
+ switch(offset & 1) {
+ case 0: return status_read(); break;
+ default: return data_read(); break;
+ }
+
+}
+
+
+//-------------------------------------------------
+// write
+//-------------------------------------------------
+
+WRITE16_MEMBER( rx01_device::write )
+{
+ switch(offset & 1) {
+ case 0: command_write(data); break;
+ case 1: data_write(data); break;
+ }
+}
+
+void rx01_device::command_write(UINT16 data)
+{
+ printf("command_write %04x\n",data);
+ m_unit = BIT(data,4);
+ m_interrupt = BIT(data,6);
+
+ floppy_drive_set_ready_state(m_image[m_unit], 1,0);
+
+
+ if (BIT(data,14)) // Initialize
+ {
+ printf("initialize\n");
+ m_state = RX01_INIT;
+ }
+ else if (BIT(data,1)) // If GO bit is selected
+ {
+ m_rxcs &= ~(1<<5); // Clear done bit
+ m_buf_pos = 0; // Point to start of buffer
+ switch((data >> 1) & 7) {
+ case 0: // Fill Buffer
+ m_rxcs |= (1<<7); // Set TR Bit
+ m_state = RX01_FILL;
+ break;
+ case 1: // Empty Buffer
+ m_state = RX01_EMPTY;
+ break;
+ case 2: // Write Sector
+ case 3: // Read Sector
+ case 6: // Write Deleted Data Sector
+ m_rxes &= ~(1<<6 | 1<<1 | 1<<0);// Reset bits 0, 1 and 6
+ m_state = RX01_SET_SECTOR;
+ break;
+ case 4: // Not Used
+ m_state = RX01_COMPLETE;
+ break;
+ case 5: // Read Status
+ m_state = RX01_COMPLETE;
+ m_rxdb = m_rxes;
+ break;
+ case 7: // Read Error Register
+ m_state = RX01_COMPLETE;
+ // set ready signal according to current drive status
+ m_rxes |= floppy_drive_get_flag_state(m_image[m_unit], FLOPPY_DRIVE_READY) << 7;
+ break;
+ }
+ }
+ machine().scheduler().timer_set(attotime::from_msec(100), FUNC(command_execution_callback), 0, this);
+}
+
+UINT16 rx01_device::status_read()
+{
+ //printf("status_read %04x\n",m_rxcs);
+ return m_rxcs;
+}
+
+void rx01_device::data_write(UINT16 data)
+{
+ printf("data_write %04x\n",data);
+ // data can be written only if TR is set
+ if (BIT(m_rxcs,7)) m_rxdb = data;
+ machine().scheduler().timer_set(attotime::from_msec(100), FUNC(command_execution_callback), 0, this);
+}
+
+UINT16 rx01_device::data_read()
+{
+ if (m_state==RX01_EMPTY && BIT(m_rxcs,7)) m_rxcs &= (1<<7); // clear TR bit;
+ printf("data_read %04x\n",m_rxdb);
+ return m_rxdb;
+}
+
+void rx01_device::service_command()
+{
+ printf("service_command %d\n",m_state);
+ m_rxes |= floppy_drive_get_flag_state(m_image[m_unit], FLOPPY_DRIVE_READY) << 7;
+ switch(m_state) {
+ case RX01_FILL :
+ m_buffer[m_buf_pos] = m_rxdb & 0xff;
+ m_buf_pos++;
+ if (m_buf_pos<128)
+ {
+ m_rxcs |= (1<<7); // Set TR Bit
+ } else {
+ //finished
+ }
+ break;
+ case RX01_EMPTY :
+ if (m_buf_pos>=128)
+ {
+ //finished
+ } else {
+ m_buffer[m_buf_pos] = m_rxdb & 0xff;
+ m_buf_pos++;
+ m_rxcs |= (1<<7); // Set TR Bit
+ }
+ break;
+ case RX01_SET_SECTOR:
+ m_rxsa = m_rxdb & 0x1f;
+ m_rxcs |= (1<<7); // Set TR Bit
+ m_state = RX01_SET_TRACK;
+ break;
+ case RX01_SET_TRACK:
+ m_rxta = m_rxdb & 0x7f;
+ m_rxcs |= (1<<7); // Set TR Bit
+ m_state = RX01_TRANSFER;
+ position_head();
+ break;
+ case RX01_TRANSFER:
+ break;
+ case RX01_COMPLETE:
+ break;
+ case RX01_INIT:
+ m_rxes |= (1<<2); // Set init done flag
+ m_rxcs |= (1<<5); // Set operation done
+ break;
+ }
+}
+
+void rx01_device::position_head()
+{
+ int cur_track = floppy_drive_get_current_track(m_image[m_unit]);
+ int dir = (cur_track < m_rxta) ? +1 : -1;
+
+ while (m_rxta != cur_track)
+ {
+ cur_track += dir;
+
+ floppy_drive_seek(m_image[m_unit], dir);
+ }
+}
+
+void rx01_device::read_sector()
+{
+ /* read data */
+ floppy_drive_read_sector_data(m_image[m_unit], 0, m_rxsa, (char *)m_buffer, 128);
+}
+
+void rx01_device::write_sector(int ddam)
+{
+ /* write data */
+ floppy_drive_write_sector_data(m_image[m_unit], 0, m_rxsa, (char *)m_buffer, 128, ddam);
+}
+
diff --git a/src/mess/machine/rx01.h b/src/mess/machine/rx01.h
new file mode 100644
index 00000000000..2fcdcb2d48e
--- /dev/null
+++ b/src/mess/machine/rx01.h
@@ -0,0 +1,81 @@
+/**********************************************************************
+
+ DEC RX01 floppy drive controller
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __RX01__
+#define __RX01__
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_RX01_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, RX01, 0)
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> rx01_device
+
+class rx01_device : public device_t
+{
+public:
+ // construction/destruction
+ rx01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ DECLARE_READ16_MEMBER( read );
+ DECLARE_WRITE16_MEMBER( write );
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ void command_write(UINT16 data);
+ UINT16 status_read();
+
+ void data_write(UINT16 data);
+ UINT16 data_read();
+
+ void service_command();
+ static TIMER_CALLBACK( command_execution_callback ) { reinterpret_cast<rx01_device *>(ptr)->service_command(); }
+
+ void position_head();
+ void read_sector();
+ void write_sector(int ddam);
+private:
+ enum rx01_state {
+ RX01_FILL,
+ RX01_EMPTY,
+ RX01_SET_SECTOR,
+ RX01_SET_TRACK,
+ RX01_TRANSFER,
+ RX01_COMPLETE,
+ RX01_INIT
+ };
+
+ device_t *m_image[2];
+ UINT8 m_buffer[128];
+ int m_buf_pos;
+
+ UINT16 m_rxcs; // Command and Status Register
+ UINT16 m_rxdb; // Data Buffer Register
+ UINT16 m_rxta; // RX Track Address
+ UINT16 m_rxsa; // RX Sector Address
+ UINT16 m_rxes; // RX Error and Status
+ int m_unit;
+ int m_interrupt;
+ rx01_state m_state;
+};
+
+// device type definition
+extern const device_type RX01;
+
+#endif
diff --git a/src/mess/machine/s100.c b/src/mess/machine/s100.c
new file mode 100644
index 00000000000..9c5f5cb8aa8
--- /dev/null
+++ b/src/mess/machine/s100.c
@@ -0,0 +1,319 @@
+/**********************************************************************
+
+ S-100 (IEEE-696/1983) bus emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "emu.h"
+#include "emuopts.h"
+#include "machine/s100.h"
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type S100_SLOT = &device_creator<s100_slot_device>;
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// s100_slot_device - constructor
+//-------------------------------------------------
+s100_slot_device::s100_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, S100_SLOT, "S100 slot", tag, owner, clock),
+ device_slot_interface(mconfig, *this)
+{
+}
+
+void s100_slot_device::static_set_s100_slot(device_t &device, const char *tag)
+{
+ s100_slot_device &s100_card = dynamic_cast<s100_slot_device &>(device);
+ s100_card.m_bus_tag = tag;
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void s100_slot_device::device_start()
+{
+ m_bus = machine().device<s100_device>(m_bus_tag);
+ device_s100_card_interface *dev = dynamic_cast<device_s100_card_interface *>(get_card_device());
+ if (dev) m_bus->add_s100_card(dev);
+}
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type S100 = &device_creator<s100_device>;
+
+
+void s100_device::static_set_cputag(device_t &device, const char *tag)
+{
+ s100_device &s100 = downcast<s100_device &>(device);
+ s100.m_cputag = tag;
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void s100_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const s100_bus_interface *intf = reinterpret_cast<const s100_bus_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<s100_bus_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_int_cb, 0, sizeof(m_out_int_cb));
+ memset(&m_out_nmi_cb, 0, sizeof(m_out_nmi_cb));
+ memset(&m_out_vi0_cb, 0, sizeof(m_out_vi0_cb));
+ memset(&m_out_vi1_cb, 0, sizeof(m_out_vi1_cb));
+ memset(&m_out_vi2_cb, 0, sizeof(m_out_vi2_cb));
+ memset(&m_out_vi3_cb, 0, sizeof(m_out_vi3_cb));
+ memset(&m_out_vi4_cb, 0, sizeof(m_out_vi4_cb));
+ memset(&m_out_vi5_cb, 0, sizeof(m_out_vi5_cb));
+ memset(&m_out_vi6_cb, 0, sizeof(m_out_vi6_cb));
+ memset(&m_out_vi7_cb, 0, sizeof(m_out_vi7_cb));
+ memset(&m_out_dma0_cb, 0, sizeof(m_out_dma0_cb));
+ memset(&m_out_dma1_cb, 0, sizeof(m_out_dma1_cb));
+ memset(&m_out_dma2_cb, 0, sizeof(m_out_dma2_cb));
+ memset(&m_out_dma3_cb, 0, sizeof(m_out_dma3_cb));
+ memset(&m_out_rdy_cb, 0, sizeof(m_out_rdy_cb));
+ memset(&m_out_hold_cb, 0, sizeof(m_out_hold_cb));
+ memset(&m_out_error_cb, 0, sizeof(m_out_error_cb));
+ memset(&m_out_terminal_cb, 0, sizeof(m_out_terminal_cb));
+ }
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// s100_device - constructor
+//-------------------------------------------------
+
+s100_device::s100_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, S100, "S100", tag, owner, clock)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void s100_device::device_start()
+{
+ m_maincpu = machine().device(m_cputag);
+
+ // resolve callbacks
+ m_out_int_func.resolve(m_out_int_cb, *this);
+ m_out_nmi_func.resolve(m_out_nmi_cb, *this);
+ m_out_vi0_func.resolve(m_out_vi0_cb, *this);
+ m_out_vi1_func.resolve(m_out_vi1_cb, *this);
+ m_out_vi2_func.resolve(m_out_vi2_cb, *this);
+ m_out_vi3_func.resolve(m_out_vi3_cb, *this);
+ m_out_vi4_func.resolve(m_out_vi4_cb, *this);
+ m_out_vi5_func.resolve(m_out_vi5_cb, *this);
+ m_out_vi6_func.resolve(m_out_vi6_cb, *this);
+ m_out_vi7_func.resolve(m_out_vi7_cb, *this);
+ m_out_dma0_func.resolve(m_out_dma0_cb, *this);
+ m_out_dma1_func.resolve(m_out_dma1_cb, *this);
+ m_out_dma2_func.resolve(m_out_dma2_cb, *this);
+ m_out_dma3_func.resolve(m_out_dma3_cb, *this);
+ m_out_rdy_func.resolve(m_out_rdy_cb, *this);
+ m_out_hold_func.resolve(m_out_hold_cb, *this);
+ m_out_error_func.resolve(m_out_error_cb, *this);
+ m_out_terminal_func.resolve(m_out_terminal_cb, *this);
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void s100_device::device_reset()
+{
+}
+
+
+//-------------------------------------------------
+// add_s100_card - add S100 card
+//-------------------------------------------------
+
+void s100_device::add_s100_card(device_s100_card_interface *card)
+{
+ m_device_list.append(*card);
+}
+
+
+//-------------------------------------------------
+// smemr_r - memory read
+//-------------------------------------------------
+
+READ8_MEMBER( s100_device::smemr_r )
+{
+ UINT8 data = 0;
+
+ device_s100_card_interface *entry = m_device_list.first();
+
+ while (entry)
+ {
+ data |= entry->s100_smemr_r(offset);
+ entry = entry->next();
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// mwrt_w - memory write
+//-------------------------------------------------
+
+WRITE8_MEMBER( s100_device::mwrt_w )
+{
+ device_s100_card_interface *entry = m_device_list.first();
+
+ while (entry)
+ {
+ entry->s100_mwrt_w(offset, data);
+ entry = entry->next();
+ }
+}
+
+
+//-------------------------------------------------
+// sinp_r - I/O read
+//-------------------------------------------------
+
+READ8_MEMBER( s100_device::sinp_r )
+{
+ UINT8 data = 0;
+
+ device_s100_card_interface *entry = m_device_list.first();
+
+ while (entry)
+ {
+ data |= entry->s100_sinp_r(offset);
+ entry = entry->next();
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// sout_w - I/O write
+//-------------------------------------------------
+
+WRITE8_MEMBER( s100_device::sout_w )
+{
+ device_s100_card_interface *entry = m_device_list.first();
+
+ while (entry)
+ {
+ entry->s100_sout_w(offset, data);
+ entry = entry->next();
+ }
+}
+
+
+WRITE_LINE_MEMBER( s100_device::int_w ) { m_out_nmi_func(state); }
+WRITE_LINE_MEMBER( s100_device::nmi_w ) { m_out_nmi_func(state); }
+WRITE_LINE_MEMBER( s100_device::vi0_w ) { m_out_vi0_func(state); }
+WRITE_LINE_MEMBER( s100_device::vi1_w ) { m_out_vi1_func(state); }
+WRITE_LINE_MEMBER( s100_device::vi2_w ) { m_out_vi2_func(state); }
+WRITE_LINE_MEMBER( s100_device::vi3_w ) { m_out_vi3_func(state); }
+WRITE_LINE_MEMBER( s100_device::vi4_w ) { m_out_vi4_func(state); }
+WRITE_LINE_MEMBER( s100_device::vi5_w ) { m_out_vi5_func(state); }
+WRITE_LINE_MEMBER( s100_device::vi6_w ) { m_out_vi6_func(state); }
+WRITE_LINE_MEMBER( s100_device::vi7_w ) { m_out_vi7_func(state); }
+WRITE_LINE_MEMBER( s100_device::dma0_w ) { m_out_dma0_func(state); }
+WRITE_LINE_MEMBER( s100_device::dma1_w ) { m_out_dma1_func(state); }
+WRITE_LINE_MEMBER( s100_device::dma2_w ) { m_out_dma2_func(state); }
+WRITE_LINE_MEMBER( s100_device::dma3_w ) { m_out_dma3_func(state); }
+WRITE_LINE_MEMBER( s100_device::rdy_w ) { m_out_rdy_func(state); }
+WRITE_LINE_MEMBER( s100_device::hold_w ) { m_out_hold_func(state); }
+WRITE_LINE_MEMBER( s100_device::error_w ) { m_out_error_func(state); }
+
+
+//-------------------------------------------------
+// terminal_receive_w - receive character
+//-------------------------------------------------
+
+WRITE8_MEMBER( s100_device::terminal_receive_w )
+{
+ device_s100_card_interface *entry = m_device_list.first();
+
+ while (entry)
+ {
+ if (entry->s100_has_terminal())
+ {
+ entry->s100_terminal_w(data);
+ break;
+ }
+ entry = entry->next();
+ }
+}
+
+
+//-------------------------------------------------
+// terminal_transmit_w - transmit character
+//-------------------------------------------------
+
+WRITE8_MEMBER( s100_device::terminal_transmit_w )
+{
+ terminal_transmit_w(data);
+}
+
+void s100_device::terminal_transmit_w(UINT8 data)
+{
+ m_out_terminal_func(0, data);
+}
+
+
+
+//**************************************************************************
+// DEVICE S100 CARD INTERFACE
+//**************************************************************************
+
+//-------------------------------------------------
+// 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)
+{
+}
+
+
+//-------------------------------------------------
+// ~device_s100_card_interface - destructor
+//-------------------------------------------------
+
+device_s100_card_interface::~device_s100_card_interface()
+{
+}
diff --git a/src/mess/machine/s100.h b/src/mess/machine/s100.h
new file mode 100644
index 00000000000..d16d2fe3d9a
--- /dev/null
+++ b/src/mess/machine/s100.h
@@ -0,0 +1,297 @@
+/**********************************************************************
+
+ S-100 (IEEE Std 696-1983) bus emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+
+ +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(_cpu_tag, _config) \
+ MCFG_DEVICE_ADD(S100_TAG, S100, 0) \
+ MCFG_DEVICE_CONFIG(_config) \
+ s100_device::static_set_cputag(*device, _cpu_tag); \
+
+
+#define S100_INTERFACE(_name) \
+ const s100_bus_interface (_name) =
+
+
+#define MCFG_S100_SLOT_ADD(_tag, _slot_intf, _def_slot, _def_inp) \
+ MCFG_DEVICE_ADD(_tag, S100_SLOT, 0) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false) \
+ s100_slot_device::static_set_s100_slot(*device, S100_TAG); \
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> s100_slot_device
+
+class s100_device;
+
+class s100_slot_device : public device_t,
+ public device_slot_interface
+{
+public:
+ // construction/destruction
+ s100_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_s100_slot(device_t &device, const char *tag);
+
+private:
+ // configuration
+ const char *m_bus_tag;
+ s100_device *m_bus;
+};
+
+
+// device type definition
+extern const device_type S100_SLOT;
+
+
+// ======================> s100_bus_interface
+
+struct s100_bus_interface
+{
+ devcb_write_line m_out_int_cb;
+ devcb_write_line m_out_nmi_cb;
+ devcb_write_line m_out_vi0_cb;
+ devcb_write_line m_out_vi1_cb;
+ devcb_write_line m_out_vi2_cb;
+ devcb_write_line m_out_vi3_cb;
+ devcb_write_line m_out_vi4_cb;
+ devcb_write_line m_out_vi5_cb;
+ devcb_write_line m_out_vi6_cb;
+ devcb_write_line m_out_vi7_cb;
+ devcb_write_line m_out_dma0_cb;
+ devcb_write_line m_out_dma1_cb;
+ devcb_write_line m_out_dma2_cb;
+ devcb_write_line m_out_dma3_cb;
+ devcb_write_line m_out_rdy_cb;
+ devcb_write_line m_out_hold_cb;
+ devcb_write_line m_out_error_cb;
+ devcb_write8 m_out_terminal_cb;
+};
+
+class device_s100_card_interface;
+
+
+// ======================> s100_device
+
+class s100_device : public device_t,
+ public s100_bus_interface
+{
+public:
+ // construction/destruction
+ s100_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ // inline configuration
+ static void static_set_cputag(device_t &device, const char *tag);
+
+ void add_s100_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( int_w );
+ DECLARE_WRITE_LINE_MEMBER( nmi_w );
+ DECLARE_WRITE_LINE_MEMBER( vi0_w );
+ DECLARE_WRITE_LINE_MEMBER( vi1_w );
+ DECLARE_WRITE_LINE_MEMBER( vi2_w );
+ DECLARE_WRITE_LINE_MEMBER( vi3_w );
+ DECLARE_WRITE_LINE_MEMBER( vi4_w );
+ DECLARE_WRITE_LINE_MEMBER( vi5_w );
+ DECLARE_WRITE_LINE_MEMBER( vi6_w );
+ DECLARE_WRITE_LINE_MEMBER( vi7_w );
+ DECLARE_WRITE_LINE_MEMBER( dma0_w );
+ DECLARE_WRITE_LINE_MEMBER( dma1_w );
+ DECLARE_WRITE_LINE_MEMBER( dma2_w );
+ DECLARE_WRITE_LINE_MEMBER( dma3_w );
+ DECLARE_WRITE_LINE_MEMBER( rdy_w );
+ DECLARE_WRITE_LINE_MEMBER( hold_w );
+ DECLARE_WRITE_LINE_MEMBER( error_w );
+
+ DECLARE_WRITE8_MEMBER( terminal_receive_w );
+ DECLARE_WRITE8_MEMBER( terminal_transmit_w );
+ void terminal_transmit_w(UINT8 data);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete();
+
+private:
+ // internal state
+ device_t *m_maincpu;
+
+ devcb_resolved_write_line m_out_int_func;
+ devcb_resolved_write_line m_out_nmi_func;
+ devcb_resolved_write_line m_out_vi0_func;
+ devcb_resolved_write_line m_out_vi1_func;
+ devcb_resolved_write_line m_out_vi2_func;
+ devcb_resolved_write_line m_out_vi3_func;
+ devcb_resolved_write_line m_out_vi4_func;
+ devcb_resolved_write_line m_out_vi5_func;
+ devcb_resolved_write_line m_out_vi6_func;
+ devcb_resolved_write_line m_out_vi7_func;
+ devcb_resolved_write_line m_out_dma0_func;
+ devcb_resolved_write_line m_out_dma1_func;
+ devcb_resolved_write_line m_out_dma2_func;
+ devcb_resolved_write_line m_out_dma3_func;
+ devcb_resolved_write_line m_out_rdy_func;
+ devcb_resolved_write_line m_out_hold_func;
+ devcb_resolved_write_line m_out_error_func;
+ devcb_resolved_write8 m_out_terminal_func;
+
+ simple_list<device_s100_card_interface> m_device_list;
+ const char *m_cputag;
+};
+
+
+// device type definition
+extern const device_type S100;
+
+
+// ======================> device_s100_card_interface
+
+// class representing interface-specific live s100 card
+class device_s100_card_interface : public device_slot_card_interface
+{
+ friend class s100_device;
+
+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(offs_t offset) { return 0; };
+ virtual void s100_mwrt_w(offs_t offset, UINT8 data) { };
+
+ // I/O access
+ virtual UINT8 s100_sinp_r(offs_t offset) { return 0; };
+ virtual void s100_sout_w(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; }
+
+ // terminal
+ virtual bool s100_has_terminal() { return false; }
+ virtual void s100_terminal_w(UINT8 data) { }
+
+ // 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_device *m_s100;
+ device_s100_card_interface *m_next;
+};
+
+#endif
diff --git a/src/mess/machine/s100_dj2db.c b/src/mess/machine/s100_dj2db.c
new file mode 100644
index 00000000000..abe840fafcc
--- /dev/null
+++ b/src/mess/machine/s100_dj2db.c
@@ -0,0 +1,517 @@
+/**********************************************************************
+
+ Morrow Designs Disk Jockey 2D/B floppy controller board emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ TODO:
+
+ - stall logic (read from fdc data register halts CPU until intrq/drq from FDC)
+
+*/
+
+#include "s100_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<s100_dj2db_device>;
+
+
+//-------------------------------------------------
+// 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 )
+//-------------------------------------------------
+
+static COM8116_INTERFACE( brg_intf )
+{
+ DEVCB_NULL,
+ DEVCB_NULL, // S1602 RRC/TRC
+ DEVCB_NULL,
+ { 6336, 4224, 2880, 2355, 2112, 1056, 528, 264, 176, 158, 132, 88, 66, 44, 33, 16 }, // from WD1943-00 datasheet
+ { 6336, 4224, 2880, 2355, 2112, 1056, 528, 264, 176, 158, 132, 88, 66, 44, 33, 16 },
+};
+
+
+//-------------------------------------------------
+// wd17xx_interface fdc_intf
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( s100_dj2db_device::fdc_intrq_w )
+{
+ if (state) m_s100->rdy_w(CLEAR_LINE);
+
+ switch (ioport("J1A")->read())
+ {
+ case 0: m_s100->vi0_w(state); break;
+ case 1: m_s100->vi1_w(state); break;
+ case 2: m_s100->vi2_w(state); break;
+ case 3: m_s100->vi3_w(state); break;
+ case 4: m_s100->vi4_w(state); break;
+ case 5: m_s100->vi5_w(state); break;
+ case 6: m_s100->vi6_w(state); break;
+ case 7: m_s100->vi7_w(state); break;
+ case 8: m_s100->int_w(state); break;
+ }
+}
+
+WRITE_LINE_MEMBER( s100_dj2db_device::fdc_drq_w )
+{
+ if (state) m_s100->rdy_w(CLEAR_LINE);
+}
+
+static const wd17xx_interface fdc_intf =
+{
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, s100_dj2db_device, fdc_intrq_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, s100_dj2db_device, fdc_drq_w),
+ { FLOPPY_0, FLOPPY_1, NULL, NULL }
+};
+
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( s100_dj2db )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( s100_dj2db )
+ MCFG_COM8116_ADD(BR1941_TAG, XTAL_5_0688MHz, brg_intf)
+ MCFG_MB8866_ADD(MB8866_TAG, fdc_intf)
+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),
+ device_s100_card_interface(mconfig, *this),
+ m_fdc(*this, MB8866_TAG),
+ m_dbrg(*this, BR1941_TAG),
+ 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()
+{
+ m_s100 = machine().device<s100_device>("s100");
+
+ m_rom = memregion("dj2db")->base();
+ m_ram = auto_alloc_array(machine(), UINT8, 0x400);
+
+ // find floppy devices
+ m_floppy0 = machine().device(FLOPPY_0);
+ m_floppy1 = machine().device(FLOPPY_1);
+
+ // state saving
+ //save_item(NAME());
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void s100_dj2db_device::device_reset()
+{
+ m_board_enbl = ioport("J4")->read();
+}
+
+
+//-------------------------------------------------
+// s100_smemr_r - memory read
+//-------------------------------------------------
+
+UINT8 s100_dj2db_device::s100_smemr_r(offs_t offset)
+{
+ UINT8 data = 0;
+
+// if (!(m_board_enbl & m_phantom)) return 0;
+
+ if ((offset >= 0xf800) && (offset < 0xfbf8))
+ {
+ data = m_rom[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 |= !wd17xx_drq_r(m_fdc) << 1;
+ data |= !wd17xx_intrq_r(m_fdc) << 2;
+
+ device_t *floppy = m_drive ? m_floppy1 : m_floppy0;
+ data |= floppy_twosid_r(floppy) << 3;
+ data |= floppy_index_r(floppy) << 4;
+ data |= floppy_ready_r(floppy) << 7;
+ }
+ else if ((offset >= 0xfbfc) && (offset < 0xfc00))
+ {
+ m_s100->rdy_w(ASSERT_LINE);
+
+ data = wd17xx_r(m_fdc, 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(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
+ if (BIT(data, 0)) m_drive = 0;
+ if (BIT(data, 1)) m_drive = 1;
+ //if (BIT(data, 2)) m_drive = 2;
+ //if (BIT(data, 3)) m_drive = 3;
+ wd17xx_set_drive(m_fdc, m_drive);
+ floppy_mon_w(m_floppy0, CLEAR_LINE);
+ floppy_mon_w(m_floppy1, CLEAR_LINE);
+
+ // side select
+ wd17xx_set_side(m_fdc, BIT(data, 4));
+
+ // interrupt enable
+ m_int_enbl = BIT(data, 5);
+
+ // access enable
+ m_access_enbl = BIT(data, 6);
+
+ // master reset
+ wd17xx_mr_w(m_fdc, BIT(data, 7));
+ }
+ else if (offset == 0xfbfa) // FUNCTION SEL
+ {
+ /*
+
+ bit description
+
+ 0 DOUBLE
+ 1 8A SET
+ 2 8A CLEAR
+ 3 LEDOFF
+ 4
+ 5
+ 6
+ 7
+
+ */
+
+ // density select
+ wd17xx_dden_w(m_fdc, BIT(data, 0));
+ }
+ else if (offset == 0xfbfb) // WAIT ENBL
+ {
+ }
+ else if ((offset >= 0xfbfc) && (offset < 0xfc00))
+ {
+ wd17xx_w(m_fdc, 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(offs_t offset)
+{
+ return 0;
+}
+
+
+//-------------------------------------------------
+// s100_sout_w - I/O write
+//-------------------------------------------------
+
+void s100_dj2db_device::s100_sout_w(offs_t offset, UINT8 data)
+{
+ if (offset == 0x41)
+ {
+ m_board_enbl = (data & ioport("J3A")->read()) ? 1 : 0;
+ }
+}
+
+
+//-------------------------------------------------
+// s100_phantom_w - phantom
+//-------------------------------------------------
+
+void s100_dj2db_device::s100_phantom_w(int state)
+{
+ if (!BIT(ioport("SW1")->read(), 2))
+ {
+ m_phantom = state;
+ }
+ else
+ {
+ m_phantom = 1;
+ }
+}
+
+
+//-------------------------------------------------
+// s100_terminal_w - terminal write
+//-------------------------------------------------
+
+void s100_dj2db_device::s100_terminal_w(UINT8 data)
+{
+}
diff --git a/src/mess/machine/s100_dj2db.h b/src/mess/machine/s100_dj2db.h
new file mode 100644
index 00000000000..eef58252923
--- /dev/null
+++ b/src/mess/machine/s100_dj2db.h
@@ -0,0 +1,87 @@
+/**********************************************************************
+
+ Morrow Designs Disk Jockey 2D/B floppy controller board emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __S100_DJ2DB__
+#define __S100_DJ2DB__
+
+
+#include "emu.h"
+#include "formats/basicdsk.h"
+#include "imagedev/flopdrv.h"
+#include "machine/s100.h"
+#include "machine/com8116.h"
+#include "machine/wd17xx.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( fdc_intrq_w );
+ DECLARE_WRITE_LINE_MEMBER( fdc_drq_w );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "dj2db"; }
+
+ // device_s100_card_interface overrides
+ virtual UINT8 s100_smemr_r(offs_t offset);
+ virtual void s100_mwrt_w(offs_t offset, UINT8 data);
+ virtual UINT8 s100_sinp_r(offs_t offset);
+ virtual void s100_sout_w(offs_t offset, UINT8 data);
+ virtual void s100_phantom_w(int state);
+ virtual bool s100_has_terminal() { return true; }
+ virtual void s100_terminal_w(UINT8 data);
+
+private:
+ // internal state
+ required_device<device_t> m_fdc;
+ required_device<com8116_device> m_dbrg;
+ device_t* m_floppy0;
+ device_t* m_floppy1;
+
+ // floppy state
+ int m_drive; // selected drive
+ int m_head; // head loaded
+ int m_int_enbl; // interrupt enable
+
+ // S-100 bus state
+ UINT8 *m_rom; // ROM
+ UINT8 *m_ram; // RAM
+ 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/mess/machine/s100_djdma.c b/src/mess/machine/s100_djdma.c
new file mode 100644
index 00000000000..31a6cbadebc
--- /dev/null
+++ b/src/mess/machine/s100_djdma.c
@@ -0,0 +1,129 @@
+/**********************************************************************
+
+ Morrow Designs Disk Jockey/DMA floppy controller board emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "s100_djdma.h"
+
+
+
+//**************************************************************************
+// MACROS/CONSTANTS
+//**************************************************************************
+
+#define Z80_TAG "14a"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type S100_DJDMA = &device_creator<s100_djdma_device>;
+
+
+//-------------------------------------------------
+// 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),
+ device_s100_card_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void s100_djdma_device::device_start()
+{
+ m_s100 = machine().device<s100_device>("s100");
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void s100_djdma_device::device_reset()
+{
+}
diff --git a/src/mess/machine/s100_djdma.h b/src/mess/machine/s100_djdma.h
new file mode 100644
index 00000000000..6ccd3119957
--- /dev/null
+++ b/src/mess/machine/s100_djdma.h
@@ -0,0 +1,54 @@
+/**********************************************************************
+
+ Morrow Designs Disk Jockey/DMA floppy controller board emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __S100_DJDMA__
+#define __S100_DJDMA__
+
+
+#include "emu.h"
+#include "cpu/z80/z80.h"
+#include "machine/s100.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();
+ virtual void device_config_complete() { m_shortname = "djdma"; }
+
+private:
+ // internal state
+};
+
+
+// device type definition
+extern const device_type S100_DJDMA;
+
+
+#endif
diff --git a/src/mess/machine/s100_mm65k16s.c b/src/mess/machine/s100_mm65k16s.c
new file mode 100644
index 00000000000..45787e161ae
--- /dev/null
+++ b/src/mess/machine/s100_mm65k16s.c
@@ -0,0 +1,269 @@
+/**********************************************************************
+
+ Morrow Designs MM65K16S memory board emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "s100_mm65k16s.h"
+
+
+
+//**************************************************************************
+// MACROS/CONSTANTS
+//**************************************************************************
+
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type S100_MM65K16S = &device_creator<s100_mm65k16s_device>;
+
+
+//-------------------------------------------------
+// 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),
+ device_s100_card_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void s100_mm65k16s_device::device_start()
+{
+ m_s100 = machine().device<s100_device>("s100");
+
+ m_ram = auto_alloc_array_clear(machine(), UINT8, 0x10000);
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void s100_mm65k16s_device::device_reset()
+{
+}
+
+
+//-------------------------------------------------
+// s100_smemr_r - memory read
+//-------------------------------------------------
+
+UINT8 s100_mm65k16s_device::s100_smemr_r(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(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/mess/machine/s100_mm65k16s.h b/src/mess/machine/s100_mm65k16s.h
new file mode 100644
index 00000000000..7632c603846
--- /dev/null
+++ b/src/mess/machine/s100_mm65k16s.h
@@ -0,0 +1,58 @@
+/**********************************************************************
+
+ Morrow Designs MM65K16S memory board emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __S100_MM65K16S__
+#define __S100_MM65K16S__
+
+#include "emu.h"
+#include "machine/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();
+ virtual void device_config_complete() { m_shortname = "mm65k16s"; }
+
+ // device_s100_card_interface overrides
+ virtual UINT8 s100_smemr_r(offs_t offset);
+ virtual void s100_mwrt_w(offs_t offset, UINT8 data);
+ virtual void s100_phantom_w(int state);
+
+private:
+ // internal state
+ UINT8* m_ram;
+};
+
+
+// device type definition
+extern const device_type S100_MM65K16S;
+
+
+#endif
diff --git a/src/mess/machine/s100_wunderbus.c b/src/mess/machine/s100_wunderbus.c
new file mode 100644
index 00000000000..1850b5dea6f
--- /dev/null
+++ b/src/mess/machine/s100_wunderbus.c
@@ -0,0 +1,554 @@
+/**********************************************************************
+
+ Morrow Designs Wunderbus I/O card emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "s100_wunderbus.h"
+
+
+
+//**************************************************************************
+// MACROS/CONSTANTS
+//**************************************************************************
+
+#define I8259A_TAG "13b"
+#define INS8250_1_TAG "6d"
+#define INS8250_2_TAG "5d"
+#define INS8250_3_TAG "4d"
+#define UPD1990C_TAG "12a"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type S100_WUNDERBUS = &device_creator<s100_wunderbus_device>;
+
+
+//-------------------------------------------------
+// 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_s100->int_w(state);
+}
+
+static struct pic8259_interface pic_intf =
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, s100_wunderbus_device, pic_int_w),
+ DEVCB_LINE_VCC,
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// ins8250_interface ace1_intf
+//-------------------------------------------------
+/*
+static INS8250_TRANSMIT( ace1_transmit )
+{
+ s100_wunderbus_device *wunderbus = downcast<s100_wunderbus_device *>(device->owner());
+
+ wunderbus->m_s100->terminal_transmit_w(data);
+}
+*/
+//-------------------------------------------------
+// s100_terminal_w - terminal write
+//-------------------------------------------------
+
+void s100_wunderbus_device::s100_terminal_w(UINT8 data)
+{
+// ins8250_receive(m_ace1, data);
+}
+
+static ins8250_interface ace1_intf =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE(I8259A_TAG, pic8259_ir3_w),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// ins8250_interface ace2_intf
+//-------------------------------------------------
+
+static ins8250_interface ace2_intf =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE(I8259A_TAG, pic8259_ir4_w),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// ins8250_interface ace3_intf
+//-------------------------------------------------
+
+static ins8250_interface ace3_intf =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE(I8259A_TAG, pic8259_ir5_w),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// UPD1990A_INTERFACE( rtc_intf )
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( s100_wunderbus_device::rtc_tp_w )
+{
+ if (state)
+ {
+ m_rtc_tp = state;
+ pic8259_ir7_w(m_pic, m_rtc_tp);
+ }
+}
+
+static UPD1990A_INTERFACE( rtc_intf )
+{
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, s100_wunderbus_device, rtc_tp_w)
+};
+
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( s100_wunderbus )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( s100_wunderbus )
+ MCFG_PIC8259_ADD(I8259A_TAG, pic_intf)
+ MCFG_INS8250_ADD(INS8250_1_TAG, ace1_intf, XTAL_18_432MHz/10)
+ MCFG_INS8250_ADD(INS8250_2_TAG, ace2_intf, XTAL_18_432MHz/10)
+ MCFG_INS8250_ADD(INS8250_3_TAG, ace3_intf, XTAL_18_432MHz/10)
+ MCFG_UPD1990A_ADD(UPD1990C_TAG, XTAL_32_768kHz, rtc_intf)
+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),
+ 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)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void s100_wunderbus_device::device_start()
+{
+ m_s100 = machine().device<s100_device>("s100");
+}
+
+
+//-------------------------------------------------
+// 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)
+{
+ pic8259_ir0_w(m_pic, state);
+}
+
+
+//-------------------------------------------------
+// s100_vi1_w - vectored interrupt 1
+//-------------------------------------------------
+
+void s100_wunderbus_device::s100_vi1_w(int state)
+{
+ pic8259_ir1_w(m_pic, state);
+}
+
+
+//-------------------------------------------------
+// s100_vi2_w - vectored interrupt 2
+//-------------------------------------------------
+
+void s100_wunderbus_device::s100_vi2_w(int state)
+{
+ pic8259_ir2_w(m_pic, state);
+}
+
+
+//-------------------------------------------------
+// s100_sinp_r - I/O read
+//-------------------------------------------------
+
+UINT8 s100_wunderbus_device::s100_sinp_r(offs_t offset)
+{
+ UINT8 address = (ioport("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(ioport("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;
+ pic8259_ir7_w(m_pic, m_rtc_tp);
+ break;
+
+ case 3: // Parallel data IN
+ break;
+
+ case 4: // 8259 0 register
+ case 5: // 8259 1 register
+ data = pic8259_r(m_pic, offset & 0x01);
+ break;
+
+ case 6: // not used
+ break;
+ }
+ break;
+
+ case 1:
+ data = m_ace1->ins8250_r(*machine().memory().first_space(), offset & 0x07);
+ break;
+
+ case 2:
+ data = m_ace2->ins8250_r(*machine().memory().first_space(), offset & 0x07);
+ break;
+
+ case 3:
+ data = m_ace3->ins8250_r(*machine().memory().first_space(), offset & 0x07);
+ break;
+ }
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// s100_sout_w - I/O write
+//-------------------------------------------------
+
+void s100_wunderbus_device::s100_sout_w(offs_t offset, UINT8 data)
+{
+ UINT8 address = (ioport("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, 0));
+ m_rtc->c0_w(BIT(data, 0));
+ m_rtc->c1_w(BIT(data, 0));
+ m_rtc->c2_w(BIT(data, 0));
+ m_rtc->stb_w(BIT(data, 0));
+ break;
+
+ case 3: // Par. data OUT
+ break;
+
+ case 4: // 8259 0 register
+ case 5: // 8259 1 register
+ pic8259_w(m_pic, 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(*machine().memory().first_space(), offset & 0x07, data);
+ break;
+
+ case 2:
+ m_ace2->ins8250_w(*machine().memory().first_space(), offset & 0x07, data);
+ break;
+
+ case 3:
+ m_ace3->ins8250_w(*machine().memory().first_space(), offset & 0x07, data);
+ break;
+ }
+ }
+}
+
diff --git a/src/mess/machine/s100_wunderbus.h b/src/mess/machine/s100_wunderbus.h
new file mode 100644
index 00000000000..f5689925def
--- /dev/null
+++ b/src/mess/machine/s100_wunderbus.h
@@ -0,0 +1,75 @@
+/**********************************************************************
+
+ Morrow Designs Wunderbus I/O card emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __S100_WUNDERBUS__
+#define __S100_WUNDERBUS__
+
+#include "emu.h"
+#include "machine/ins8250.h"
+#include "machine/pic8259.h"
+#include "machine/s100.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 );
+ required_device<device_t> m_pic;
+ required_device<ins8250_device> m_ace1;
+ required_device<ins8250_device> m_ace2;
+ required_device<ins8250_device> m_ace3;
+ required_device<upd1990a_device> m_rtc;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "s100_wunderbus"; }
+
+ // 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(offs_t offset);
+ virtual void s100_sout_w(offs_t offset, UINT8 data);
+ virtual bool s100_has_terminal() { return true; }
+ virtual void s100_terminal_w(UINT8 data);
+
+private:
+ // internal state
+ UINT8 m_group;
+ int m_rtc_tp;
+};
+
+
+// device type definition
+extern const device_type S100_WUNDERBUS;
+
+
+#endif
diff --git a/src/mess/machine/s1410.c b/src/mess/machine/s1410.c
new file mode 100644
index 00000000000..c25d46a8629
--- /dev/null
+++ b/src/mess/machine/s1410.c
@@ -0,0 +1,227 @@
+/**********************************************************************
+
+ Xebec S1410 5.25" Winchester Disk Controller emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+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 "emu.h"
+#include "s1410.h"
+#include "cpu/z80/z80.h"
+#include "machine/devhelpr.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define Z8400A_TAG "z80"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type S1410 = &device_creator<s1410_device>;
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void s1410_device::device_config_complete()
+{
+ m_shortname = "s1410";
+}
+
+
+//-------------------------------------------------
+// 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()
+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)
+ : device_t(mconfig, S1410, "Xebec S1410", tag, owner, clock)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void s1410_device::device_start()
+{
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void s1410_device::device_reset()
+{
+}
diff --git a/src/mess/machine/s1410.h b/src/mess/machine/s1410.h
new file mode 100644
index 00000000000..d28535f066c
--- /dev/null
+++ b/src/mess/machine/s1410.h
@@ -0,0 +1,73 @@
+/**********************************************************************
+
+ Xebec S1410 5.25" Winchester Disk Controller emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __S1410__
+#define __S1410__
+
+#include "emu.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define S1410_TAG "s1410"
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_S1410_ADD() \
+ MCFG_DEVICE_ADD(S1410_TAG, S1410, 0)
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> s1410_interface
+
+struct s1410_interface
+{
+};
+
+// ======================> s1410_device
+
+class s1410_device : public device_t,
+ public s1410_interface
+{
+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;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete();
+
+private:
+};
+
+
+// device type definition
+extern const device_type S1410;
+
+
+
+#endif
diff --git a/src/mess/machine/s3c44b0.c b/src/mess/machine/s3c44b0.c
new file mode 100644
index 00000000000..2bf609def85
--- /dev/null
+++ b/src/mess/machine/s3c44b0.c
@@ -0,0 +1,2058 @@
+/*******************************************************************************
+
+ 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);
+ }
+}
+
+/*******************************************************************************
+ 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))
+
+/***************************************************************************
+ PROTOTYPES
+***************************************************************************/
+
+static UINT32 s3c44b0_get_mclk( device_t *device);
+
+static void s3c44b0_bdma_request_iis( device_t *device);
+//static void s3c44b0_dma_request_pwm( device_t *device);
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+INLINE s3c44b0_t *get_token( device_t *device)
+{
+ assert(device != NULL);
+ return (s3c44b0_t *)downcast<legacy_device_base *>(device)->token();
+}
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+/* ... */
+
+static void s3c44b0_reset( device_t *device)
+{
+ fatalerror( "s3c44b0_reset\n");
+}
+
+/* LCD Controller */
+
+static rgb_t s3c44b0_get_color_stn_04( device_t *device, UINT8 data)
+{
+ UINT8 r, g, b;
+ r = g = b = BITS( data, 3, 0) << 4;
+ return MAKE_RGB( r, g, b);
+}
+
+static UINT8 s3c44b0_get_color_stn_08_r( device_t *device, UINT8 data)
+{
+ s3c44b0_lcd_t *lcd = &(get_token( device)->lcd);
+ return ((lcd->regs.redlut >> (BITS( data, 7, 5) << 2)) & 0xF) << 4;
+}
+
+static UINT8 s3c44b0_get_color_stn_08_g( device_t *device, UINT8 data)
+{
+ s3c44b0_lcd_t *lcd = &(get_token( device)->lcd);
+ return ((lcd->regs.greenlut >> (BITS( data, 4, 2) << 2)) & 0xF) << 4;
+}
+
+static UINT8 s3c44b0_get_color_stn_08_b( device_t *device, UINT8 data)
+{
+ s3c44b0_lcd_t *lcd = &(get_token( device)->lcd);
+ return ((lcd->regs.bluelut >> (BITS( data, 1, 0) << 2)) & 0xF) << 4;
+}
+
+static void s3c44b0_lcd_dma_reload( device_t *device)
+{
+ s3c44b0_lcd_t *lcd = &(get_token( device)->lcd);
+ int lcdbank, lcdbaseu, lcdbasel;
+ lcdbank = BITS( lcd->regs.lcdsaddr1, 26, 21);
+ lcdbaseu = BITS( lcd->regs.lcdsaddr1, 20, 0);
+ lcdbasel = BITS( lcd->regs.lcdsaddr2, 20, 0);
+ lcd->vramaddr_cur = (lcdbank << 22) | (lcdbaseu << 1);
+ lcd->vramaddr_max = (lcdbank << 22) | (lcdbasel << 1);
+ if (lcdbasel == 0) lcd->vramaddr_max += 1 << 22;
+ lcd->offsize = BITS( lcd->regs.lcdsaddr3, 19, 9);
+ lcd->pagewidth_cur = 0;
+ lcd->pagewidth_max = BITS( lcd->regs.lcdsaddr3, 8, 0);
+ lcd->bswp = BIT( lcd->regs.lcdsaddr2, 29); // note: juicebox changes bswp when video playback starts
+// verboselog( device->machine(), 3, "LCD - vramaddr %08X %08X offsize %08X pagewidth %08X\n", lcd->vramaddr_cur, lcd->vramaddr_max, lcd->offsize, lcd->pagewidth_max);
+}
+
+static void s3c44b0_lcd_dma_init( device_t *device)
+{
+ s3c44b0_lcd_t *lcd = &(get_token( device)->lcd);
+ lcd->modesel = BITS( lcd->regs.lcdsaddr1, 28, 27);
+// verboselog( device->machine(), 3, "LCD - modesel %d bswp %d\n", lcd->modesel, lcd->bswp);
+ s3c44b0_lcd_dma_reload( device);
+}
+
+static void s3c44b0_lcd_dma_read( device_t *device, int count, UINT8 *data)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ s3c44b0_lcd_t *lcd = &s3c44b0->lcd;
+ UINT8 *vram;
+ vram = (UINT8 *)s3c44b0->space->get_read_ptr( lcd->vramaddr_cur);
+ for (int i = 0; i < count / 2; i++)
+ {
+ if (lcd->bswp == 0)
+ {
+ if ((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);
+ }
+ lcd->vramaddr_cur += 2;
+ lcd->pagewidth_cur++;
+ if (lcd->pagewidth_cur >= lcd->pagewidth_max)
+ {
+ lcd->vramaddr_cur += lcd->offsize << 1;
+ if (lcd->vramaddr_cur >= lcd->vramaddr_max)
+ {
+ s3c44b0_lcd_dma_reload( device);
+ }
+ lcd->pagewidth_cur = 0;
+ vram = (UINT8 *)s3c44b0->space->get_read_ptr( lcd->vramaddr_cur);
+ }
+ else
+ {
+ vram += 2;
+ }
+ data += 2;
+ }
+}
+
+static void s3c44b0_lcd_render_stn_04( device_t *device)
+{
+ s3c44b0_lcd_t *lcd = &(get_token( device)->lcd);
+ UINT8 *bitmap = lcd->bitmap + ((lcd->vpos - lcd->vpos_min) * (lcd->hpos_max - lcd->hpos_min + 1)) + (lcd->hpos - lcd->hpos_min);
+ UINT8 data[16];
+ s3c44b0_lcd_dma_read( device, 16, data);
+ for (int i = 0; i < 16; i++)
+ {
+ for (int j = 0; j < 2; j++)
+ {
+ *bitmap++ = s3c44b0_get_color_stn_04( device, (data[i] >> 4) & 0x0F);
+ data[i] = data[i] << 4;
+ lcd->hpos++;
+ if (lcd->hpos >= lcd->hpos_min + (lcd->pagewidth_max << 2))
+ {
+ lcd->vpos++;
+ if (lcd->vpos > lcd->vpos_max)
+ {
+ lcd->vpos = lcd->vpos_min;
+ bitmap = lcd->bitmap;
+ }
+ lcd->hpos = lcd->hpos_min;
+ }
+ }
+ }
+}
+
+static void s3c44b0_lcd_render_stn_08( device_t *device)
+{
+ s3c44b0_lcd_t *lcd = &(get_token( device)->lcd);
+ UINT8 *bitmap = lcd->bitmap + ((lcd->vpos - lcd->vpos_min) * (lcd->hpos_max - lcd->hpos_min + 1)) + (lcd->hpos - lcd->hpos_min);
+ UINT8 data[16];
+ s3c44b0_lcd_dma_read( device, 16, data);
+ for (int i = 0; i < 16; i++)
+ {
+ UINT8 xxx[3];
+ xxx[0] = s3c44b0_get_color_stn_08_r( device, data[i]);
+ xxx[1] = s3c44b0_get_color_stn_08_g( device, data[i]);
+ xxx[2] = s3c44b0_get_color_stn_08_b( device, data[i]);
+ for (int j = 0; j < 3; j++)
+ {
+ *bitmap++ = xxx[j];
+ lcd->hpos++;
+ if (lcd->hpos >= lcd->hpos_min + (lcd->pagewidth_max * 6))
+ {
+ lcd->vpos++;
+ if (lcd->vpos > lcd->vpos_max)
+ {
+ lcd->vpos = lcd->vpos_min;
+ bitmap = lcd->bitmap;
+ }
+ lcd->hpos = lcd->hpos_min;
+ }
+ }
+ }
+}
+
+static attotime s3c44b0_time_until_pos( device_t *device, int vpos, int hpos)
+{
+ running_machine &machine = device->machine();
+ s3c44b0_lcd_t *lcd = (s3c44b0_lcd_t *)&(get_token( device)->lcd);
+ attoseconds_t time1, time2;
+ attotime retval;
+ verboselog( device->machine(), 3, "s3c44b0_time_until_pos - vpos %d hpos %d\n", vpos, hpos);
+ time1 = (attoseconds_t)vpos * lcd->scantime + (attoseconds_t)hpos * lcd->pixeltime;
+ time2 = (machine.time() - lcd->frame_time).as_attoseconds();
+ verboselog( device->machine(), 3, "machine %f frametime %f time1 %f time2 %f\n", machine.time().as_double(), lcd->frame_time.as_double(), attotime( 0, time1).as_double(), attotime( 0, time2).as_double());
+ while (time1 <= time2) time1 += lcd->frame_period;
+ retval = attotime( 0, time1 - time2);
+ verboselog( device->machine(), 3, "result %f\n", retval.as_double());
+ return retval;
+}
+
+static int s3c44b0_lcd_get_vpos( device_t *device)
+{
+ running_machine &machine = device->machine();
+ s3c44b0_lcd_t *lcd = (s3c44b0_lcd_t *)&(get_token( device)->lcd);
+ attoseconds_t delta;
+ int vpos;
+ delta = (machine.time() - lcd->frame_time).as_attoseconds();
+ delta = delta + (lcd->pixeltime / 2);
+ vpos = delta / lcd->scantime;
+ return (lcd->vpos_min + vpos) % lcd->vpos_end;
+}
+
+static int s3c44b0_lcd_get_hpos( device_t *device)
+{
+ running_machine &machine = device->machine();
+ s3c44b0_lcd_t *lcd = (s3c44b0_lcd_t *)&(get_token( device)->lcd);
+ attoseconds_t delta;
+ int vpos;
+ delta = (machine.time() - lcd->frame_time).as_attoseconds();
+ delta = delta + (lcd->pixeltime / 2);
+ vpos = delta / lcd->scantime;
+ delta = delta - (vpos * lcd->scantime);
+ return delta / lcd->pixeltime;
+}
+
+static TIMER_CALLBACK( s3c44b0_lcd_timer_exp )
+{
+ device_t *device = (device_t *)ptr;
+ s3c44b0_lcd_t *lcd = &(get_token( device)->lcd);
+ int vpos = 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", lcd->vramaddr_cur, lcd->vpos, lcd->hpos);
+ switch (lcd->modesel)
+ {
+ case S3C44B0_MODESEL_04 : s3c44b0_lcd_render_stn_04( device); break;
+ case S3C44B0_MODESEL_08 : s3c44b0_lcd_render_stn_08( device); break;
+ default : verboselog( machine, 0, "s3c44b0_lcd_timer_exp: modesel %d not supported\n", lcd->modesel); break;
+ }
+ verboselog( machine, 3, "LCD - (2) vramaddr %08X vpos %d hpos %d\n", lcd->vramaddr_cur, lcd->vpos, lcd->hpos);
+ if (lcd->vpos < vpos)
+ {
+// verboselog( machine, 3, "LCD - (1) frame_time %f\n", attotime_to_double( lcd->frame_time));
+ lcd->frame_time = machine.time() + s3c44b0_time_until_pos( device, lcd->vpos_min, lcd->hpos_min);
+// verboselog( machine, 3, "LCD - (2) frame_time %f\n", attotime_to_double( lcd->frame_time));
+ }
+ lcd->timer->adjust( s3c44b0_time_until_pos( device, lcd->vpos, lcd->hpos), 0);
+}
+
+static void s3c44b0_video_start( device_t *device, running_machine &machine)
+{
+ // do nothing
+}
+
+static UINT32 s3c44b0_video_update( device_t *device, screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ s3c44b0_lcd_t *lcd = &(get_token( device)->lcd);
+ if (lcd->regs.lcdcon1 & (1 << 0))
+ {
+ if (lcd->bitmap)
+ {
+ for (int y = 0; y < screen.height(); y++)
+ {
+ UINT32 *scanline = &bitmap.pix32(y);
+ UINT8 *vram = lcd->bitmap + y * (lcd->hpos_max - lcd->hpos_min + 1);
+ for (int x = 0; x < screen.width(); x++)
+ {
+ *scanline++ = MAKE_RGB( 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;
+}
+
+static READ32_DEVICE_HANDLER( s3c44b0_lcd_r )
+{
+ s3c44b0_lcd_t *lcd = &(get_token( device)->lcd);
+ UINT32 data = ((UINT32*)&lcd->regs)[offset];
+ switch (offset)
+ {
+ case S3C44B0_LCDCON1 :
+ {
+ int vpos = 0;
+ // make sure line counter is going
+ if (lcd->regs.lcdcon1 & (1 << 0))
+ {
+ vpos = s3c44b0_lcd_get_vpos( device);
+ int hpos = s3c44b0_lcd_get_hpos( device);
+ if (hpos < lcd->hpos_min) vpos = vpos - 1;
+ if ((vpos < lcd->vpos_min) || (vpos > lcd->vpos_max)) vpos = lcd->vpos_max;
+ vpos = lcd->vpos_max - vpos;
+ }
+ data = (data & ~0xFFC00000) | (vpos << 22);
+ }
+ break;
+ }
+// verboselog( device->machine(), 9, "(LCD) %08X -> %08X\n", S3C44B0_BASE_LCD + (offset << 2), data);
+ return data;
+}
+
+static void s3c44b0_lcd_configure( device_t *device)
+{
+ s3c44b0_lcd_t *lcd = &(get_token( device)->lcd);
+ screen_device *screen = device->machine().primary_screen;
+ int dismode, clkval, lineval, wdly, hozval, lineblank, wlh, mclk;
+ double vclk, framerate;
+ int width, height;
+ verboselog( device->machine(), 5, "s3c44b0_lcd_configure\n");
+ dismode = BITS( lcd->regs.lcdcon1, 6, 5);
+ clkval = BITS( lcd->regs.lcdcon1, 21, 12);
+ lineval = BITS( lcd->regs.lcdcon2, 9, 0);
+ wdly = BITS( lcd->regs.lcdcon1, 9, 8);
+ hozval = BITS( lcd->regs.lcdcon2, 20, 10);
+ lineblank = BITS( lcd->regs.lcdcon2, 31, 21);
+ wlh = BITS( lcd->regs.lcdcon1, 11, 10);
+ mclk = s3c44b0_get_mclk( device);
+ verboselog( device->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( device->machine(), 3, "LCD - vclk %f\n", vclk);
+ framerate = 1 / (((1 / vclk) * (hozval + 1) + (1 / mclk) * (wlh + wdly + lineblank)) * (lineval + 1));
+ framerate = framerate / 3; // ???
+ verboselog( device->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)", dismode); break;
+ }
+ height = lineval + 1;
+ lcd->framerate = framerate;
+ verboselog( device->machine(), 3, "video_screen_configure %d %d %f\n", width, height, lcd->framerate);
+ screen->configure( screen->width(), screen->height(), screen->visible_area(), HZ_TO_ATTOSECONDS( lcd->framerate));
+ lcd->hpos_min = 25;
+ lcd->hpos_max = 25 + width - 1;
+ lcd->hpos_end = 25 + width - 1 + 25;
+ lcd->vpos_min = 25;
+ lcd->vpos_max = 25 + height - 1;
+ lcd->vpos_end = 25 + height - 1 + 25;
+ verboselog( device->machine(), 3, "LCD - min_x %d min_y %d max_x %d max_y %d\n", lcd->hpos_min, lcd->vpos_min, lcd->hpos_max, lcd->vpos_max);
+ if (lcd->bitmap)
+ {
+ auto_free( device->machine(), lcd->bitmap);
+ }
+ lcd->bitmap = auto_alloc_array( device->machine(), UINT8, (lcd->hpos_max - lcd->hpos_min + 1) * (lcd->vpos_max - lcd->vpos_min + 1) * 3);
+ lcd->frame_period = HZ_TO_ATTOSECONDS( lcd->framerate);
+ lcd->scantime = lcd->frame_period / lcd->vpos_end;
+ lcd->pixeltime = lcd->frame_period / (lcd->vpos_end * lcd->hpos_end);
+// printf( "frame_period %f\n", attotime( 0, lcd->frame_period).as_double());
+// printf( "scantime %f\n", attotime( 0, lcd->scantime).as_double());
+// printf( "pixeltime %f\n", attotime( 0, lcd->pixeltime).as_double());
+}
+
+static void s3c44b0_lcd_start( device_t *device)
+{
+ running_machine &machine = device->machine();
+ s3c44b0_lcd_t *lcd = &(get_token( device)->lcd);
+ screen_device *screen = device->machine().primary_screen;
+ verboselog( device->machine(), 1, "LCD start\n");
+ s3c44b0_lcd_configure( device);
+ s3c44b0_lcd_dma_init( device);
+ lcd->vpos = lcd->vpos_min;
+ lcd->hpos = lcd->hpos_min;
+ lcd->frame_time = screen->time_until_pos( 0, 0);
+ lcd->timer->adjust( lcd->frame_time, 0);
+ lcd->frame_time = machine.time() + lcd->frame_time;
+}
+
+static void s3c44b0_lcd_stop( device_t *device)
+{
+ s3c44b0_lcd_t *lcd = &(get_token( device)->lcd);
+ verboselog( device->machine(), 1, "LCD stop\n");
+ lcd->timer->adjust( attotime::never, 0);
+}
+
+static void s3c44b0_lcd_recalc( device_t *device)
+{
+ s3c44b0_lcd_t *lcd = &(get_token( device)->lcd);
+ if (lcd->regs.lcdcon1 & (1 << 0))
+ {
+ s3c44b0_lcd_start( device);
+ }
+ else
+ {
+ s3c44b0_lcd_stop( device);
+ }
+}
+
+static WRITE32_DEVICE_HANDLER( s3c44b0_lcd_w )
+{
+ s3c44b0_lcd_t *lcd = &(get_token( device)->lcd);
+ UINT32 old_value = ((UINT32*)&lcd->regs)[offset];
+// verboselog( device->machine(), 9, "(LCD) %08X <- %08X\n", S3C44B0_BASE_LCD + (offset << 2), data);
+ COMBINE_DATA(&((UINT32*)&lcd->regs)[offset]);
+ switch (offset)
+ {
+ case S3C44B0_LCDCON1 :
+ {
+ if ((old_value & (1 << 0)) != (data & (1 << 0)))
+ {
+ s3c44b0_lcd_recalc( device);
+ }
+ }
+ break;
+ }
+}
+
+/* Clock & Power Management */
+
+static UINT32 s3c44b0_get_mclk( device_t *device)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ UINT32 data, mdiv, pdiv, sdiv;
+ data = s3c44b0->clkpow.regs.pllcon;
+ mdiv = BITS( data, 19, 12);
+ pdiv = BITS( data, 9, 4);
+ sdiv = BITS( data, 1, 0);
+ return (UINT32)((double)((mdiv + 8) * device->clock()) / (double)((pdiv + 2) * (1 << sdiv)));
+}
+
+static READ32_DEVICE_HANDLER( s3c44b0_clkpow_r )
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ UINT32 data = ((UINT32*)&s3c44b0->clkpow.regs)[offset];
+ verboselog( device->machine(), 9, "(CLKPOW) %08X -> %08X\n", S3C44B0_BASE_CLKPOW + (offset << 2), data);
+ return data;
+}
+
+static WRITE32_DEVICE_HANDLER( s3c44b0_clkpow_w )
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ verboselog( device->machine(), 9, "(CLKPOW) %08X <- %08X\n", S3C44B0_BASE_CLKPOW + (offset << 2), data);
+ COMBINE_DATA(&((UINT32*)&s3c44b0->clkpow.regs)[offset]);
+ switch (offset)
+ {
+ case S3C44B0_PLLCON :
+ {
+ verboselog( device->machine(), 5, "CLKPOW - mclk %d\n", s3c44b0_get_mclk( device));
+ s3c44b0->cpu->set_unscaled_clock( s3c44b0_get_mclk( device) * CLOCK_MULTIPLIER);
+ }
+ break;
+ case S3C44B0_CLKCON :
+ {
+ if (data & (1 << 2))
+ {
+ s3c44b0->cpu->spin_until_interrupt();
+ }
+ }
+ break;
+ }
+}
+
+/* Interrupt Controller */
+
+static void s3c44b0_check_pending_irq( device_t *device)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ UINT32 temp;
+ // normal irq
+ temp = (s3c44b0->irq.regs.intpnd & ~s3c44b0->irq.regs.intmsk) & ~s3c44b0->irq.regs.intmod;
+ if (temp != 0)
+ {
+ UINT32 int_type = 0;
+ while ((temp & 1) == 0)
+ {
+ int_type++;
+ temp = temp >> 1;
+ }
+ s3c44b0->irq.regs.i_ispr |= (1 << int_type);
+ if (s3c44b0->irq.line_irq != ASSERT_LINE)
+ {
+ s3c44b0->cpu->set_input_line( ARM7_IRQ_LINE, ASSERT_LINE);
+ s3c44b0->irq.line_irq = ASSERT_LINE;
+ }
+ }
+ else
+ {
+ if (s3c44b0->irq.line_irq != CLEAR_LINE)
+ {
+ s3c44b0->cpu->set_input_line( ARM7_IRQ_LINE, CLEAR_LINE);
+ s3c44b0->irq.line_irq = CLEAR_LINE;
+ }
+ }
+ // fast irq
+ temp = (s3c44b0->irq.regs.intpnd & ~s3c44b0->irq.regs.intmsk) & s3c44b0->irq.regs.intmod;
+ if (temp != 0)
+ {
+ UINT32 int_type = 0;
+ while ((temp & 1) == 0)
+ {
+ int_type++;
+ temp = temp >> 1;
+ }
+ if (s3c44b0->irq.line_fiq != ASSERT_LINE)
+ {
+ s3c44b0->cpu->set_input_line( ARM7_FIRQ_LINE, ASSERT_LINE);
+ s3c44b0->irq.line_fiq = ASSERT_LINE;
+ }
+ }
+ else
+ {
+ if (s3c44b0->irq.line_fiq != CLEAR_LINE)
+ {
+ s3c44b0->cpu->set_input_line( ARM7_FIRQ_LINE, CLEAR_LINE);
+ s3c44b0->irq.line_fiq = CLEAR_LINE;
+ }
+ }
+}
+
+static void s3c44b0_request_irq( device_t *device, UINT32 int_type)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ verboselog( device->machine(), 5, "request irq %d\n", int_type);
+ s3c44b0->irq.regs.intpnd |= (1 << int_type);
+ s3c44b0_check_pending_irq( device);
+}
+
+static void s3c44b0_check_pending_eint( device_t *device)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ UINT32 temp = s3c44b0->gpio.regs.extintpnd;
+ if (temp != 0)
+ {
+ UINT32 int_type = 0;
+ while ((temp & 1) == 0)
+ {
+ int_type++;
+ temp = temp >> 1;
+ }
+ s3c44b0_request_irq( device, S3C44B0_INT_EINT4_7);
+ }
+}
+
+void s3c44b0_request_eint( device_t *device, UINT32 number)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ verboselog( device->machine(), 5, "request external interrupt %d\n", number);
+ if (number < 4)
+ {
+ s3c44b0_request_irq( device, S3C44B0_INT_EINT0 + number);
+ }
+ else
+ {
+ s3c44b0->gpio.regs.extintpnd |= (1 << (number - 4));
+ s3c44b0_check_pending_eint( device);
+ }
+}
+
+static READ32_DEVICE_HANDLER( s3c44b0_irq_r )
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ UINT32 data = ((UINT32*)&s3c44b0->irq.regs)[offset];
+ verboselog( device->machine(), 9, "(IRQ) %08X -> %08X\n", S3C44B0_BASE_INT + (offset << 2), data);
+ return data;
+}
+
+static WRITE32_DEVICE_HANDLER( s3c44b0_irq_w )
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ verboselog( device->machine(), 9, "(IRQ) %08X <- %08X\n", S3C44B0_BASE_INT + (offset << 2), data);
+ COMBINE_DATA(&((UINT32*)&s3c44b0->irq.regs)[offset]);
+ switch (offset)
+ {
+ case S3C44B0_INTMSK :
+ {
+ s3c44b0_check_pending_irq( device);
+ }
+ break;
+ case S3C44B0_I_ISPC :
+ {
+ s3c44b0->irq.regs.intpnd = (s3c44b0->irq.regs.intpnd & ~data); // The bit of INTPND bit is cleared to zero by writing '1' on I_ISPC/F_ISPC
+ s3c44b0->irq.regs.i_ispr = (s3c44b0->irq.regs.i_ispr & ~data); // The pending bit in I_ISPR register should be cleared by writing I_ISPC register.
+ s3c44b0_check_pending_irq( device);
+ }
+ break;
+ case S3C44B0_F_ISPC :
+ {
+ s3c44b0->irq.regs.intpnd = (s3c44b0->irq.regs.intpnd & ~data); // The bit of INTPND bit is cleared to zero by writing '1' on I_ISPC/F_ISPC
+ s3c44b0_check_pending_irq( device);
+ }
+ break;
+ }
+}
+
+/* PWM Timer */
+
+static UINT16 s3c44b0_pwm_calc_observation( device_t *device, int ch)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ double timeleft, x1, x2;
+ UINT32 cnto;
+ timeleft = (s3c44b0->pwm.timer[ch]->remaining()).as_double();
+// printf( "timeleft %f freq %d cntb %d cmpb %d\n", timeleft, s3c44b0->pwm.freq[ch], s3c44b0->pwm.cnt[ch], s3c44b0->pwm.cmp[ch]);
+ x1 = 1 / ((double)s3c44b0->pwm.freq[ch] / (s3c44b0->pwm.cnt[ch]- s3c44b0->pwm.cmp[ch] + 1));
+ x2 = x1 / timeleft;
+// printf( "x1 %f\n", x1);
+ cnto = s3c44b0->pwm.cmp[ch] + ((s3c44b0->pwm.cnt[ch]- s3c44b0->pwm.cmp[ch]) / x2);
+// printf( "cnto %d\n", cnto);
+ return cnto;
+}
+
+static READ32_DEVICE_HANDLER( s3c44b0_pwm_r )
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ UINT32 data = ((UINT32*)&s3c44b0->pwm.regs)[offset];
+ switch (offset)
+ {
+ case S3C44B0_TCNTO0 :
+ {
+ data = (data & ~0x0000FFFF) | s3c44b0_pwm_calc_observation( device, 0);
+ }
+ break;
+ case S3C44B0_TCNTO1 :
+ {
+ data = (data & ~0x0000FFFF) | s3c44b0_pwm_calc_observation( device, 1);
+ }
+ break;
+ case S3C44B0_TCNTO2 :
+ {
+ data = (data & ~0x0000FFFF) | s3c44b0_pwm_calc_observation( device, 2);
+ }
+ break;
+ case S3C44B0_TCNTO3 :
+ {
+ data = (data & ~0x0000FFFF) | s3c44b0_pwm_calc_observation( device, 3);
+ }
+ break;
+ case S3C44B0_TCNTO4 :
+ {
+ data = (data & ~0x0000FFFF) | s3c44b0_pwm_calc_observation( device, 4);
+ }
+ break;
+ case S3C44B0_TCNTO5 :
+ {
+ data = (data & ~0x0000FFFF) | s3c44b0_pwm_calc_observation( device, 5);
+ }
+ break;
+ }
+ verboselog( device->machine(), 9, "(PWM) %08X -> %08X\n", S3C44B0_BASE_PWM + (offset << 2), data);
+ return data;
+}
+
+static void s3c44b0_pwm_start( device_t *device, int timer)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ 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( device->machine(), 1, "PWM %d start\n", timer);
+ mclk = s3c44b0_get_mclk( device);
+ prescaler = (s3c44b0->pwm.regs.tcfg0 >> prescaler_shift[timer]) & 0xFF;
+ mux = (s3c44b0->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( s3c44b0->pwm.regs.tcntb0, 15, 0);
+ cmp = BITS( s3c44b0->pwm.regs.tcmpb0, 15, 0);
+ auto_reload = BIT( s3c44b0->pwm.regs.tcon, 3);
+ }
+ break;
+ case 1 :
+ {
+ cnt = BITS( s3c44b0->pwm.regs.tcntb1, 15, 0);
+ cmp = BITS( s3c44b0->pwm.regs.tcmpb1, 15, 0);
+ auto_reload = BIT( s3c44b0->pwm.regs.tcon, 11);
+ }
+ break;
+ case 2 :
+ {
+ cnt = BITS( s3c44b0->pwm.regs.tcntb2, 15, 0);
+ cmp = BITS( s3c44b0->pwm.regs.tcmpb2, 15, 0);
+ auto_reload = BIT( s3c44b0->pwm.regs.tcon, 15);
+ }
+ break;
+ case 3 :
+ {
+ cnt = BITS( s3c44b0->pwm.regs.tcntb3, 15, 0);
+ cmp = BITS( s3c44b0->pwm.regs.tcmpb3, 15, 0);
+ auto_reload = BIT( s3c44b0->pwm.regs.tcon, 19);
+ }
+ break;
+ case 4 :
+ {
+ cnt = BITS( s3c44b0->pwm.regs.tcntb4, 15, 0);
+ cmp = BITS( s3c44b0->pwm.regs.tcmpb4, 15, 0);
+ auto_reload = BIT( s3c44b0->pwm.regs.tcon, 23);
+ }
+ break;
+ case 5 :
+ {
+ cnt = BITS( s3c44b0->pwm.regs.tcntb5, 15, 0);
+ cmp = 0;
+ auto_reload = BIT( s3c44b0->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( device->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);
+ s3c44b0->pwm.cnt[timer] = cnt;
+ s3c44b0->pwm.cmp[timer] = cmp;
+ s3c44b0->pwm.freq[timer] = freq;
+ if (cnt == 0)
+ {
+ s3c44b0->pwm.timer[timer]->adjust( attotime::never, 0);
+ }
+ else
+ {
+ if (auto_reload)
+ {
+ s3c44b0->pwm.timer[timer]->adjust( attotime::from_hz( hz), timer, attotime::from_hz( hz));
+ }
+ else
+ {
+ s3c44b0->pwm.timer[timer]->adjust( attotime::from_hz( hz), timer);
+ }
+ }
+}
+
+static void s3c44b0_pwm_stop( device_t *device, int timer)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ verboselog( device->machine(), 1, "PWM %d stop\n", timer);
+ s3c44b0->pwm.timer[timer]->adjust( attotime::never, 0);
+}
+
+static void s3c44b0_pwm_recalc( device_t *device, int timer)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ const int tcon_shift[] = { 0, 8, 12, 16, 20, 24};
+ if (s3c44b0->pwm.regs.tcon & (1 << tcon_shift[timer]))
+ {
+ s3c44b0_pwm_start( device, timer);
+ }
+ else
+ {
+ s3c44b0_pwm_stop( device, timer);
+ }
+}
+
+static WRITE32_DEVICE_HANDLER( s3c44b0_pwm_w )
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ UINT32 old_value = ((UINT32*)&s3c44b0->pwm.regs)[offset];
+ verboselog( device->machine(), 9, "(PWM) %08X <- %08X\n", S3C44B0_BASE_PWM + (offset << 2), data);
+ COMBINE_DATA(&((UINT32*)&s3c44b0->pwm.regs)[offset]);
+ switch (offset)
+ {
+ case S3C44B0_TCON :
+ {
+ if ((data & (1 << 0)) != (old_value & (1 << 0)))
+ {
+ s3c44b0_pwm_recalc( device, 0);
+ }
+ if ((data & (1 << 8)) != (old_value & (1 << 8)))
+ {
+ s3c44b0_pwm_recalc( device, 1);
+ }
+ if ((data & (1 << 12)) != (old_value & (1 << 12)))
+ {
+ s3c44b0_pwm_recalc( device, 2);
+ }
+ if ((data & (1 << 16)) != (old_value & (1 << 16)))
+ {
+ s3c44b0_pwm_recalc( device, 3);
+ }
+ if ((data & (1 << 20)) != (old_value & (1 << 20)))
+ {
+ s3c44b0_pwm_recalc( device, 4);
+ }
+ if ((data & (1 << 24)) != (old_value & (1 << 24)))
+ {
+ s3c44b0_pwm_recalc( device, 5);
+ }
+ }
+ break;
+ }
+}
+
+static TIMER_CALLBACK( s3c44b0_pwm_timer_exp )
+{
+ device_t *device = (device_t *)ptr;
+ s3c44b0_t *s3c44b0 = get_token( device);
+ 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( s3c44b0->pwm.regs.tcfg1, 27, 24) == (ch + 1))
+ {
+ fatalerror( "s3c44b0_dma_request_pwm( device);");
+ }
+ else
+ {
+ s3c44b0_request_irq( device, ch_int[ch]);
+ }
+}
+
+/* IIC */
+
+INLINE void iface_i2c_scl_w( device_t *device, int state)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ if (s3c44b0->iface->i2c.scl_w)
+ {
+ (s3c44b0->iface->i2c.scl_w)( device, state);
+ }
+}
+
+INLINE void iface_i2c_sda_w( device_t *device, int state)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ if (s3c44b0->iface->i2c.sda_w)
+ {
+ (s3c44b0->iface->i2c.sda_w)( device, state);
+ }
+}
+
+INLINE int iface_i2c_sda_r( device_t *device)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ if (s3c44b0->iface->i2c.sda_r)
+ {
+ return (s3c44b0->iface->i2c.sda_r)( device);
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+static void i2c_send_start( device_t *device)
+{
+ verboselog( device->machine(), 5, "i2c_send_start\n");
+ iface_i2c_sda_w( device, 1);
+ iface_i2c_scl_w( device, 1);
+ iface_i2c_sda_w( device, 0);
+ iface_i2c_scl_w( device, 0);
+}
+
+static void i2c_send_stop( device_t *device)
+{
+ verboselog( device->machine(), 5, "i2c_send_stop\n");
+ iface_i2c_sda_w( device, 0);
+ iface_i2c_scl_w( device, 1);
+ iface_i2c_sda_w( device, 1);
+ iface_i2c_scl_w( device, 0);
+}
+
+static UINT8 i2c_receive_byte( device_t *device, int ack)
+{
+ UINT8 data = 0;
+ verboselog( device->machine(), 5, "i2c_receive_byte ...\n");
+ iface_i2c_sda_w( device, 1);
+ for (int i = 0; i < 8; i++)
+ {
+ iface_i2c_scl_w( device, 1);
+ data = (data << 1) + (iface_i2c_sda_r( device) ? 1 : 0);
+ iface_i2c_scl_w( device, 0);
+ }
+ verboselog( device->machine(), 5, "recv data %02X\n", data);
+ verboselog( device->machine(), 5, "send ack %d\n", ack);
+ iface_i2c_sda_w( device, ack ? 0 : 1);
+ iface_i2c_scl_w( device, 1);
+ iface_i2c_scl_w( device, 0);
+ return data;
+}
+
+static int i2c_send_byte( device_t *device, UINT8 data)
+{
+ int ack;
+ verboselog( device->machine(), 5, "i2c_send_byte ...\n");
+ verboselog( device->machine(), 5, "send data %02X\n", data);
+ for (int i = 0; i < 8; i++)
+ {
+ iface_i2c_sda_w( device, (data & 0x80) ? 1 : 0);
+ data = data << 1;
+ iface_i2c_scl_w( device, 1);
+ iface_i2c_scl_w( device, 0);
+ }
+ iface_i2c_sda_w( device, 1); // ack bit
+ iface_i2c_scl_w( device, 1);
+ ack = iface_i2c_sda_r( device);
+ verboselog( device->machine(), 5, "recv ack %d\n", ack);
+ iface_i2c_scl_w( device, 0);
+ return ack;
+}
+
+static void iic_start( device_t *device)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ int mode_selection;
+ verboselog( device->machine(), 1, "IIC start\n");
+ i2c_send_start( device);
+ mode_selection = BITS( s3c44b0->iic.regs.iicstat, 7, 6);
+ switch (mode_selection)
+ {
+ case 2 : i2c_send_byte( device, s3c44b0->iic.regs.iicds | 0x01); break;
+ case 3 : i2c_send_byte( device, s3c44b0->iic.regs.iicds & 0xFE); break;
+ }
+ s3c44b0->iic.timer->adjust( attotime::from_usec( 1), 0);
+}
+
+static void iic_stop( device_t *device)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ verboselog( device->machine(), 1, "IIC stop\n");
+ i2c_send_stop( device);
+ s3c44b0->iic.timer->adjust( attotime::never, 0);
+}
+
+static void iic_resume( device_t *device)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ int mode_selection;
+ verboselog( device->machine(), 1, "IIC resume\n");
+ mode_selection = BITS( s3c44b0->iic.regs.iicstat, 7, 6);
+ switch (mode_selection)
+ {
+ case 2 : s3c44b0->iic.regs.iicds = i2c_receive_byte( device, BIT( s3c44b0->iic.regs.iiccon, 7)); break;
+ case 3 : i2c_send_byte( device, s3c44b0->iic.regs.iicds & 0xFF); break;
+ }
+ s3c44b0->iic.timer->adjust( attotime::from_usec( 1), 0);
+}
+
+static READ32_DEVICE_HANDLER( s3c44b0_iic_r )
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ UINT32 data = ((UINT32*)&s3c44b0->iic.regs)[offset];
+ switch (offset)
+ {
+ case S3C44B0_IICSTAT :
+ {
+ data = data & ~0x0000000F;
+ }
+ break;
+ }
+ verboselog( device->machine(), 9, "(IIC) %08X -> %08X\n", S3C44B0_BASE_IIC + (offset << 2), data);
+ return data;
+}
+
+static WRITE32_DEVICE_HANDLER( s3c44b0_iic_w )
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ UINT32 old_value = ((UINT32*)&s3c44b0->iic.regs)[offset];
+ verboselog( device->machine(), 9, "(IIC) %08X <- %08X\n", S3C44B0_BASE_IIC + (offset << 2), data);
+ COMBINE_DATA(&((UINT32*)&s3c44b0->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)s3c24xx_get_pclk( device) / 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( s3c44b0->iic.regs.iicstat, 5);
+ if (start_stop_condition != 0)
+ {
+ if (s3c44b0->iic.count == 0)
+ {
+ iic_start( device);
+
+ }
+ else
+ {
+ iic_resume( device);
+ }
+ }
+ else
+ {
+ iic_stop( device);
+ }
+ }
+ }
+ }
+ break;
+ case S3C44B0_IICSTAT :
+ {
+ int interrupt_pending_flag;
+ s3c44b0->iic.count = 0;
+ interrupt_pending_flag = BIT( s3c44b0->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 (s3c44b0->iic.count == 0)
+ {
+ iic_start( device);
+
+ }
+ else
+ {
+ iic_resume( device);
+ }
+ }
+ else
+ {
+ iic_stop( device);
+ }
+ }
+ }
+ break;
+ }
+}
+
+static TIMER_CALLBACK( s3c44b0_iic_timer_exp )
+{
+ device_t *device = (device_t *)ptr;
+ s3c44b0_t *s3c44b0 = get_token( device);
+ int enable_interrupt;
+ verboselog( machine, 2, "IIC timer callback\n");
+ s3c44b0->iic.count++;
+ enable_interrupt = BIT( s3c44b0->iic.regs.iiccon, 5);
+
+ s3c44b0->iic.regs.iicds = 0xFF; // TEST
+
+ if (enable_interrupt)
+ {
+ s3c44b0->iic.regs.iiccon |= (1 << 4); // [bit 4] interrupt is pending
+ s3c44b0_request_irq( device, S3C44B0_INT_IIC);
+ }
+}
+
+/* I/O Port */
+
+INLINE UINT32 iface_gpio_port_r( device_t *device, int port)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ if (s3c44b0->iface->gpio.port_r)
+ {
+ return (s3c44b0->iface->gpio.port_r)( device, port);
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+INLINE void iface_gpio_port_w( device_t *device, int port, UINT32 data)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ if (s3c44b0->iface->gpio.port_w)
+ {
+ (s3c44b0->iface->gpio.port_w)( device, port, data);
+ }
+}
+
+static READ32_DEVICE_HANDLER( s3c44b0_gpio_r )
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ UINT32 data = ((UINT32*)&s3c44b0->gpio.regs)[offset];
+ switch (offset)
+ {
+ case S3C44B0_GPADAT :
+ {
+ data = iface_gpio_port_r( device, S3C44B0_GPIO_PORT_A) & S3C44B0_GPADAT_MASK;
+ }
+ break;
+ case S3C44B0_GPBDAT :
+ {
+ data = iface_gpio_port_r( device, S3C44B0_GPIO_PORT_B) & S3C44B0_GPBDAT_MASK;
+ }
+ break;
+ case S3C44B0_GPCDAT :
+ {
+ data = iface_gpio_port_r( device, S3C44B0_GPIO_PORT_C) & S3C44B0_GPCDAT_MASK;
+ }
+ break;
+ case S3C44B0_GPDDAT :
+ {
+ data = iface_gpio_port_r( device, S3C44B0_GPIO_PORT_D) & S3C44B0_GPDDAT_MASK;
+ }
+ break;
+ case S3C44B0_GPEDAT :
+ {
+ data = iface_gpio_port_r( device, S3C44B0_GPIO_PORT_E) & S3C44B0_GPEDAT_MASK;
+ }
+ break;
+ case S3C44B0_GPFDAT :
+ {
+ data = iface_gpio_port_r( device, S3C44B0_GPIO_PORT_F) & S3C44B0_GPFDAT_MASK;
+ }
+ break;
+ case S3C44B0_GPGDAT :
+ {
+ data = iface_gpio_port_r( device, S3C44B0_GPIO_PORT_G) & S3C44B0_GPGDAT_MASK;
+ }
+ break;
+ }
+ verboselog( device->machine(), 9, "(GPIO) %08X -> %08X\n", S3C44B0_BASE_GPIO + (offset << 2), data);
+ return data;
+}
+
+static WRITE32_DEVICE_HANDLER( s3c44b0_gpio_w )
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ UINT32 old_value = ((UINT32*)&s3c44b0->gpio.regs)[offset];
+ verboselog( device->machine(), 9, "(GPIO) %08X <- %08X\n", S3C44B0_BASE_GPIO + (offset << 2), data);
+ COMBINE_DATA(&((UINT32*)&s3c44b0->gpio.regs)[offset]);
+ switch (offset)
+ {
+ case S3C44B0_GPADAT :
+ {
+ iface_gpio_port_w( device, S3C44B0_GPIO_PORT_A, data & S3C44B0_GPADAT_MASK);
+ }
+ break;
+ case S3C44B0_GPBDAT :
+ {
+ iface_gpio_port_w( device, S3C44B0_GPIO_PORT_B, data & S3C44B0_GPBDAT_MASK);
+ }
+ break;
+ case S3C44B0_GPCDAT :
+ {
+ iface_gpio_port_w( device, S3C44B0_GPIO_PORT_C, data & S3C44B0_GPCDAT_MASK);
+ }
+ break;
+ case S3C44B0_GPDDAT :
+ {
+ iface_gpio_port_w( device, S3C44B0_GPIO_PORT_D, data & S3C44B0_GPDDAT_MASK);
+ }
+ break;
+ case S3C44B0_GPEDAT :
+ {
+ iface_gpio_port_w( device, S3C44B0_GPIO_PORT_E, data & S3C44B0_GPEDAT_MASK);
+ }
+ break;
+ case S3C44B0_GPFDAT :
+ {
+ iface_gpio_port_w( device, S3C44B0_GPIO_PORT_F, data & S3C44B0_GPFDAT_MASK);
+ }
+ break;
+ case S3C44B0_GPGDAT :
+ {
+ iface_gpio_port_w( device, S3C44B0_GPIO_PORT_G, data & S3C44B0_GPGDAT_MASK);
+ }
+ break;
+ case S3C44B0_EXTINTPND :
+ {
+ s3c44b0->gpio.regs.extintpnd = (old_value & ~data);
+ s3c44b0_check_pending_eint( device);
+ }
+ break;
+ }
+}
+
+/* UART */
+
+static UINT32 s3c44b0_uart_r( device_t *device, int ch, UINT32 offset)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ UINT32 data = ((UINT32*)&s3c44b0->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( device->machine(), 5, "UART %d read %02X (%c)\n", ch, rxdata, ((rxdata >= 32) && (rxdata < 128)) ? (char)rxdata : '?');
+ s3c44b0->uart[ch].regs.utrstat &= ~1; // [bit 0] Receive buffer data ready
+ }
+ break;
+ }
+ return data;
+}
+
+static void s3c44b0_uart_w( device_t *device, int ch, UINT32 offset, UINT32 data, UINT32 mem_mask)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ COMBINE_DATA(&((UINT32*)&s3c44b0->uart[ch].regs)[offset]);
+ s3c44b0_uart_t *uart = &s3c44b0->uart[ch];
+ switch (offset)
+ {
+ case S3C44B0_UTXH :
+ {
+ UINT8 txdata = data & 0xFF;
+ verboselog( device->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 = s3c44b0_get_mclk( device);
+ hz = (mclk / (uart->regs.ubrdiv + 1)) / 16;
+ verboselog( device->machine(), 5, "UART %d - mclk %08X hz %08X\n", ch, mclk, hz);
+ uart->timer->adjust( attotime::from_hz( hz), ch, attotime::from_hz( hz));
+ }
+ break;
+ }
+}
+
+static READ32_DEVICE_HANDLER( s3c44b0_uart_0_r )
+{
+ UINT32 data = s3c44b0_uart_r( device, 0, offset);
+// verboselog( device->machine(), 9, "(UART 0) %08X -> %08X\n", S3C44B0_BASE_UART_0 + (offset << 2), data);
+ return data;
+}
+
+static READ32_DEVICE_HANDLER( s3c44b0_uart_1_r )
+{
+ UINT32 data = s3c44b0_uart_r( device, 1, offset);
+// verboselog( device->machine(), 9, "(UART 1) %08X -> %08X\n", S3C44B0_BASE_UART_1 + (offset << 2), data);
+ return data;
+}
+
+static WRITE32_DEVICE_HANDLER( s3c44b0_uart_0_w )
+{
+ verboselog( device->machine(), 9, "(UART 0) %08X <- %08X (%08X)\n", S3C44B0_BASE_UART_0 + (offset << 2), data, mem_mask);
+ s3c44b0_uart_w( device, 0, offset, data, mem_mask);
+}
+
+static WRITE32_DEVICE_HANDLER( s3c44b0_uart_1_w )
+{
+ verboselog( device->machine(), 9, "(UART 1) %08X <- %08X (%08X)\n", S3C44B0_BASE_UART_1 + (offset << 2), data, mem_mask);
+ s3c44b0_uart_w( device, 1, offset, data, mem_mask);
+}
+
+void s3c44b0_uart_fifo_w( device_t *device, int uart, UINT8 data)
+{
+// printf( "s3c44b0_uart_fifo_w (%c)\n", data);
+ s3c44b0_t *s3c44b0 = get_token( device);
+ s3c44b0->uart[uart].regs.urxh = data;
+ s3c44b0->uart[uart].regs.utrstat |= 1; // [bit 0] Receive buffer data ready
+}
+
+static TIMER_CALLBACK( s3c44b0_uart_timer_exp )
+{
+ device_t *device = (device_t *)ptr;
+ s3c44b0_t *s3c44b0 = get_token( device);
+ int ch = param;
+ s3c44b0_uart_t *uart = &s3c44b0->uart[ch];
+ verboselog( machine, 2, "UART %d timer callback\n", ch);
+ if ((uart->regs.ucon & (1 << 9)) != 0)
+ {
+ const int ch_int[] = { S3C44B0_INT_UTXD0, S3C44B0_INT_UTXD1 };
+ s3c44b0_request_irq( device, ch_int[ch]);
+ }
+}
+
+/* Watchdog Timer */
+
+static UINT16 s3c44b0_wdt_calc_current_count( device_t *device)
+{
+ return 0;
+}
+
+static READ32_DEVICE_HANDLER( s3c44b0_wdt_r )
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ UINT32 data = ((UINT32*)&s3c44b0->wdt.regs)[offset];
+ switch (offset)
+ {
+ case S3C44B0_WTCNT :
+ {
+ // is wdt active?
+ if ((s3c44b0->wdt.regs.wtcon & (1 << 5)) != 0)
+ {
+ data = s3c44b0_wdt_calc_current_count( device);
+ }
+ }
+ break;
+ }
+ verboselog( device->machine(), 9, "(WDT) %08X -> %08X\n", S3C44B0_BASE_WDT + (offset << 2), data);
+ return data;
+}
+
+static void s3c44b0_wdt_start( device_t *device)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ UINT32 mclk, prescaler, clock;
+ double freq, hz;
+ verboselog( device->machine(), 1, "WDT start\n");
+ mclk = s3c44b0_get_mclk( device);
+ prescaler = BITS( s3c44b0->wdt.regs.wtcon, 15, 8);
+ clock = 16 << BITS( s3c44b0->wdt.regs.wtcon, 4, 3);
+ freq = (double)mclk / (prescaler + 1) / clock;
+ hz = freq / s3c44b0->wdt.regs.wtcnt;
+ verboselog( device->machine(), 5, "WDT mclk %d prescaler %d clock %d freq %f hz %f\n", mclk, prescaler, clock, freq, hz);
+ s3c44b0->wdt.timer->adjust( attotime::from_hz( hz), 0, attotime::from_hz( hz));
+}
+
+static void s3c44b0_wdt_stop( device_t *device)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ verboselog( device->machine(), 1, "WDT stop\n");
+ s3c44b0->wdt.regs.wtcnt = s3c44b0_wdt_calc_current_count( device);
+ s3c44b0->wdt.timer->adjust( attotime::never, 0);
+}
+
+static void s3c44b0_wdt_recalc( device_t *device)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ if ((s3c44b0->wdt.regs.wtcon & (1 << 5)) != 0)
+ {
+ s3c44b0_wdt_start( device);
+ }
+ else
+ {
+ s3c44b0_wdt_stop( device);
+ }
+}
+
+static WRITE32_DEVICE_HANDLER( s3c44b0_wdt_w )
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ UINT32 old_value = ((UINT32*)&s3c44b0->wdt.regs)[offset];
+ verboselog( device->machine(), 9, "(WDT) %08X <- %08X\n", S3C44B0_BASE_WDT + (offset << 2), data);
+ COMBINE_DATA(&((UINT32*)&s3c44b0->wdt.regs)[offset]);
+ switch (offset)
+ {
+ case S3C44B0_WTCON :
+ {
+ if ((data & (1 << 5)) != (old_value & (1 << 5)))
+ {
+ s3c44b0_wdt_recalc( device);
+ }
+ }
+ break;
+ }
+}
+
+static TIMER_CALLBACK( s3c44b0_wdt_timer_exp )
+{
+ device_t *device = (device_t *)ptr;
+ s3c44b0_t *s3c44b0 = get_token( device);
+ verboselog( machine, 2, "WDT timer callback\n");
+ if ((s3c44b0->wdt.regs.wtcon & (1 << 2)) != 0)
+ {
+ s3c44b0_request_irq( device, S3C44B0_INT_WDT);
+ }
+ if ((s3c44b0->wdt.regs.wtcon & (1 << 0)) != 0)
+ {
+ s3c44b0_reset( device);
+ }
+}
+
+/* CPU Wrapper */
+
+static READ32_DEVICE_HANDLER( s3c44b0_cpuwrap_r )
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ UINT32 data = ((UINT32*)&s3c44b0->cpuwrap.regs)[offset];
+ verboselog( device->machine(), 9, "(CPUWRAP) %08X -> %08X\n", S3C44B0_BASE_CPU_WRAPPER + (offset << 2), data);
+ return data;
+}
+
+static WRITE32_DEVICE_HANDLER( s3c44b0_cpuwrap_w )
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ verboselog( device->machine(), 9, "(CPUWRAP) %08X <- %08X\n", S3C44B0_BASE_CPU_WRAPPER + (offset << 2), data);
+ COMBINE_DATA(&((UINT32*)&s3c44b0->cpuwrap.regs)[offset]);
+}
+
+/* A/D Converter */
+
+static READ32_DEVICE_HANDLER( s3c44b0_adc_r )
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ UINT32 data = ((UINT32*)&s3c44b0->adc.regs)[offset];
+ verboselog( device->machine(), 9, "(ADC) %08X -> %08X\n", S3C44B0_BASE_ADC + (offset << 2), data);
+ return data;
+}
+
+static void s3c44b0_adc_start( device_t *device)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ UINT32 mclk, prescaler;
+ double freq, hz;
+ verboselog( device->machine(), 1, "ADC start\n");
+ mclk = s3c44b0_get_mclk( device);
+ prescaler = BITS( s3c44b0->adc.regs.adcpsr, 7, 0);
+ freq = (double)mclk / (2 * (prescaler + 1)) / 16;
+ hz = freq / 1; //s3c44b0->wdt.regs.wtcnt;
+ verboselog( device->machine(), 5, "ADC mclk %d prescaler %d freq %f hz %f\n", mclk, prescaler, freq, hz);
+ s3c44b0->adc.timer->adjust( attotime::from_hz( hz), 0);
+}
+
+static void s3c44b0_adc_stop( device_t *device)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ verboselog( device->machine(), 1, "ADC stop\n");
+ s3c44b0->adc.timer->adjust( attotime::never, 0);
+}
+
+static void s3c44b0_adc_recalc( device_t *device)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ if ((s3c44b0->adc.regs.adccon & (1 << 0)) != 0)
+ {
+ s3c44b0_adc_start( device);
+ }
+ else
+ {
+ s3c44b0_adc_stop( device);
+ }
+}
+
+static WRITE32_DEVICE_HANDLER( s3c44b0_adc_w )
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ UINT32 old_value = ((UINT32*)&s3c44b0->wdt.regs)[offset];
+ verboselog( device->machine(), 9, "(ADC) %08X <- %08X\n", S3C44B0_BASE_ADC + (offset << 2), data);
+ COMBINE_DATA(&((UINT32*)&s3c44b0->adc.regs)[offset]);
+ switch (offset)
+ {
+ case S3C44B0_ADCCON :
+ {
+ if ((data & (1 << 0)) != (old_value & (1 << 0)))
+ {
+ s3c44b0_adc_recalc( device);
+ }
+ s3c44b0->adc.regs.adccon &= ~(1 << 0); // "this bit is cleared after the start-up"
+ }
+ break;
+ }
+}
+
+static TIMER_CALLBACK( s3c44b0_adc_timer_exp )
+{
+ device_t *device = (device_t *)ptr;
+ s3c44b0_t *s3c44b0 = get_token( device);
+ verboselog( machine, 2, "ADC timer callback\n");
+ s3c44b0->adc.regs.adccon |= (1 << 6);
+ s3c44b0_request_irq( device, S3C44B0_INT_ADC);
+}
+
+/* SIO */
+
+static READ32_DEVICE_HANDLER( s3c44b0_sio_r )
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ UINT32 data = ((UINT32*)&s3c44b0->sio.regs)[offset];
+ verboselog( device->machine(), 9, "(SIO) %08X -> %08X\n", S3C44B0_BASE_SIO + (offset << 2), data);
+ return data;
+}
+
+static void s3c44b0_sio_start( device_t *device)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ UINT32 mclk, prescaler;
+ double freq, hz;
+ verboselog( device->machine(), 1, "SIO start\n");
+ mclk = s3c44b0_get_mclk( device);
+ prescaler = BITS( s3c44b0->sio.regs.sbrdr, 11, 0);
+ freq = (double)mclk / 2 / (prescaler + 1);
+ hz = freq / 1; //s3c44b0->wdt.regs.wtcnt;
+ verboselog( device->machine(), 5, "SIO mclk %d prescaler %d freq %f hz %f\n", mclk, prescaler, freq, hz);
+ s3c44b0->sio.timer->adjust( attotime::from_hz( hz), 0);
+// printf( "SIO transmit %02X (%c)\n", s3c44b0->sio.regs.siodat, ((s3c44b0->sio.regs.siodat >= 32) && (s3c44b0->sio.regs.siodat < 128)) ? (char)s3c44b0->sio.regs.siodat : '?');
+}
+
+static void s3c44b0_sio_stop( device_t *device)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ verboselog( device->machine(), 1, "SIO stop\n");
+// s3c44b0->wdt.regs.wtcnt = s3c44b0_wdt_calc_current_count( device);
+ s3c44b0->sio.timer->adjust( attotime::never, 0);
+}
+
+static void s3c44b0_sio_recalc( device_t *device)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ if ((s3c44b0->sio.regs.siocon & (1 << 3)) != 0)
+ {
+ s3c44b0_sio_start( device);
+ }
+ else
+ {
+ s3c44b0_sio_stop( device);
+ }
+}
+
+static WRITE32_DEVICE_HANDLER( s3c44b0_sio_w )
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ UINT32 old_value = ((UINT32*)&s3c44b0->sio.regs)[offset];
+ verboselog( device->machine(), 9, "(SIO) %08X <- %08X\n", S3C44B0_BASE_SIO + (offset << 2), data);
+ COMBINE_DATA(&((UINT32*)&s3c44b0->sio.regs)[offset]);
+ switch (offset)
+ {
+ case S3C44B0_SIOCON :
+ {
+ if ((old_value & (1 << 3)) != (data & (1 << 3)))
+ {
+ s3c44b0_sio_recalc( device);
+ }
+ s3c44b0->sio.regs.siocon &= ~(1 << 3); // "This bit is cleared just after writing this bit as 1."
+ }
+ break;
+ }
+}
+
+static TIMER_CALLBACK( s3c44b0_sio_timer_exp )
+{
+ device_t *device = (device_t *)ptr;
+ s3c44b0_t *s3c44b0 = get_token( device);
+ verboselog( machine, 2, "SIO timer callback\n");
+
+ s3c44b0->sio.regs.siodat = 0x00; // TEST
+
+ if ((s3c44b0->sio.regs.siocon & (1 << 0)) != 0)
+ {
+ s3c44b0_request_irq( device, S3C44B0_INT_SIO);
+ }
+}
+
+/* IIS */
+
+INLINE void iface_i2s_data_w( device_t *device, int ch, UINT16 data)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ if (s3c44b0->iface->i2s.data_w)
+ {
+ (s3c44b0->iface->i2s.data_w)( device, ch, data, 0);
+ }
+}
+
+static void s3c44b0_iis_start( device_t *device)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ 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( device->machine(), 1, "IIS start\n");
+ mclk = s3c44b0_get_mclk( device);
+ prescaler = BITS( s3c44b0->iis.regs.iispsr, 3, 0);
+ freq = (double)mclk / div[prescaler];
+ hz = freq / 256 * 2;
+ verboselog( device->machine(), 5, "IIS mclk %d prescaler %d freq %f hz %f\n", mclk, prescaler, freq, hz);
+ s3c44b0->iis.timer->adjust( attotime::from_hz( hz), 0, attotime::from_hz( hz));
+}
+
+static void s3c44b0_iis_stop( device_t *device)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ verboselog( device->machine(), 1, "IIS stop\n");
+ s3c44b0->iis.timer->adjust( attotime::never, 0);
+}
+
+static READ32_DEVICE_HANDLER( s3c44b0_iis_r )
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ UINT32 data = ((UINT32*)&s3c44b0->iis.regs)[offset];
+ verboselog( device->machine(), 9, "(IIS) %08X -> %08X\n", S3C44B0_BASE_IIS + (offset << 2), data);
+ return data;
+}
+
+static WRITE32_DEVICE_HANDLER( s3c44b0_iis_w )
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ UINT32 old_value = ((UINT32*)&s3c44b0->iis.regs)[offset];
+ verboselog( device->machine(), 9, "(IIS) %08X <- %08X\n", S3C44B0_BASE_IIS + (offset << 2), data);
+ COMBINE_DATA(&((UINT32*)&s3c44b0->iis.regs)[offset]);
+ switch (offset)
+ {
+ case S3C44B0_IISCON :
+ {
+ if ((old_value & (1 << 0)) != (data & (1 << 0)))
+ {
+ if ((data & (1 << 0)) != 0)
+ {
+ s3c44b0_iis_start( device);
+ }
+ else
+ {
+ s3c44b0_iis_stop( device);
+ }
+ }
+ }
+ break;
+ case S3C44B0_IISFIFO :
+ {
+ if (ACCESSING_BITS_16_31)
+ {
+ s3c44b0->iis.fifo[s3c44b0->iis.fifo_index++] = BITS( data, 31, 16);
+ }
+ if (ACCESSING_BITS_0_15)
+ {
+ s3c44b0->iis.fifo[s3c44b0->iis.fifo_index++] = BITS( data, 15, 0);
+ }
+ if (s3c44b0->iis.fifo_index == 2)
+ {
+ s3c44b0->iis.fifo_index = 0;
+ iface_i2s_data_w( device, 0, s3c44b0->iis.fifo[0]);
+ iface_i2s_data_w( device, 1, s3c44b0->iis.fifo[1]);
+ }
+ }
+ break;
+ }
+}
+
+static TIMER_CALLBACK( s3c44b0_iis_timer_exp )
+{
+ device_t *device = (device_t *)ptr;
+ s3c44b0_t *s3c44b0 = get_token( device);
+ s3c44b0_iis_t *iis = &s3c44b0->iis;
+ verboselog( machine, 2, "IIS timer callback\n");
+ if ((iis->regs.iiscon & (1 << 5)) != 0)
+ {
+ s3c44b0_bdma_request_iis( device);
+ }
+}
+
+/* ZDMA */
+
+static void s3c44b0_zdma_trigger( device_t *device, int ch)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ s3c44b0_dma_t *dma = &s3c44b0->zdma[ch];
+ UINT32 saddr, daddr;
+ int dal, dst, opt, das, cnt;
+ verboselog( device->machine(), 5, "s3c44b0_zdma_trigger %d\n", ch);
+ dst = BITS( dma->regs.dcsrc, 31, 30);
+ dal = BITS( dma->regs.dcsrc, 29, 28);
+ saddr = BITS( dma->regs.dcsrc, 27, 0);
+ verboselog( device->machine(), 5, "dst %d dal %d saddr %08X\n", dst, dal, saddr);
+ opt = BITS( dma->regs.dcdst, 31, 30);
+ das = BITS( dma->regs.dcdst, 29, 28);
+ daddr = BITS( dma->regs.dcdst, 27, 0);
+ verboselog( device->machine(), 5, "opt %d das %d daddr %08X\n", opt, das, daddr);
+ cnt = BITS( dma->regs.dccnt, 19, 0);
+ verboselog( device->machine(), 5, "icnt %08X\n", cnt);
+ while (cnt > 0)
+ {
+ verboselog( device->machine(), 9, "[%08X] -> [%08X]\n", saddr, daddr);
+ switch (dst)
+ {
+ case 0 : s3c44b0->space->write_byte( daddr, s3c44b0->space->read_byte( saddr)); break;
+ case 1 : s3c44b0->space->write_word( daddr, s3c44b0->space->read_word( saddr)); break;
+ case 2 : s3c44b0->space->write_dword( daddr, s3c44b0->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);
+ }
+ dma->regs.dcsrc = CLR_BITS( dma->regs.dcsrc, 27, 0) | saddr;
+ dma->regs.dcdst = CLR_BITS( dma->regs.dcdst, 27, 0) | daddr;
+ dma->regs.dccnt = CLR_BITS( dma->regs.dcdst, 19, 0) | cnt;
+ if (cnt == 0)
+ {
+ if ((dma->regs.dccnt & (1 << 23)) != 0)
+ {
+ const int ch_int[] = { S3C44B0_INT_ZDMA0, S3C44B0_INT_ZDMA1 };
+ s3c44b0_request_irq( device, ch_int[ch]);
+ }
+ }
+}
+
+static void s3c44b0_zdma_start( device_t *device, int ch)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ s3c44b0_dma_t *dma = &s3c44b0->zdma[ch];
+ verboselog( device->machine(), 5, "ZDMA %d start\n", ch);
+ dma->regs.dcsrc = dma->regs.disrc;
+ dma->regs.dcdst = dma->regs.didst;
+ dma->regs.dccnt = dma->regs.dicnt;
+ s3c44b0_zdma_trigger( device, ch);
+}
+
+static UINT32 s3c44b0_zdma_r( device_t *device, int ch, UINT32 offset)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ UINT32 data = ((UINT32*)&s3c44b0->zdma[ch].regs)[offset];
+ return data;
+}
+
+static void s3c44b0_zdma_w( device_t *device, int ch, UINT32 offset, UINT32 data, UINT32 mem_mask)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ UINT32 old_value = ((UINT32*)&s3c44b0->zdma[ch].regs)[offset];
+ COMBINE_DATA(&((UINT32*)&s3c44b0->zdma[ch].regs)[offset]);
+ switch (offset)
+ {
+ case S3C44B0_DCON :
+ {
+ if ((old_value & 3) != (data & 3))
+ {
+ switch (data & 3)
+ {
+ case 1 : s3c44b0_zdma_start( device, ch); break;
+ }
+ }
+ s3c44b0->zdma[ch].regs.dcon &= ~3; // "After writing 01,10,11, CMD bit is cleared automatically"
+ }
+ break;
+ }
+}
+
+static READ32_DEVICE_HANDLER( s3c44b0_zdma_0_r )
+{
+ UINT32 data = s3c44b0_zdma_r( device, 0, offset);
+ verboselog( device->machine(), 9, "(ZDMA 0) %08X -> %08X\n", S3C44B0_BASE_ZDMA_0 + (offset << 2), data);
+ return data;
+}
+
+static READ32_DEVICE_HANDLER( s3c44b0_zdma_1_r )
+{
+ UINT32 data = s3c44b0_zdma_r( device, 1, offset);
+ verboselog( device->machine(), 9, "(ZDMA 1) %08X -> %08X\n", S3C44B0_BASE_ZDMA_1 + (offset << 2), data);
+ return data;
+}
+
+static WRITE32_DEVICE_HANDLER( s3c44b0_zdma_0_w )
+{
+ verboselog( device->machine(), 9, "(ZDMA 0) %08X <- %08X (%08X)\n", S3C44B0_BASE_ZDMA_0 + (offset << 2), data, mem_mask);
+ s3c44b0_zdma_w( device, 0, offset, data, mem_mask);
+}
+
+static WRITE32_DEVICE_HANDLER( s3c44b0_zdma_1_w )
+{
+ verboselog( device->machine(), 9, "(ZDMA 1) %08X <- %08X (%08X)\n", S3C44B0_BASE_ZDMA_1 + (offset << 2), data, mem_mask);
+ s3c44b0_zdma_w( device, 1, offset, data, mem_mask);
+}
+
+static TIMER_CALLBACK( s3c44b0_zdma_timer_exp )
+{
+ int ch = param;
+ verboselog( machine, 2, "ZDMA %d timer callback\n", ch);
+}
+
+/* BDMA */
+
+static void s3c44b0_bdma_trigger( device_t *device, int ch)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ s3c44b0_dma_t *dma = &s3c44b0->bdma[ch];
+ UINT32 saddr, daddr;
+ int dal, dst, tdm, das, cnt;
+ verboselog( device->machine(), 5, "s3c44b0_bdma_trigger %d\n", ch);
+ dst = BITS( dma->regs.dcsrc, 31, 30);
+ dal = BITS( dma->regs.dcsrc, 29, 28);
+ saddr = BITS( dma->regs.dcsrc, 27, 0);
+ verboselog( device->machine(), 5, "dst %d dal %d saddr %08X\n", dst, dal, saddr);
+ tdm = BITS( dma->regs.dcdst, 31, 30);
+ das = BITS( dma->regs.dcdst, 29, 28);
+ daddr = BITS( dma->regs.dcdst, 27, 0);
+ verboselog( device->machine(), 5, "tdm %d das %d daddr %08X\n", tdm, das, daddr);
+ cnt = BITS( dma->regs.dccnt, 19, 0);
+ verboselog( device->machine(), 5, "icnt %08X\n", cnt);
+ verboselog( device->machine(), 9, "[%08X] -> [%08X]\n", saddr, daddr);
+ switch (dst)
+ {
+ case 0 : s3c44b0->space->write_byte( daddr, s3c44b0->space->read_byte( saddr)); break;
+ case 1 : s3c44b0->space->write_word( daddr, s3c44b0->space->read_word( saddr)); break;
+ case 2 : s3c44b0->space->write_dword( daddr, s3c44b0->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);
+ dma->regs.dcsrc = CLR_BITS( dma->regs.dcsrc, 27, 0) | saddr;
+ dma->regs.dcdst = CLR_BITS( dma->regs.dcdst, 27, 0) | daddr;
+ dma->regs.dccnt = CLR_BITS( dma->regs.dcdst, 19, 0) | cnt;
+ if (cnt == 0)
+ {
+ if ((dma->regs.dccnt & (1 << 23)) != 0)
+ {
+ const int ch_int[] = { S3C44B0_INT_BDMA0, S3C44B0_INT_BDMA1 };
+ s3c44b0_request_irq( device, ch_int[ch]);
+ }
+ }
+}
+
+static void s3c44b0_bdma_request_iis( device_t *device)
+{
+// s3c44b0_t *s3c44b0 = get_token( device);
+// s3c44b0_dma_regs_t *regs = &s3c24xx->bdma[0].regs;
+ verboselog( device->machine(), 5, "s3c44b0_bdma_request_iis\n");
+ s3c44b0_bdma_trigger( device, 0);
+}
+
+static UINT32 s3c44b0_bdma_r( device_t *device, int ch, UINT32 offset)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ UINT32 data = ((UINT32*)&s3c44b0->bdma[ch].regs)[offset];
+ return data;
+}
+
+static void s3c44b0_bdma_start( device_t *device, int ch)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ s3c44b0_dma_t *dma = &s3c44b0->bdma[ch];
+ int qsc;
+ verboselog( device->machine(), 5, "BDMA %d start\n", ch);
+ qsc = BITS( dma->regs.dicnt, 31, 30);
+ if ((ch == 0) && (qsc == 1))
+ {
+ // IIS
+ }
+ else
+ {
+ printf( "s3c44b0_bdma_start - todo\n");
+ }
+ dma->regs.dcsrc = dma->regs.disrc;
+ dma->regs.dcdst = dma->regs.didst;
+ dma->regs.dccnt = dma->regs.dicnt;
+}
+
+static void s3c44b0_bdma_stop( device_t *device, int ch)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ verboselog( device->machine(), 5, "BDMA %d stop\n", ch);
+ s3c44b0->bdma[ch].timer->adjust( attotime::never, ch);
+}
+
+static void s3c44b0_bdma_w( device_t *device, int ch, UINT32 offset, UINT32 data, UINT32 mem_mask)
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ UINT32 old_value = ((UINT32*)&s3c44b0->bdma[ch].regs)[offset];
+ COMBINE_DATA(&((UINT32*)&s3c44b0->bdma[ch].regs)[offset]);
+ switch (offset)
+ {
+ case S3C44B0_DICNT :
+ {
+ if ((old_value & (1 << 20)) != (data & (1 << 20)))
+ {
+ if ((data & (1 << 20)) != 0)
+ {
+ s3c44b0_bdma_start( device, ch);
+ }
+ else
+ {
+ s3c44b0_bdma_stop( device, ch);
+ }
+ }
+ }
+ break;
+ }
+}
+
+static READ32_DEVICE_HANDLER( s3c44b0_bdma_0_r )
+{
+ UINT32 data = s3c44b0_bdma_r( device, 0, offset);
+ verboselog( device->machine(), 9, "(BDMA 0) %08X -> %08X\n", S3C44B0_BASE_BDMA_0 + (offset << 2), data);
+ return data;
+}
+
+static READ32_DEVICE_HANDLER( s3c44b0_bdma_1_r )
+{
+ UINT32 data = s3c44b0_bdma_r( device, 1, offset);
+ verboselog( device->machine(), 9, "(BDMA 1) %08X -> %08X\n", S3C44B0_BASE_BDMA_1 + (offset << 2), data);
+ return data;
+}
+
+static WRITE32_DEVICE_HANDLER( s3c44b0_bdma_0_w )
+{
+ verboselog( device->machine(), 9, "(BDMA 0) %08X <- %08X (%08X)\n", S3C44B0_BASE_BDMA_0 + (offset << 2), data, mem_mask);
+ s3c44b0_bdma_w( device, 0, offset, data, mem_mask);
+}
+
+static WRITE32_DEVICE_HANDLER( s3c44b0_bdma_1_w )
+{
+ verboselog( device->machine(), 9, "(BDMA 1) %08X <- %08X (%08X)\n", S3C44B0_BASE_BDMA_1 + (offset << 2), data, mem_mask);
+ s3c44b0_bdma_w( device, 1, offset, data, mem_mask);
+}
+
+static TIMER_CALLBACK( s3c44b0_bdma_timer_exp )
+{
+// device_t *device = (device_t *)ptr;
+// s3c44b0_t *s3c44b0 = get_token( device);
+ int ch = param;
+ verboselog( machine, 2, "BDMA %d timer callback\n", ch);
+}
+
+// ...
+
+static DEVICE_RESET( s3c44b0 )
+{
+ s3c44b0_t *s3c44b0 = get_token( device);
+ s3c44b0->iis.fifo_index = 0;
+// s3c44b0->iic.data_index = 0;
+#if defined(DEVICE_S3C2410) || defined(DEVICE_S3C2440)
+ s3c44b0->gpio.regs.gstatus2 = 0x00000001; // Boot is caused by power on reset
+#endif
+ s3c44b0->irq.line_irq = s3c44b0->irq.line_fiq = CLEAR_LINE;
+}
+
+VIDEO_START( s3c44b0 )
+{
+ device_t *device = machine.device( S3C44B0_TAG);
+ s3c44b0_video_start( device, machine);
+}
+
+SCREEN_UPDATE_RGB32( s3c44b0 )
+{
+ device_t *device = screen.machine().device( S3C44B0_TAG);
+ return s3c44b0_video_update( device, screen, bitmap, cliprect);
+}
+
+DEVICE_START( s3c44b0 )
+{
+ running_machine &machine = device->machine();
+ address_space *space = machine.device( "maincpu")->memory().space( AS_PROGRAM);
+ s3c44b0_t *s3c44b0 = get_token( device);
+ s3c44b0->iface = (const s3c44b0_interface *)device->static_config();
+ s3c44b0->space = space;
+ s3c44b0->cpu = downcast<cpu_device *>(device->machine().device( "maincpu"));
+ for (int i = 0; i < 6; i++) s3c44b0->pwm.timer[i] = machine.scheduler().timer_alloc(FUNC(s3c44b0_pwm_timer_exp), (void*)device);
+ for (int i = 0; i < 2; i++) s3c44b0->uart[i].timer = machine.scheduler().timer_alloc(FUNC(s3c44b0_uart_timer_exp), (void*)device);
+ for (int i = 0; i < 2; i++) s3c44b0->zdma[i].timer = machine.scheduler().timer_alloc(FUNC(s3c44b0_zdma_timer_exp), (void*)device);
+ for (int i = 0; i < 2; i++) s3c44b0->bdma[i].timer = machine.scheduler().timer_alloc(FUNC(s3c44b0_bdma_timer_exp), (void*)device);
+ s3c44b0->lcd.timer = machine.scheduler().timer_alloc(FUNC(s3c44b0_lcd_timer_exp), (void*)device);
+ s3c44b0->wdt.timer = machine.scheduler().timer_alloc(FUNC(s3c44b0_wdt_timer_exp), (void*)device);
+ s3c44b0->sio.timer = machine.scheduler().timer_alloc(FUNC(s3c44b0_sio_timer_exp), (void*)device);
+ s3c44b0->adc.timer = machine.scheduler().timer_alloc(FUNC(s3c44b0_adc_timer_exp), (void*)device);
+ s3c44b0->iic.timer = machine.scheduler().timer_alloc(FUNC(s3c44b0_iic_timer_exp), (void*)device);
+ s3c44b0->iis.timer = machine.scheduler().timer_alloc(FUNC(s3c44b0_iis_timer_exp), (void*)device);
+ space->install_legacy_readwrite_handler( *device, 0x01c00000, 0x01c0000b, 0, 0, FUNC(s3c44b0_cpuwrap_r), FUNC(s3c44b0_cpuwrap_w));
+ space->install_legacy_readwrite_handler( *device, 0x01d00000, 0x01d0002b, 0, 0, FUNC(s3c44b0_uart_0_r), FUNC(s3c44b0_uart_0_w));
+ space->install_legacy_readwrite_handler( *device, 0x01d04000, 0x01d0402b, 0, 0, FUNC(s3c44b0_uart_1_r), FUNC(s3c44b0_uart_1_w));
+ space->install_legacy_readwrite_handler( *device, 0x01d14000, 0x01d14013, 0, 0, FUNC(s3c44b0_sio_r), FUNC(s3c44b0_sio_w));
+ space->install_legacy_readwrite_handler( *device, 0x01d18000, 0x01d18013, 0, 0, FUNC(s3c44b0_iis_r), FUNC(s3c44b0_iis_w));
+ space->install_legacy_readwrite_handler( *device, 0x01d20000, 0x01d20057, 0, 0, FUNC(s3c44b0_gpio_r), FUNC(s3c44b0_gpio_w));
+ space->install_legacy_readwrite_handler( *device, 0x01d30000, 0x01d3000b, 0, 0, FUNC(s3c44b0_wdt_r), FUNC(s3c44b0_wdt_w));
+ space->install_legacy_readwrite_handler( *device, 0x01d40000, 0x01d4000b, 0, 0, FUNC(s3c44b0_adc_r), FUNC(s3c44b0_adc_w));
+ space->install_legacy_readwrite_handler( *device, 0x01d50000, 0x01d5004f, 0, 0, FUNC(s3c44b0_pwm_r), FUNC(s3c44b0_pwm_w));
+ space->install_legacy_readwrite_handler( *device, 0x01d60000, 0x01d6000f, 0, 0, FUNC(s3c44b0_iic_r), FUNC(s3c44b0_iic_w));
+ space->install_legacy_readwrite_handler( *device, 0x01d80000, 0x01d8000f, 0, 0, FUNC(s3c44b0_clkpow_r), FUNC(s3c44b0_clkpow_w));
+ space->install_legacy_readwrite_handler( *device, 0x01e00000, 0x01e0003f, 0, 0, FUNC(s3c44b0_irq_r), FUNC(s3c44b0_irq_w));
+ space->install_legacy_readwrite_handler( *device, 0x01e80000, 0x01e8001b, 0, 0, FUNC(s3c44b0_zdma_0_r), FUNC(s3c44b0_zdma_0_w));
+ space->install_legacy_readwrite_handler( *device, 0x01e80020, 0x01e8003b, 0, 0, FUNC(s3c44b0_zdma_1_r), FUNC(s3c44b0_zdma_1_w));
+ space->install_legacy_readwrite_handler( *device, 0x01f00000, 0x01f00047, 0, 0, FUNC(s3c44b0_lcd_r), FUNC(s3c44b0_lcd_w));
+ space->install_legacy_readwrite_handler( *device, 0x01f80000, 0x01f8001b, 0, 0, FUNC(s3c44b0_bdma_0_r), FUNC(s3c44b0_bdma_0_w));
+ space->install_legacy_readwrite_handler( *device, 0x01f80020, 0x01f8003b, 0, 0, FUNC(s3c44b0_bdma_1_r), FUNC(s3c44b0_bdma_1_w));
+}
+
+DEVICE_GET_INFO( s3c44b0 )
+{
+ switch ( state )
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(s3c44b0_t); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+// case DEVINFO_INT_CLASS: info->i = DEVICE_CLASS_PERIPHERAL; break;
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(s3c44b0); break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(s3c44b0); break;
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "S3C44B0"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.00"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright the MESS Team"); break;
+ case DEVINFO_STR_NAME: strcpy(info->s, "Samsung S3C44B0"); break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(S3C44B0, s3c44b0);
diff --git a/src/mess/machine/s3c44b0.h b/src/mess/machine/s3c44b0.h
new file mode 100644
index 00000000000..a60afd7fd13
--- /dev/null
+++ b/src/mess/machine/s3c44b0.h
@@ -0,0 +1,688 @@
+/*******************************************************************************
+
+ Samsung S3C44B0
+
+ (c) 2011 Tim Schuerewegen
+
+*******************************************************************************/
+
+#ifndef __S3C44B0_H__
+#define __S3C44B0_H__
+
+#include "devlegcy.h"
+
+/*******************************************************************************
+ MACROS / CONSTANTS
+*******************************************************************************/
+
+#define S3C44B0_TAG "s3c44b0"
+
+#define MCFG_S3C44B0_ADD(_tag, _clock, _config) \
+ MCFG_DEVICE_ADD(_tag, S3C44B0, _clock) \
+ MCFG_DEVICE_CONFIG(_config)
+
+#define S3C44B0_INTERFACE(name) \
+ const s3c44b0_interface(name) =
+
+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
+};
+
+DECLARE_LEGACY_DEVICE(S3C44B0, s3c44b0);
+
+/*******************************************************************************
+ TYPE DEFINITIONS
+*******************************************************************************/
+
+typedef UINT32 (*s3c44b0_gpio_port_r_func)( device_t *device, int port);
+typedef void (*s3c44b0_gpio_port_w_func)( device_t *device, int port, UINT32 data);
+
+typedef struct _s3c44b0_interface_gpio s3c44b0_interface_gpio;
+struct _s3c44b0_interface_gpio
+{
+ s3c44b0_gpio_port_r_func port_r;
+ s3c44b0_gpio_port_w_func port_w;
+};
+
+typedef struct _s3c44b0_interface_i2c s3c44b0_interface_i2c;
+struct _s3c44b0_interface_i2c
+{
+ write_line_device_func scl_w;
+ read_line_device_func sda_r;
+ write_line_device_func sda_w;
+};
+
+typedef struct _s3c44b0_interface_adc s3c44b0_interface_adc;
+struct _s3c44b0_interface_adc
+{
+ read32_device_func data_r;
+};
+
+typedef struct _s3c44b0_interface_i2s s3c44b0_interface_i2s;
+struct _s3c44b0_interface_i2s
+{
+ write16_device_func data_w;
+};
+
+typedef struct _s3c44b0_interface s3c44b0_interface;
+struct _s3c44b0_interface
+{
+ s3c44b0_interface_gpio gpio;
+ s3c44b0_interface_i2c i2c;
+ s3c44b0_interface_adc adc;
+ s3c44b0_interface_i2s i2s;
+};
+
+/*******************************************************************************
+ PROTOTYPES
+*******************************************************************************/
+
+DEVICE_GET_INFO( s3c44b0 );
+
+VIDEO_START( s3c44b0 );
+SCREEN_UPDATE_RGB32( s3c44b0 );
+
+void s3c44b0_request_eint( device_t *device, UINT32 number);
+
+/*******************************************************************************
+ 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
+
+/*******************************************************************************
+ TYPE DEFINITIONS
+*******************************************************************************/
+
+typedef struct
+{
+ UINT32 data[0x34/4];
+} s3c44b0_memcon_regs_t;
+
+typedef struct
+{
+ 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;
+} s3c44b0_irq_regs_t;
+
+typedef struct
+{
+ UINT32 dcon;
+ UINT32 disrc;
+ UINT32 didst;
+ UINT32 dicnt;
+ UINT32 dcsrc;
+ UINT32 dcdst;
+ UINT32 dccnt;
+} s3c44b0_dma_regs_t;
+
+typedef struct
+{
+ UINT32 pllcon;
+ UINT32 clkcon;
+ UINT32 clkslow;
+ UINT32 locktime;
+} s3c44b0_clkpow_regs_t;
+
+typedef struct
+{
+ UINT32 lcdcon1;
+ UINT32 lcdcon2;
+ UINT32 lcdsaddr1;
+ UINT32 lcdsaddr2;
+ UINT32 lcdsaddr3;
+ UINT32 redlut;
+ UINT32 greenlut;
+ UINT32 bluelut;
+ UINT32 reserved[8];
+ UINT32 lcdcon3;
+ UINT32 dithmode;
+} s3c44b0_lcd_regs_t;
+
+typedef struct
+{
+ UINT32 ulcon;
+ UINT32 ucon;
+ UINT32 ufcon;
+ UINT32 umcon;
+ UINT32 utrstat;
+ UINT32 uerstat;
+ UINT32 ufstat;
+ UINT32 umstat;
+ UINT32 utxh;
+ UINT32 urxh;
+ UINT32 ubrdiv;
+} s3c44b0_uart_regs_t;
+
+typedef struct
+{
+ UINT32 siocon;
+ UINT32 siodat;
+ UINT32 sbrdr;
+ UINT32 itvcnt;
+ UINT32 dcntz;
+} s3c44b0_sio_regs_t;
+
+typedef struct
+{
+ 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;
+} s3c44b0_pwm_regs_t;
+
+typedef struct
+{
+ UINT32 wtcon;
+ UINT32 wtdat;
+ UINT32 wtcnt;
+} s3c44b0_wdt_regs_t;
+
+typedef struct
+{
+ UINT32 iiccon;
+ UINT32 iicstat;
+ UINT32 iicadd;
+ UINT32 iicds;
+} s3c44b0_iic_regs_t;
+
+typedef struct
+{
+ UINT32 iiscon;
+ UINT32 iismod;
+ UINT32 iispsr;
+ UINT32 iisfcon;
+ UINT32 iisfifo;
+} s3c44b0_iis_regs_t;
+
+typedef struct
+{
+ 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;
+} s3c44b0_gpio_regs_t;
+
+typedef struct
+{
+ 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;
+} s3c44b0_rtc_regs_t;
+
+typedef struct
+{
+ UINT32 adccon;
+ UINT32 adcpsr;
+ UINT32 adcdat;
+} s3c44b0_adc_regs_t;
+
+typedef struct
+{
+ UINT32 syscfg;
+ UINT32 ncachbe0;
+ UINT32 ncachbe1;
+} s3c44b0_cpuwrap_regs_t;
+
+typedef struct
+{
+ s3c44b0_memcon_regs_t regs;
+} s3c44b0_memcon_t;
+
+typedef struct
+{
+ s3c44b0_irq_regs_t regs;
+ int line_irq, line_fiq;
+} s3c44b0_irq_t;
+
+typedef struct
+{
+ s3c44b0_dma_regs_t regs;
+ emu_timer *timer;
+} s3c44b0_dma_t;
+
+typedef struct
+{
+ s3c44b0_clkpow_regs_t regs;
+} s3c44b0_clkpow_t;
+
+typedef struct
+{
+ int x1, y1, x2, y2;
+} rectangle_t;
+
+typedef struct
+{
+ 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;
+} s3c44b0_lcd_t;
+
+typedef struct
+{
+ s3c44b0_uart_regs_t regs;
+ emu_timer *timer;
+} s3c44b0_uart_t;
+
+typedef struct
+{
+ s3c44b0_sio_regs_t regs;
+ emu_timer *timer;
+} s3c44b0_sio_t;
+
+typedef struct
+{
+ s3c44b0_pwm_regs_t regs;
+ emu_timer *timer[6];
+ UINT32 cnt[6];
+ UINT32 cmp[6];
+ UINT32 freq[6];
+} s3c44b0_pwm_t;
+
+typedef struct
+{
+ s3c44b0_wdt_regs_t regs;
+ emu_timer *timer;
+} s3c44b0_wdt_t;
+
+typedef struct
+{
+ s3c44b0_iic_regs_t regs;
+ emu_timer *timer;
+ int count;
+} s3c44b0_iic_t;
+
+typedef struct
+{
+ s3c44b0_iis_regs_t regs;
+ emu_timer *timer;
+ UINT16 fifo[16/2];
+ int fifo_index;
+} s3c44b0_iis_t;
+
+typedef struct
+{
+ s3c44b0_gpio_regs_t regs;
+} s3c44b0_gpio_t;
+
+typedef struct
+{
+ s3c44b0_rtc_regs_t regs;
+ emu_timer *timer_tick_count;
+ emu_timer *timer_update;
+} s3c44b0_rtc_t;
+
+typedef struct
+{
+ s3c44b0_adc_regs_t regs;
+ emu_timer *timer;
+} s3c44b0_adc_t;
+
+typedef struct
+{
+ s3c44b0_cpuwrap_regs_t regs;
+} s3c44b0_cpuwrap_t;
+
+typedef struct
+{
+ const s3c44b0_interface *iface;
+ address_space* space;
+ cpu_device *cpu;
+ s3c44b0_memcon_t memcon;
+ s3c44b0_irq_t irq;
+ s3c44b0_dma_t zdma[2];
+ s3c44b0_dma_t bdma[2];
+ s3c44b0_clkpow_t clkpow;
+ s3c44b0_lcd_t lcd;
+ s3c44b0_uart_t uart[2];
+ s3c44b0_sio_t sio;
+ s3c44b0_pwm_t pwm;
+ s3c44b0_wdt_t wdt;
+ s3c44b0_iic_t iic;
+ s3c44b0_iis_t iis;
+ s3c44b0_gpio_t gpio;
+ s3c44b0_rtc_t rtc;
+ s3c44b0_adc_t adc;
+ s3c44b0_cpuwrap_t cpuwrap;
+} s3c44b0_t;
+
+#endif
diff --git a/src/mess/machine/samcoupe.c b/src/mess/machine/samcoupe.c
new file mode 100644
index 00000000000..4e32e051f49
--- /dev/null
+++ b/src/mess/machine/samcoupe.c
@@ -0,0 +1,278 @@
+/***************************************************************************
+
+ SAM Coupe Driver - Written By Lee Hammerton, Dirk Best
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/samcoupe.h"
+#include "machine/msm6242.h"
+#include "machine/ram.h"
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define LMPR_RAM0 0x20 /* If bit set ram is paged into bank 0, else its rom0 */
+#define LMPR_ROM1 0x40 /* If bit set rom1 is paged into bank 3, else its ram */
+#define HMPR_MCNTRL 0x80 /* If set external RAM is enabled */
+
+
+/***************************************************************************
+ MEMORY BANKING
+***************************************************************************/
+
+static void samcoupe_update_bank(address_space *space, int bank_num, UINT8 *memory, int is_readonly)
+{
+ char bank[10];
+ sprintf(bank,"bank%d",bank_num);
+ samcoupe_state *state = space->machine().driver_data<samcoupe_state>();
+ if (memory)
+ {
+ state->membank(bank)->set_base(memory);
+ space->install_read_bank (((bank_num-1) * 0x4000), ((bank_num-1) * 0x4000) + 0x3FFF, bank);
+ if (is_readonly) {
+ space->unmap_write(((bank_num-1) * 0x4000), ((bank_num-1) * 0x4000) + 0x3FFF);
+ } else {
+ space->install_write_bank(((bank_num-1) * 0x4000), ((bank_num-1) * 0x4000) + 0x3FFF, bank);
+ }
+ } else {
+ space->nop_readwrite(((bank_num-1) * 0x4000), ((bank_num-1) * 0x4000) + 0x3FFF);
+ }
+}
+
+
+static void samcoupe_install_ext_mem(address_space *space)
+{
+ samcoupe_state *state = space->machine().driver_data<samcoupe_state>();
+ UINT8 *mem;
+
+ /* bank 3 */
+ if (state->m_lext >> 6 < space->machine().device<ram_device>(RAM_TAG)->size() >> 20)
+ mem = &space->machine().device<ram_device>(RAM_TAG)->pointer()[(space->machine().device<ram_device>(RAM_TAG)->size() & 0xfffff) + (state->m_lext >> 6) * 0x100000 + (state->m_lext & 0x3f) * 0x4000];
+ else
+ mem = NULL;
+
+ samcoupe_update_bank(space, 3, mem, FALSE);
+
+ /* bank 4 */
+ if (state->m_hext >> 6 < space->machine().device<ram_device>(RAM_TAG)->size() >> 20)
+ mem = &space->machine().device<ram_device>(RAM_TAG)->pointer()[(space->machine().device<ram_device>(RAM_TAG)->size() & 0xfffff) + (state->m_hext >> 6) * 0x100000 + (state->m_hext & 0x3f) * 0x4000];
+ else
+ mem = NULL;
+
+ samcoupe_update_bank(space, 4, mem, FALSE);
+}
+
+
+void samcoupe_update_memory(address_space *space)
+{
+ samcoupe_state *state = space->machine().driver_data<samcoupe_state>();
+ const int PAGE_MASK = ((space->machine().device<ram_device>(RAM_TAG)->size() & 0xfffff) / 0x4000) - 1;
+ UINT8 *rom = state->memregion("maincpu")->base();
+ UINT8 *memory;
+ int is_readonly;
+
+ /* BANK1 */
+ if (state->m_lmpr & LMPR_RAM0) /* Is ram paged in at bank 1 */
+ {
+ if ((state->m_lmpr & 0x1F) <= PAGE_MASK)
+ memory = &space->machine().device<ram_device>(RAM_TAG)->pointer()[(state->m_lmpr & PAGE_MASK) * 0x4000];
+ else
+ memory = NULL; /* Attempt to page in non existant ram region */
+ is_readonly = FALSE;
+ }
+ else
+ {
+ memory = rom; /* Rom0 paged in */
+ is_readonly = TRUE;
+ }
+ samcoupe_update_bank(space, 1, memory, is_readonly);
+
+
+ /* BANK2 */
+ if (((state->m_lmpr + 1) & 0x1f) <= PAGE_MASK)
+ memory = &space->machine().device<ram_device>(RAM_TAG)->pointer()[((state->m_lmpr + 1) & PAGE_MASK) * 0x4000];
+ else
+ memory = NULL; /* Attempt to page in non existant ram region */
+ samcoupe_update_bank(space, 2, memory, FALSE);
+
+ /* only update bank 3 and 4 when external memory is not enabled */
+ if (state->m_hmpr & HMPR_MCNTRL)
+ {
+ samcoupe_install_ext_mem(space);
+ }
+ else
+ {
+ /* BANK3 */
+ if ((state->m_hmpr & 0x1F) <= PAGE_MASK )
+ memory = &space->machine().device<ram_device>(RAM_TAG)->pointer()[(state->m_hmpr & PAGE_MASK)*0x4000];
+ else
+ memory = NULL; /* Attempt to page in non existant ram region */
+ samcoupe_update_bank(space, 3, memory, FALSE);
+
+
+ /* BANK4 */
+ if (state->m_lmpr & LMPR_ROM1) /* Is Rom1 paged in at bank 4 */
+ {
+ memory = rom + 0x4000;
+ is_readonly = TRUE;
+ }
+ else
+ {
+ if (((state->m_hmpr + 1) & 0x1f) <= PAGE_MASK)
+ memory = &space->machine().device<ram_device>(RAM_TAG)->pointer()[((state->m_hmpr + 1) & PAGE_MASK) * 0x4000];
+ else
+ memory = NULL; /* Attempt to page in non existant ram region */
+ is_readonly = FALSE;
+ }
+ samcoupe_update_bank(space, 4, memory, FALSE);
+ }
+
+ /* video memory location */
+ if (state->m_vmpr & 0x40) /* if bit set in 2 bank screen mode */
+ state->m_videoram = &space->machine().device<ram_device>(RAM_TAG)->pointer()[((state->m_vmpr & 0x1e) & PAGE_MASK) * 0x4000];
+ else
+ state->m_videoram = &space->machine().device<ram_device>(RAM_TAG)->pointer()[((state->m_vmpr & 0x1f) & PAGE_MASK) * 0x4000];
+}
+
+
+WRITE8_MEMBER(samcoupe_state::samcoupe_ext_mem_w)
+{
+ address_space *space_program = machine().device("maincpu")->memory().space(AS_PROGRAM);
+
+ if (offset & 1)
+ m_hext = data;
+ else
+ m_lext = data;
+
+ /* external RAM enabled? */
+ if (m_hmpr & HMPR_MCNTRL)
+ {
+ samcoupe_install_ext_mem(space_program);
+ }
+}
+
+
+/***************************************************************************
+ REAL TIME CLOCK
+***************************************************************************/
+
+static READ8_DEVICE_HANDLER( samcoupe_rtc_r )
+{
+ address_space *spaceio = device->machine().device("maincpu")->memory().space(AS_IO);
+ msm6242_device *rtc = dynamic_cast<msm6242_device*>(device);
+ return rtc->read(*spaceio,offset >> 12);
+}
+
+
+static WRITE8_DEVICE_HANDLER( samcoupe_rtc_w )
+{
+ address_space *spaceio = device->machine().device("maincpu")->memory().space(AS_IO);
+ msm6242_device *rtc = dynamic_cast<msm6242_device*>(device);
+ rtc->write(*spaceio,offset >> 12, data);
+}
+
+
+/***************************************************************************
+ MOUSE
+***************************************************************************/
+
+static TIMER_CALLBACK( samcoupe_mouse_reset )
+{
+ samcoupe_state *state = machine.driver_data<samcoupe_state>();
+ state->m_mouse_index = 0;
+}
+
+UINT8 samcoupe_mouse_r(running_machine &machine)
+{
+ samcoupe_state *state = machine.driver_data<samcoupe_state>();
+ UINT8 result;
+
+ /* on a read, reset the timer */
+ state->m_mouse_reset->adjust(attotime::from_usec(50));
+
+ /* update when we are about to read the first real values */
+ if (state->m_mouse_index == 2)
+ {
+ /* update values */
+ int mouse_x = machine.root_device().ioport("mouse_x")->read();
+ int mouse_y = machine.root_device().ioport("mouse_y")->read();
+
+ int mouse_dx = state->m_mouse_x - mouse_x;
+ int mouse_dy = state->m_mouse_y - mouse_y;
+
+ state->m_mouse_x = mouse_x;
+ state->m_mouse_y = mouse_y;
+
+ /* button state */
+ state->m_mouse_data[2] = machine.root_device().ioport("mouse_buttons")->read();
+
+ /* y-axis */
+ state->m_mouse_data[3] = (mouse_dy & 0xf00) >> 8;
+ state->m_mouse_data[4] = (mouse_dy & 0x0f0) >> 4;
+ state->m_mouse_data[5] = (mouse_dy & 0x00f) >> 0;
+
+ /* x-axis */
+ state->m_mouse_data[6] = (mouse_dx & 0xf00) >> 8;
+ state->m_mouse_data[7] = (mouse_dx & 0x0f0) >> 4;
+ state->m_mouse_data[8] = (mouse_dx & 0x00f) >> 0;
+ }
+
+ /* get current value */
+ result = state->m_mouse_data[state->m_mouse_index++];
+
+ /* reset if we are at the end */
+ if (state->m_mouse_index == sizeof(state->m_mouse_data))
+ state->m_mouse_index = 1;
+
+ return result;
+}
+
+MACHINE_START( samcoupe )
+{
+ samcoupe_state *state = machine.driver_data<samcoupe_state>();
+ state->m_mouse_reset = machine.scheduler().timer_alloc(FUNC(samcoupe_mouse_reset));
+
+ /* schedule our video updates */
+ state->m_video_update_timer = machine.scheduler().timer_alloc(FUNC(sam_video_update_callback));
+ state->m_video_update_timer->adjust(machine.primary_screen->time_until_pos(0, 0));
+}
+
+/***************************************************************************
+ RESET
+***************************************************************************/
+
+MACHINE_RESET( samcoupe )
+{
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ address_space *spaceio = machine.device("maincpu")->memory().space(AS_IO);
+ samcoupe_state *state = machine.driver_data<samcoupe_state>();
+
+ /* initialize state */
+ state->m_lmpr = 0x0f; /* ROM0 paged in, ROM1 paged out RAM Banks */
+ state->m_hmpr = 0x01;
+ state->m_vmpr = 0x81;
+ state->m_line_int = 0xff; /* line interrupts disabled */
+ state->m_status = 0x1f; /* no interrupts active */
+
+ /* initialize mouse */
+ state->m_mouse_index = 0;
+ state->m_mouse_data[0] = 0xff;
+ state->m_mouse_data[1] = 0xff;
+
+ if (machine.root_device().ioport("config")->read() & 0x01)
+ {
+ /* install RTC */
+ device_t *rtc = machine.device("sambus_clock");
+ spaceio->install_legacy_readwrite_handler(*rtc, 0xef, 0xef, 0xffff, 0xff00, FUNC(samcoupe_rtc_r), FUNC(samcoupe_rtc_w));
+ }
+ else
+ {
+ /* no RTC support */
+ spaceio->unmap_readwrite(0xef, 0xef, 0xffff, 0xff00);
+ }
+
+ /* initialize memory */
+ samcoupe_update_memory(space);
+}
diff --git a/src/mess/machine/sapi1.c b/src/mess/machine/sapi1.c
new file mode 100644
index 00000000000..64874e03de9
--- /dev/null
+++ b/src/mess/machine/sapi1.c
@@ -0,0 +1,55 @@
+/***************************************************************************
+
+ SAPI-1 driver by Miodrag Milanovic
+
+ 09/09/2008 Preliminary driver.
+
+****************************************************************************/
+
+#include "includes/sapi1.h"
+
+
+/* Driver initialization */
+DRIVER_INIT_MEMBER(sapi1_state,sapi1)
+{
+}
+
+MACHINE_RESET( sapi1 )
+{
+ sapi1_state *state = machine.driver_data<sapi1_state>();
+ state->m_keyboard_mask = 0;
+}
+
+MACHINE_START(sapi1)
+{
+}
+
+READ8_MEMBER( sapi1_state::sapi1_keyboard_r )
+{
+ UINT8 key = 0xff;
+ if (BIT(m_keyboard_mask, 0)) { key &= ioport("LINE0")->read(); }
+ if (BIT(m_keyboard_mask, 1)) { key &= ioport("LINE1")->read(); }
+ if (BIT(m_keyboard_mask, 2)) { key &= ioport("LINE2")->read(); }
+ if (BIT(m_keyboard_mask, 3)) { key &= ioport("LINE3")->read(); }
+ if (BIT(m_keyboard_mask, 4)) { key &= ioport("LINE4")->read(); }
+ return key;
+}
+
+WRITE8_MEMBER( sapi1_state::sapi1_keyboard_w )
+{
+ m_keyboard_mask = (data ^ 0xff ) & 0x1f;
+}
+
+
+MACHINE_RESET( sapizps3 )
+{
+ sapi1_state *state = machine.driver_data<sapi1_state>();
+ state->m_keyboard_mask = 0;
+ state->membank("bank1")->set_entry(1);
+}
+
+DRIVER_INIT_MEMBER(sapi1_state,sapizps3)
+{
+ UINT8 *RAM = memregion("maincpu")->base();
+ membank("bank1")->configure_entries(0, 2, &RAM[0x0000], 0xf800);
+}
diff --git a/src/mess/machine/sc499.c b/src/mess/machine/sc499.c
new file mode 100644
index 00000000000..812ddda9720
--- /dev/null
+++ b/src/mess/machine/sc499.c
@@ -0,0 +1,1183 @@
+/*
+ * sc499.c - ARCHIVE SC-499 cartridge tape controller (for Apollo DN3x00)
+ *_DeviceClass
+ * Created on: April 17, 2011
+ * Author: Hans Ostermeyer
+ *
+ * Released for general non-commercial use under the MAME license
+ * Visit http://mamedev.org for licensing and usage restrictions.
+ *
+ * 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 "machine/sc499.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 MAINCPU "maincpu"
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+//const device_type SC499 = sc499_device_config::static_alloc_device_config;
+
+sc499_device *sc499_device::m_device;
+
+//**************************************************************************
+// 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_TAG "sc499_ctape"
+#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>;
+
+//-------------------------------------------------
+// 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)
+{
+ memset(static_cast<sc499_interface *>(this), 0, sizeof(sc499_interface));
+}
+
+//-------------------------------------------------
+// static_set_interface - set the interface struct
+//-------------------------------------------------
+
+void sc499_device::static_set_interface(device_t &device, const sc499_interface &interface)
+{
+ sc499_device &sc499 = downcast<sc499_device &>(device);
+ static_cast<sc499_interface &>(sc499) = interface;
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void sc499_device::device_start()
+{
+ // FIXME: temporary hack: we allow only one device:
+ sc499_device::m_device = this;
+
+ LOG1(("start sc499"));
+
+ m_timer = m_device->machine().scheduler().timer_alloc(FUNC(static_timer_func), this);
+ m_timer1 = m_device->machine().scheduler().timer_alloc(FUNC(static_timer_func), this);
+
+ device_t *ctape_device = machine().device(SC499_CTAPE_TAG);
+ m_image = dynamic_cast<device_image_interface *> (ctape_device);
+
+ 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 = auto_alloc_array(machine(), UINT8, SC499_CTAPE_BLOCK_SIZE);
+ assert(m_ctape_block_buffer!= NULL);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void sc499_device::device_reset()
+{
+ LOG1(("reset sc499"));
+
+ 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;
+}
+
+/*-------------------------------------------------
+ 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 */
+
+ 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_get_previouspc(cpu), tag());
+ }
+ else
+ {
+ sprintf(statebuf, "%d.%03d", s, ms);
+ }
+ 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->length())
+ {
+ // tape has changed, get new size
+ m_image_length = m_image->length();
+ 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::timer_func(int timer_type)
+{
+ LOG2(("timer_func param=%d status=%x",timer_type, m_status));
+
+ switch (timer_type)
+ {
+ 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, timer_type, 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",
+ timer_type, m_status, m_tape_pos, m_underrun_counter));
+ }
+ else
+ {
+ LOG2(("timer_func param=%d status=%x tape_pos=%d - read data underrun %d",
+ timer_type, 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",
+ timer_type, m_status, m_tape_pos));
+ m_timer1->adjust(attotime::never, timer_type, 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",
+ timer_type, m_status, m_tape_pos, m_underrun_counter));
+ }
+
+ read_block();
+ m_underrun_counter = 0;
+ if (block_is_filemark())
+ {
+ m_timer1->adjust(attotime::never, timer_type, 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",timer_type));
+ m_timer->reset();
+ break;
+ }
+
+}
+
+TIMER_CALLBACK( sc499_device::static_timer_func )
+{
+ reinterpret_cast<sc499_device *> (ptr)->timer_func(param);
+}
+
+/*-------------------------------------------------
+ set_interrupt - set the IRQ state
+ -------------------------------------------------*/
+
+void sc499_device::set_interrupt(enum line_state state)
+{
+ if (set_irq != NULL && state != irq_state)
+ {
+ LOG2(("set_interrupt(%d)",state));
+ (*set_irq)(this, state);
+ irq_state = state;
+ }
+}
+
+/*-------------------------------------------------
+ set_dma_drq - set dma request output
+ -------------------------------------------------*/
+
+void sc499_device::set_dma_drq(enum line_state state)
+{
+ if (dma_drq != NULL && state != dma_drq_state)
+ {
+ LOG2(("set_dma_drq(%d)",state));
+ (*dma_drq)(this, state);
+ 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;
+
+ 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;
+}
+
+void sc499_device::write_port(offs_t offset, UINT8 data)
+{
+ 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_DEVICE_HANDLER( sc499_r )
+UINT8 sc499_device::read_port(offs_t offset)
+{
+ 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::set_tc_state(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_read() {
+ 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_write(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()
+{
+ if (m_tape_pos == 0)
+ {
+ // check if tape has been replaced or removed
+ check_tape();
+ }
+
+ m_image->fseek((UINT64) m_tape_pos * SC499_CTAPE_BLOCK_SIZE, SEEK_SET);
+
+ if (m_image->image_feof())
+ {
+ 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
+ {
+ m_image->fread(m_ctape_block_buffer, 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->fseek((UINT64) m_tape_pos * SC499_CTAPE_BLOCK_SIZE, SEEK_SET);
+ m_image->fwrite(m_ctape_block_buffer, SC499_CTAPE_BLOCK_SIZE);
+ 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, fm_pattern, 4) == 0 &&
+ memcmp(m_ctape_block_buffer, 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};
+
+ memcpy(m_ctape_block_buffer, fm_pattern, 4);
+ memcpy(m_ctape_block_buffer+4, m_ctape_block_buffer, SC499_CTAPE_BLOCK_SIZE-4);
+}
+
+//**************************************************************************
+// GLOBAL STUBS
+//**************************************************************************
+
+READ8_DEVICE_HANDLER( sc499_r )
+{
+ return downcast<sc499_device *> (device)->read_port(offset);
+}
+
+WRITE8_DEVICE_HANDLER( sc499_w )
+{
+ downcast<sc499_device *> (device)->write_port(offset, data);
+}
+
+void sc499_set_tc_state(running_machine *machine, int state)
+{
+ sc499_device::m_device->set_tc_state(state);
+}
+
+UINT8 sc499_dack_r(running_machine *machine)
+{
+ return sc499_device::m_device->dack_read();
+}
+
+void sc499_dack_w(running_machine *machine, UINT8 data)
+{
+ sc499_device::m_device->dack_write(data);
+}
+
+void sc499_set_verbose(int on_off)
+{
+ verbose = on_off == 0 ? 0 : VERBOSE > 1 ? VERBOSE : 1;
+}
+
+//##########################################################################
+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 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 "act"; }
+ virtual const option_guide *create_option_guide() const { return NULL; }
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+ virtual void device_start() { };
+};
+
+// device type definition
+extern const device_type SC499_CTAPE;
+
+const device_type SC499_CTAPE = &device_creator<sc499_ctape_image_device>;
+
+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),
+ device_image_interface(mconfig, *this)
+{
+}
+
+void sc499_ctape_image_device::device_config_complete()
+{
+ update_names(SC499_CTAPE, "ctape", "ct");
+};
+
+MACHINE_CONFIG_FRAGMENT( sc499_ctape )
+ MCFG_DEVICE_ADD(SC499_CTAPE_TAG, SC499_CTAPE, 0)
+MACHINE_CONFIG_END
diff --git a/src/mess/machine/sc499.h b/src/mess/machine/sc499.h
new file mode 100644
index 00000000000..90c43b7c55e
--- /dev/null
+++ b/src/mess/machine/sc499.h
@@ -0,0 +1,159 @@
+/*
+ * sc499.h - Archive Cartridge tape controller SC-499
+ *
+ * Created on: February 21, 2011
+ * Author: Hans Ostermeyer
+ *
+ * Released for general non-commercial use under the MAME license
+ * Visit http://mamedev.org for licensing and usage restrictions.
+ *
+ */
+
+#pragma once
+
+#ifndef SC499_H_
+#define SC499_H_
+
+#include "emu.h"
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+ ***************************************************************************/
+
+READ8_DEVICE_HANDLER( sc499_r );
+WRITE8_DEVICE_HANDLER( sc499_w );
+
+void sc499_set_tc_state(running_machine *machine, int state);
+UINT8 sc499_dack_r(running_machine *machine);
+void sc499_dack_w(running_machine *machine, UINT8 data);
+
+void sc499_set_verbose(int on_off);
+
+//**************************************************************************
+// DEVICE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_SC499_ADD(_tag, _interface) \
+ MCFG_FRAGMENT_ADD( sc499_ctape ) \
+ MCFG_DEVICE_ADD(_tag, SC499, 0) \
+ sc499_device::static_set_interface(*device, _interface);
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+typedef void (*sc499_set_irq)(const device_t *, int);
+typedef void (*sc499_dma_drq)(const device_t *,int);
+
+struct sc499_interface
+{
+ sc499_set_irq set_irq;
+ sc499_dma_drq dma_drq;
+ device_t *(*get_device)(running_machine*);
+};
+
+#define SC499_INTERFACE(name) const struct sc499_interface (name)
+
+// ======================> sc499_device
+
+class sc499_device: public device_t, public sc499_interface
+{
+public:
+ // construction/destruction
+ sc499_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // static configuration helpers
+ static void static_set_interface(device_t &device, const sc499_interface &interface);
+
+ int sc499_receive(const UINT8 data[], int length);
+ // device register I/O
+ UINT8 read_port(offs_t offset);
+ void write_port(offs_t offset, UINT8 data);
+
+ void set_tc_state(int state);
+ UINT8 dack_read();
+ void dack_write( UINT8 data);
+
+ // static pointer to myself (nasty: used for logging and dma ...)
+ static sc499_device *m_device;
+
+ virtual void device_reset();
+
+private:
+ // device-level overrides
+ virtual void device_start();
+
+ const char *cpu_context();
+
+ void tape_status_clear(UINT16 value);
+ void tape_status_set(UINT16 value);
+
+ void check_tape();
+
+ void timer_func(int param);
+ static TIMER_CALLBACK( static_timer_func );
+
+ 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;
+
+ UINT8 *m_ctape_block_buffer;
+
+ device_image_interface *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;
+};
+
+// device type definition
+extern const device_type SC499;
+
+MACHINE_CONFIG_EXTERN( sc499_ctape );
+
+#endif /* SC499_H_ */
diff --git a/src/mess/machine/scsibus.c b/src/mess/machine/scsibus.c
new file mode 100644
index 00000000000..986cdb017b7
--- /dev/null
+++ b/src/mess/machine/scsibus.c
@@ -0,0 +1,1018 @@
+/*
+ SCSIBus.c
+
+ Implementation of a raw SCSI/SASI bus for machines that don't use a SCSI
+ controler chip such as the RM Nimbus, which implements it as a bunch of
+ 74LS series chips.
+
+*/
+
+#include "emu.h"
+#include "machine/scsi.h"
+#include "machine/scsidev.h"
+#include "machine/scsibus.h"
+#include "debugger.h"
+#include "debug/debugcpu.h"
+#include "debug/debugcon.h"
+
+/*
+ LOGLEVEL
+ 0 no logging,
+ 1 just commands
+ 2 1 + data
+ 3 2 + line changes
+*/
+
+#define LOGLEVEL 0
+#define ENABLE_DATA_DUMP 1
+
+#define LOG(level,...) if(LOGLEVEL>=level) logerror(__VA_ARGS__)
+
+typedef struct _scsibus_t scsibus_t;
+struct _scsibus_t
+{
+ scsidev_device *devices[8];
+ const SCSIBus_interface *interface;
+
+ devcb_resolved_write_line out_bsy_func;
+ devcb_resolved_write_line out_sel_func;
+ devcb_resolved_write_line out_cd_func;
+ devcb_resolved_write_line out_io_func;
+ devcb_resolved_write_line out_msg_func;
+ devcb_resolved_write_line out_req_func;
+ devcb_resolved_write_line out_rst_func;
+
+ UINT8 linestate;
+ UINT8 last_id;
+ UINT8 phase;
+
+ UINT8 command[CMD_BUF_SIZE];
+ UINT8 cmd_idx;
+ UINT8 is_linked;
+
+ UINT8 status;
+ UINT8 sense;
+
+ UINT8 data[ADAPTEC_BUF_SIZE];
+ UINT16 data_idx;
+ int xfer_count;
+ int bytes_left;
+ int data_last;
+ int sectorbytes;
+
+ emu_timer *req_timer;
+ emu_timer *ack_timer;
+ emu_timer *sel_timer;
+ emu_timer *dataout_timer;
+};
+
+static void set_scsi_line_now(device_t *device, UINT8 line, UINT8 state);
+static void set_scsi_line_ack(device_t *device, UINT8 state);
+static void scsi_in_line_changed(device_t *device, UINT8 line, UINT8 state);
+static void scsi_out_line_change(device_t *device, UINT8 line, UINT8 state);
+static void scsi_out_line_change_now(device_t *device, UINT8 line, UINT8 state);
+static void scsi_out_line_req(device_t *device, UINT8 state);
+static TIMER_CALLBACK(req_timer_callback);
+static TIMER_CALLBACK(ack_timer_callback);
+static TIMER_CALLBACK(sel_timer_callback);
+static TIMER_CALLBACK(dataout_timer_callback);
+
+static void scsi_change_phase(device_t *device, UINT8 newphase);
+
+static const char *const linenames[] =
+{
+ "select", "busy", "request", "acknoledge", "C/D", "I/O", "message", "reset"
+};
+
+static const char *const phasenames[] =
+{
+ "data out", "data in", "command", "status", "none", "none", "message out", "message in", "bus free","select"
+};
+
+INLINE scsibus_t *get_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == SCSIBUS);
+
+ return (scsibus_t *) downcast<legacy_device_base *>(device)->token();
+}
+
+static void dump_bytes(UINT8 *buff, int count)
+{
+ int byteno;
+
+ for(byteno=0; byteno<count; byteno++)
+ {
+ logerror("%02X ",buff[byteno]);
+ }
+}
+
+static void dump_command_bytes(scsibus_t *bus)
+{
+
+ logerror("sending command 0x%02X to ScsiID %d\n",bus->command[0],bus->last_id);
+ dump_bytes(bus->command,bus->cmd_idx);
+ logerror("\n\n");
+}
+
+#if ENABLE_DATA_DUMP
+static void dump_data_bytes(scsibus_t *bus, int count)
+{
+
+ logerror("Data buffer[0..%d]\n",count);
+ dump_bytes(bus->data,count);
+ logerror("\n\n");
+}
+#endif
+
+static void scsibus_read_data(scsibus_t *bus)
+{
+ bus->data_last = (bus->bytes_left >= bus->sectorbytes) ? bus->sectorbytes : bus->bytes_left;
+
+ LOG(2,"SCSIBUS:scsibus_read_data bus->bytes_left=%04X, bus->data_last=%04X, bus->xfer_count=%04X\n",bus->bytes_left,bus->data_last,bus->xfer_count);
+
+ if (bus->data_last > 0)
+ {
+ bus->devices[bus->last_id]->ReadData(bus->data, bus->data_last);
+ bus->bytes_left-=bus->data_last;
+ bus->data_idx=0;
+ }
+}
+
+static void scsibus_write_data(scsibus_t *bus)
+{
+ if(bus->bytes_left >= bus->sectorbytes)
+ {
+ bus->devices[bus->last_id]->WriteData(bus->data, bus->sectorbytes);
+
+ bus->bytes_left-=bus->sectorbytes;
+ bus->data_idx=0;
+ }
+}
+
+/* SCSI Bus read/write */
+
+UINT8 scsi_data_r(device_t *device)
+{
+ scsibus_t *bus = get_token(device);
+ UINT8 result = 0;
+
+ switch (bus->phase)
+ {
+ case SCSI_PHASE_DATAIN :
+ result=bus->data[bus->data_idx++];
+
+ // 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((bus->data_idx==bus->sectorbytes) && (bus->bytes_left>0) && IS_READ_COMMAND())
+ {
+ scsibus_read_data(bus);
+ }
+ break;
+
+ case SCSI_PHASE_STATUS :
+ result=bus->status; // return command status
+ break;
+
+ case SCSI_PHASE_MESSAGE_IN :
+ result=0; // no errors for the time being !
+ break;
+ }
+
+ LOG(2,"scsi_data_r : %02x phase=%s, data_idx=%d, cmd_idx=%d\n",result,phasenames[bus->phase],bus->data_idx,bus->cmd_idx);
+ return result;
+}
+
+READ8_DEVICE_HANDLER( scsi_data_r )
+{
+ return scsi_data_r(device);
+}
+
+void scsi_data_w(device_t *device, UINT8 data)
+{
+ scsibus_t *bus = get_token(device);
+
+ switch (bus->phase)
+ {
+ // Note this assumes we only have one initiator and therefore
+ // only one line active.
+ case SCSI_PHASE_BUS_FREE :
+ bus->last_id=scsibus_driveno(data);
+ break;
+
+ case SCSI_PHASE_COMMAND :
+ bus->command[bus->cmd_idx++]=data;
+ break;
+
+ case SCSI_PHASE_DATAOUT :
+
+ //LOG(1,"SCSIBUS:xfer_count=%02X, bytes_left=%02X data_idx=%02X\n",bus->xfer_count,bus->bytes_left,bus->data_idx);
+
+ if(IS_COMMAND(SCSI_CMD_FORMAT_UNIT))
+ {
+ // Only store the first 4 bytes of the bad block list (the header)
+ //if(bus->data_idx<4)
+ bus->data[bus->data_idx++]=data;
+ dump_data_bytes(bus,4);
+ //else
+ // bus->data_idx++;
+
+ // If we have the first byte, then cancel the dataout timout
+ if(bus->data_idx==1)
+ bus->dataout_timer->adjust(attotime::never);
+
+ // When we have the first 3 bytes, calculate how many more are in the
+ // bad block list.
+ if(bus->data_idx==3)
+ {
+ bus->xfer_count+=((bus->data[2]<<8)+bus->data[3]);
+ bus->data_last=bus->xfer_count;
+ LOG(1,"format_unit reading an extra %d bytes\n",bus->xfer_count-4);
+ dump_data_bytes(bus,4);
+ }
+ }
+ else
+ {
+ bus->data[bus->data_idx++]=data;
+ }
+
+ // If the data buffer is full, and we are writing blocks flush it to the SCSI disk
+ if((bus->data_idx == bus->sectorbytes) && IS_WRITE_COMMAND())
+ scsibus_write_data(bus);
+ break;
+ }
+}
+
+WRITE8_DEVICE_HANDLER( scsi_data_w )
+{
+ scsi_data_w(device, data);
+}
+
+/* Get/Set lines */
+
+UINT8 get_scsi_lines(device_t *device)
+{
+ scsibus_t *bus = get_token(device);
+
+ return bus->linestate;
+}
+
+UINT8 get_scsi_line(device_t *device, UINT8 lineno)
+{
+ scsibus_t *bus = get_token(device);
+ UINT8 result=0;
+
+ switch (lineno)
+ {
+ case SCSI_LINE_SEL : result=(bus->linestate & (1<<SCSI_LINE_SEL)) >> SCSI_LINE_SEL; break;
+ case SCSI_LINE_BSY : result=(bus->linestate & (1<<SCSI_LINE_BSY)) >> SCSI_LINE_BSY; break;
+ case SCSI_LINE_REQ : result=(bus->linestate & (1<<SCSI_LINE_REQ)) >> SCSI_LINE_REQ; break;
+ case SCSI_LINE_ACK : result=(bus->linestate & (1<<SCSI_LINE_ACK)) >> SCSI_LINE_ACK; break;
+ case SCSI_LINE_CD : result=(bus->linestate & (1<<SCSI_LINE_CD )) >> SCSI_LINE_CD; break;
+ case SCSI_LINE_IO : result=(bus->linestate & (1<<SCSI_LINE_IO )) >> SCSI_LINE_IO; break;
+ case SCSI_LINE_MSG : result=(bus->linestate & (1<<SCSI_LINE_MSG)) >> SCSI_LINE_MSG; break;
+ case SCSI_LINE_RESET : result=(bus->linestate & (1<<SCSI_LINE_RESET)) >> SCSI_LINE_RESET; break;
+ }
+
+ LOG(3,"get_scsi_line(%s)=%d\n",linenames[lineno],result);
+
+ return result;
+}
+
+READ_LINE_DEVICE_HANDLER( scsi_bsy_r ) { return get_scsi_line(device, SCSI_LINE_BSY); }
+READ_LINE_DEVICE_HANDLER( scsi_sel_r ) { return get_scsi_line(device, SCSI_LINE_SEL); }
+READ_LINE_DEVICE_HANDLER( scsi_cd_r ) { return get_scsi_line(device, SCSI_LINE_CD); }
+READ_LINE_DEVICE_HANDLER( scsi_io_r ) { return get_scsi_line(device, SCSI_LINE_IO); }
+READ_LINE_DEVICE_HANDLER( scsi_msg_r ) { return get_scsi_line(device, SCSI_LINE_MSG); }
+READ_LINE_DEVICE_HANDLER( scsi_req_r ) { return get_scsi_line(device, SCSI_LINE_REQ); }
+READ_LINE_DEVICE_HANDLER( scsi_ack_r ) { return get_scsi_line(device, SCSI_LINE_ACK); }
+READ_LINE_DEVICE_HANDLER( scsi_rst_r ) { return get_scsi_line(device, SCSI_LINE_RESET); }
+
+void set_scsi_line(device_t *device, UINT8 line, UINT8 state)
+{
+ scsibus_t *bus = get_token(device);
+ UINT8 changed;
+
+ changed = ((bus->linestate & (1<<line)) != (state << line));
+
+ LOG(3,"set_scsi_line(%s,%d), changed=%d, linestate=%02X\n",linenames[line],state,changed,bus->linestate);
+
+ if(changed)
+ {
+ if (line==SCSI_LINE_ACK)
+ set_scsi_line_ack(device,state);
+ else
+ set_scsi_line_now(device,line,state);
+ }
+}
+
+WRITE_LINE_DEVICE_HANDLER( scsi_bsy_w ) { return set_scsi_line(device, SCSI_LINE_BSY, state); }
+WRITE_LINE_DEVICE_HANDLER( scsi_sel_w ) { return set_scsi_line(device, SCSI_LINE_SEL, state); }
+WRITE_LINE_DEVICE_HANDLER( scsi_cd_w ) { return set_scsi_line(device, SCSI_LINE_CD, state); }
+WRITE_LINE_DEVICE_HANDLER( scsi_io_w ) { return set_scsi_line(device, SCSI_LINE_IO, state); }
+WRITE_LINE_DEVICE_HANDLER( scsi_msg_w ) { return set_scsi_line(device, SCSI_LINE_MSG, state); }
+WRITE_LINE_DEVICE_HANDLER( scsi_req_w ) { return set_scsi_line(device, SCSI_LINE_REQ, state); }
+WRITE_LINE_DEVICE_HANDLER( scsi_ack_w ) { return set_scsi_line(device, SCSI_LINE_ACK, state); }
+WRITE_LINE_DEVICE_HANDLER( scsi_rst_w ) { return set_scsi_line(device, SCSI_LINE_RESET, state); }
+
+static void set_scsi_line_now(device_t *device, UINT8 line, UINT8 state)
+{
+ scsibus_t *bus = get_token(device);
+
+ if(state)
+ bus->linestate |= (1<<line);
+ else
+ bus->linestate &= ~(1<<line);
+
+ scsi_in_line_changed(device,line,state);
+}
+
+void set_scsi_line_ack(device_t *device, UINT8 state)
+{
+ scsibus_t *bus = get_token(device);
+
+ bus->ack_timer->adjust(attotime::from_nsec(ACK_DELAY_NS),state);
+}
+
+static void scsibus_exec_command(device_t *device)
+{
+ scsibus_t *bus = get_token(device);
+ int command_local = 0;
+ int newphase;
+
+ if(LOGLEVEL)
+ dump_command_bytes(bus);
+
+ //bus->is_linked=bus->command[bus->cmd_idx-1] & 0x01;
+ bus->is_linked=0;
+
+ // Assume command will succeed, if not set sytatus below.
+ if (bus->command[0]!=SCSI_CMD_REQUEST_SENSE)
+ SET_STATUS_SENSE(SCSI_STATUS_OK,SCSI_SENSE_NO_SENSE);
+
+ // Check for locally executed commands, and if found execute them
+ switch (bus->command[0])
+ {
+ // Test ready
+ case SCSI_CMD_TEST_READY :
+ LOG(1,"SCSIBUS: test_ready\n");
+ command_local=1;
+ bus->xfer_count=0;
+ bus->data_last=bus->xfer_count;
+ bus->bytes_left=0;
+ bus->devices[bus->last_id]->SetPhase(SCSI_PHASE_STATUS);
+ break;
+
+ // Recalibrate drive
+ case SCSI_CMD_RECALIBRATE :
+ LOG(1,"SCSIBUS: Recalibrate drive\n");
+ command_local=1;
+ bus->xfer_count=0;
+ bus->data_last=bus->xfer_count;
+ bus->bytes_left=0;
+ bus->devices[bus->last_id]->SetPhase(SCSI_PHASE_STATUS);
+ break;
+
+ // Request sense, return previous error codes
+ case SCSI_CMD_REQUEST_SENSE :
+ LOG(1,"SCSIBUS: request_sense\n");
+ command_local=1;
+ bus->xfer_count=SCSI_SENSE_SIZE;
+ bus->data_last=bus->xfer_count;
+ bus->bytes_left=0;
+ bus->data[0]=bus->sense;
+ bus->data[1]=0x00;
+ bus->data[2]=0x00;
+ bus->data[3]=0x00;
+ SET_STATUS_SENSE(SCSI_STATUS_OK,SCSI_SENSE_NO_SENSE);
+ bus->devices[bus->last_id]->SetPhase(SCSI_PHASE_DATAOUT);
+ break;
+
+ // Format unit
+ case SCSI_CMD_FORMAT_UNIT :
+ LOG(1,"SCSIBUS: format unit bus->command[1]=%02X & 0x10\n",(bus->command[1] & 0x10));
+ command_local=1;
+ if((bus->command[1] & 0x10)==0x10)
+ bus->devices[bus->last_id]->SetPhase(SCSI_PHASE_DATAOUT);
+ else
+ bus->devices[bus->last_id]->SetPhase(SCSI_PHASE_STATUS);
+
+ bus->xfer_count=4;
+ bus->data_last=bus->xfer_count;
+ bus->bytes_left=0;
+ bus->dataout_timer->adjust(attotime::from_seconds(FORMAT_UNIT_TIMEOUT));
+ break;
+
+ // Check track format Xebec
+ case SCSI_CMD_CHECK_TRACK_FORMAT :
+ LOG(1,"SCSIBUS: check track format\n");
+ command_local=1;
+ bus->xfer_count=0;
+ bus->data_last=bus->xfer_count;
+ bus->bytes_left=0;
+ bus->devices[bus->last_id]->SetPhase(SCSI_PHASE_STATUS);
+ break;
+
+ // Setup drive parameters Xebec
+ case SCSI_CMD_INIT_DRIVE_PARAMS :
+ LOG(1,"SCSIBUS: init_drive_params: Xebec S1410\n");
+ command_local=1;
+ bus->xfer_count=XEBEC_PARAMS_SIZE;
+ bus->data_last=bus->xfer_count;
+ bus->bytes_left=0;
+ bus->devices[bus->last_id]->SetPhase(SCSI_PHASE_DATAOUT);
+ break;
+
+ // Format bad track Xebec
+ case SCSI_CMD_FORMAT_ALT_TRACK :
+ LOG(1,"SCSIBUS: format_alt_track: Xebec S1410\n");
+ command_local=1;
+ bus->xfer_count=XEBEC_ALT_TRACK_SIZE;
+ bus->data_last=bus->xfer_count;
+ bus->bytes_left=0;
+ bus->devices[bus->last_id]->SetPhase(SCSI_PHASE_DATAOUT);
+ break;
+
+ // Write buffer Xebec S1410 specific
+ case SCSI_CMD_WRITE_SEC_BUFFER :
+ LOG(1,"SCSIBUS: write_sector_buffer: Xebec S1410\n");
+ command_local=1;
+ bus->xfer_count=XEBEC_SECTOR_BUFFER_SIZE;
+ bus->data_last=bus->xfer_count;
+ bus->bytes_left=0;
+ bus->devices[bus->last_id]->SetPhase(SCSI_PHASE_DATAOUT);
+ break;
+
+ // Read buffer Xebec S1410 specific
+ case SCSI_CMD_READ_SEC_BUFFER :
+ LOG(1,"SCSIBUS: read_sector_buffer: Xebec S1410\n");
+ command_local=1;
+ bus->xfer_count=XEBEC_SECTOR_BUFFER_SIZE;
+ bus->data_last=bus->xfer_count;
+ bus->bytes_left=0;
+ bus->devices[bus->last_id]->SetPhase(SCSI_PHASE_DATAIN);
+ break;
+
+ // Write buffer, Adaptec ACB40x0 specific
+ case SCSI_CMD_WRITE_DATA_BUFFER :
+ LOG(1,"SCSIBUS: write_buffer: Adaptec ACB40x0\n");
+ command_local=1;
+ bus->xfer_count=ADAPTEC_DATA_BUFFER_SIZE;
+ bus->data_last=bus->xfer_count;
+ bus->bytes_left=0;
+ bus->devices[bus->last_id]->SetPhase(SCSI_PHASE_DATAOUT);
+ break;
+
+ // Read buffer, Adaptec ACB40x0 specific
+ case SCSI_CMD_READ_DATA_BUFFER :
+ LOG(1,"SCSIBUS: read_data_buffer: Adaptec ACB40x0\n");
+ command_local=1;
+ bus->xfer_count=ADAPTEC_DATA_BUFFER_SIZE;
+ bus->data_last=bus->xfer_count;
+ bus->bytes_left=0;
+ bus->devices[bus->last_id]->SetPhase(SCSI_PHASE_DATAIN);
+ break;
+
+ // Send diagnostic info
+ case SCSI_CMD_SEND_DIAGNOSTIC :
+ LOG(1,"SCSIBUS: send_diagnostic\n");
+ command_local=1;
+ bus->xfer_count=(bus->command[3]<<8)+bus->command[4];
+ bus->data_last=bus->xfer_count;
+ bus->bytes_left=0;
+ bus->devices[bus->last_id]->SetPhase(SCSI_PHASE_DATAOUT);
+ break;
+
+ case SCSI_CMD_SEARCH_DATA_EQUAL :
+ LOG(1,"SCSIBUS: Search_data_equal ACB40x0\n");
+ command_local=1;
+ bus->xfer_count=0;
+ bus->data_last=bus->xfer_count;
+ bus->bytes_left=0;
+ bus->devices[bus->last_id]->SetPhase(SCSI_PHASE_STATUS);
+ break;
+
+ case SCSI_CMD_READ_DEFECT :
+ LOG(1,"SCSIBUS: read defect list\n");
+ command_local=1;
+
+ bus->data[0] = 0x00;
+ bus->data[1] = bus->command[2];
+ bus->data[3] = 0x00; // defect list len msb
+ bus->data[4] = 0x00; // defect list len lsb
+
+ bus->xfer_count=4;
+ bus->data_last=bus->xfer_count;
+ bus->bytes_left=0;
+ bus->devices[bus->last_id]->SetPhase(SCSI_PHASE_DATAIN);
+ break;
+
+ // write buffer
+ case SCSI_CMD_BUFFER_WRITE :
+ LOG(1,"SCSIBUS: write_buffer\n");
+ command_local=1;
+ bus->xfer_count=(bus->command[7]<<8)+bus->command[8];
+ bus->data_last=bus->xfer_count;
+ bus->bytes_left=0;
+ bus->devices[bus->last_id]->SetPhase(SCSI_PHASE_DATAOUT);
+ break;
+
+ // read buffer
+ case SCSI_CMD_BUFFER_READ :
+ LOG(1,"SCSIBUS: read_buffer\n");
+ command_local=1;
+ bus->xfer_count=(bus->command[7]<<8)+bus->command[8];
+ bus->data_last=bus->xfer_count;
+ bus->bytes_left=0;
+ bus->devices[bus->last_id]->SetPhase(SCSI_PHASE_DATAIN);
+ break;
+
+ // Xebec S1410
+ case SCSI_CMD_RAM_DIAGS :
+ case SCSI_CMD_DRIVE_DIAGS :
+ case SCSI_CMD_CONTROLER_DIAGS :
+ LOG(1,"SCSIBUS: Xebec RAM, disk or Controler diags [%02X]\n",bus->command[0]);
+ command_local=1;
+ bus->xfer_count=0;
+ bus->data_last=bus->xfer_count;
+ bus->bytes_left=0;
+ bus->devices[bus->last_id]->SetPhase(SCSI_PHASE_STATUS);
+ break;
+
+ // Commodore D9060/9090
+ case SCSI_CMD_PHYSICAL_DEVICE_ID :
+ LOG(1,"SCSIBUS: physical device ID\n");
+ command_local=1;
+ bus->xfer_count=0;
+ bus->data_last=bus->xfer_count;
+ bus->bytes_left=0;
+ bus->devices[bus->last_id]->SetPhase(SCSI_PHASE_STATUS);
+ break;
+ }
+
+
+ // Check for locally executed command, if not then pass it on
+ // to the disk driver
+ if(!command_local)
+ {
+ bus->devices[bus->last_id]->SetCommand(bus->command, bus->cmd_idx);
+ bus->devices[bus->last_id]->ExecCommand(&bus->xfer_count);
+ bus->bytes_left=bus->xfer_count;
+ bus->data_last=bus->xfer_count;
+ bus->data_idx=0;
+ }
+
+ bus->devices[bus->last_id]->GetPhase(&newphase);
+
+ scsi_change_phase(device,newphase);
+
+ LOG(1,"SCSIBUS:xfer_count=%02X, bytes_left=%02X data_idx=%02X\n",bus->xfer_count,bus->bytes_left,bus->data_idx);
+
+ // This is correct as we need to read from disk for commands other than just read data
+ if ((bus->phase == SCSI_PHASE_DATAIN) && (!command_local))
+ scsibus_read_data(bus);
+}
+
+static int datain_done(scsibus_t *bus)
+{
+ int result=0;
+
+ // Read data commands
+ if(IS_READ_COMMAND() && (bus->data_idx == bus->data_last) && (bus->bytes_left == 0))
+ result=1;
+ else if (bus->data_idx==bus->data_last)
+ result=1;
+
+ return result;
+}
+
+static int dataout_done(scsibus_t *bus)
+{
+ int result=0;
+
+ // Write data commands
+ if(IS_WRITE_COMMAND() && (bus->data_idx == 0) && (bus->bytes_left == 0))
+ result=1;
+ else if (bus->data_idx==bus->data_last)
+ result=1;
+
+ return result;
+}
+
+static void check_process_dataout(device_t *device)
+{
+ scsibus_t *bus = get_token(device);
+ int capacity=0;
+ int tracks;
+ adaptec_sense_t *sense;
+
+ LOG(1,"SCSIBUS:check_process_dataout cmd=%02X\n",bus->command[0]);
+
+ switch (bus->command[0])
+ {
+ case SCSI_CMD_INIT_DRIVE_PARAMS :
+ tracks=((bus->data[0]<<8)+bus->data[1]);
+ capacity=(tracks * bus->data[2]) * 17;
+ LOG(1,"Tracks=%d, Heads=%d\n",tracks,bus->data[2]);
+ LOG(1,"Setting disk capacity to %d blocks\n",capacity);
+ //debugger_break(device->machine());
+ break;
+
+ case SCSI_CMD_MODE_SELECT :
+ sense=(adaptec_sense_t *)bus->data;
+ tracks=(sense->cylinder_count[0]<<8)+sense->cylinder_count[1];
+ capacity=(tracks * sense->head_count * 17);
+ LOG(1,"Tracks=%d, Heads=%d sec/track=%d\n",tracks,sense->head_count,sense->sectors_per_track);
+ LOG(1,"Setting disk capacity to %d blocks\n",capacity);
+ dump_data_bytes(bus,0x16);
+ //debugger_break(device->machine());
+ break;
+ }
+}
+
+
+static void scsi_in_line_changed(device_t *device, UINT8 line, UINT8 state)
+{
+ scsibus_t *bus = get_token(device);
+ void *hdfile;
+
+ // Reset aborts and returns to bus free
+ if((line==SCSI_LINE_RESET) && (state==0))
+ {
+ scsi_change_phase(device,SCSI_PHASE_BUS_FREE);
+ bus->cmd_idx=0;
+ bus->data_idx=0;
+ bus->is_linked=0;
+
+ return;
+ }
+
+ switch (bus->phase)
+ {
+ case SCSI_PHASE_BUS_FREE :
+ if((line==SCSI_LINE_SEL) && (bus->devices[bus->last_id]!=NULL))
+ {
+ // Check to see if device had image file mounted, if not, do not set busy,
+ // and stay busfree.
+ bus->devices[bus->last_id]->GetDevice(&hdfile);
+ if(hdfile!=(void *)NULL)
+ {
+ if(state==0)
+ bus->sel_timer->adjust(attotime::from_nsec(BSY_DELAY_NS));
+ else
+ scsi_change_phase(device,SCSI_PHASE_COMMAND);
+ }
+ }
+ break;
+
+ case SCSI_PHASE_COMMAND :
+ if(line==SCSI_LINE_ACK)
+ {
+ if(state)
+ {
+ // If the command is ready go and execute it
+ if(bus->cmd_idx==get_scsi_cmd_len(bus->command[0]))
+ {
+ scsibus_exec_command(device);
+ }
+ else
+ scsi_out_line_change(device,SCSI_LINE_REQ,0);
+ }
+ else
+ scsi_out_line_change(device,SCSI_LINE_REQ,1);
+ }
+ break;
+
+ case SCSI_PHASE_DATAIN :
+ if(line==SCSI_LINE_ACK)
+ {
+ if(state)
+ {
+ if(datain_done(bus))
+ scsi_change_phase(device,SCSI_PHASE_STATUS);
+ else
+ scsi_out_line_change(device,SCSI_LINE_REQ,0);
+ }
+ else
+ scsi_out_line_change(device,SCSI_LINE_REQ,1);
+ }
+ break;
+
+ case SCSI_PHASE_DATAOUT :
+ if(line==SCSI_LINE_ACK)
+ {
+ if(state)
+ {
+ if(dataout_done(bus))
+ {
+ check_process_dataout(device);
+ scsi_change_phase(device,SCSI_PHASE_STATUS);
+ }
+ else
+ scsi_out_line_change(device,SCSI_LINE_REQ,0);
+ }
+ else
+ scsi_out_line_change(device,SCSI_LINE_REQ,1);
+ }
+ break;
+
+ case SCSI_PHASE_STATUS :
+ if(line==SCSI_LINE_ACK)
+ {
+ if(state)
+ {
+ if(bus->cmd_idx > 0)
+ {
+ scsi_change_phase(device,SCSI_PHASE_MESSAGE_IN);
+ }
+ else
+ scsi_out_line_change(device,SCSI_LINE_REQ,0);
+ }
+ else
+ {
+ bus->cmd_idx++;
+ scsi_out_line_change(device,SCSI_LINE_REQ,1);
+ }
+ }
+ break;
+
+ case SCSI_PHASE_MESSAGE_IN :
+ if(line==SCSI_LINE_ACK)
+ {
+ if(state)
+ {
+ if(bus->cmd_idx > 0)
+ {
+ if(bus->is_linked)
+ scsi_change_phase(device,SCSI_PHASE_COMMAND);
+ else
+ scsi_change_phase(device,SCSI_PHASE_BUS_FREE);
+ }
+ else
+ scsi_out_line_change(device,SCSI_LINE_REQ,0);
+ }
+ else
+ {
+ bus->cmd_idx++;
+ scsi_out_line_change(device,SCSI_LINE_REQ,1);
+ }
+ }
+ break;
+ }
+}
+
+static void scsi_out_line_change(device_t *device, UINT8 line, UINT8 state)
+{
+ if(line==SCSI_LINE_REQ)
+ scsi_out_line_req(device,state);
+ else
+ scsi_out_line_change_now(device,line,state);
+}
+
+static void scsi_out_line_change_now(device_t *device, UINT8 line, UINT8 state)
+{
+ scsibus_t *bus = get_token(device);
+
+ if(state)
+ bus->linestate |= (1<<line);
+ else
+ bus->linestate &= ~(1<<line);
+
+ LOG(3,"scsi_out_line_change(%s,%d)\n",linenames[line],state);
+
+ if(bus->interface->line_change_cb!=NULL)
+ bus->interface->line_change_cb(device,line,state);
+
+ switch (line)
+ {
+ case SCSI_LINE_BSY: bus->out_bsy_func(state); break;
+ case SCSI_LINE_SEL: bus->out_sel_func(state); break;
+ case SCSI_LINE_CD: bus->out_cd_func(state); break;
+ case SCSI_LINE_IO: bus->out_io_func(state); break;
+ case SCSI_LINE_MSG: bus->out_msg_func(state); break;
+ case SCSI_LINE_REQ: bus->out_req_func(state); break;
+ case SCSI_LINE_RESET: bus->out_rst_func(state); break;
+ }
+}
+
+static void scsi_out_line_req(device_t *device, UINT8 state)
+{
+ scsibus_t *bus = get_token(device);
+
+ bus->req_timer->adjust(attotime::from_nsec(REQ_DELAY_NS),state);
+}
+
+
+static TIMER_CALLBACK(req_timer_callback)
+{
+ scsi_out_line_change_now((device_t *)ptr, SCSI_LINE_REQ, param);
+}
+
+static TIMER_CALLBACK(ack_timer_callback)
+{
+ set_scsi_line_now((device_t *)ptr, SCSI_LINE_ACK, param);
+}
+
+static TIMER_CALLBACK(sel_timer_callback)
+{
+ scsi_out_line_change_now((device_t *)ptr, SCSI_LINE_BSY, param);
+}
+
+static TIMER_CALLBACK(dataout_timer_callback)
+{
+ scsibus_t *bus = get_token((device_t *)ptr);
+
+ // 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) && (bus->data_idx==0))
+ scsi_change_phase((device_t *)ptr,SCSI_PHASE_STATUS);
+
+}
+
+UINT8 get_scsi_phase(device_t *device)
+{
+ scsibus_t *bus = get_token(device);
+
+ return bus->phase;
+}
+
+
+static void scsi_change_phase(device_t *device, UINT8 newphase)
+{
+ scsibus_t *bus = get_token(device);
+
+ LOG(1,"scsi_change_phase() from=%s, to=%s\n",phasenames[bus->phase],phasenames[newphase]);
+
+ bus->phase=newphase;
+ bus->cmd_idx=0;
+ bus->data_idx=0;
+
+ switch(bus->phase)
+ {
+ case SCSI_PHASE_BUS_FREE :
+ scsi_out_line_change(device,SCSI_LINE_CD,1);
+ scsi_out_line_change(device,SCSI_LINE_IO,1);
+ scsi_out_line_change(device,SCSI_LINE_MSG,1);
+ scsi_out_line_change(device,SCSI_LINE_REQ,1);
+ scsi_out_line_change(device,SCSI_LINE_BSY,1);
+ LOG(1,"SCSIBUS: done\n\n");
+ //if (IS_COMMAND(SCSI_CMD_READ_CAPACITY))
+ // debugger_break(device->machine());
+ break;
+
+ case SCSI_PHASE_COMMAND :
+ scsi_out_line_change(device,SCSI_LINE_CD,0);
+ scsi_out_line_change(device,SCSI_LINE_IO,1);
+ scsi_out_line_change(device,SCSI_LINE_MSG,1);
+ scsi_out_line_change(device,SCSI_LINE_REQ,0);
+ LOG(1,"\nSCSIBUS: Command begin\n");
+ break;
+
+ case SCSI_PHASE_DATAOUT :
+ scsi_out_line_change(device,SCSI_LINE_CD,1);
+ scsi_out_line_change(device,SCSI_LINE_IO,1);
+ scsi_out_line_change(device,SCSI_LINE_MSG,1);
+ scsi_out_line_change(device,SCSI_LINE_REQ,0);
+ break;
+
+ case SCSI_PHASE_DATAIN :
+ scsi_out_line_change(device,SCSI_LINE_CD,1);
+ scsi_out_line_change(device,SCSI_LINE_IO,0);
+ scsi_out_line_change(device,SCSI_LINE_MSG,1);
+ scsi_out_line_change(device,SCSI_LINE_REQ,0);
+ break;
+
+ case SCSI_PHASE_STATUS :
+ scsi_out_line_change(device,SCSI_LINE_CD,0);
+ scsi_out_line_change(device,SCSI_LINE_IO,0);
+ scsi_out_line_change(device,SCSI_LINE_MSG,1);
+ scsi_out_line_change(device,SCSI_LINE_REQ,0);
+ break;
+
+ case SCSI_PHASE_MESSAGE_OUT :
+ scsi_out_line_change(device,SCSI_LINE_CD,0);
+ scsi_out_line_change(device,SCSI_LINE_IO,1);
+ scsi_out_line_change(device,SCSI_LINE_MSG,0);
+ scsi_out_line_change(device,SCSI_LINE_REQ,0);
+ break;
+
+ case SCSI_PHASE_MESSAGE_IN :
+ scsi_out_line_change(device,SCSI_LINE_CD,0);
+ scsi_out_line_change(device,SCSI_LINE_IO,0);
+ scsi_out_line_change(device,SCSI_LINE_MSG,0);
+ scsi_out_line_change(device,SCSI_LINE_REQ,0);
+ break;
+ }
+}
+
+UINT8 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;
+ }
+}
+
+// get the length of a SCSI command based on it's command byte type
+int 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("scsibus: Unknown SCSI command group %d, command byte=%02X", group,cbyte);
+
+ return 6;
+}
+
+void init_scsibus(device_t *device, int sectorbytes)
+{
+ scsibus_t *bus = get_token(device);
+ const SCSIConfigTable *scsidevs = bus->interface->scsidevs;
+ int devno;
+
+ // try to open the devices
+ for (devno = 0; devno < scsidevs->devs_present; devno++)
+ {
+ LOG(1,"SCSIBUS:init devno=%d \n",devno);
+ bus->devices[scsidevs->devices[devno].scsiID] = device->machine().device<scsidev_device>( scsidevs->devices[devno].tag );
+ }
+
+ bus->sectorbytes = sectorbytes;
+}
+
+static DEVICE_START( scsibus )
+{
+ scsibus_t *bus = get_token(device);
+
+ assert(device->static_config() != NULL);
+ bus->interface = (const SCSIBus_interface*)device->static_config();
+
+ memset(bus->devices, 0, sizeof(bus->devices));
+
+ bus->out_bsy_func.resolve(bus->interface->out_bsy_func, *device);
+ bus->out_sel_func.resolve(bus->interface->out_sel_func, *device);
+ bus->out_cd_func.resolve(bus->interface->out_cd_func, *device);
+ bus->out_io_func.resolve(bus->interface->out_io_func, *device);
+ bus->out_msg_func.resolve(bus->interface->out_msg_func, *device);
+ bus->out_req_func.resolve(bus->interface->out_req_func, *device);
+ bus->out_rst_func.resolve(bus->interface->out_rst_func, *device);
+
+ // All lines start high - inactive
+ bus->linestate=0xFF;
+
+ // Start with bus free
+ bus->phase=SCSI_PHASE_BUS_FREE;
+
+ // Setup req/ack/sel timers
+ bus->req_timer=device->machine().scheduler().timer_alloc(FUNC(req_timer_callback), (void *)device);
+ bus->ack_timer=device->machine().scheduler().timer_alloc(FUNC(ack_timer_callback), (void *)device);
+ bus->sel_timer=device->machine().scheduler().timer_alloc(FUNC(sel_timer_callback), (void *)device);
+ bus->dataout_timer=device->machine().scheduler().timer_alloc(FUNC(dataout_timer_callback), (void *)device);
+
+}
+
+static DEVICE_STOP( scsibus )
+{
+}
+
+static DEVICE_RESET( scsibus )
+{
+}
+
+DEVICE_GET_INFO( scsibus )
+{
+ switch ( state )
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(scsibus_t); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(scsibus); break;
+ case DEVINFO_FCT_STOP: info->stop = DEVICE_STOP_NAME(scsibus); break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(scsibus); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "SCSI bus"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "SCSI"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright the MAME and MESS Teams"); break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(SCSIBUS, scsibus);
diff --git a/src/mess/machine/scsibus.h b/src/mess/machine/scsibus.h
new file mode 100644
index 00000000000..bec06511835
--- /dev/null
+++ b/src/mess/machine/scsibus.h
@@ -0,0 +1,219 @@
+/*
+ SCSIBus.h
+
+ Implementation of a raw SCSI/SASI bus for machines that don't use a SCSI
+ controler chip such as the RM Nimbus, which implements it as a bunch of
+ 74LS series chips.
+
+*/
+
+#ifndef _SCSIBUS_H_
+#define _SCSIBUS_H_
+
+#include "emu.h"
+#include "machine/scsi.h"
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+DECLARE_LEGACY_DEVICE(SCSIBUS, scsibus);
+
+#define MCFG_SCSIBUS_ADD(_tag, _intrf) \
+ MCFG_DEVICE_ADD(_tag, SCSIBUS, 0) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define SCSI_LINE_SEL 0
+#define SCSI_LINE_BSY 1
+#define SCSI_LINE_REQ 2
+#define SCSI_LINE_ACK 3
+#define SCSI_LINE_CD 4
+#define SCSI_LINE_IO 5
+#define SCSI_LINE_MSG 6
+#define SCSI_LINE_RESET 7
+
+// Perhaps thse should be in scsi.h ?
+#define SCSI_PHASE_BUS_FREE 8
+#define SCSI_PHASE_SELECT 9
+
+#define REQ_DELAY_NS 90
+#define ACK_DELAY_NS 90
+#define BSY_DELAY_NS 50
+
+#define CMD_BUF_SIZE 32
+#define ADAPTEC_BUF_SIZE 1024
+
+#define SCSI_CMD_TEST_READY 0x00
+#define SCSI_CMD_RECALIBRATE 0x01
+#define SCSI_CMD_REQUEST_SENSE 0x03
+#define SCSI_CMD_FORMAT_UNIT 0x04
+#define SCSI_CMD_CHECK_TRACK_FORMAT 0x05
+#define SCSI_CMD_INIT_DRIVE_PARAMS 0x0C
+#define SCSI_CMD_FORMAT_ALT_TRACK 0x0E
+#define SCSI_CMD_WRITE_SEC_BUFFER 0x0F
+#define SCSI_CMD_READ_SEC_BUFFER 0x10
+#define SCSI_COMMAND_INQUIRY 0x12
+#define SCSI_CMD_WRITE_DATA_BUFFER 0x13
+#define SCSI_CMD_READ_DATA_BUFFER 0x14
+#define SCSI_CMD_MODE_SELECT 0x15
+#define SCSI_CMD_SEND_DIAGNOSTIC 0x1D
+#define SCSI_CMD_READ_CAPACITY 0x25
+#define SCSI_CMD_SEARCH_DATA_EQUAL 0x31
+#define SCSI_CMD_READ_DEFECT 0x37
+#define SCSI_CMD_BUFFER_WRITE 0x3B
+#define SCSI_CMD_BUFFER_READ 0x3C
+
+// Xebec SASI
+#define SCSI_CMD_RAM_DIAGS 0xE0
+#define SCSI_CMD_DRIVE_DIAGS 0xE3
+#define SCSI_CMD_CONTROLER_DIAGS 0xE4
+
+// Commodore D9060/9090 SASI
+#define SCSI_CMD_PHYSICAL_DEVICE_ID 0xc0
+
+#define RW_BUFFER_HEAD_BYTES 0x04
+
+#define ADAPTEC_DATA_BUFFER_SIZE 0x0400
+#define XEBEC_SECTOR_BUFFER_SIZE 0x0200
+
+#define XEBEC_PARAMS_SIZE 0x08
+#define XEBEC_ALT_TRACK_SIZE 0x03
+
+#define IS_COMMAND(cmd) (bus->command[0]==cmd)
+#define IS_READ_COMMAND() ((bus->command[0]==0x08) || (bus->command[0]==0x28) || (bus->command[0]==0xa8))
+#define IS_WRITE_COMMAND() ((bus->command[0]==0x0a) || (bus->command[0]==0x2a))
+#define SET_STATUS_SENSE(stat,sen) { bus->status=(stat); bus->sense=(sen); }
+
+#define FORMAT_UNIT_TIMEOUT 5
+
+//
+// Status / Sense data taken from Adaptec ACB40x0 documentation.
+//
+
+#define SCSI_STATUS_OK 0x00
+#define SCSI_STATUS_CHECK 0x02
+#define SCSI_STATUS_EQUAL 0x04
+#define SCSI_STATUS_BUSY 0x08
+
+#define SCSI_SENSE_ADDR_VALID 0x80
+#define SCSI_SENSE_NO_SENSE 0x00
+#define SCSI_SENSE_NO_INDEX 0x01
+#define SCSI_SENSE_SEEK_NOT_COMP 0x02
+#define SCSI_SENSE_WRITE_FAULT 0x03
+#define SCSI_SENSE_DRIVE_NOT_READY 0x04
+#define SCSI_SENSE_NO_TRACK0 0x06
+#define SCSI_SENSE_ID_CRC_ERROR 0x10
+#define SCSI_SENSE_UNCORRECTABLE 0x11
+#define SCSI_SENSE_ADDRESS_NF 0x12
+#define SCSI_SENSE_RECORD_NOT_FOUND 0x14
+#define SCSI_SENSE_SEEK_ERROR 0x15
+#define SCSI_SENSE_DATA_CHECK_RETRY 0x18
+#define SCSI_SENSE_ECC_VERIFY 0x19
+#define SCSI_SENSE_INTERLEAVE_ERROR 0x1A
+#define SCSI_SENSE_UNFORMATTED 0x1C
+#define SCSI_SENSE_ILLEGAL_COMMAND 0x20
+#define SCSI_SENSE_ILLEGAL_ADDRESS 0x21
+#define SCSI_SENSE_VOLUME_OVERFLOW 0x23
+#define SCSI_SENSE_BAD_ARGUMENT 0x24
+#define SCSI_SENSE_INVALID_LUN 0x25
+#define SCSI_SENSE_CART_CHANGED 0x28
+#define SCSI_SENSE_ERROR_OVERFLOW 0x2C
+
+#define SCSI_SENSE_SIZE 4
+
+typedef struct
+{
+ // 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;
+} adaptec_sense_t;
+
+/***************************************************************************
+ INTERFACE
+***************************************************************************/
+
+typedef struct _SCSIBus_interface SCSIBus_interface;
+struct _SCSIBus_interface
+{
+ const SCSIConfigTable *scsidevs; /* SCSI devices */
+ void (*line_change_cb)(device_t *device, UINT8 line, UINT8 state);
+
+ devcb_write_line out_bsy_func;
+ devcb_write_line out_sel_func;
+ devcb_write_line out_cd_func;
+ devcb_write_line out_io_func;
+ devcb_write_line out_msg_func;
+ devcb_write_line out_req_func;
+ devcb_write_line out_rst_func;
+};
+
+/* SCSI Bus read/write */
+
+UINT8 scsi_data_r(device_t *device);
+void scsi_data_w(device_t *device, UINT8 data);
+
+READ8_DEVICE_HANDLER( scsi_data_r );
+WRITE8_DEVICE_HANDLER( scsi_data_w );
+
+/* Get/Set lines */
+
+UINT8 get_scsi_lines(device_t *device);
+UINT8 get_scsi_line(device_t *device, UINT8 lineno);
+void set_scsi_line(device_t *device, UINT8 line, UINT8 state);
+
+READ_LINE_DEVICE_HANDLER( scsi_bsy_r );
+READ_LINE_DEVICE_HANDLER( scsi_sel_r );
+READ_LINE_DEVICE_HANDLER( scsi_cd_r );
+READ_LINE_DEVICE_HANDLER( scsi_io_r );
+READ_LINE_DEVICE_HANDLER( scsi_msg_r );
+READ_LINE_DEVICE_HANDLER( scsi_req_r );
+READ_LINE_DEVICE_HANDLER( scsi_ack_r );
+READ_LINE_DEVICE_HANDLER( scsi_rst_r );
+
+WRITE_LINE_DEVICE_HANDLER( scsi_bsy_w );
+WRITE_LINE_DEVICE_HANDLER( scsi_sel_w );
+WRITE_LINE_DEVICE_HANDLER( scsi_cd_w );
+WRITE_LINE_DEVICE_HANDLER( scsi_io_w );
+WRITE_LINE_DEVICE_HANDLER( scsi_msg_w );
+WRITE_LINE_DEVICE_HANDLER( scsi_req_w );
+WRITE_LINE_DEVICE_HANDLER( scsi_ack_w );
+WRITE_LINE_DEVICE_HANDLER( scsi_rst_w );
+
+/* Get current bus phase */
+
+UINT8 get_scsi_phase(device_t *device);
+
+/* utility functions */
+
+/* get a drive's number from it's select line */
+UINT8 scsibus_driveno(UINT8 drivesel);
+
+/* get the number of bytes for a scsi command */
+int get_scsi_cmd_len(int cbyte);
+
+/* Initialisation at machine reset time */
+void init_scsibus(device_t *device, int sectorbytes);
+
+#endif
diff --git a/src/mess/machine/ser_mouse.c b/src/mess/machine/ser_mouse.c
new file mode 100644
index 00000000000..7db5a057a3d
--- /dev/null
+++ b/src/mess/machine/ser_mouse.c
@@ -0,0 +1,246 @@
+/***************************************************************************
+
+ machine/ser_mouse.c
+
+ Code for emulating PC-style serial mouses
+
+***************************************************************************/
+
+#include "machine/ser_mouse.h"
+
+
+const device_type MSFT_SERIAL_MOUSE = &device_creator<microsoft_mouse_device>;
+const device_type MSYSTEM_SERIAL_MOUSE = &device_creator<mouse_systems_mouse_device>;
+
+serial_mouse_device::serial_mouse_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),
+ device_rs232_port_interface(mconfig, *this),
+ device_serial_interface(mconfig, *this)
+{
+}
+
+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)
+{
+}
+
+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)
+{
+}
+
+void serial_mouse_device::device_start()
+{
+ m_owner = dynamic_cast<rs232_port_device *>(owner());
+ m_timer = timer_alloc();
+ m_enabled = false;
+ set_frame();
+ set_tra_rate(1200);
+}
+
+void serial_mouse_device::device_reset()
+{
+ m_head = m_tail = 0;
+ tx(0);
+ m_dcd = 0;
+ m_owner->out_dcd(0);
+ m_dsr = 0;
+ m_owner->out_dsr(0);
+ m_ri = 0;
+ m_owner->out_ri(0);
+ m_cts = 0;
+ m_owner->out_cts(0);
+}
+
+void serial_mouse_device::tra_complete()
+{
+ if(m_tail != m_head)
+ transmit_register_setup(unqueue_data());
+}
+
+void serial_mouse_device::tra_callback()
+{
+ m_rbit = transmit_register_get_data_bit();
+ m_owner->out_rx(m_rbit);
+}
+
+/**************************************************************************
+ * 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)
+{
+ 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 = ioport("ser_mouse_x")->read();
+
+ dx = nx - ox;
+ if (dx<=-0x800) dx = nx + 0x1000 - ox; /* Prevent jumping */
+ if (dx>=0x800) dx = nx - 0x1000 - ox;
+ ox = nx;
+
+ ny = ioport("ser_mouse_y")->read();
+
+ dy = ny - oy;
+ if (dy<=-0x800) dy = ny + 0x1000 - oy;
+ if (dy>=0x800) dy = ny - 0x1000 - oy;
+ oy = ny;
+
+ nb = ioport("ser_mouse_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));
+ m_rbit = 1;
+ m_owner->out_rx(1);
+ }
+ else if(!state && m_enabled)
+ {
+ m_timer->adjust(attotime::never);
+ m_head = m_tail = 0;
+ m_rbit = 0;
+ m_owner->out_rx(0);
+ }
+ m_enabled = state;
+
+}
+
+void microsoft_mouse_device::check_state()
+{
+ if (m_dtr && m_rts)
+ {
+ /* RTS toggled */
+ if (!m_old_rts && m_rts)
+ {
+ /* reset mouse */
+ serial_mouse_device::device_reset();
+ /* Identify as Microsoft 3 Button Mouse */
+ queue_data('M');
+ queue_data('3');
+ }
+ /* start a timer to scan the mouse input */
+ set_mouse_enable(true);
+ }
+ else
+ set_mouse_enable(false);
+}
+
+
+
+/**************************************************************************
+ * 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/mess/machine/ser_mouse.h b/src/mess/machine/ser_mouse.h
new file mode 100644
index 00000000000..3e1466b21c9
--- /dev/null
+++ b/src/mess/machine/ser_mouse.h
@@ -0,0 +1,77 @@
+/*****************************************************************************
+ *
+ * machine/ser_mouse.h
+ *
+ ****************************************************************************/
+
+#ifndef SER_MOUSE_H_
+#define SER_MOUSE_H_
+
+#include "emu.h"
+#include "machine/serial.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);
+
+ virtual ioport_constructor device_input_ports() const;
+
+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 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 input_callback(UINT8 state) { m_input_state = state; }
+ virtual void tra_complete();
+ virtual void tra_callback();
+private:
+ UINT8 m_queue[256];
+ UINT8 m_head, m_tail, m_mb;
+
+ emu_timer *m_timer;
+ rs232_port_device *m_owner;
+ bool m_enabled;
+};
+
+class microsoft_mouse_device : public serial_mouse_device
+{
+public:
+ microsoft_mouse_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ virtual void dtr_w(UINT8 state) { m_dtr = state; check_state(); }
+ virtual void rts_w(UINT8 state) { m_rts = state; check_state(); m_old_rts = state; }
+protected:
+ virtual void set_frame() { set_data_frame(7, 1, SERIAL_PARITY_NONE); }
+ virtual void mouse_trans(int dx, int dy, int nb, int mbc);
+ virtual void device_reset() {m_old_rts = 0; serial_mouse_device::device_reset();}
+ virtual void device_config_complete() { m_shortname = "microsoft_mouse"; }
+private:
+ void check_state();
+ UINT8 m_old_rts;
+};
+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);
+ virtual void dtr_w(UINT8 state) { m_dtr = state; check_state(); }
+ virtual void rts_w(UINT8 state) { m_rts = state; check_state(); }
+protected:
+ virtual void set_frame() { set_data_frame(8, 1, SERIAL_PARITY_NONE); }
+ virtual void mouse_trans(int dx, int dy, int nb, int mbc);
+ virtual void device_config_complete() { m_shortname = "mouse_systems_mouse"; }
+private:
+ void check_state() { set_mouse_enable((m_dtr && m_rts)?true:false); }
+};
+
+extern const device_type MSYSTEM_SERIAL_MOUSE;
+
+#endif /* SER_MOUSE_H_ */
diff --git a/src/mess/machine/serial.c b/src/mess/machine/serial.c
new file mode 100644
index 00000000000..123a988cd31
--- /dev/null
+++ b/src/mess/machine/serial.c
@@ -0,0 +1,136 @@
+#include "emu.h"
+#include "serial.h"
+
+const device_type SERIAL_PORT = &device_creator<serial_port_device>;
+
+device_serial_port_interface::device_serial_port_interface(const machine_config &mconfig, device_t &device)
+ : device_slot_card_interface(mconfig, device)
+{
+ m_rbit = FALSE;
+ m_tbit = FALSE;
+}
+
+device_serial_port_interface::~device_serial_port_interface()
+{
+}
+
+serial_port_device::serial_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, SERIAL_PORT, "Serial Port", tag, owner, clock),
+ device_slot_interface(mconfig, *this),
+ m_dev(NULL)
+{
+}
+
+serial_port_device::serial_port_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),
+ device_slot_interface(mconfig, *this),
+ m_dev(NULL)
+{
+}
+
+serial_port_device::~serial_port_device()
+{
+}
+
+void serial_port_device::device_config_complete()
+{
+ const serial_port_interface *intf = reinterpret_cast<const serial_port_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<serial_port_interface *>(this) = *intf;
+ }
+ else
+ {
+ memset(&m_out_rx_cb, 0, sizeof(m_out_rx_cb));
+ }
+ m_dev = dynamic_cast<device_serial_port_interface *>(get_card_device());
+}
+
+void serial_port_device::device_start()
+{
+ m_out_rx_func.resolve(m_out_rx_cb, *this);
+}
+
+const device_type RS232_PORT = &device_creator<rs232_port_device>;
+
+device_rs232_port_interface::device_rs232_port_interface(const machine_config &mconfig, device_t &device)
+ : device_serial_port_interface(mconfig, device)
+{
+ m_dtr = FALSE;
+ m_rts = FALSE;
+ m_dcd = FALSE;
+ m_dsr = FALSE;
+ m_ri = FALSE;
+ m_cts = FALSE;
+}
+
+device_rs232_port_interface::~device_rs232_port_interface()
+{
+}
+
+rs232_port_device::rs232_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : serial_port_device(mconfig, RS232_PORT, "RS232 Port", tag, owner, clock)
+{
+}
+
+rs232_port_device::~rs232_port_device()
+{
+}
+
+void rs232_port_device::device_config_complete()
+{
+ const rs232_port_interface *intf = reinterpret_cast<const rs232_port_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<rs232_port_interface *>(this) = *intf;
+ memcpy(&(serial_port_interface::m_out_rx_cb), &(rs232_port_interface::m_out_rx_cb), sizeof(rs232_port_interface::m_out_rx_cb));
+ }
+ else
+ {
+ memset(&(serial_port_interface::m_out_rx_cb), 0, sizeof(serial_port_interface::m_out_rx_cb));
+ memset(&m_out_dcd_cb, 0, sizeof(m_out_dcd_cb));
+ memset(&m_out_dsr_cb, 0, sizeof(m_out_dsr_cb));
+ memset(&m_out_ri_cb, 0, sizeof(m_out_ri_cb));
+ memset(&m_out_cts_cb, 0, sizeof(m_out_cts_cb));
+ }
+ m_dev = dynamic_cast<device_rs232_port_interface *>(get_card_device());
+ serial_port_device::m_dev = dynamic_cast<device_serial_port_interface *>(get_card_device());
+ loopdtr = 0;
+ looprts = 0;
+}
+
+void rs232_port_device::device_start()
+{
+ serial_port_device::device_start();
+ m_out_dcd_func.resolve(m_out_dcd_cb, *this);
+ m_out_dsr_func.resolve(m_out_dsr_cb, *this);
+ m_out_ri_func.resolve(m_out_ri_cb, *this);
+ m_out_cts_func.resolve(m_out_cts_cb, *this);
+}
+
+// XXX:make loopback handshaking optional if needed
+WRITE_LINE_MEMBER( rs232_port_device::dtr_w )
+{
+ if(m_dev)
+ return m_dev->dtr_w(state);
+
+ if(serial_port_device::m_dev)
+ {
+ loopdtr = state;
+ out_dcd(state);
+ out_dsr(state);
+ }
+}
+
+WRITE_LINE_MEMBER( rs232_port_device::rts_w )
+{
+ if(m_dev)
+ return m_dev->rts_w(state);
+
+ if(serial_port_device::m_dev)
+ {
+ looprts = state;
+ out_cts(state);
+ }
+}
+
diff --git a/src/mess/machine/serial.h b/src/mess/machine/serial.h
new file mode 100644
index 00000000000..6f942a25b97
--- /dev/null
+++ b/src/mess/machine/serial.h
@@ -0,0 +1,123 @@
+#ifndef __SERIAL_H__
+#define __SERIAL_H__
+
+#include "emu.h"
+
+#define MCFG_SERIAL_PORT_ADD(_tag, _intf, _slot_intf, _def_slot, _def_inp) \
+ MCFG_DEVICE_ADD(_tag, SERIAL_PORT, 0) \
+ MCFG_DEVICE_CONFIG(_intf) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false)
+
+#define MCFG_RS232_PORT_ADD(_tag, _intf, _slot_intf, _def_slot, _def_inp) \
+ MCFG_DEVICE_ADD(_tag, RS232_PORT, 0) \
+ MCFG_DEVICE_CONFIG(_intf) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false)
+
+struct serial_port_interface
+{
+ devcb_write_line m_out_rx_cb;
+};
+
+class device_serial_port_interface : public device_slot_card_interface
+{
+public:
+ device_serial_port_interface(const machine_config &mconfig, device_t &device);
+ virtual ~device_serial_port_interface();
+
+ virtual void tx(UINT8 state) { m_tbit = state; }
+ virtual UINT8 rx() { return m_rbit; }
+protected:
+ UINT8 m_rbit;
+ UINT8 m_tbit;
+};
+
+class serial_port_device : public device_t,
+ public serial_port_interface,
+ public device_slot_interface
+{
+public:
+ serial_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ serial_port_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
+ virtual ~serial_port_device();
+
+ DECLARE_WRITE_LINE_MEMBER( tx ) { if(m_dev) m_dev->tx(state); }
+ DECLARE_READ_LINE_MEMBER( rx ) { return (m_dev) ? m_dev->rx() : 0; }
+
+ void out_rx(UINT8 param) { m_out_rx_func(param); }
+protected:
+ virtual void device_start();
+ virtual void device_config_complete();
+ device_serial_port_interface *m_dev;
+private:
+ devcb_resolved_write_line m_out_rx_func;
+};
+
+extern const device_type SERIAL_PORT;
+
+struct rs232_port_interface
+{
+ devcb_write_line m_out_rx_cb;
+ devcb_write_line m_out_dcd_cb;
+ devcb_write_line m_out_dsr_cb;
+ devcb_write_line m_out_ri_cb;
+ devcb_write_line m_out_cts_cb;
+};
+
+class device_rs232_port_interface : public device_serial_port_interface
+{
+public:
+ device_rs232_port_interface(const machine_config &mconfig, device_t &device);
+ virtual ~device_rs232_port_interface();
+
+ virtual void dtr_w(UINT8 state) { m_dtr = state; }
+ virtual void rts_w(UINT8 state) { m_rts = state; }
+
+ virtual UINT8 dcd_r() { return m_dcd; }
+ virtual UINT8 dsr_r() { return m_dsr; }
+ virtual UINT8 ri_r() { return m_ri; }
+ virtual UINT8 cts_r() { return m_cts; }
+protected:
+ UINT8 m_dtr;
+ UINT8 m_rts;
+ UINT8 m_dcd;
+ UINT8 m_dsr;
+ UINT8 m_ri;
+ UINT8 m_cts;
+};
+
+class rs232_port_device : public serial_port_device,
+ public rs232_port_interface
+{
+public:
+ rs232_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ virtual ~rs232_port_device();
+
+ DECLARE_WRITE_LINE_MEMBER( dtr_w );
+ DECLARE_WRITE_LINE_MEMBER( rts_w );
+
+ DECLARE_READ_LINE_MEMBER( dcd_r ) { return (m_dev) ? m_dev->dcd_r() : loopdtr; }
+ DECLARE_READ_LINE_MEMBER( dsr_r ) { return (m_dev) ? m_dev->dsr_r() : loopdtr; }
+ DECLARE_READ_LINE_MEMBER( ri_r ) { return (m_dev) ? m_dev->ri_r() : 0; }
+ DECLARE_READ_LINE_MEMBER( cts_r ) { return (m_dev) ? m_dev->cts_r() : looprts; }
+
+ void out_dcd(UINT8 param) { m_out_dcd_func(param); }
+ void out_dsr(UINT8 param) { m_out_dsr_func(param); }
+ void out_ri(UINT8 param) { m_out_ri_func(param); }
+ void out_cts(UINT8 param) { m_out_cts_func(param); }
+
+protected:
+ virtual void device_start();
+ virtual void device_config_complete();
+ device_rs232_port_interface *m_dev;
+private:
+ devcb_resolved_write_line m_out_dcd_func;
+ devcb_resolved_write_line m_out_dsr_func;
+ devcb_resolved_write_line m_out_ri_func;
+ devcb_resolved_write_line m_out_cts_func;
+ UINT8 loopdtr;
+ UINT8 looprts;
+};
+
+extern const device_type RS232_PORT;
+
+#endif
diff --git a/src/mess/machine/serialbox.c b/src/mess/machine/serialbox.c
new file mode 100644
index 00000000000..9c2a4a80eec
--- /dev/null
+++ b/src/mess/machine/serialbox.c
@@ -0,0 +1,151 @@
+/**********************************************************************
+
+ Serial Box 64K Serial Port Buffer emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#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<serial_box_device>;
+
+
+//-------------------------------------------------
+// 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),
+ 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/mess/machine/serialbox.h b/src/mess/machine/serialbox.h
new file mode 100644
index 00000000000..58c3c38ccc0
--- /dev/null
+++ b/src/mess/machine/serialbox.h
@@ -0,0 +1,69 @@
+/**********************************************************************
+
+ Serial Box 64K Serial Port Buffer emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __SERIAL_BOX__
+#define __SERIAL_BOX__
+
+
+#include "emu.h"
+#include "cpu/m6502/m6502.h"
+#include "machine/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();
+ virtual void device_config_complete() { m_shortname = "serbox"; }
+
+ // 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<cpu_device> m_maincpu;
+};
+
+
+// device type definition
+extern const device_type SERIAL_BOX;
+
+
+
+#endif
diff --git a/src/mess/machine/sgi.c b/src/mess/machine/sgi.c
new file mode 100644
index 00000000000..711e003e90d
--- /dev/null
+++ b/src/mess/machine/sgi.c
@@ -0,0 +1,512 @@
+/*********************************************************************
+
+ sgi.c
+
+ Silicon Graphics MC (Memory Controller) code
+
+*********************************************************************/
+
+#include "emu.h"
+#include "sgi.h"
+
+#define VERBOSE_LEVEL ( 2 )
+
+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( "%08x: %s", (unsigned) cpu_get_pc(machine.device("maincpu")), buf );
+ }
+}
+
+typedef struct
+{
+ emu_timer *tUpdateTimer;
+ UINT32 nCPUControl0;
+ UINT32 nCPUControl1;
+ UINT32 nWatchdog;
+ UINT32 nSysID;
+ UINT32 nRPSSDiv;
+ UINT32 nRefCntPreload;
+ UINT32 nRefCnt;
+ UINT32 nGIO64ArbParam;
+ UINT32 nArbCPUTime;
+ UINT32 nArbBurstTime;
+ UINT32 nMemCfg0;
+ UINT32 nMemCfg1;
+ UINT32 nCPUMemAccCfg;
+ UINT32 nGIOMemAccCfg;
+ UINT32 nCPUErrorAddr;
+ UINT32 nCPUErrorStatus;
+ UINT32 nGIOErrorAddr;
+ UINT32 nGIOErrorStatus;
+ UINT32 nSysSemaphore;
+ UINT32 nGIOLock;
+ UINT32 nEISALock;
+ UINT32 nGIO64TransMask;
+ UINT32 nGIO64Subst;
+ UINT32 nDMAIntrCause;
+ UINT32 nDMAControl;
+ UINT32 nDMATLBEntry0Hi;
+ UINT32 nDMATLBEntry0Lo;
+ UINT32 nDMATLBEntry1Hi;
+ UINT32 nDMATLBEntry1Lo;
+ UINT32 nDMATLBEntry2Hi;
+ UINT32 nDMATLBEntry2Lo;
+ UINT32 nDMATLBEntry3Hi;
+ UINT32 nDMATLBEntry3Lo;
+ UINT32 nRPSSCounter;
+ UINT32 nDMAMemAddr;
+ UINT32 nDMALineCntWidth;
+ UINT32 nDMALineZoomStride;
+ UINT32 nDMAGIO64Addr;
+ UINT32 nDMAMode;
+ UINT32 nDMAZoomByteCnt;
+ UINT32 nDMARunning;
+} MC_t;
+static MC_t *pMC;
+
+READ32_HANDLER( sgi_mc_r )
+{
+ offset <<= 2;
+ switch( offset )
+ {
+ case 0x0000:
+ case 0x0004:
+ //verboselog( space->machine(), 3, "CPU Control 0 Read: %08x (%08x)\n", pMC->nCPUControl0, mem_mask );
+ return pMC->nCPUControl0;
+ case 0x0008:
+ case 0x000c:
+ //verboselog( space->machine(), 2, "CPU Control 1 Read: %08x (%08x)\n", pMC->nCPUControl1, mem_mask );
+ return pMC->nCPUControl1;
+ case 0x0010:
+ case 0x0014:
+ //verboselog( space->machine(), 2, "Watchdog Timer Read: %08x (%08x)\n", pMC->nWatchdog, mem_mask );
+ return pMC->nWatchdog;
+ case 0x0018:
+ case 0x001c:
+ //verboselog( space->machine(), 2, "System ID Read: %08x (%08x)\n", pMC->nSysID, mem_mask );
+ return pMC->nSysID;
+ case 0x0028:
+ case 0x002c:
+ //verboselog( space->machine(), 2, "RPSS Divider Read: %08x (%08x)\n", pMC->nRPSSDiv, mem_mask );
+ return pMC->nRPSSDiv;
+ case 0x0030:
+ case 0x0034:
+ //verboselog( space->machine(), 2, "R4000 EEPROM Read\n" );
+ return 0;
+ case 0x0040:
+ case 0x0044:
+ //verboselog( space->machine(), 2, "Refresh Count Preload Read: %08x (%08x)\n", pMC->nRefCntPreload, mem_mask );
+ return pMC->nRefCntPreload;
+ case 0x0048:
+ case 0x004c:
+ //verboselog( space->machine(), 2, "Refresh Count Read: %08x (%08x)\n", pMC->nRefCnt, mem_mask );
+ return pMC->nRefCnt;
+ case 0x0080:
+ case 0x0084:
+ //verboselog( space->machine(), 2, "GIO64 Arbitration Param Read: %08x (%08x)\n", pMC->nGIO64ArbParam, mem_mask );
+ return pMC->nGIO64ArbParam;
+ case 0x0088:
+ case 0x008c:
+ //verboselog( space->machine(), 2, "Arbiter CPU Time Read: %08x (%08x)\n", pMC->nArbCPUTime, mem_mask );
+ return pMC->nArbCPUTime;
+ case 0x0098:
+ case 0x009c:
+ //verboselog( space->machine(), 2, "Arbiter Long Burst Time Read: %08x (%08x)\n", pMC->nArbBurstTime, mem_mask );
+ return pMC->nArbBurstTime;
+ case 0x00c0:
+ case 0x00c4:
+ //verboselog( space->machine(), 3, "Memory Configuration Register 0 Read: %08x (%08x)\n", pMC->nMemCfg0, mem_mask );
+ return pMC->nMemCfg0;
+ case 0x00c8:
+ case 0x00cc:
+ //verboselog( space->machine(), 3, "Memory Configuration Register 1 Read: %08x (%08x)\n", pMC->nMemCfg1, mem_mask );
+ return pMC->nMemCfg1;
+ case 0x00d0:
+ case 0x00d4:
+ //verboselog( space->machine(), 2, "CPU Memory Access Config Params Read: %08x (%08x)\n", pMC->nCPUMemAccCfg, mem_mask );
+ return pMC->nCPUMemAccCfg;
+ case 0x00d8:
+ case 0x00dc:
+ //verboselog( space->machine(), 2, "GIO Memory Access Config Params Read: %08x (%08x)\n", pMC->nGIOMemAccCfg, mem_mask );
+ return pMC->nGIOMemAccCfg;
+ case 0x00e0:
+ case 0x00e4:
+ //verboselog( space->machine(), 2, "CPU Error Address Read: %08x (%08x)\n", pMC->nCPUErrorAddr, mem_mask );
+ return pMC->nCPUErrorAddr;
+ case 0x00e8:
+ case 0x00ec:
+ //verboselog( space->machine(), 2, "CPU Error Status Read: %08x (%08x)\n", pMC->nCPUErrorStatus, mem_mask );
+ return pMC->nCPUErrorStatus;
+ case 0x00f0:
+ case 0x00f4:
+ //verboselog( space->machine(), 2, "GIO Error Address Read: %08x (%08x)\n", pMC->nGIOErrorAddr, mem_mask );
+ return pMC->nGIOErrorAddr;
+ case 0x00f8:
+ case 0x00fc:
+ //verboselog( space->machine(), 2, "GIO Error Status Read: %08x (%08x)\n", pMC->nGIOErrorStatus, mem_mask );
+ return pMC->nGIOErrorStatus;
+ case 0x0100:
+ case 0x0104:
+ //verboselog( space->machine(), 2, "System Semaphore Read: %08x (%08x)\n", pMC->nSysSemaphore, mem_mask );
+ return pMC->nSysSemaphore;
+ case 0x0108:
+ case 0x010c:
+ //verboselog( space->machine(), 2, "GIO Lock Read: %08x (%08x)\n", pMC->nGIOLock, mem_mask );
+ return pMC->nGIOLock;
+ case 0x0110:
+ case 0x0114:
+ //verboselog( space->machine(), 2, "EISA Lock Read: %08x (%08x)\n", pMC->nEISALock, mem_mask );
+ return pMC->nEISALock;
+ case 0x0150:
+ case 0x0154:
+ //verboselog( space->machine(), 2, "GIO64 Translation Address Mask Read: %08x (%08x)\n", pMC->nGIO64TransMask, mem_mask );
+ return pMC->nGIO64TransMask;
+ case 0x0158:
+ case 0x015c:
+ //verboselog( space->machine(), 2, "GIO64 Translation Address Substitution Bits Read: %08x (%08x)\n", pMC->nGIO64Subst, mem_mask );
+ return pMC->nGIO64Subst;
+ case 0x0160:
+ case 0x0164:
+ //verboselog( space->machine(), 2, "DMA Interrupt Cause: %08x (%08x)\n", pMC->nDMAIntrCause, mem_mask );
+ return pMC->nDMAIntrCause;
+ case 0x0168:
+ case 0x016c:
+ //verboselog( space->machine(), 2, "DMA Control Read: %08x (%08x)\n", pMC->nDMAControl, mem_mask );
+ return pMC->nDMAControl;
+ case 0x0180:
+ case 0x0184:
+ //verboselog( space->machine(), 2, "DMA TLB Entry 0 High Read: %08x (%08x)\n", pMC->nDMATLBEntry0Hi, mem_mask );
+ return pMC->nDMATLBEntry0Hi;
+ case 0x0188:
+ case 0x018c:
+ //verboselog( space->machine(), 2, "DMA TLB Entry 0 Low Read: %08x (%08x)\n", pMC->nDMATLBEntry0Lo, mem_mask );
+ return pMC->nDMATLBEntry0Lo;
+ case 0x0190:
+ case 0x0194:
+ //verboselog( space->machine(), 2, "DMA TLB Entry 1 High Read: %08x (%08x)\n", pMC->nDMATLBEntry1Hi, mem_mask );
+ return pMC->nDMATLBEntry1Hi;
+ case 0x0198:
+ case 0x019c:
+ //verboselog( space->machine(), 2, "DMA TLB Entry 1 Low Read: %08x (%08x)\n", pMC->nDMATLBEntry1Lo, mem_mask );
+ return pMC->nDMATLBEntry1Lo;
+ case 0x01a0:
+ case 0x01a4:
+ //verboselog( space->machine(), 2, "DMA TLB Entry 2 High Read: %08x (%08x)\n", pMC->nDMATLBEntry2Hi, mem_mask );
+ return pMC->nDMATLBEntry2Hi;
+ case 0x01a8:
+ case 0x01ac:
+ //verboselog( space->machine(), 2, "DMA TLB Entry 2 Low Read: %08x (%08x)\n", pMC->nDMATLBEntry2Lo, mem_mask );
+ return pMC->nDMATLBEntry2Lo;
+ case 0x01b0:
+ case 0x01b4:
+ //verboselog( space->machine(), 2, "DMA TLB Entry 3 High Read: %08x (%08x)\n", pMC->nDMATLBEntry3Hi, mem_mask );
+ return pMC->nDMATLBEntry3Hi;
+ case 0x01b8:
+ case 0x01bc:
+ //verboselog( space->machine(), 2, "DMA TLB Entry 3 Low Read: %08x (%08x)\n", pMC->nDMATLBEntry3Lo, mem_mask );
+ return pMC->nDMATLBEntry3Lo;
+ case 0x1000:
+ case 0x1004:
+ //verboselog( space->machine(), 2, "RPSS 100ns Counter Read: %08x (%08x)\n", pMC->nRPSSCounter, mem_mask );
+ return pMC->nRPSSCounter;
+ case 0x2000:
+ case 0x2004:
+ case 0x2008:
+ case 0x200c:
+ //verboselog( space->machine(), 0, "DMA Memory Address Read: %08x (%08x)\n", pMC->nDMAMemAddr, mem_mask );
+ return pMC->nDMAMemAddr;
+ case 0x2010:
+ case 0x2014:
+ //verboselog( space->machine(), 0, "DMA Line Count and Width Read: %08x (%08x)\n", pMC->nDMALineCntWidth, mem_mask );
+ return pMC->nDMALineCntWidth;
+ case 0x2018:
+ case 0x201c:
+ //verboselog( space->machine(), 0, "DMA Line Zoom and Stride Read: %08x (%08x)\n", pMC->nDMALineZoomStride, mem_mask );
+ return pMC->nDMALineZoomStride;
+ case 0x2020:
+ case 0x2024:
+ case 0x2028:
+ case 0x202c:
+ //verboselog( space->machine(), 0, "DMA GIO64 Address Read: %08x (%08x)\n", pMC->nDMAGIO64Addr, mem_mask );
+ return pMC->nDMAGIO64Addr;
+ case 0x2030:
+ case 0x2034:
+ //verboselog( space->machine(), 0, "DMA Mode Write: %08x (%08x)\n", pMC->nDMAMode, mem_mask );
+ return pMC->nDMAMode;
+ case 0x2038:
+ case 0x203c:
+ //verboselog( space->machine(), 0, "DMA Zoom Count Read: %08x (%08x)\n", pMC->nDMAZoomByteCnt, mem_mask );
+ return pMC->nDMAZoomByteCnt;
+// case 0x2040:
+// case 0x2044:
+// //verboselog( space->machine(), 2, "DMA Start Write: %08x (%08x)\n", data, mem_mask );
+ // Start DMA
+// pMC->nDMARunning = 1;
+// break;
+ case 0x2048:
+ case 0x204c:
+ //verboselog( space->machine(), 0, "VDMA Running Read: %08x (%08x)\n", pMC->nDMARunning, mem_mask );
+ if( pMC->nDMARunning == 1 )
+ {
+ pMC->nDMARunning = 0;
+ return 0x00000040;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ //verboselog( space->machine(), 0, "Unmapped MC read: 0x%08x (%08x)\n", 0x1fa00000 + offset, mem_mask );
+ return 0;
+}
+
+WRITE32_HANDLER( sgi_mc_w )
+{
+ offset <<= 2;
+ switch( offset )
+ {
+ case 0x0000:
+ case 0x0004:
+ //verboselog( space->machine(), 2, "CPU Control 0 Write: %08x (%08x)\n", data, mem_mask );
+ pMC->nCPUControl0 = data;
+ break;
+ case 0x0008:
+ case 0x000c:
+ //verboselog( space->machine(), 2, "CPU Control 1 Write: %08x (%08x)\n", data, mem_mask );
+ pMC->nCPUControl1 = data;
+ break;
+ case 0x0010:
+ case 0x0014:
+ //verboselog( space->machine(), 2, "Watchdog Timer Clear" );
+ pMC->nWatchdog = 0;
+ break;
+ case 0x0028:
+ case 0x002c:
+ //verboselog( space->machine(), 2, "RPSS Divider Write: %08x (%08x)\n", data, mem_mask );
+ pMC->nRPSSDiv = data;
+ break;
+ case 0x0030:
+ case 0x0034:
+ //verboselog( space->machine(), 2, "R4000 EEPROM Write\n" );
+ break;
+ case 0x0040:
+ case 0x0044:
+ //verboselog( space->machine(), 2, "Refresh Count Preload Write: %08x (%08x)\n", data, mem_mask );
+ pMC->nRefCntPreload = data;
+ break;
+ case 0x0080:
+ case 0x0084:
+ //verboselog( space->machine(), 2, "GIO64 Arbitration Param Write: %08x (%08x)\n", data, mem_mask );
+ pMC->nGIO64ArbParam = data;
+ break;
+ case 0x0088:
+ case 0x008c:
+ //verboselog( space->machine(), 3, "Arbiter CPU Time Write: %08x (%08x)\n", data, mem_mask );
+ pMC->nArbCPUTime = data;
+ break;
+ case 0x0098:
+ case 0x009c:
+ //verboselog( space->machine(), 3, "Arbiter Long Burst Time Write: %08x (%08x)\n", data, mem_mask );
+ pMC->nArbBurstTime = data;
+ break;
+ case 0x00c0:
+ case 0x00c4:
+ //verboselog( space->machine(), 3, "Memory Configuration Register 0 Write: %08x (%08x)\n", data, mem_mask );
+ pMC->nMemCfg0 = data;
+ break;
+ case 0x00c8:
+ case 0x00cc:
+ //verboselog( space->machine(), 3, "Memory Configuration Register 1 Write: %08x (%08x)\n", data, mem_mask );
+ pMC->nMemCfg1 = data;
+ break;
+ case 0x00d0:
+ case 0x00d4:
+ //verboselog( space->machine(), 2, "CPU Memory Access Config Params Write: %08x (%08x)\n", data, mem_mask );
+ pMC->nCPUMemAccCfg = data;
+ break;
+ case 0x00d8:
+ case 0x00dc:
+ //verboselog( space->machine(), 2, "GIO Memory Access Config Params Write: %08x (%08x)\n", data, mem_mask );
+ pMC->nGIOMemAccCfg = data;
+ break;
+ case 0x00e8:
+ case 0x00ec:
+ //verboselog( space->machine(), 2, "CPU Error Status Clear\n" );
+ pMC->nCPUErrorStatus = 0;
+ break;
+ case 0x00f8:
+ case 0x00fc:
+ //verboselog( space->machine(), 2, "GIO Error Status Clear\n" );
+ pMC->nGIOErrorStatus = 0;
+ break;
+ case 0x0100:
+ case 0x0104:
+ //verboselog( space->machine(), 2, "System Semaphore Write: %08x (%08x)\n", data, mem_mask );
+ pMC->nSysSemaphore = data;
+ break;
+ case 0x0108:
+ case 0x010c:
+ //verboselog( space->machine(), 2, "GIO Lock Write: %08x (%08x)\n", data, mem_mask );
+ pMC->nGIOLock = data;
+ break;
+ case 0x0110:
+ case 0x0114:
+ //verboselog( space->machine(), 2, "EISA Lock Write: %08x (%08x)\n", data, mem_mask );
+ pMC->nEISALock = data;
+ break;
+ case 0x0150:
+ case 0x0154:
+ //verboselog( space->machine(), 2, "GIO64 Translation Address Mask Write: %08x (%08x)\n", data, mem_mask );
+ pMC->nGIO64TransMask = data;
+ break;
+ case 0x0158:
+ case 0x015c:
+ //verboselog( space->machine(), 2, "GIO64 Translation Address Substitution Bits Write: %08x (%08x)\n", data, mem_mask );
+ pMC->nGIO64Subst = data;
+ break;
+ case 0x0160:
+ case 0x0164:
+ //verboselog( space->machine(), 0, "DMA Interrupt Cause Write: %08x (%08x)\n", data, mem_mask );
+ pMC->nDMAIntrCause = data;
+ break;
+ case 0x0168:
+ case 0x016c:
+ //verboselog( space->machine(), 0, "DMA Control Write: %08x (%08x)\n", data, mem_mask );
+ pMC->nDMAControl = data;
+ break;
+ case 0x0180:
+ case 0x0184:
+ //verboselog( space->machine(), 0, "DMA TLB Entry 0 High Write: %08x (%08x)\n", data, mem_mask );
+ pMC->nDMATLBEntry0Hi = data;
+ break;
+ case 0x0188:
+ case 0x018c:
+ //verboselog( space->machine(), 0, "DMA TLB Entry 0 Low Write: %08x (%08x)\n", data, mem_mask );
+ pMC->nDMATLBEntry0Lo = data;
+ break;
+ case 0x0190:
+ case 0x0194:
+ //verboselog( space->machine(), 0, "DMA TLB Entry 1 High Write: %08x (%08x)\n", data, mem_mask );
+ pMC->nDMATLBEntry1Hi = data;
+ break;
+ case 0x0198:
+ case 0x019c:
+ //verboselog( space->machine(), 0, "DMA TLB Entry 1 Low Write: %08x (%08x)\n", data, mem_mask );
+ pMC->nDMATLBEntry1Lo = data;
+ break;
+ case 0x01a0:
+ case 0x01a4:
+ //verboselog( space->machine(), 0, "DMA TLB Entry 2 High Write: %08x (%08x)\n", data, mem_mask );
+ pMC->nDMATLBEntry2Hi = data;
+ break;
+ case 0x01a8:
+ case 0x01ac:
+ //verboselog( space->machine(), 0, "DMA TLB Entry 2 Low Write: %08x (%08x)\n", data, mem_mask );
+ pMC->nDMATLBEntry2Lo = data;
+ break;
+ case 0x01b0:
+ case 0x01b4:
+ //verboselog( space->machine(), 0, "DMA TLB Entry 3 High Write: %08x (%08x)\n", data, mem_mask );
+ pMC->nDMATLBEntry3Hi = data;
+ break;
+ case 0x01b8:
+ case 0x01bc:
+ //verboselog( space->machine(), 0, "DMA TLB Entry 3 Low Write: %08x (%08x)\n", data, mem_mask );
+ pMC->nDMATLBEntry3Lo = data;
+ break;
+ case 0x2000:
+ case 0x2004:
+ //verboselog( space->machine(), 0, "DMA Memory Address Write: %08x (%08x)\n", data, mem_mask );
+ pMC->nDMAMemAddr = data;
+ break;
+ case 0x2008:
+ case 0x200c:
+ //verboselog( space->machine(), 0, "DMA Memory Address + Default Params Write: %08x (%08x)\n", data, mem_mask );
+ pMC->nDMAMemAddr = data;
+ break;
+ case 0x2010:
+ case 0x2014:
+ //verboselog( space->machine(), 0, "DMA Line Count and Width Write: %08x (%08x)\n", data, mem_mask );
+ pMC->nDMALineCntWidth = data;
+ break;
+ case 0x2018:
+ case 0x201c:
+ //verboselog( space->machine(), 0, "DMA Line Zoom and Stride Write: %08x (%08x)\n", data, mem_mask );
+ pMC->nDMALineZoomStride = data;
+ break;
+ case 0x2020:
+ case 0x2024:
+ //verboselog( space->machine(), 0, "DMA GIO64 Address Write: %08x (%08x)\n", data, mem_mask );
+ pMC->nDMAGIO64Addr = data;
+ break;
+ case 0x2028:
+ case 0x202c:
+ //verboselog( space->machine(), 0, "DMA GIO64 Address Write + Start DMA: %08x (%08x)\n", data, mem_mask );
+ pMC->nDMAGIO64Addr = data;
+ // Start DMA
+ pMC->nDMARunning = 1;
+ break;
+ case 0x2030:
+ case 0x2034:
+ //verboselog( space->machine(), 0, "DMA Mode Write: %08x (%08x)\n", data, mem_mask );
+ pMC->nDMAMode = data;
+ break;
+ case 0x2038:
+ case 0x203c:
+ //verboselog( space->machine(), 0, "DMA Zoom Count + Byte Count Write: %08x (%08x)\n", data, mem_mask );
+ pMC->nDMAZoomByteCnt = data;
+ break;
+ case 0x2040:
+ case 0x2044:
+ //verboselog( space->machine(), 0, "DMA Start Write: %08x (%08x)\n", data, mem_mask );
+ // Start DMA
+ pMC->nDMARunning = 1;
+ break;
+ case 0x2070:
+ case 0x2074:
+ //verboselog( space->machine(), 0, "DMA GIO64 Address Write + Default Params Write + Start DMA: %08x (%08x)\n", data, mem_mask );
+ pMC->nDMAGIO64Addr = data;
+ // Start DMA
+ pMC->nDMARunning = 1;
+ break;
+ default:
+ //verboselog( space->machine(), 0, "Unmapped MC write: 0x%08x: %08x (%08x)\n", 0x1fa00000 + offset, data, mem_mask );
+ break;
+ }
+}
+
+static void sgi_mc_update(void)
+{
+ pMC->nRPSSCounter += 1000;
+}
+
+static TIMER_CALLBACK(mc_update_callback)
+{
+ sgi_mc_update();
+}
+
+static void sgi_mc_timer_init(running_machine &machine)
+{
+ pMC->tUpdateTimer = machine.scheduler().timer_alloc(FUNC(mc_update_callback));
+ pMC->tUpdateTimer->adjust(attotime::from_hz(10000), 0, attotime::from_hz(10000));
+}
+
+void sgi_mc_init(running_machine &machine)
+{
+ pMC = auto_alloc_clear(machine, MC_t);
+
+ // if Indigo2, ID appropriately
+ if (!strcmp(machine.system().name, "ip244415"))
+ {
+ pMC->nSysID = 0x11; // rev. B MC, EISA bus present
+ }
+
+ sgi_mc_timer_init(machine);
+}
diff --git a/src/mess/machine/sgi.h b/src/mess/machine/sgi.h
new file mode 100644
index 00000000000..0b8591fac2a
--- /dev/null
+++ b/src/mess/machine/sgi.h
@@ -0,0 +1,18 @@
+/*********************************************************************
+
+ sgi.h
+
+ Silicon Graphics MC (Memory Controller) code
+
+*********************************************************************/
+
+#ifndef _SGIMC_H
+#define _SGIMC_H
+
+void sgi_mc_init(running_machine &machine);
+
+READ32_HANDLER(sgi_mc_r);
+WRITE32_HANDLER(sgi_mc_w);
+
+
+#endif /* _SGIMC_H */
diff --git a/src/mess/machine/smartmed.c b/src/mess/machine/smartmed.c
new file mode 100644
index 00000000000..87e62ddb513
--- /dev/null
+++ b/src/mess/machine/smartmed.c
@@ -0,0 +1,807 @@
+/*
+ smartmed.c: SmartMedia Flash ROM emulation
+
+ The SmartMedia is a Flash ROM in a fancy card. It is used in a variety of
+ digital devices (still cameras...) and can be interfaced with a computer.
+
+ References:
+ Datasheets for various SmartMedia chips were found on Samsung and Toshiba's
+ sites (http://www.toshiba.com/taec and
+ http://www.samsung.com/Products/Semiconductor/Flash/FlashCard/SmartMedia)
+
+ TODO:
+ * support multi-plane mode?
+ * use HD-format images instead of our experimental custom format?
+
+ Raphael Nabet 2004
+*/
+
+#include "emu.h"
+
+#include "smartmed.h"
+
+#include "harddisk.h"
+#include "imagedev/harddriv.h"
+#include "formats/imageutl.h"
+
+#define MAX_SMARTMEDIA 1
+
+/* machine-independent big-endian 32-bit integer */
+typedef struct UINT32BE
+{
+ UINT8 bytes[4];
+} UINT32BE;
+
+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
+
+/* SmartMedia image header */
+typedef struct disk_image_header
+{
+ UINT8 version;
+ UINT32BE page_data_size;
+ UINT32BE page_total_size;
+ UINT32BE num_pages;
+ UINT32BE log2_pages_per_block;
+} disk_image_header;
+
+typedef struct disk_image_format_2_header
+{
+ UINT8 data1[3];
+ UINT8 padding1[256-3];
+ UINT8 data2[16];
+ UINT8 data3[16];
+ UINT8 padding2[768-32];
+} disk_image_format_2_header;
+
+enum
+{
+ header_len = sizeof(disk_image_header)
+};
+
+
+const device_type NAND = &device_creator<nand_device>;
+
+nand_device::nand_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, NAND, "NAND Flash Memory", tag, owner, clock)
+{
+}
+nand_device::nand_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)
+{
+}
+
+void nand_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const nand_interface *intf = reinterpret_cast<const nand_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<nand_interface *>(this) = *intf;
+ m_id_len = m_chip.id_len;
+ memcpy( m_id, m_chip.id, m_chip.id_len);
+ m_page_data_size = m_chip.page_size;
+ m_page_total_size = m_chip.page_size + m_chip.oob_size;
+ m_log2_pages_per_block = compute_log2( m_chip.pages_per_block);
+ m_num_pages = m_chip.pages_per_block * m_chip.blocks_per_device;
+ m_col_address_cycles = m_chip.col_address_cycles;
+ m_row_address_cycles = m_chip.row_address_cycles;
+ m_sequential_row_read = m_chip.sequential_row_read;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_chip, 0, sizeof(m_chip));
+ memset(&m_devcb_write_line_cb, 0, sizeof(m_devcb_write_line_cb));
+ m_id_len = 0;
+ m_page_data_size = 0;
+ m_page_total_size = 0;
+ m_log2_pages_per_block = 0;
+ m_num_pages = 0;
+ m_pagereg = NULL;
+ m_col_address_cycles = 0;
+ m_row_address_cycles = 0;
+ m_sequential_row_read = 0;
+ }
+}
+/*
+ Init a SmartMedia image
+*/
+void nand_device::device_start()
+{
+ m_data_ptr = NULL;
+ m_data_uid_ptr = NULL;
+ m_mode = SM_M_INIT;
+ m_pointer_mode = SM_PM_A;
+ m_page_addr = 0;
+ m_byte_addr = 0;
+ m_status = 0xC0;
+ m_accumulated_status = 0;
+ m_mp_opcode = 0;
+ m_mode_3065 = 0;
+ m_pagereg = auto_alloc_array(machine(), UINT8, m_page_total_size);
+
+ #ifdef SMARTMEDIA_IMAGE_SAVE
+ m_image_format = 0;
+ #endif
+ m_devcb_write_line_rnb.resolve( m_devcb_write_line_cb, *this);
+}
+
+/*
+ Load a SmartMedia image
+*/
+bool smartmedia_image_device::smartmedia_format_1()
+{
+ disk_image_header custom_header;
+ int bytes_read;
+
+ bytes_read = fread(&custom_header, sizeof(custom_header));
+ if (bytes_read != sizeof(custom_header))
+ {
+ return IMAGE_INIT_FAIL;
+ }
+
+ if (custom_header.version > 1)
+ {
+ return IMAGE_INIT_FAIL;
+ }
+
+ m_page_data_size = get_UINT32BE(custom_header.page_data_size);
+ m_page_total_size = get_UINT32BE(custom_header.page_total_size);
+ m_num_pages = get_UINT32BE(custom_header.num_pages);
+ m_log2_pages_per_block = get_UINT32BE(custom_header.log2_pages_per_block);
+ m_data_ptr = auto_alloc_array(machine(), UINT8, m_page_total_size*m_num_pages);
+ m_data_uid_ptr = auto_alloc_array(machine(), UINT8, 256 + 16);
+ m_mode = SM_M_INIT;
+ m_pointer_mode = SM_PM_A;
+ m_page_addr = 0;
+ m_byte_addr = 0;
+ m_status = 0x40;
+ if (!is_readonly())
+ m_status |= 0x80;
+ m_accumulated_status = 0;
+ m_pagereg = auto_alloc_array(machine(), UINT8, m_page_total_size);
+ memset( m_id, 0, sizeof( m_id));
+ m_id_len = 0;
+ m_col_address_cycles = 1;
+ m_row_address_cycles = (m_num_pages > 0x10000) ? 3 : 2;
+ m_sequential_row_read = 1;
+
+ if (custom_header.version == 0)
+ {
+ m_id_len = 2;
+ fread(m_id, m_id_len);
+ fread(&m_mp_opcode, 1);
+ }
+ else if (custom_header.version == 1)
+ {
+ m_id_len = 3;
+ fread(m_id, m_id_len);
+ fread(&m_mp_opcode, 1);
+ fread(m_data_uid_ptr, 256 + 16);
+ }
+ fread(m_data_ptr, m_page_total_size*m_num_pages);
+
+ #ifdef SMARTMEDIA_IMAGE_SAVE
+ m_image_format = 1;
+ #endif
+
+ return IMAGE_INIT_PASS;
+}
+
+int smartmedia_image_device::detect_geometry( UINT8 id1, UINT8 id2)
+{
+ int result = FALSE;
+
+ switch (id1)
+ {
+ case 0xEC :
+ {
+ switch (id2)
+ {
+ case 0xA4 : m_page_data_size = 0x0100; m_num_pages = 0x00800; m_page_total_size = 0x0108; m_log2_pages_per_block = 0; result = TRUE; break;
+ case 0x6E : m_page_data_size = 0x0100; m_num_pages = 0x01000; m_page_total_size = 0x0108; m_log2_pages_per_block = 0; result = TRUE; break;
+ case 0xEA : m_page_data_size = 0x0100; m_num_pages = 0x02000; m_page_total_size = 0x0108; m_log2_pages_per_block = 4; result = TRUE; break;
+ case 0xE3 : m_page_data_size = 0x0200; m_num_pages = 0x02000; m_page_total_size = 0x0210; m_log2_pages_per_block = 4; result = TRUE; break;
+ case 0xE6 : m_page_data_size = 0x0200; m_num_pages = 0x04000; m_page_total_size = 0x0210; m_log2_pages_per_block = 4; result = TRUE; break;
+ case 0x73 : m_page_data_size = 0x0200; m_num_pages = 0x08000; m_page_total_size = 0x0210; m_log2_pages_per_block = 5; result = TRUE; break;
+ case 0x75 : m_page_data_size = 0x0200; m_num_pages = 0x10000; m_page_total_size = 0x0210; m_log2_pages_per_block = 5; result = TRUE; break;
+ case 0x76 : m_page_data_size = 0x0200; m_num_pages = 0x20000; m_page_total_size = 0x0210; m_log2_pages_per_block = 5; result = TRUE; break;
+ case 0x79 : m_page_data_size = 0x0200; m_num_pages = 0x40000; m_page_total_size = 0x0210; m_log2_pages_per_block = 5; result = TRUE; break;
+ }
+ }
+ break;
+ case 0x98 :
+ {
+ switch (id2)
+ {
+ case 0x75 : m_page_data_size = 0x0200; m_num_pages = 0x10000; m_page_total_size = 0x0210; m_log2_pages_per_block = 5; result = TRUE; break;
+ }
+ }
+ break;
+ }
+
+ return result;
+}
+
+bool smartmedia_image_device::smartmedia_format_2()
+{
+ disk_image_format_2_header custom_header;
+ int bytes_read, i, j;
+
+ bytes_read = fread(&custom_header, sizeof(custom_header));
+ if (bytes_read != sizeof(custom_header))
+ {
+ return IMAGE_INIT_FAIL;
+ }
+
+ if ((custom_header.data1[0] != 0xEC) && (custom_header.data1[0] != 0x98))
+ {
+ return IMAGE_INIT_FAIL;
+ }
+
+ if (!detect_geometry(custom_header.data1[0], custom_header.data1[1]))
+ {
+ return IMAGE_INIT_FAIL;
+ }
+
+ m_data_ptr = auto_alloc_array(machine(), UINT8, m_page_total_size*m_num_pages);
+ m_data_uid_ptr = auto_alloc_array(machine(), UINT8, 256 + 16);
+ m_mode = SM_M_INIT;
+ m_pointer_mode = SM_PM_A;
+ m_page_addr = 0;
+ m_byte_addr = 0;
+ m_status = 0x40;
+ if (!is_readonly())
+ m_status |= 0x80;
+ m_accumulated_status = 0;
+ m_pagereg = auto_alloc_array(machine(), UINT8, m_page_total_size);
+ m_id_len = 3;
+ memcpy( m_id, custom_header.data1, m_id_len);
+ m_mp_opcode = 0;
+ m_col_address_cycles = 1;
+ m_row_address_cycles = (m_num_pages > 0x10000) ? 3 : 2;
+ m_sequential_row_read = 1;
+
+ for (i=0;i<8;i++)
+ {
+ memcpy( m_data_uid_ptr + i * 32, custom_header.data2, 16);
+ for (j=0;j<16;j++) m_data_uid_ptr[i*32+16+j] = custom_header.data2[j] ^ 0xFF;
+ }
+ memcpy( m_data_uid_ptr + 256, custom_header.data3, 16);
+
+ fread(m_data_ptr, m_page_total_size*m_num_pages);
+
+ #ifdef SMARTMEDIA_IMAGE_SAVE
+ m_image_format = 2;
+ #endif
+
+ return IMAGE_INIT_PASS;
+}
+
+bool smartmedia_image_device::call_load()
+{
+ int result;
+ UINT64 position;
+ // try format 1
+ position = ftell();
+ result = smartmedia_format_1();
+ if (result != IMAGE_INIT_PASS)
+ {
+ // try format 2
+ fseek( position, SEEK_SET);
+ result = smartmedia_format_2();
+ }
+ return result;
+}
+
+/*
+ Unload a SmartMedia image
+*/
+void smartmedia_image_device::call_unload()
+{
+ #ifdef SMARTMEDIA_IMAGE_SAVE
+ if (!is_readonly())
+ {
+ if (m_image_format == 1)
+ {
+ disk_image_header custom_header;
+ int bytes_read;
+ fseek( 0, SEEK_SET);
+ bytes_read = fread( &custom_header, sizeof( custom_header));
+ if (bytes_read == sizeof( custom_header))
+ {
+ if (custom_header.version == 0)
+ {
+ fseek( 2 + 1, SEEK_CUR);
+ fwrite( m_data_ptr, m_page_total_size * m_num_pages);
+ }
+ else if (custom_header.version == 1)
+ {
+ fseek( 3 + 1 + 256 + 16, SEEK_CUR);
+ fwrite( m_data_ptr, m_page_total_size * m_num_pages);
+ }
+ }
+ }
+ else if (m_image_format == 2)
+ {
+ fseek( sizeof( disk_image_format_2_header), SEEK_SET);
+ fwrite( m_data_ptr, m_page_total_size * m_num_pages);
+ }
+ }
+ #endif
+
+ m_page_data_size = 0;
+ m_page_total_size = 0;
+ m_num_pages = 0;
+ m_log2_pages_per_block = 0;
+ m_data_ptr = NULL;
+ m_data_uid_ptr = NULL;
+ m_mode = SM_M_INIT;
+ m_pointer_mode = SM_PM_A;
+ m_page_addr = 0;
+ m_byte_addr = 0;
+ m_status = 0xC0;
+ m_accumulated_status = 0;
+ m_pagereg = auto_alloc_array(machine(), UINT8, m_page_total_size);
+ memset( m_id, 0, sizeof( m_id));
+ m_id_len = 0;
+ m_mp_opcode = 0;
+ m_mode_3065 = 0;
+ m_col_address_cycles = 0;
+ m_row_address_cycles = 0;
+ m_sequential_row_read = 0;
+
+ #ifdef SMARTMEDIA_IMAGE_SAVE
+ m_image_format = 0;
+ #endif
+
+ return;
+}
+
+int nand_device::is_present()
+{
+ return m_num_pages != 0;
+}
+
+int nand_device::is_protected()
+{
+ return (m_status & 0x80) == 0;
+}
+
+int nand_device::is_busy()
+{
+ return (m_status & 0x40) == 0;
+}
+
+void nand_device::set_data_ptr(void *ptr)
+{
+ m_data_ptr = (UINT8 *)ptr;
+}
+
+/*
+ write a byte to SmartMedia command port
+*/
+void nand_device::command_w(UINT8 data)
+{
+ if (!is_present())
+ return;
+
+ switch (data)
+ {
+ case 0xff: // Reset
+ m_mode = SM_M_INIT;
+ m_pointer_mode = SM_PM_A;
+ m_status = (m_status & 0x80) | 0x40;
+ m_accumulated_status = 0;
+ m_mode_3065 = 0;
+ if (!m_devcb_write_line_rnb.isnull())
+ {
+ m_devcb_write_line_rnb( 0);
+ m_devcb_write_line_rnb( 1);
+ }
+ break;
+ case 0x00: // Read (1st cycle)
+ m_mode = SM_M_READ;
+ m_pointer_mode = SM_PM_A;
+ m_page_addr = 0;
+ m_addr_load_ptr = 0;
+ break;
+ case 0x01:
+ if (m_page_data_size != 512)
+ {
+ logerror("smartmedia: unsupported upper data field select (256-byte pages)\n");
+ m_mode = SM_M_INIT;
+ }
+ else
+ {
+ m_mode = SM_M_READ;
+ m_pointer_mode = SM_PM_B;
+ m_page_addr = 0;
+ m_addr_load_ptr = 0;
+ }
+ break;
+ case 0x50:
+ if (m_page_data_size > 512)
+ {
+ logerror("smartmedia: unsupported spare area select\n");
+ m_mode = SM_M_INIT;
+ }
+ else
+ {
+ m_mode = SM_M_READ;
+ m_pointer_mode = SM_PM_C;
+ m_page_addr = 0;
+ m_addr_load_ptr = 0;
+ }
+ break;
+ case 0x80: // Page Program (1st cycle)
+ m_mode = SM_M_PROGRAM;
+ m_page_addr = 0;
+ m_addr_load_ptr = 0;
+ m_program_byte_count = 0;
+ memset(m_pagereg, 0xff, m_page_total_size);
+ break;
+ case 0x10: // Page Program (2nd cycle)
+ case 0x15:
+ if ((m_mode != SM_M_PROGRAM) && (m_mode != SM_M_RANDOM_DATA_INPUT))
+ {
+ logerror("smartmedia: illegal page program confirm command\n");
+ m_mode = SM_M_INIT;
+ }
+ else
+ {
+ int i;
+ m_status = (m_status & 0x80) | m_accumulated_status;
+ //logerror( "smartmedia: program, page_addr %08X\n", m_page_addr);
+ for (i=0; i<m_page_total_size; i++)
+ m_data_ptr[m_page_addr*m_page_total_size + i] &= m_pagereg[i];
+ m_status |= 0x40;
+ if (data == 0x15)
+ m_accumulated_status = m_status & 0x1f;
+ else
+ m_accumulated_status = 0;
+ m_mode = SM_M_INIT;
+ if (!m_devcb_write_line_rnb.isnull())
+ {
+ m_devcb_write_line_rnb( 0);
+ m_devcb_write_line_rnb( 1);
+ }
+ }
+ break;
+ /*case 0x11:
+ break;*/
+ case 0x60: // Block Erase (1st cycle)
+ m_mode = SM_M_ERASE;
+ m_page_addr = 0;
+ m_addr_load_ptr = 0;
+ break;
+ case 0xd0: // Block Erase (2nd cycle)
+ if (m_mode != SM_M_ERASE)
+ {
+ logerror("smartmedia: illegal block erase confirm command\n");
+ m_mode = SM_M_INIT;
+ }
+ else
+ {
+ m_status &= 0x80;
+ memset(m_data_ptr + ((m_page_addr & (-1 << m_log2_pages_per_block)) * m_page_total_size), 0xFF, (size_t)(1 << m_log2_pages_per_block) * m_page_total_size);
+ //logerror( "smartmedia: erase, page_addr %08X, offset %08X, length %08X\n", m_page_addr, (m_page_addr & (-1 << m_log2_pages_per_block)) * m_page_total_size, (1 << m_log2_pages_per_block) * m_page_total_size);
+ m_status |= 0x40;
+ m_mode = SM_M_INIT;
+ if (m_pointer_mode == SM_PM_B)
+ m_pointer_mode = SM_PM_A;
+ if (!m_devcb_write_line_rnb.isnull())
+ {
+ m_devcb_write_line_rnb( 0);
+ m_devcb_write_line_rnb( 1);
+ }
+ }
+ break;
+ case 0x70: // Read Status
+ m_mode = SM_M_READSTATUS;
+ break;
+ /*case 0x71:
+ break;*/
+ case 0x90: // Read ID
+ m_mode = SM_M_READID;
+ m_addr_load_ptr = 0;
+ break;
+ /*case 0x91:
+ break;*/
+ case 0x30: // Read (2nd cycle)
+ if (m_col_address_cycles == 1)
+ {
+ m_mode = SM_M_30;
+ }
+ else
+ {
+ if (m_mode != SM_M_READ)
+ {
+ logerror("smartmedia: illegal read 2nd cycle command\n");
+ m_mode = SM_M_INIT;
+ }
+ else if (m_addr_load_ptr < (m_col_address_cycles + m_row_address_cycles))
+ {
+ logerror("smartmedia: read 2nd cycle, not enough address cycles (actual: %d, expected: %d)\n", m_addr_load_ptr, m_col_address_cycles + m_row_address_cycles);
+ m_mode = SM_M_INIT;
+ }
+ else
+ {
+ if (!m_devcb_write_line_rnb.isnull())
+ {
+ m_devcb_write_line_rnb( 0);
+ m_devcb_write_line_rnb( 1);
+ }
+ }
+ }
+ break;
+ case 0x65:
+ if (m_mode != SM_M_30)
+ {
+ logerror("smartmedia: unexpected address port write\n");
+ m_mode = SM_M_INIT;
+ }
+ else
+ {
+ m_mode_3065 = 1;
+ }
+ break;
+ case 0x05: // Random Data Output (1st cycle)
+ if ((m_mode != SM_M_READ) && (m_mode != SM_M_RANDOM_DATA_OUTPUT))
+ {
+ logerror("smartmedia: illegal random data output command\n");
+ m_mode = SM_M_INIT;
+ }
+ else
+ {
+ m_mode = SM_M_RANDOM_DATA_OUTPUT;
+ m_addr_load_ptr = 0;
+ }
+ break;
+ case 0xE0: // Random Data Output (2nd cycle)
+ if (m_mode != SM_M_RANDOM_DATA_OUTPUT)
+ {
+ logerror("smartmedia: illegal random data output confirm command\n");
+ m_mode = SM_M_INIT;
+ }
+ else
+ {
+ // do nothing
+ }
+ break;
+ case 0x85: // Random Data Input
+ if ((m_mode != SM_M_PROGRAM) && (m_mode != SM_M_RANDOM_DATA_INPUT))
+ {
+ logerror("smartmedia: illegal random data input command\n");
+ m_mode = SM_M_INIT;
+ }
+ else
+ {
+ m_mode = SM_M_RANDOM_DATA_INPUT;
+ m_addr_load_ptr = 0;
+ m_program_byte_count = 0;
+ }
+ break;
+ default:
+ logerror("smartmedia: unsupported command 0x%02x\n", data);
+ m_mode = SM_M_INIT;
+ break;
+ }
+}
+
+/*
+ write a byte to SmartMedia address port
+*/
+void nand_device::address_w(UINT8 data)
+{
+ if (!is_present())
+ return;
+
+ switch (m_mode)
+ {
+ case SM_M_INIT:
+ logerror("smartmedia: unexpected address port write\n");
+ break;
+ case SM_M_READ:
+ case SM_M_PROGRAM:
+ if ((m_addr_load_ptr == 0) && (m_col_address_cycles == 1))
+ {
+ switch (m_pointer_mode)
+ {
+ case SM_PM_A:
+ m_byte_addr = data;
+ break;
+ case SM_PM_B:
+ m_byte_addr = data + 256;
+ m_pointer_mode = SM_PM_A;
+ break;
+ case SM_PM_C:
+ if (!m_mode_3065)
+ m_byte_addr = (data & 0x0f) + m_page_data_size;
+ else
+ m_byte_addr = (data & 0x0f) + 256;
+ break;
+ }
+ }
+ else
+ {
+ if (m_addr_load_ptr < m_col_address_cycles)
+ {
+ m_byte_addr &= ~(0xFF << (m_addr_load_ptr * 8));
+ m_byte_addr |= (data << (m_addr_load_ptr * 8));
+ }
+ else if (m_addr_load_ptr < m_col_address_cycles + m_row_address_cycles)
+ {
+ m_page_addr &= ~(0xFF << ((m_addr_load_ptr - m_col_address_cycles) * 8));
+ m_page_addr |= (data << ((m_addr_load_ptr - m_col_address_cycles) * 8));
+ }
+ }
+ m_addr_load_ptr++;
+ break;
+ case SM_M_ERASE:
+ if (m_addr_load_ptr < m_row_address_cycles)
+ {
+ m_page_addr &= ~(0xFF << (m_addr_load_ptr * 8));
+ m_page_addr |= (data << (m_addr_load_ptr * 8));
+ }
+ m_addr_load_ptr++;
+ break;
+ case SM_M_RANDOM_DATA_INPUT:
+ case SM_M_RANDOM_DATA_OUTPUT:
+ if (m_addr_load_ptr < m_col_address_cycles)
+ {
+ m_byte_addr &= ~(0xFF << (m_addr_load_ptr * 8));
+ m_byte_addr |= (data << (m_addr_load_ptr * 8));
+ }
+ m_addr_load_ptr++;
+ break;
+ case SM_M_READSTATUS:
+ case SM_M_30:
+ logerror("smartmedia: unexpected address port write\n");
+ break;
+ case SM_M_READID:
+ if (m_addr_load_ptr == 0)
+ m_byte_addr = data;
+ m_addr_load_ptr++;
+ break;
+ }
+}
+
+/*
+ read a byte from SmartMedia data port
+*/
+UINT8 nand_device::data_r()
+{
+ UINT8 reply = 0;
+ if (!is_present())
+ return 0;
+
+ switch (m_mode)
+ {
+ case SM_M_INIT:
+ case SM_M_30:
+ logerror("smartmedia: unexpected data port read\n");
+ break;
+ case SM_M_READ:
+ case SM_M_RANDOM_DATA_OUTPUT:
+ if (!m_mode_3065)
+ {
+ if (m_byte_addr < m_page_total_size)
+ {
+ reply = m_data_ptr[m_page_addr*m_page_total_size + m_byte_addr];
+ }
+ else
+ {
+ reply = 0xFF;
+ }
+ }
+ else
+ {
+ reply = m_data_uid_ptr[m_page_addr*m_page_total_size + m_byte_addr];
+ }
+ m_byte_addr++;
+ if ((m_byte_addr == m_page_total_size) && (m_sequential_row_read != 0))
+ {
+ m_byte_addr = (m_pointer_mode != SM_PM_C) ? 0 : m_page_data_size;
+ m_page_addr++;
+ if (m_page_addr == m_num_pages)
+ m_page_addr = 0;
+ }
+ break;
+ case SM_M_PROGRAM:
+ case SM_M_RANDOM_DATA_INPUT:
+ case SM_M_ERASE:
+ logerror("smartmedia: unexpected data port read\n");
+ break;
+ case SM_M_READSTATUS:
+ reply = m_status & 0xc1;
+ break;
+ case SM_M_READID:
+ if (m_byte_addr < m_id_len)
+ reply = m_id[m_byte_addr];
+ else
+ reply = 0;
+ m_byte_addr++;
+ break;
+ }
+
+ return reply;
+}
+
+/*
+ write a byte to SmartMedia data port
+*/
+void nand_device::data_w(UINT8 data)
+{
+ if (!is_present())
+ return;
+
+ switch (m_mode)
+ {
+ case SM_M_INIT:
+ case SM_M_READ:
+ case SM_M_30:
+ case SM_M_RANDOM_DATA_OUTPUT:
+ logerror("smartmedia: unexpected data port write\n");
+ break;
+ case SM_M_PROGRAM:
+ case SM_M_RANDOM_DATA_INPUT:
+ if (m_program_byte_count++ < m_page_total_size)
+ {
+ m_pagereg[m_byte_addr] = data;
+ }
+ m_byte_addr++;
+ if (m_byte_addr == m_page_total_size)
+ m_byte_addr = (m_pointer_mode != SM_PM_C) ? 0 : m_page_data_size;
+ break;
+ case SM_M_ERASE:
+ case SM_M_READSTATUS:
+ case SM_M_READID:
+ logerror("smartmedia: unexpected data port write\n");
+ break;
+ }
+}
+
+
+/*
+ Initialize one SmartMedia chip: may be called at driver init or image load
+ time (or machine init time if you don't use MESS image core)
+*/
+void nand_device::device_reset()
+{
+ m_mode = SM_M_INIT;
+ m_pointer_mode = SM_PM_A;
+ m_status = (m_status & 0x80) | 0x40;
+ m_accumulated_status = 0;
+}
+
+
+const device_type SMARTMEDIA = &device_creator<smartmedia_image_device>;
+
+smartmedia_image_device::smartmedia_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nand_device(mconfig, SMARTMEDIA, "SmartMedia Flash ROM", tag, owner, clock),
+ device_image_interface(mconfig, *this),
+ m_image_interface(NULL)
+{
+}
+
+void smartmedia_image_device::device_config_complete()
+{
+ nand_device::device_config_complete();
+ update_names();
+}
+
diff --git a/src/mess/machine/smartmed.h b/src/mess/machine/smartmed.h
new file mode 100644
index 00000000000..0a384838d8d
--- /dev/null
+++ b/src/mess/machine/smartmed.h
@@ -0,0 +1,201 @@
+/*
+ smartmed.h: header file for smartmed.c
+*/
+
+#ifndef __SMARTMEDIA_H__
+#define __SMARTMEDIA_H__
+
+//#define SMARTMEDIA_IMAGE_SAVE
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _smartmedia_cartslot_config smartmedia_cartslot_config;
+struct _smartmedia_cartslot_config
+{
+ const char * interface;
+};
+
+
+enum sm_mode_t
+{
+ SM_M_INIT, // initial state
+ SM_M_READ, // read page data
+ SM_M_PROGRAM, // program page data
+ SM_M_ERASE, // erase block data
+ SM_M_READSTATUS,// read status
+ SM_M_READID, // read ID
+ SM_M_30,
+ SM_M_RANDOM_DATA_INPUT,
+ SM_M_RANDOM_DATA_OUTPUT
+};
+
+enum pointer_sm_mode_t
+{
+ SM_PM_A, // accessing first 256-byte half of 512-byte data field
+ SM_PM_B, // accessing second 256-byte half of 512-byte data field
+ SM_PM_C // accessing spare field
+};
+
+
+// "Sequential Row Read is available only on K9F5608U0D_Y,P,V,F or K9F5608D0D_Y,P"
+
+#define NAND_CHIP_K9F5608U0D { 2, { 0xEC, 0x75 }, 512, 16, 32, 2048, 1, 2, 1 } /* K9F5608U0D */
+#define NAND_CHIP_K9F5608U0D_J { 2, { 0xEC, 0x75 }, 512, 16, 32, 2048, 1, 2, 0 } /* K9F5608U0D-Jxxx */
+#define NAND_CHIP_K9F5608U0B { 2, { 0xEC, 0x75 }, 512, 16, 32, 2048, 1, 2, 0 } /* K9F5608U0B */
+#define NAND_CHIP_K9F1G08U0B { 5, { 0xEC, 0xF1, 0x00, 0x95, 0x40 }, 2048, 64, 64, 1024, 2, 2, 0 } /* K9F1G08U0B */
+#define NAND_CHIP_K9LAG08U0M { 5, { 0xEC, 0xD5, 0x55, 0x25, 0x68 }, 2048, 64, 128, 8192, 2, 3, 0 } /* K9LAG08U0M */
+
+typedef struct _nand_chip nand_chip;
+struct _nand_chip
+{
+ int id_len;
+ UINT8 id[5];
+ int page_size;
+ int oob_size;
+ int pages_per_block;
+ int blocks_per_device;
+ int col_address_cycles;
+ int row_address_cycles;
+ int sequential_row_read;
+};
+
+// ======================> nand_interface
+
+struct nand_interface
+{
+ nand_chip m_chip;
+ devcb_write_line m_devcb_write_line_cb;
+};
+
+// ======================> nand_device
+class nand_device : public device_t,
+ public nand_interface
+{
+public:
+ // construction/destruction
+ nand_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ nand_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
+
+ int is_present();
+ int is_protected();
+ int is_busy();
+
+ UINT8 data_r();
+ void command_w(UINT8 data);
+ void address_w(UINT8 data);
+ void data_w(UINT8 data);
+
+ void read(int offset, void *data, int size);
+
+ void set_data_ptr(void *ptr);
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete();
+
+ int m_page_data_size; // 256 for a 2MB card, 512 otherwise
+ int m_page_total_size;// 264 for a 2MB card, 528 otherwise
+ int m_num_pages; // 8192 for a 4MB card, 16184 for 8MB, 32768 for 16MB,
+ // 65536 for 32MB, 131072 for 64MB, 262144 for 128MB...
+ // 0 means no card loaded
+ int m_log2_pages_per_block; // log2 of number of pages per erase block (usually 4 or 5)
+
+ UINT8 *m_data_ptr; // FEEPROM data area
+ UINT8 *m_data_uid_ptr;
+
+ sm_mode_t m_mode; // current operation mode
+ pointer_sm_mode_t m_pointer_mode; // pointer mode
+
+ unsigned int m_page_addr; // page address pointer
+ int m_byte_addr; // byte address pointer
+ int m_addr_load_ptr; // address load pointer
+
+ int m_status; // current status
+ int m_accumulated_status; // accumulated status
+
+ UINT8 *m_pagereg; // page register used by program command
+ UINT8 m_id[5]; // chip ID
+ UINT8 m_mp_opcode; // multi-plane operation code
+
+ int m_mode_3065;
+
+ // Palm Z22 NAND has 512 + 16 byte pages but, for some reason, Palm OS writes 512 + 64 bytes when
+ // programming a page, so we need to keep track of the number of bytes written so we can ignore the
+ // last 48 (64 - 16) bytes or else the first 48 bytes get overwritten
+ int m_program_byte_count;
+
+ int m_id_len;
+ int m_col_address_cycles;
+ int m_row_address_cycles;
+ int m_sequential_row_read;
+
+ devcb_resolved_write_line m_devcb_write_line_rnb;
+
+ #ifdef SMARTMEDIA_IMAGE_SAVE
+ int m_image_format;
+ #endif
+};
+
+// device type definition
+extern const device_type NAND;
+
+class smartmedia_image_device : public nand_device,
+ public device_image_interface
+{
+public:
+ // construction/destruction
+ smartmedia_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_MEMCARD; }
+
+ 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_image_interface; }
+ virtual const char *file_extensions() const { return "smc"; }
+ virtual const option_guide *create_option_guide() const { return NULL; }
+
+ virtual bool call_load();
+ virtual void call_unload();
+ virtual bool call_softlist_load(char *swlist, char *swname, rom_entry *start_entry) { return load_software(swlist, swname, start_entry); }
+
+ void set_image_interface(const char *image_interface) { m_image_interface = image_interface; }
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+
+ bool smartmedia_format_1();
+ bool smartmedia_format_2();
+ int detect_geometry( UINT8 id1, UINT8 id2);
+
+ const char *m_image_interface;
+};
+
+// device type definition
+extern const device_type SMARTMEDIA;
+
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+#define MCFG_NAND_ADD(_tag, _config) \
+ MCFG_DEVICE_ADD(_tag, NAND, 0) \
+ MCFG_DEVICE_CONFIG(_config)
+
+#define NAND_INTERFACE(name) \
+ const nand_interface(name) =
+
+#define MCFG_SMARTMEDIA_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, SMARTMEDIA, 0)
+
+#define MCFG_SMARTMEDIA_INTERFACE(_interface) \
+ downcast<smartmedia_image_device *>(device)->set_image_interface(_interface);
+
+#endif /* __SMARTMEDIA_H__ */
diff --git a/src/mess/machine/smc92x4.c b/src/mess/machine/smc92x4.c
new file mode 100644
index 00000000000..aded6ee2b78
--- /dev/null
+++ b/src/mess/machine/smc92x4.c
@@ -0,0 +1,2015 @@
+/*
+ HDC9224 and HDC9234 Hard and Floppy Disk Controller
+
+ This controller handles MFM and FM encoded floppy disks and hard disks.
+ The SMC9224 is used in some DEC systems. The HDC9234 is used in the
+ Myarc HFDC card for the TI99/4a. The main difference between the two
+ chips is the way the ECC bytes are computed; there are differences in
+ the way seek times are computed, too.
+
+ References:
+ * SMC HDC9234 preliminary data book (1988)
+
+ Michael Zapf, April 2010
+
+ First version by Raphael Nabet, 2003
+*/
+
+#include "emu.h"
+#include "smc92x4.h"
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/*
+ Definition of bits in the status register
+*/
+#define ST_INTPEND 0x80 /* interrupt pending */
+#define ST_DMAREQ 0x40 /* DMA request */
+#define ST_DONE 0x20 /* command done */
+#define ST_TERMCOD 0x18 /* termination code (see below) */
+#define ST_RDYCHNG 0x04 /* ready change */
+#define ST_OVRUN 0x02 /* overrun/underrun */
+#define ST_BADSECT 0x01 /* bad sector */
+
+/*
+ Definition of the termination codes (INT_STATUS)
+*/
+#define ST_TC_SUCCESS 0x00 /* Successful completion */
+#define ST_TC_RDIDERR 0x08 /* Error in READ-ID sequence */
+#define ST_TC_SEEKERR 0x10 /* Error in SEEK sequence */
+#define ST_TC_DATAERR 0x18 /* Error in DATA-TRANSFER seq. */
+
+
+/*
+ Definition of bits in the Termination-Conditions register
+*/
+#define TC_CRCPRE 0x80 /* CRC register preset, must be 1 */
+#define TC_UNUSED 0x40 /* bit 6 is not used and must be 0 */
+#define TC_INTDONE 0x20 /* interrupt on done */
+#define TC_TDELDAT 0x10 /* terminate on deleted data */
+#define TC_TDSTAT3 0x08 /* terminate on drive status 3 change */
+#define TC_TWPROT 0x04 /* terminate on write-protect (FDD only) */
+#define TC_INTRDCH 0x02 /* interrupt on ready change (FDD only) */
+#define TC_TWRFLT 0x01 /* interrupt on write-fault (HDD only) */
+
+/*
+ Definition of bits in the Chip-Status register
+*/
+#define CS_RETREQ 0x80 /* retry required */
+#define CS_ECCATT 0x40 /* ECC correction attempted */
+#define CS_CRCERR 0x20 /* ECC/CRC error */
+#define CS_DELDATA 0x10 /* deleted data mark */
+#define CS_SYNCERR 0x08 /* synchronization error */
+#define CS_COMPERR 0x04 /* compare error */
+#define CS_PRESDRV 0x03 /* present drive selected */
+
+/*
+ Definition of bits in the Mode register
+*/
+#define MO_TYPE 0x80 /* Hard disk (1) or floppy (0) */
+#define MO_CRCECC 0x60 /* Values for CRC/ECC handling */
+#define MO_DENSITY 0x10 /* FM = 1; MFM = 0 */
+#define MO_UNUSED 0x08 /* Unused, 0 */
+#define MO_STEPRATE 0x07 /* Step rates */
+
+/*
+ hfdc state structure
+
+ status
+ ab7 ecc error
+ ab6 index pulse
+ ab5 seek complete
+ ab4 track 0
+ ab3 user-defined
+ ab2 write-protected
+ ab1 drive ready
+ ab0 write fault
+
+ 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
+ ab4 step pulse
+ ab3 desired head 3
+ ab2 desired head 2
+ ab1 desired head 1
+ ab0 desired head 0
+*/
+
+#define OUT1_DRVSEL3 0x80
+#define OUT1_DRVSEL2 0x40
+#define OUT1_DRVSEL1 0x20
+#define OUT1_DRVSEL0 0x10
+#define OUT2_DRVSEL3_ 0x80
+#define OUT2_REDWRT 0x40
+#define OUT2_STEPDIR 0x20
+#define OUT2_STEPPULSE 0x10
+#define OUT2_HEADSEL3 0x08
+#define OUT2_HEADSEL2 0x04
+#define OUT2_HEADSEL1 0x02
+#define OUT2_HEADSEL0 0x01
+
+#define DRIVE_TYPE 0x03
+#define TYPE_AT 0x00
+#define TYPE_FLOPPY 0x02 /* for testing on any floppy type */
+#define TYPE_FLOPPY8 0x02
+#define TYPE_FLOPPY5 0x03
+
+#define MAX_SECTOR_LEN 256
+
+#define FORMAT_LONG false
+
+#define ERROR 0
+#define DONE 1
+#define AGAIN 2
+#define UNDEF 3
+
+enum
+{
+ DATA_TIMER,
+ READ_TIMER,
+ WRITE_TIMER,
+ SEEK_TIMER,
+ TRACK_TIMER
+};
+
+/*
+ Step rates in microseconds for MFM. This is set in the mode register,
+ bits 0-2. Single density 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 };
+
+/*
+ 0.2 seconds for a revolution (300 rpm), +50% average waiting for index
+ hole. Should be properly done with the index hole detection; we're
+ simulating this with a timer for now.
+*/
+#define TRACKTIME_FLOPPY 300000
+#define TRACKTIME_HD 1000
+
+/*
+ Register names of the HDC. The left part is the set of write registers,
+ while the right part are the read registers.
+*/
+enum
+{
+ DMA7_0=0,
+ DMA15_8=1,
+ DMA23_16=2,
+ DESIRED_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
+};
+
+#define TRKSIZE_DD 6144
+#define TRKSIZE_SD 3172
+
+#define VERBOSE 1
+#define LOG logerror
+
+smc92x4_device::smc92x4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+: device_t(mconfig, SMC92X4, "SMC 9224/9234 Hard/Floppy Disk Controller", tag, owner, clock)
+{
+}
+
+int smc92x4_device::image_is_single_density()
+{
+ floppy_image_legacy *image = flopimg_get_image(m_drive);
+ return (floppy_get_track_size(image, 0, 0)<4000);
+}
+
+bool smc92x4_device::in_single_density_mode()
+{
+ return ((m_register_w[MODE]&MO_DENSITY)!=0);
+}
+
+void smc92x4_device::copyid(chrn_id id1, chrn_id_hd *id2)
+{
+ id2->C = id1.C & 0xff;
+ id2->H = id1.H;
+ id2->R = id1.R;
+ id2->N = id1.N;
+ id2->data_id = id1.data_id;
+ id2->flags = id1.flags;
+}
+
+/*
+ Set IRQ
+*/
+void smc92x4_device::set_interrupt()
+{
+ if ((m_register_r[INT_STATUS] & ST_INTPEND) == 0)
+ {
+ m_register_r[INT_STATUS] |= ST_INTPEND;
+ m_out_intrq(ASSERT_LINE);
+ }
+}
+
+/*
+ Assert Command Done status bit, triggering interrupts as needed
+*/
+void smc92x4_device::set_command_done(int flags)
+{
+ //assert(! (m_status & ST_DONE))
+ if (VERBOSE>7) LOG("smc92x4 command %02x done, flags=%02x\n", m_command, flags);
+
+ m_register_r[INT_STATUS] |= ST_DONE;
+ m_register_r[INT_STATUS] &= ~ST_TERMCOD; /* clear the previously set flags */
+ m_register_r[INT_STATUS] |= flags;
+
+ /* sm92x4 spec, p. 6 */
+ if (m_register_w[INT_COMM_TERM] & TC_INTDONE)
+ set_interrupt();
+}
+
+/*
+ Preserve previously set termination code
+*/
+void smc92x4_device::set_command_done()
+{
+ //assert(! (m_status & ST_DONE))
+ if (VERBOSE>7) LOG("smc92x4 command %02x done\n", m_command);
+
+ m_register_r[INT_STATUS] |= ST_DONE;
+
+ /* sm92x4 spec, p. 6 */
+ if (m_register_w[INT_COMM_TERM] & TC_INTDONE)
+ set_interrupt();
+}
+
+/*
+ Clear IRQ
+*/
+void smc92x4_device::clear_interrupt()
+{
+ if ((m_register_r[INT_STATUS] & ST_INTPEND) != 0)
+ m_out_intrq(CLEAR_LINE);
+}
+
+/*
+ Sets the DMA address on the external counter. This counter is attached
+ to the auxiliary bus on the PCB.
+*/
+void smc92x4_device::set_dma_address(int pos2316, int pos1508, int pos0700)
+{
+ m_out_auxbus(OUTPUT_DMA_ADDR, m_register_r[pos2316]);
+ m_out_auxbus(OUTPUT_DMA_ADDR, m_register_r[pos1508]);
+ m_out_auxbus(OUTPUT_DMA_ADDR, m_register_r[pos0700]);
+}
+
+void smc92x4_device::dma_add_offset(int offset)
+{
+ int dma_address = (m_register_w[DMA23_16]<<16) + (m_register_w[DMA15_8]<<8) + m_register_w[DMA7_0];
+ dma_address += offset;
+
+ 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);
+}
+
+/*
+ Get the state from outside and latch it in the register.
+ There should be a bus driver on the PCB which provides the signals from
+ both the hard and floppy drives during S0=S1=0 and STB*=0 times via the
+ auxiliary bus.
+*/
+void smc92x4_device::sync_status_in()
+{
+ UINT8 prev;
+ prev = m_register_r[DRIVE_STATUS];
+ m_register_r[DRIVE_STATUS] = m_in_auxbus(0);
+
+ /* Raise interrupt if ready changes. TODO: Check this more closely. */
+ if (((m_register_r[DRIVE_STATUS] & DS_READY) != (prev & DS_READY))
+ & (m_register_r[INT_STATUS] & ST_RDYCHNG))
+ {
+ set_interrupt();
+ }
+}
+
+/*
+ Push the output registers over the auxiliary bus. It is expected that
+ the PCB contains latches to store the values.
+*/
+void smc92x4_device::sync_latches_out()
+{
+ m_output1 = (m_output1 & 0xf0) | (m_register_w[RETRY_COUNT]&0x0f);
+ m_out_auxbus(OUTPUT_OUTPUT1, m_output1);
+ m_out_auxbus(OUTPUT_OUTPUT2, m_output2);
+}
+
+/*************************************************************
+ Timed requests and callbacks
+*************************************************************/
+#if 0
+/* setup a timed data request - data request will be triggered in a few usecs time */
+void smc92x4_device::timed_data_request()
+{
+ int time = in_single_density_mode()? 128 : 32;
+
+ if (!m_use_real_timing)
+ time = 1;
+
+ /* set new timer */
+ m_timer_data->adjust(attotime::from_usec(time));
+}
+#endif
+
+/* setup a timed read sector - read sector will be triggered in a few usecs time */
+void smc92x4_device::timed_sector_read_request()
+{
+ int time=0;
+
+ // set new timer
+ // Average time from sector to sector.
+ if (m_selected_drive_type & TYPE_FLOPPY)
+ time = (in_single_density_mode())? 30000 : 15000;
+ else
+ time = 1000;
+
+ if (!m_use_real_timing)
+ time = 1;
+
+ m_timer_rs->adjust(attotime::from_usec(time));
+ m_to_be_continued = true;
+}
+
+/* setup a timed write sector - write sector will be triggered in a few usecs time */
+void smc92x4_device::timed_sector_write_request()
+{
+ int time=0;
+
+ /* Average time from sector to sector. */
+ if (m_selected_drive_type & TYPE_FLOPPY)
+ time = (in_single_density_mode())? 30000 : 15000;
+ else
+ time = 1000;
+
+ if (!m_use_real_timing)
+ time = 1;
+
+ m_timer_ws->adjust(attotime::from_usec(time));
+ m_to_be_continued = true;
+}
+
+/*
+ Set up a timed track read/write
+*/
+void smc92x4_device::timed_track_request()
+{
+ int time = 0;
+
+ if (m_selected_drive_type & TYPE_FLOPPY)
+ time = TRACKTIME_FLOPPY;
+ else
+ time = TRACKTIME_HD;
+
+ if (!m_use_real_timing)
+ time = 1;
+
+ m_timer_track->adjust(attotime::from_usec(time));
+
+ m_to_be_continued = true;
+}
+
+/*
+ Set up a timed track seek
+*/
+void smc92x4_device::timed_seek_request()
+{
+ int time = 0;
+
+ int index = m_register_w[MODE] & MO_STEPRATE;
+ int fm = in_single_density_mode();
+
+ /* Get seek time. */
+ if ((m_selected_drive_type & DRIVE_TYPE) == TYPE_FLOPPY8)
+ time = step_flop8[index];
+
+ else if ((m_selected_drive_type & DRIVE_TYPE) == TYPE_FLOPPY5)
+ time = step_flop5[index];
+ else
+ time = step_hd[index];
+
+ if (fm)
+ time = time * 2;
+
+ if (!m_use_real_timing)
+ {
+ if (VERBOSE>5) LOG("smc92x4 info: Disk access without delays\n");
+ time = 1;
+ }
+ m_timer_seek->adjust(attotime::from_usec(time));
+ m_to_be_continued = true;
+}
+
+void smc92x4_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ int transfer_enabled;
+ int deldata;
+ int redcur;
+ int precomp;
+ int write_long;
+ mfm_harddisk_device *harddisk;
+
+ switch (id)
+ {
+ case DATA_TIMER:
+ // Not implemented yet
+ break;
+ case READ_TIMER:
+ transfer_enabled = m_command & 0x01;
+ // Now read the sector.
+ data_transfer_read(m_recent_id, transfer_enabled);
+ sync_status_in();
+ break;
+ case WRITE_TIMER:
+ deldata = m_command & 0x10;
+ redcur = m_command & 0x08;
+ precomp = m_command & 0x07;
+ write_long = ((m_register_w[MODE]& MO_CRCECC)==0x40);
+
+ if (deldata)
+ if (VERBOSE>0) LOG("smc92x4 warn: Write deleted data mark not supported. Writing normal mark.\n");
+
+ // Now write the sector.
+ data_transfer_write(m_recent_id, deldata, redcur, precomp, write_long);
+ sync_status_in();
+ break;
+ case SEEK_TIMER:
+ // Callback for seek request.
+ /* int buffered = ((m_register_w[MODE] & MO_STEPRATE)==0); */
+ /* int buffered = (m_command & 0x01); */
+
+ if (m_selected_drive_type & TYPE_FLOPPY)
+ {
+ if (m_drive==NULL)
+ {
+ if (VERBOSE>0) LOG("smc92x4 error: seek callback: no floppy\n");
+ m_register_r[INT_STATUS] |= ST_TC_SEEKERR;
+ }
+ else
+ {
+ if (VERBOSE>5) LOG("smc92x4 step %s direction %d\n", m_drive->tag(), m_step_direction);
+ floppy_drive_seek(m_drive, m_step_direction);
+ }
+ }
+ else
+ {
+ if (VERBOSE>6) LOG("smc92x4 step harddisk direction %d\n", m_step_direction);
+ harddisk = static_cast<mfm_harddisk_device *>(m_drive);
+ harddisk->seek(m_step_direction);
+ }
+ sync_status_in();
+ break;
+ case TRACK_TIMER:
+ // Callback for track access. Nothing interesting here, just used for
+ // delaying.
+ break;
+ }
+ process_after_callback();
+}
+
+
+/*********************************************************************
+ Common functions
+*********************************************************************/
+
+/*
+ Calculate the ident byte from the cylinder. The specification does not
+ define idents beyond cylinder 1023, but formatting programs seem to
+ continue with 0xfd for cylinders between 1024 and 2047.
+*/
+UINT8 smc92x4_device::cylinder_to_ident(int cylinder)
+{
+ if (cylinder < 256) return 0xfe;
+ if (cylinder < 512) return 0xff;
+ if (cylinder < 768) return 0xfc;
+ if (cylinder < 1024) return 0xfd;
+ return 0xfd;
+}
+
+/*
+ Calculate the offset from the ident. This is only useful for AT drives;
+ these drives cannot have more than 1024 cylinders.
+*/
+int smc92x4_device::ident_to_cylinder(UINT8 ident)
+{
+ switch (ident)
+ {
+ case 0xfe: return 0;
+ case 0xff: return 256;
+ case 0xfc: return 512;
+ case 0xfd: return 768;
+ default: return -1;
+ }
+}
+
+/*
+ Common function to set the read registers from the recently read id.
+*/
+void smc92x4_device::update_id_regs(chrn_id_hd id)
+{
+ // Flags for current head register. Note that the sizes are not in
+ // sequence (128, 256, 512, 1024). This is only interesting for AT
+ // mode.
+ static const UINT8 sizeflag[] = { 0x60, 0x00, 0x20, 0x40 };
+
+ m_register_r[CURRENT_CYLINDER] = id.C & 0xff;
+ m_register_r[CURRENT_HEAD] = id.H & 0x0f;
+
+ if (id.flags & BAD_SECTOR)
+ m_register_r[CURRENT_HEAD] |= 0x80;
+
+ if ((m_selected_drive_type & DRIVE_TYPE) == TYPE_AT)
+ m_register_r[CURRENT_HEAD] |= sizeflag[id.N];
+ else
+ m_register_r[CURRENT_HEAD] |= ((id.C & 0x700)>>4);
+
+ m_register_r[CURRENT_IDENT] = cylinder_to_ident(id.C);
+}
+
+/*
+ Common procedure: read_id_field (as described in the specification)
+*/
+void smc92x4_device::read_id_field(int *steps, int *direction, chrn_id_hd *id)
+{
+ int des_cylinder, cur_cylinder;
+ bool found = false;
+ mfm_harddisk_device *harddisk;
+
+ sync_latches_out();
+ sync_status_in();
+
+ // Set command termination code. The error code is set first, and
+ // on success, it is cleared.
+ m_register_r[INT_STATUS] |= ST_TC_RDIDERR;
+
+ /* Try to find an ID field. */
+ if (m_selected_drive_type & TYPE_FLOPPY)
+ {
+ chrn_id idflop;
+ if (flopimg_get_image(m_drive) == NULL)
+ {
+ if (VERBOSE>2) LOG("smc92x4 warn: No disk in drive\n");
+ m_register_r[CHIP_STATUS] |= CS_SYNCERR;
+ return;
+ }
+
+ /* Check whether image and controller are set to the same density. */
+ if ((image_is_single_density() && in_single_density_mode())
+ || (!image_is_single_density() && !in_single_density_mode()))
+ {
+ found = floppy_drive_get_next_id(m_drive, m_register_w[DESIRED_HEAD]&0x0f, &idflop);
+ copyid(idflop, id); /* Need to use bigger values for HD, but we don't use separate variables here */
+ }
+ else
+ {
+ if (VERBOSE>2) LOG("smc92x4 warn: Controller and medium density do not match.\n");
+ }
+ sync_status_in();
+
+ if (!found)
+ {
+ if (VERBOSE>1) LOG("smc92x4 error: read_id_field (floppy): sync error\n");
+ m_register_r[CHIP_STATUS] |= CS_SYNCERR;
+ return;
+ }
+ }
+ else
+ {
+ harddisk = static_cast<mfm_harddisk_device *>(m_drive);
+
+ harddisk->get_next_id(m_register_w[DESIRED_HEAD]&0x0f, id);
+ sync_status_in();
+ if (!(m_register_r[DRIVE_STATUS]& DS_READY))
+ {
+ if (VERBOSE>1) LOG("smc92x4 error: read_id_field (harddisk): sync error\n");
+ m_register_r[CHIP_STATUS] |= CS_SYNCERR;
+ return;
+ }
+ }
+
+ m_register_r[CHIP_STATUS] &= ~CS_SYNCERR;
+
+ /* Update the registers. */
+ update_id_regs(*id);
+
+ if (id->flags & BAD_CRC)
+ {
+ m_register_r[CHIP_STATUS] |= CS_CRCERR;
+ return;
+ }
+
+ /* Calculate the steps. */
+ if ((m_selected_drive_type & DRIVE_TYPE) == TYPE_AT)
+ {
+ /* Note: the spec says CURRENT_REGISTER, but that seems wrong. */
+ des_cylinder = ((m_register_r[DATA] & 0x03)<<8) | m_register_w[DESIRED_CYLINDER];
+ cur_cylinder = ident_to_cylinder(m_register_r[CURRENT_IDENT]) + m_register_r[CURRENT_CYLINDER];
+ }
+ else
+ {
+ des_cylinder = ((m_register_w[DESIRED_HEAD] & 0x70)<<4) | m_register_w[DESIRED_CYLINDER];
+ cur_cylinder = ((m_register_r[CURRENT_HEAD] & 0x70)<<4) | m_register_r[CURRENT_CYLINDER];
+ }
+
+ if (des_cylinder >= cur_cylinder)
+ {
+ *steps = des_cylinder - cur_cylinder;
+ *direction = +1;
+ }
+ else
+ {
+ *steps = cur_cylinder - des_cylinder;
+ *direction = -1;
+ }
+
+ if (VERBOSE>6) LOG("smc92x4 seek required: %d steps\n", *steps);
+
+ m_register_r[INT_STATUS] &= ~ST_TC_RDIDERR;
+}
+
+/*
+ Common procedure: verify (as described in the specification)
+*/
+int smc92x4_device::verify(chrn_id_hd *id, bool check_sector)
+{
+ int maxtry = 132; /* approx. 33792/(256*32) */
+ int pass = 0;
+ int found = false;
+ int foundsect = false;
+ int des_cylinder = 0;
+ mfm_harddisk_device *harddisk;
+
+ // Set command termination code. The error code is set first, and
+ // on success, it is cleared.
+ m_register_r[INT_STATUS] |= ST_TC_SEEKERR;
+
+ while (pass < maxtry && !foundsect)
+ {
+ pass++;
+ /* Try to find an ID field. */
+ if (m_selected_drive_type & TYPE_FLOPPY)
+ {
+ chrn_id idflop;
+ found = floppy_drive_get_next_id(m_drive, m_register_w[DESIRED_HEAD]&0x0f, &idflop);
+ copyid(idflop, id);
+ if (/* pass==1 && */!found)
+ {
+ m_register_r[CHIP_STATUS] |= CS_SYNCERR;
+ if (VERBOSE>1) LOG("smc92x4 error: verify (floppy): sync error\n");
+ return ERROR;
+ }
+ }
+ else
+ {
+ harddisk = static_cast<mfm_harddisk_device *>(m_drive);
+ harddisk->get_next_id(m_register_w[DESIRED_HEAD]&0x0f, id);
+ sync_status_in();
+ if (!(m_register_r[DRIVE_STATUS]& DS_READY))
+ {
+ if (VERBOSE>1) LOG("smc92x4 error: verify (harddisk): sync error\n");
+ m_register_r[CHIP_STATUS] |= CS_SYNCERR;
+ return ERROR;
+ }
+ }
+
+ m_register_r[CHIP_STATUS] &= ~CS_SYNCERR;
+
+ /* Compare with the desired sector ID. */
+ if ((m_selected_drive_type & DRIVE_TYPE) == TYPE_AT)
+ {
+ /* Note: the spec says CURRENT_CYLINDER, but that seems wrong. */
+ des_cylinder = ((m_register_r[DATA] & 0x03)<<8) | m_register_w[DESIRED_CYLINDER];
+ }
+ else
+ {
+ des_cylinder = ((m_register_w[DESIRED_HEAD] & 0x70)<<4) | m_register_w[DESIRED_CYLINDER];
+ }
+ if (VERBOSE>6) LOG("smc92x4 check id: current = (%d,%d,%d), required = (%d,%d,%d)\n", id->C, id->H, id->R, des_cylinder, m_register_w[DESIRED_HEAD] & 0x0f, m_register_w[DESIRED_SECTOR]);
+ if ((des_cylinder == id->C)
+ && ((m_register_w[DESIRED_HEAD] & 0x0f) == id->H))
+ {
+ if (!check_sector || (m_register_w[DESIRED_SECTOR] == id->R))
+ foundsect = true;
+ }
+ }
+ if (!foundsect)
+ {
+ m_register_r[CHIP_STATUS] |= CS_COMPERR;
+ if (VERBOSE>1) LOG("smc92x4 error: verify: sector not found, seek error (desired cyl=%d/sec=%d, current cyl=%d/sec=%d)\n", des_cylinder, m_register_w[DESIRED_SECTOR], id->C, id->R);
+ return ERROR;
+ }
+
+ m_register_r[INT_STATUS] &= ~ST_TC_SEEKERR;
+ return DONE;
+}
+
+/*
+ Common procedure: data_transfer(read) (as described in the specification)
+*/
+void smc92x4_device::data_transfer_read(chrn_id_hd id, int transfer_enable)
+{
+ int i, retry, sector_len;
+ mfm_harddisk_device *harddisk;
+
+ int sector_data_id;
+ UINT8 *buf;
+
+ sync_latches_out();
+ sync_status_in();
+
+ // Set command termination code. The error code is set first, and
+ // on success, it is cleared.
+ m_register_r[INT_STATUS] |= ST_TC_DATAERR;
+
+ // Save the value. Note that the retry count is only in the first four
+ // bits, and it is stored in one's complement. In this implementation
+ // we don't work with it.
+ retry = m_register_w[RETRY_COUNT];
+
+ /* We are already at the correct sector (found by the verify sequence) */
+
+ /* Find the data sync mark. Easy, we assume it has been found. */
+
+ if (id.flags & ID_FLAG_DELETED_DATA)
+ m_register_r[CHIP_STATUS] |= CS_DELDATA;
+ else
+ m_register_r[CHIP_STATUS] &= ~CS_DELDATA;
+
+ /* Found. Now update the current cylinder/head registers. */
+ update_id_regs(id);
+
+ /* Initiate the DMA. We assume the DMARQ is positive. */
+ m_register_r[INT_STATUS] &= ~ST_OVRUN;
+
+ sector_len = 1 << (id.N+7);
+ sector_data_id = id.data_id;
+ buf = (UINT8 *)malloc(sector_len);
+
+ if (m_selected_drive_type & TYPE_FLOPPY)
+ {
+ floppy_drive_read_sector_data(m_drive, id.H, sector_data_id, buf, sector_len);
+ }
+ else
+ {
+ // TODO: Should we get the sector length from the harddisk?
+ harddisk = static_cast<mfm_harddisk_device *>(m_drive);
+ harddisk->read_sector(id.C, id.H, id.R, buf);
+ }
+ sync_status_in();
+
+ if (transfer_enable)
+ {
+ /* Copy via DMA into controller RAM. */
+ set_dma_address(DMA23_16, DMA15_8, DMA7_0);
+
+ m_out_dip(ASSERT_LINE);
+ for (i=0; i < sector_len; i++)
+ {
+ m_out_dma(0, buf[i]);
+ }
+ m_out_dip(CLEAR_LINE);
+ }
+ free(buf);
+
+ /* Check CRC. We assume everything is OK, no retry required. */
+ m_register_r[CHIP_STATUS] &= ~CS_RETREQ;
+ m_register_r[CHIP_STATUS] &= ~CS_CRCERR;
+ m_register_r[CHIP_STATUS] &= ~CS_ECCATT;
+
+ /* Update the DMA registers. */
+ if (transfer_enable) dma_add_offset(sector_len);
+
+ /* Decrement sector count. */
+ m_register_w[SECTOR_COUNT] = (m_register_w[SECTOR_COUNT]-1)&0xff;
+
+ /* Clear the error bits. */
+ m_register_r[INT_STATUS] &= ~ST_TC_DATAERR;
+
+ if (m_register_w[SECTOR_COUNT] == 0)
+ return;
+
+ /* Else this is a multi-sector operation. */
+ m_register_w[DESIRED_SECTOR] =
+ m_register_r[DESIRED_SECTOR] =
+ (m_register_w[DESIRED_SECTOR]+1) & 0xff;
+
+ /* Reinitialize retry count. */
+ m_register_w[RETRY_COUNT] = retry;
+}
+
+/*
+ Common procedure: data_transfer(write) (as described in the specification)
+*/
+void smc92x4_device::data_transfer_write(chrn_id_hd id, int deldata, int redcur, int precomp, bool write_long)
+{
+ int retry, i, sector_len;
+ UINT8 *buf;
+ int sector_data_id;
+ mfm_harddisk_device *harddisk;
+ sync_latches_out();
+ sync_status_in();
+
+ // Set command termination code. The error code is set first, and
+ // on success, it is cleared.
+ m_register_r[INT_STATUS] |= ST_TC_DATAERR;
+
+ // Save the value. Note that the retry count is only in the first four
+ // bits, and it is stored in one's complement. In this implementation
+ // we don't work with it.
+ retry = m_register_w[RETRY_COUNT];
+
+ /* Initiate the DMA. We assume the DMARQ is positive. */
+ m_register_r[INT_STATUS] &= ~ST_OVRUN;
+
+ sector_len = 1 << (id.N+7);
+ sector_data_id = id.data_id;
+
+ buf = (UINT8 *)malloc(sector_len);
+
+ /* Copy via DMA from controller RAM. */
+ set_dma_address(DMA23_16, DMA15_8, DMA7_0);
+
+ m_out_dip(ASSERT_LINE);
+ for (i=0; i<sector_len; i++)
+ {
+ buf[i] = m_in_dma(0);
+ }
+ m_out_dip(CLEAR_LINE);
+
+ if (write_long)
+ {
+ if (VERBOSE>1) LOG("smc92x4 warn: write sector: Write_long not supported. Performing a normal write.\n");
+ }
+
+ if (m_selected_drive_type & TYPE_FLOPPY)
+ {
+ floppy_drive_write_sector_data(m_drive, id.H, sector_data_id, (char *) buf, sector_len, false);
+ }
+ else
+ {
+ harddisk = static_cast<mfm_harddisk_device *>(m_drive);
+ harddisk->write_sector(id.C, id.H, id.R, buf);
+ }
+ free(buf);
+ sync_status_in();
+
+ m_register_r[CHIP_STATUS] &= ~CS_RETREQ;
+ m_register_r[CHIP_STATUS] &= ~CS_CRCERR;
+ m_register_r[CHIP_STATUS] &= ~CS_ECCATT;
+
+ /* Update the DMA registers. */
+ dma_add_offset(sector_len);
+
+ /* Decrement sector count. */
+ m_register_w[SECTOR_COUNT] = (m_register_w[SECTOR_COUNT]-1)&0xff;
+
+ /* Clear the error bits. */
+ m_register_r[INT_STATUS] &= ~ST_TC_DATAERR;
+
+ if (m_register_w[SECTOR_COUNT] == 0) return;
+
+ /* Else this is a multi-sector operation. */
+ m_register_w[DESIRED_SECTOR] = m_register_r[DESIRED_SECTOR] = (m_register_w[DESIRED_SECTOR]+1) & 0xff;
+
+ /* Reinitialize retry count. */
+ m_register_w[RETRY_COUNT] = retry;
+}
+
+/*
+ Read sectors physical / logical. Physical means that the first, the
+ second, the third sector appearing under the head will be read. These
+ sectors are usually not in logical sequence. The ordering depends on
+ the interleave pattern.
+*/
+void smc92x4_device::read_write_sectors()
+{
+ int logical = m_command & 0x04;
+ int implied_seek_disabled = m_command & 0x02; /* for read */
+ int write = (m_command & 0x80);
+
+ m_after_seek = false;
+
+ m_to_be_continued = false;
+
+ if (write) /* write sectors */
+ {
+ logical = m_command & 0x20;
+ implied_seek_disabled = m_command & 0x40;
+ }
+
+ if (!logical)
+ implied_seek_disabled = false;
+
+ if (!m_found_id)
+ {
+ /* First start. */
+ read_id_field(&m_seek_count, &m_step_direction, &m_recent_id);
+ }
+
+ if ((m_register_r[INT_STATUS] & ST_TC_DATAERR) == ST_TC_SUCCESS)
+ {
+ m_found_id = true;
+ /* Perform the seek for the cylinder. */
+ if (!implied_seek_disabled && m_seek_count > 0)
+ {
+ timed_seek_request();
+ }
+ else
+ {
+ if (write) write_sectors_continue();
+ else read_sectors_continue();
+ }
+ }
+ else
+ {
+ set_command_done(ST_TC_RDIDERR);
+ }
+}
+
+
+void smc92x4_device::read_sectors_continue()
+{
+ bool check_sector = true; /* always check the first sector */
+ int state = AGAIN;
+ int logical = m_command & 0x04;
+
+ /* Needed for the two ways of re-entry: during the seek process, and during sector read */
+ if (!m_after_seek)
+ {
+ if (VERBOSE>7) LOG("smc92x4 continue with sector read\n");
+ m_seek_count--;
+ if (m_seek_count > 0)
+ {
+ read_write_sectors();
+ return;
+ }
+ m_after_seek = true;
+ }
+ else
+ {
+ /* we are here after the sector read. */
+ m_to_be_continued = false;
+ if (m_register_r[INT_STATUS] & ST_TERMCOD)
+ {
+ if (VERBOSE>1) LOG("smc92x4 error: data error during sector read: INTSTATUS=%02x\n", m_register_r[INT_STATUS]);
+ set_command_done(ST_TC_DATAERR);
+ return;
+ }
+ }
+
+ m_to_be_continued = false;
+
+ /* Wait for SEEK_COMPLETE. We assume the signal has appeared. */
+
+ if (m_register_w[SECTOR_COUNT] > 0 /* && !(m_register_r[DRIVE_STATUS] & DS_INDEX) */)
+ {
+ /* Call the verify sequence. */
+ state = verify(&m_recent_id, check_sector);
+ if (state==ERROR)
+ {
+ // TODO: set command done?
+ if (VERBOSE>0) LOG("smc92x4 error: verify error during sector read\n");
+ return;
+ }
+
+ /* For read physical, only verify the first sector. */
+ if (!logical)
+ check_sector = false;
+
+ if (m_recent_id.flags & BAD_SECTOR)
+ {
+ if (VERBOSE>0) LOG("smc92x4 error: Bad sector, seek error\n");
+ set_command_done(ST_TC_SEEKERR);
+ }
+ else
+ {
+ timed_sector_read_request();
+ }
+ }
+ else
+ {
+ set_command_done(ST_TC_SUCCESS);
+ if (VERBOSE>7) LOG("smc92x4 read sector command done\n");
+ }
+}
+
+void smc92x4_device::write_sectors_continue()
+{
+ bool check_sector = true; /* always check the first sector */
+ int state = AGAIN;
+ int logical = m_command & 0x20;
+
+ /* Needed for the two ways of re-entry: during the seek process, and during sector write */
+ if (!m_after_seek)
+ {
+ m_seek_count--;
+ if (m_seek_count > 0)
+ {
+ read_write_sectors();
+ return;
+ }
+ m_after_seek = true;
+ }
+ else
+ {
+ /* we are here after the sector write. */
+ m_to_be_continued = false;
+ if (m_register_r[INT_STATUS] & ST_TERMCOD)
+ {
+ if (VERBOSE>0) LOG("smc92x4 error: data error during sector write\n");
+ set_command_done(ST_TC_DATAERR);
+ return;
+ }
+ }
+
+ m_to_be_continued = false;
+
+ if ((m_register_w[RETRY_COUNT] & 0xf0)!= 0xf0)
+ if (VERBOSE>1) LOG("smc92x4 warn: RETRY_COUNT in write sector should be set to 0. Ignored.\n");
+
+ /* Wait for SEEK_COMPLETE. We assume the signal has appeared. */
+ if (m_register_w[SECTOR_COUNT] > 0)
+ {
+ /* Call the verify sequence. */
+ state = verify(&m_recent_id, check_sector);
+ if (state==ERROR)
+ {
+ if (VERBOSE>0) LOG("smc92x4 error: verify error during sector write\n");
+ return;
+ }
+
+ /* For write physical, only verify the first sector. */
+ if (!logical)
+ check_sector = false;
+
+/* printf("smc92x4 write sectors CYL=%02x, HEA=%02x, SEC=%02x, MOD=%02x, CNT=%02x, TRY=%02x\n",
+ m_register_w[DESIRED_CYLINDER],
+ m_register_w[DESIRED_HEAD],
+ m_register_w[DESIRED_SECTOR],
+ m_register_w[MODE],
+ m_register_w[SECTOR_COUNT],
+ m_register_w[RETRY_COUNT]); */
+ timed_sector_write_request();
+ }
+ else
+ {
+ set_command_done(ST_TC_SUCCESS);
+ if (VERBOSE>7) LOG("smc92x4 write sector command done\n");
+ }
+}
+
+/*********************************************************************
+ Command implementations
+*********************************************************************/
+
+/*
+ Handle the restore command
+*/
+void smc92x4_device::restore_drive()
+{
+ /* TODO: int_after_seek_complete required for buffered seeks */
+ sync_status_in();
+
+ if (m_seek_count>=4096 || !(m_register_r[DRIVE_STATUS] & DS_READY))
+ {
+ if (VERBOSE>0) LOG("smc92x4 error: seek error in restore\n");
+ m_register_r[INT_STATUS] |= ST_TC_SEEKERR;
+ return;
+ }
+
+ if (m_register_r[DRIVE_STATUS] & DS_TRK00)
+ {
+ m_register_r[INT_STATUS] |= ST_TC_SUCCESS;
+ /* Issue interrupt */
+ set_interrupt();
+ return;
+ }
+
+ m_step_direction = -1;
+ timed_seek_request();
+}
+
+void smc92x4_device::restore_continue()
+{
+ m_seek_count++;
+
+ /* Next iteration */
+ restore_drive();
+
+ m_to_be_continued = false;
+}
+
+/*
+ Handle the step command. Note that the CURRENT_CYLINDER register is not
+ updated (this would break the format procedure).
+*/
+void smc92x4_device::step_in_out()
+{
+ int direction = (m_command & 0x02)? -1 : +1;
+ // bit 0: 0 -> command ends after last seek pulse, 1 -> command
+ // ends when the drive asserts the seek complete pin
+ int buffered = m_command & 0x01;
+
+ m_step_direction = direction;
+ m_buffered = (buffered!=0);
+
+ timed_seek_request();
+ if (VERBOSE>6) LOG("smc92x4 waiting for drive step\n");
+}
+
+void smc92x4_device::step_continue()
+{
+ if (VERBOSE>7) LOG("smc92x4 step continue\n");
+ m_to_be_continued = false;
+ set_command_done(ST_TC_SUCCESS);
+}
+
+/*
+ Poll drives
+ This command is used to find out which drive has complete a buffered
+ seek (RESTORE, SEEK IN/OUT with BUFFERED set to one)
+*/
+void smc92x4_device::poll_drives()
+{
+ int mask = 0x08;
+ int i;
+ int flags = m_command & 0x0f;
+
+/* Spec is unclear: Do we continue to poll the drives after we have checked each
+one for the first time? We are not interested in locking up the emulator, so
+we decide to poll only once. */
+ for (i=3; i>=0; i--)
+ {
+ if (flags & mask)
+ {
+ /* Poll drive */
+ drive_select(i|((m_types[i])<<2));
+ if (m_register_r[DRIVE_STATUS] & DS_SKCOM) return;
+ }
+ mask = mask>>1;
+ }
+}
+
+void smc92x4_device::drive_select(int driveparm)
+{
+ m_output1 = (0x10 << (driveparm & 0x03)) | (m_register_w[RETRY_COUNT]&0x0f);
+ m_selected_drive_type = (driveparm>>2) & 0x03;
+ m_head_load_delay_enable = (driveparm>>4)&0x01;
+
+ // We need to store the type of the drive for the poll_drives command
+ // to be able to correctly select the device (floppy or hard disk).
+ m_types[driveparm&0x03] = m_selected_drive_type;
+
+ // Copy the DMA registers to registers CURRENT_HEAD, CURRENT_CYLINDER,
+ // and CURRENT_IDENT. This is required during formatting (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];
+
+ sync_latches_out();
+ sync_status_in();
+}
+
+/*
+ Command SEEK/READID
+*/
+void smc92x4_device::seek_read_id()
+{
+ int step_enable = (m_command & 0x04);
+ int verify_id = (m_command & 0x01);
+ int wait = (m_command & 0x02);
+
+ m_to_be_continued = false;
+
+ if (!m_found_id)
+ {
+ /* First start. */
+ read_id_field(&m_seek_count, &m_step_direction, &m_recent_id);
+ m_found_id = true;
+ }
+
+ if ((m_register_r[INT_STATUS] & ST_TC_DATAERR) == ST_TC_SUCCESS)
+ {
+ /* Perform the seek for the cylinder. */
+ if (step_enable && m_seek_count > 0)
+ {
+ timed_seek_request();
+ }
+ else
+ {
+ if (wait)
+ if (VERBOSE>1) LOG("smc92x4 warn: seed_read_id: Waiting for seek_complete not implemented.\n");
+
+ if (verify_id)
+ {
+ verify(&m_recent_id, true);
+ }
+ }
+ }
+ else
+ {
+ set_command_done(ST_TC_RDIDERR);
+ }
+}
+
+void smc92x4_device::seek_read_id_continue()
+{
+ m_seek_count--;
+ seek_read_id();
+ m_to_be_continued = false;
+}
+
+/*
+ Formats a track starting from the detection of an index mark until the
+ detection of another index mark.
+ 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. Usually we have 247 bytes for FM and 598 for MFM.
+
+ 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.
+
+ Options: Command = 011m rppp
+ m = set data mark (0 = set deleted)
+ r = current (1 = reduced)
+ ppp = precompensation (for sector size = (2^ppp) * 128; ppp<4 for floppy )
+
+ ===============
+
+ One deviation from the specification: The TI-99 family uses the SDF
+ and TDF formats. The TDF formats complies with the formats produced
+ by the standard TI disk controller. It does not use index address marks.
+ So we could integrate a translation in ti99_dsk when writing to disk,
+ but when reading, how can ti99_dsk know whether to blow up the format
+ to full length for this controller or keep it as is for the other
+ controller? Unless someone comes up with a better idea, we implement
+ an "undocumented" option in this controller, allowing to create a
+ different track layout.
+
+ So there are two layouts for the floppy track:
+
+ - full format, including the index address mark, according to the
+ specification
+
+ - short format without index AM which matches the PC99 format used
+ for the TI-99 family.
+
+ The formats are determined by setting the flag in the smc92x4
+ interface structure.
+*/
+void smc92x4_device::format_floppy_track(int flags)
+{
+ floppy_image_legacy *floppy;
+ int i,index,j, exp_size;
+ int gap0, gap1, gap2, gap3, gap4, sync1, sync2, count, size, fm;
+ int gap_byte, pre_gap, crc, mark, inam;
+ UINT8 curr_cyl, curr_head, curr_sect, curr_size;
+
+ int normal_data_mark = flags & 0x10;
+
+ UINT8 *buffer;
+
+ /* Determine the track size. We cannot allow different sizes in this design. */
+ int data_count = 0;
+
+ sync_status_in();
+
+ floppy = flopimg_get_image(m_drive);
+
+ if (floppy != NULL)
+ data_count = floppy_get_track_size(floppy, 0, 0);
+
+ if (data_count==0)
+ {
+ if (in_single_density_mode())
+ data_count = TRKSIZE_SD;
+ else
+ data_count = TRKSIZE_DD;
+ }
+
+ /* Build buffer */
+ buffer = (UINT8*)malloc(data_count);
+
+ fm = in_single_density_mode();
+
+ sync2 = (~m_register_w[DESIRED_CYLINDER])&0xff;
+ gap2 = (-m_register_w[DMA23_16])&0xff;
+ count = (~m_register_w[SECTOR_COUNT])&0xff;
+ size = (~m_register_w[RETRY_COUNT])&0xff;
+ gap_byte = (fm)? 0xff : 0x4e;
+
+ if (m_full_track_layout)
+ {
+ /* Including the index AM. */
+ gap0 = (-m_register_w[DMA7_0])&0xff;
+ gap1 = (-m_register_w[DMA15_8])&0xff;
+ gap3 = (-m_register_w[DESIRED_SECTOR])&0xff;
+ gap4 = (fm)? 247 : 598;
+ pre_gap = gap_byte;
+ sync1 = sync2;
+ inam = sync2 + ((fm)? 1 : 4);
+ }
+ else
+ {
+ /* Specific overrides for this format. We do not have the index mark. */
+ gap0 = (fm)? 16 : 40;
+ gap1 = 0;
+ gap3 = (fm)? 45 : 24;
+ gap4 = (fm)? 231 : 712;
+ pre_gap = (fm)? 0x00 : 0x4e;
+ sync1 = (fm)? 6 : 10;
+ inam = 0;
+ }
+
+ index = 0;
+
+ mark = (fm)? 10 : 16; /* ID/DAM + A1 + CRC */
+
+ exp_size = gap0 + inam + gap1 + count*(sync1 + mark + gap2 + sync2 + size*128 + gap3) + gap4;
+
+ if (exp_size != data_count)
+ if (VERBOSE>0) LOG("smc92x4 warn: The current track length in the image (%d) does not match the new track length (%d). Keeping the old length. This will break the image (sorry).\n", data_count, exp_size);
+
+ /* use the backup registers set up during drive_select */
+ set_dma_address(CURRENT_IDENT, CURRENT_CYLINDER, CURRENT_HEAD);
+
+ memset(&buffer[index], pre_gap, gap0);
+ index += gap0;
+
+ if (m_full_track_layout)
+ {
+ /* Create the Index AM */
+ memset(&buffer[index], 0x00, sync1);
+ index += sync1;
+ if (!fm)
+ {
+ memset(&buffer[index], 0xc2, 3);
+ index += 3;
+ }
+ memset(&buffer[index], gap_byte, gap1);
+ index += gap1;
+ }
+
+ /* for each sector */
+ for (j=0; j < count; j++)
+ {
+ memset(&buffer[index], 0x00, sync1);
+ index += sync1;
+
+ if (!fm)
+ {
+ memset(&buffer[index], 0xa1, 3);
+ index += 3;
+ }
+
+ buffer[index++] = 0xfe;
+
+ m_out_dip(ASSERT_LINE);
+// if (!fm) curr_ident = m_in_dma();
+ if (!fm) m_in_dma(0);
+ curr_cyl = m_in_dma(0);
+ curr_head = m_in_dma(0);
+ curr_sect = m_in_dma(0);
+ curr_size = m_in_dma(0);
+ m_out_dip(CLEAR_LINE);
+
+ buffer[index++] = curr_cyl;
+ buffer[index++] = curr_head;
+ buffer[index++] = curr_sect;
+ buffer[index++] = curr_size;
+
+ if (j==0)
+ if (VERBOSE>6) LOG("current_floppy=%s, format track %d, head %d\n", m_drive->tag(), curr_cyl, curr_head);
+
+ /* Calculate CRC16 (5 bytes for ID) */
+ crc = ccitt_crc16(0xffff, &buffer[index-5], 5);
+ buffer[index++] = (crc>>8)&0xff;
+ buffer[index++] = crc & 0xff;
+
+ memset(&buffer[index], gap_byte, gap2);
+ index += gap2;
+
+ memset(&buffer[index], 0x00, sync2);
+ index += sync2;
+
+ if (!fm)
+ {
+ memset(&buffer[index], 0xa1, 3);
+ index += 3;
+ }
+
+ if (normal_data_mark) buffer[index++] = 0xfb;
+ else buffer[index++] = 0xf8;
+
+ /* Sector data */
+ for (i=0; i < 128*size; i++) buffer[index++] = 0xe5;
+
+ /* Calculate CRC16 (128*size+1 bytes for sector) */
+ crc = ccitt_crc16(0xffff, &buffer[index-128*size-1], 128*size+1);
+ buffer[index++] = (crc>>8)&0xff;
+ buffer[index++] = crc & 0xff;
+
+ memset(&buffer[index], gap_byte, gap3);
+ index += gap3;
+ }
+
+ memset(&buffer[index], gap_byte, gap4);
+ index += gap4;
+
+ floppy_drive_write_track_data_info_buffer(m_drive, m_register_w[DESIRED_HEAD]&0x0f, (char *)buffer, &data_count);
+ free(buffer);
+ sync_status_in();
+}
+
+/*
+ Create the track layout of a MFM hard disk. Like floppy disks,
+ MFM hard disks are interfaced on a track base, that is, we have to
+ create a complete track layout.
+
+ For more explanations see the comments to format_floppy_track.
+*/
+void smc92x4_device::format_harddisk_track(int flags)
+{
+ int i,index,j;
+ int gap1, gap2, gap3, gap4, sync, count, size, gap_byte, crc;
+ UINT8 curr_ident, curr_cyl, curr_head, curr_sect, curr_size;
+
+ int normal_data_mark = flags & 0x10;
+ int data_count=0;
+
+ mfm_harddisk_device *harddisk = static_cast<mfm_harddisk_device *>(m_drive);
+
+ UINT8 *buffer;
+
+ sync_status_in();
+
+ /* Build buffer */
+// gap0 = (-m_register_w[DMA7_0])&0xff;
+ gap1 = (-m_register_w[DMA15_8])&0xff;
+ gap2 = (-m_register_w[DMA23_16])&0xff;
+ gap3 = (-m_register_w[DESIRED_SECTOR])&0xff;
+ gap4 = 340;
+
+ sync = (~m_register_w[DESIRED_CYLINDER])&0xff;
+ count = (~m_register_w[SECTOR_COUNT])&0xff;
+ size = (~m_register_w[RETRY_COUNT])&0xff;
+
+ data_count = gap1 + count*(sync+12+gap2+sync+size*128+gap3)+gap4;
+
+ buffer = (UINT8*)malloc(data_count);
+
+ index = 0;
+ gap_byte = 0x4e;
+
+ /* use the backup registers set up during drive_select */
+ set_dma_address(CURRENT_IDENT, CURRENT_CYLINDER, CURRENT_HEAD);
+
+ for (i=0; i < gap1; i++) buffer[index++] = gap_byte;
+
+ /* Now write the sectors. */
+ for (j=0; j < count; j++)
+ {
+ for (i=0; i < sync; i++) buffer[index++] = 0x00;
+ buffer[index++] = 0xa1;
+
+ m_out_dip(ASSERT_LINE);
+ curr_ident = m_in_dma(0);
+ curr_cyl = m_in_dma(0);
+ curr_head = m_in_dma(0);
+ curr_sect = m_in_dma(0);
+ curr_size = m_in_dma(0);
+ m_out_dip(CLEAR_LINE);
+
+ buffer[index++] = curr_ident;
+ buffer[index++] = curr_cyl;
+ buffer[index++] = curr_head;
+ buffer[index++] = curr_sect;
+ buffer[index++] = curr_size;
+
+ /* Calculate CRC16 (5 bytes for ID) */
+ crc = ccitt_crc16(0xffff, &buffer[index-5], 5);
+ buffer[index++] = (crc>>8)&0xff;
+ buffer[index++] = crc & 0xff;
+
+ /* GAP 2 */
+ for (i=0; i < gap2; i++) buffer[index++] = gap_byte;
+ for (i=0; i < sync; i++) buffer[index++] = 0x00;
+
+ buffer[index++] = 0xa1;
+
+ if (normal_data_mark) buffer[index++] = 0xfb;
+ else buffer[index++] = 0xf8;
+
+ /* Sector data */
+ for (i=0; i < 128*size; i++) buffer[index++] = 0xe5;
+
+ /* Calculate CRC16 (128*size+1 bytes for sector) */
+ crc = ccitt_crc16(0xffff, &buffer[index-128*size-1], 128*size+1);
+ buffer[index++] = (crc>>8)&0xff;
+ buffer[index++] = crc & 0xff;
+
+ /* GAP 3 */
+ for (i=0; i < 3; i++) buffer[index++] = 0; /* check that, unclear in spec */
+ for (i=0; i < gap3 - 3; i++) buffer[index++] = gap_byte;
+ }
+ /* GAP 4 */
+ for (i=0; i < gap4; i++) buffer[index++] = gap_byte;
+
+ // Now write the whole track
+ harddisk->write_track(m_register_w[DESIRED_HEAD]&0x0f, buffer, data_count);
+
+ free(buffer);
+ sync_status_in();
+}
+
+/*
+ Read a floppy track.
+ A complete track is read at the position of the head. It reads the
+ track from one index pulse to the next index pulse. (Note that the
+ spec talks about "index mark" and "signal from the drive" which is
+ a bit confusing, since the index AM is behind Gap0, the index hole
+ is before Gap0. We should check with a real device. Also, it does not
+ speak about the head, so we assume the head is set in the DESIRED_HEAD
+ register.)
+
+ TODO: The TDF format does not support index marks. Need to define TDF
+ in a more flexible way. Also consider format variations.
+ (Hint: Do a check for the standard "IBM" format. Should probably do
+ a translation from IBM to PC99 and back. Requires to parse the track
+ image before. Need to decide whether we generally translate to the IBM
+ format or generally to the PC99 format between controller and format.
+ Format is the image is always PC99.)
+*/
+void smc92x4_device::read_floppy_track(bool transfer_only_ids)
+{
+ floppy_image_legacy *floppy;
+ /* Determine the track size. We cannot allow different sizes in this design. */
+ int data_count = 0;
+ int i;
+ UINT8 *buffer;
+
+ sync_latches_out();
+
+ floppy = flopimg_get_image(m_drive);
+
+ /* Determine the track size. We cannot allow different sizes in this design. */
+ if (floppy != NULL)
+ data_count = floppy_get_track_size(floppy, 0, 0);
+
+ if (data_count==0)
+ {
+ if (in_single_density_mode())
+ data_count = TRKSIZE_SD;
+ else
+ data_count = TRKSIZE_DD;
+ }
+
+ buffer = (UINT8*)malloc(data_count);
+
+ floppy_drive_read_track_data_info_buffer(m_drive, m_register_w[DESIRED_HEAD]&0x0f, (char *)buffer, &data_count);
+ sync_status_in();
+
+ // Transfer the buffer to the external memory. We assume the memory
+ // pointer has been set appropriately in the registers.
+ set_dma_address(DMA23_16, DMA15_8, DMA7_0);
+
+ if (transfer_only_ids)
+ {
+ if (VERBOSE>1) LOG("smc92x4 warn: read track: Ignoring transfer-only-ids. Reading complete track.\n");
+ }
+
+ m_out_dip(ASSERT_LINE);
+ for (i=0; i < data_count; i++)
+ {
+ m_out_dma(0, buffer[i]);
+ }
+ m_out_dip(CLEAR_LINE);
+
+ free(buffer);
+}
+
+void smc92x4_device::read_harddisk_track(bool transfer_only_ids)
+{
+ /* Determine the track size. We cannot allow different sizes in this design. */
+ int i;
+ UINT8 *buffer;
+ int data_count=0;
+ mfm_harddisk_device *harddisk = static_cast<mfm_harddisk_device *>(m_drive);
+
+ sync_latches_out();
+
+ data_count = harddisk->get_track_length();
+ buffer = (UINT8*)malloc(data_count);
+
+ /* buffer and data_count are allocated and set by the function. */
+ harddisk->read_track(m_register_w[DESIRED_HEAD]&0x0f, buffer);
+ sync_status_in();
+
+ if (!(m_register_r[DRIVE_STATUS] & DS_READY))
+ {
+ if (VERBOSE>0) LOG("smc92x4 error: read harddisk track failed.\n");
+ }
+
+ // Transfer the buffer to the external memory. We assume the memory
+ // pointer has been set appropriately in the registers.
+ set_dma_address(DMA23_16, DMA15_8, DMA7_0);
+
+ if (transfer_only_ids)
+ {
+ if (VERBOSE>1) LOG("smc92x4 warn: read track: Ignoring transfer-only-ids. Reading complete track.\n");
+ }
+
+ m_out_dip(ASSERT_LINE);
+ for (i=0; i < data_count; i++)
+ {
+ m_out_dma(0, buffer[i]);
+ }
+ m_out_dip(CLEAR_LINE);
+
+ free(buffer);
+}
+
+
+void smc92x4_device::read_track()
+{
+ int transfer_only_ids = m_command & 0x01;
+
+ if (m_selected_drive_type & TYPE_FLOPPY)
+ {
+ read_floppy_track(transfer_only_ids);
+ }
+ else
+ {
+ read_harddisk_track(transfer_only_ids);
+ }
+ timed_track_request();
+}
+
+void smc92x4_device::read_track_continue()
+{
+ m_to_be_continued = false;
+ set_command_done(ST_TC_SUCCESS);
+}
+
+void smc92x4_device::format_track()
+{
+ int flags = m_command & 0x1f;
+
+ if (m_selected_drive_type & TYPE_FLOPPY)
+ format_floppy_track(flags);
+ else
+ format_harddisk_track(flags);
+
+ timed_track_request();
+}
+
+void smc92x4_device::format_track_continue()
+{
+ m_to_be_continued = false;
+ set_command_done(ST_TC_SUCCESS);
+}
+
+/*
+ Continue to process after callback
+*/
+void smc92x4_device::process_after_callback()
+{
+ UINT8 opcode = m_command;
+ if (opcode >= 0x02 && opcode <= 0x03)
+ {
+ restore_continue();
+ }
+ else if (opcode >= 0x04 && opcode <= 0x07)
+ {
+ step_continue();
+ }
+ else if (opcode >= 0x50 && opcode <= 0x57)
+ {
+ seek_read_id_continue();
+ }
+ else if ((opcode >= 0x58 && opcode <= 0x59)||(opcode >= 0x5C && opcode <= 0x5f))
+ {
+ read_sectors_continue();
+ }
+ else if (opcode >= 0x5a && opcode <= 0x5b)
+ {
+ read_track_continue();
+ }
+ else if (opcode >= 0x60 && opcode <= 0x7f)
+ {
+ format_track_continue();
+ }
+ else if (opcode >= 0x80)
+ {
+ write_sectors_continue();
+ }
+ else
+ {
+ if (VERBOSE>1) LOG("smc92x4 warn: Invalid command %x or command changed while waiting for callback\n", opcode);
+ }
+}
+
+/*
+ Process a command
+*/
+void smc92x4_device::process_command(UINT8 opcode)
+{
+ if (VERBOSE>6) LOG("smc92x4 process command %02x\n", opcode);
+ if (m_to_be_continued)
+ {
+ if (VERBOSE>1) LOG("smc92x4 warn: previous command %02x not complete\n", m_command);
+ }
+
+ /* Reset DONE and BAD_SECTOR. */
+ m_register_r[INT_STATUS] &= ~(ST_DONE | ST_BADSECT);
+
+ // Reset interrupt line (not explicitly mentioned in spec, but seems reasonable
+ clear_interrupt();
+ m_register_r[INT_STATUS] &= ~(ST_INTPEND | ST_RDYCHNG);
+
+ m_command = opcode;
+ m_found_id = false;
+ m_seek_count = 0;
+
+ if (opcode == 0x00)
+ {
+ /* RESET */
+ /* same effect as the RST* pin being active */
+ if (VERBOSE>0) LOG("smc92x4 info: reset command\n");
+ reset();
+ }
+ else if (opcode == 0x01)
+ {
+ /* DESELECT DRIVE */
+ /* done when no drive is in use */
+ if (VERBOSE>2) LOG("smc92x4 info: drdeselect command\n");
+ m_output1 &= ~(OUT1_DRVSEL3|OUT1_DRVSEL2|OUT1_DRVSEL1|OUT1_DRVSEL0);
+ m_output2 |= OUT2_DRVSEL3_;
+ /* sync the latches on the PCB */
+ sync_latches_out();
+ sync_status_in();
+ }
+ else if (opcode >= 0x02 && opcode <= 0x03)
+ {
+ /* RESTORE DRIVE */
+ // bit 0: 0 -> command ends after last seek pulse, 1 -> command
+ // ends when the drive asserts the seek complete pin
+ if (VERBOSE>2) LOG("smc92x4 info: restore command %X\n", opcode);
+ restore_drive();
+ }
+ else if (opcode >= 0x04 && opcode <= 0x07)
+ {
+ /* STEP IN/OUT ONE CYLINDER */
+ if (VERBOSE>2) LOG("smc92x4 info: step in/out command %X\n", opcode);
+ step_in_out();
+ }
+ else if (opcode >= 0x08 && opcode <= 0x0f)
+ {
+ /* TAPE BACKUP (08-0f)*/
+ if (VERBOSE>0) LOG("smc92x4 error: tape backup command %X not implemented\n", opcode);
+ }
+ else if (opcode >= 0x10 && opcode <= 0x1f)
+ {
+ /* POLLDRIVE */
+ if (VERBOSE>2) LOG("smc92x4 info: polldrive command %X\n", opcode);
+ poll_drives();
+ }
+ else if (opcode >= 0x20 && opcode <= 0x3f)
+ {
+ /* DRIVE SELECT */
+ if (VERBOSE>2) LOG("smc92x4 info: drselect command %X\n", opcode);
+ drive_select(opcode&0x1f);
+ }
+ else if (opcode >= 0x40 && opcode <= 0x4f)
+ {
+ /* SETREGPTR */
+ if (VERBOSE>2) LOG("smc92x4 info: setregptr command %X\n", opcode);
+ m_register_pointer = opcode & 0xf;
+ // Spec does not say anything about the effect of setting an
+ // invalid value (only "care should be taken")
+ if (m_register_pointer > 10)
+ {
+ if (VERBOSE>1) LOG("smc92x4 error: set register pointer: Invalid register number: %d. Setting to 10.\n", m_register_pointer);
+ m_register_pointer = 10;
+ }
+ }
+ else if (opcode >= 0x50 && opcode <= 0x57)
+ {
+ /* SEEK/READ ID */
+ if (VERBOSE>2) LOG("smc92x4 seekreadid command %X\n", opcode);
+ seek_read_id();
+ }
+ else if ((opcode >= 0x58 && opcode <= 0x59)
+ || (opcode >= 0x5C && opcode <= 0x5f)
+ || (opcode >= 0x80))
+ {
+ /* READ/WRITE SECTORS PHYSICAL/LOGICAL */
+ if (VERBOSE>2) LOG("smc92x4 info: read/write sector command %X\n", opcode);
+ read_write_sectors();
+ }
+ else if (opcode >= 0x5A && opcode <= 0x5b)
+ {
+ /* READ TRACK */
+ if (VERBOSE>2) LOG("smc92x4 info: read track command %X\n", opcode);
+ read_track();
+ }
+ else if (opcode >= 0x60 && opcode <= 0x7f)
+ {
+ /* FORMAT TRACK */
+ if (VERBOSE>2) LOG("smc92x4 info: format track command %X\n", opcode);
+ format_track();
+ }
+ else
+ {
+ if (VERBOSE>0) LOG("smc92x4 error: Invalid command %x, ignored\n", opcode);
+ }
+
+ if (!m_to_be_continued)
+ set_command_done();
+}
+
+/***************************************************************************
+ Memory accessors
+****************************************************************************/
+
+/*
+ Read a byte of data from a smc92x4 controller
+ The address (offset) encodes the C/D* line (command and /data)
+*/
+READ8_MEMBER( smc92x4_device::read )
+{
+ UINT8 reply = 0;
+
+ if ((offset & 1) == 0)
+ {
+ /* data register */
+ reply = m_register_r[m_register_pointer];
+ if (VERBOSE>6) LOG("smc92x4 register_r[%d] -> %02x\n", 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];
+ // Spec (p.3) : The interrupt pin is reset to its inactive state
+ // when the UDC interrupt status register is read.
+ if (VERBOSE>6) LOG("smc92x4 interrupt status read = %02x\n", reply);
+ clear_interrupt();
+ /* Clear the bits due to int status register read. */
+ m_register_r[INT_STATUS] &= ~(ST_INTPEND | ST_RDYCHNG);
+ }
+ return reply;
+}
+
+/*
+ Write a byte to a smc99x4 controller
+ The address (offset) encodes the C/D* line (command and /data)
+*/
+WRITE8_MEMBER( smc92x4_device::write )
+{
+ data &= 0xff;
+
+ if ((offset & 1) == 0)
+ {
+ /* data register */
+ if (VERBOSE>6) LOG("smc92x4 register_w[%d] <- %X\n", m_register_pointer, data);
+ m_register_w[m_register_pointer] = data;
+
+ // The DMA registers and the sector register for read and
+ // write are identical.
+ if (m_register_pointer < DESIRED_HEAD)
+ m_register_r[m_register_pointer] = data;
+
+ /* Autoincrement until DATA is reached. */
+ if (m_register_pointer < DATA)
+ m_register_pointer++;
+ }
+ else
+ process_command(data); // command register
+}
+
+
+
+/***************************************************************************
+ DEVICE FUNCTIONS
+***************************************************************************/
+
+void smc92x4_device::device_start()
+{
+ const smc92x4_interface *intf = reinterpret_cast<const smc92x4_interface *>(static_config());
+
+ m_out_intrq.resolve(intf->out_intrq, *this);
+ m_out_dip.resolve(intf->out_dip, *this);
+ m_out_auxbus.resolve(intf->out_auxbus, *this);
+ m_in_auxbus.resolve(intf->in_auxbus, *this);
+ m_out_dma.resolve(intf->dma_write, *this);
+ m_in_dma.resolve(intf->dma_read, *this);
+
+ m_full_track_layout = intf->full_track_layout;
+
+ // allocate timers
+ // m_timer_data = timer_alloc(DATA_TIMER);
+ m_timer_rs = timer_alloc(READ_TIMER);
+ m_timer_ws = timer_alloc(WRITE_TIMER);
+ m_timer_track = timer_alloc(TRACK_TIMER);
+ m_timer_seek = timer_alloc(SEEK_TIMER);
+
+ m_use_real_timing = true;
+}
+
+void smc92x4_device::device_reset()
+{
+ clear_interrupt();
+ m_out_dip(CLEAR_LINE);
+
+ for (int i=0; i<=11; i++)
+ m_register_r[i] = m_register_w[i] = 0;
+
+ m_to_be_continued = false;
+}
+
+void smc92x4_device::set_timing(bool realistic)
+{
+ m_use_real_timing = realistic;
+ if (VERBOSE>0) LOG("smc92x4: use realistic timing: %02x\n", realistic);
+}
+
+void smc92x4_device::connect_drive(device_t *drive)
+{
+ m_drive = drive;
+ if (VERBOSE>3)
+ {
+ if (drive==NULL) LOG("smc92x4: Unselect all drives\n");
+ else LOG("smc92x4: Connect drive %s\n", drive->tag());
+ }
+}
+
+void smc92x4_device::reset()
+{
+ device_reset();
+}
+
+const device_type SMC92X4 = &device_creator<smc92x4_device>;
diff --git a/src/mess/machine/smc92x4.h b/src/mess/machine/smc92x4.h
new file mode 100644
index 00000000000..af4b17f1341
--- /dev/null
+++ b/src/mess/machine/smc92x4.h
@@ -0,0 +1,219 @@
+/* Interface */
+
+#ifndef __SMC92X4_H__
+#define __SMC92X4_H__
+
+#include "ti99/ti99_hd.h"
+#include "imagedev/flopdrv.h"
+#include "formats/imageutl.h"
+#include "imagedev/harddriv.h"
+#include "harddisk.h"
+
+#define INPUT_STATUS 0x00
+#define OUTPUT_DMA_ADDR 0x01
+#define OUTPUT_OUTPUT1 0x02
+#define OUTPUT_OUTPUT2 0x03
+
+#define MFMHD_TRACK00 0x80
+#define MFMHD_SEEKCOMP 0x40
+#define MFMHD_WRFAULT 0x20
+#define MFMHD_READY 0x10
+#define MFMHD_INDEX 0x08
+
+#define BAD_SECTOR 0x1000
+#define BAD_CRC 0x2000
+
+extern const device_type SMC92X4;
+/*
+ Definition of bits in the Disk-Status register
+*/
+#define DS_ECCERR 0x80 /* ECC error */
+#define DS_INDEX 0x40 /* index point */
+#define DS_SKCOM 0x20 /* seek complete */
+#define DS_TRK00 0x10 /* track 0 */
+#define DS_UDEF 0x08 /* user-defined */
+#define DS_WRPROT 0x04 /* write protect */
+#define DS_READY 0x02 /* drive ready bit */
+#define DS_WRFAULT 0x01 /* write fault */
+
+typedef struct _smc92x4_interface
+{
+ // Disk format support. This flag allows to choose between the full
+ // FM/MFM format and an abbreviated track layout. The difference results
+ // from legal variations of the layout. This is not part of
+ // the smc92x4 specification, but it allows to keep the image format
+ // simple without too much case checking. Should be removed as soon as
+ // the respective disk formats support the full format.
+ int full_track_layout;
+
+ // Interrupt line. To be connected with the controller PCB.
+ devcb_write_line out_intrq;
+
+ // DMA in progress line. To be connected with the controller PCB.
+ devcb_write_line out_dip;
+
+ // 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.
+ devcb_write8 out_auxbus;
+
+ // Auxiliary Bus. This is only used for S0=S1=0.
+ devcb_read8 in_auxbus;
+
+ // 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.
+ devcb_read8 dma_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. */
+ devcb_write8 dma_write;
+
+} smc92x4_interface;
+
+
+class smc92x4_device : public device_t
+{
+public:
+ smc92x4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ DECLARE_READ8_MEMBER( read );
+ DECLARE_WRITE8_MEMBER( write );
+
+ // Used to turn off the delays.
+ void set_timing(bool realistic);
+
+ // Used to reconfigure the drive connections. Drive selection is done
+ // using the select lines and maybe also the user-programmable outputs.
+ void connect_drive(device_t *drive);
+
+ void reset();
+
+protected:
+ void device_start(void);
+ void device_reset(void);
+
+private:
+ devcb_resolved_write_line m_out_intrq; // INT line
+ devcb_resolved_write_line m_out_dip; // DMA in progress line
+ devcb_resolved_write8 m_out_auxbus; // AB0-7 lines (using S0,S1 as address)
+ devcb_resolved_read8 m_in_auxbus; // AB0-7 lines (S0=S1=0)
+ devcb_resolved_read8 m_in_dma; // DMA read access to the cache buffer
+ devcb_resolved_write8 m_out_dma; // DMA write access to the cache buffer
+
+ UINT8 m_output1; // internal register "output1"
+ UINT8 m_output2; // internal register "output2"
+
+ void set_dip(line_state value);
+ int image_is_single_density();
+ bool in_single_density_mode();
+ void copyid(chrn_id id1, chrn_id_hd *id2);
+ void set_interrupt();
+ void clear_interrupt();
+ void set_command_done(int flags);
+ void set_command_done();
+ void set_dma_address(int pos2316, int pos1508, int pos0700);
+ void dma_add_offset(int offset);
+ void sync_status_in();
+ void sync_latches_out();
+ void timed_sector_read_request();
+ void timed_sector_write_request();
+ void timed_track_request();
+ void timed_seek_request();
+ void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+ UINT8 cylinder_to_ident(int cylinder);
+ int ident_to_cylinder(UINT8 ident);
+ void update_id_regs(chrn_id_hd id);
+ void read_id_field(int *steps, int *direction, chrn_id_hd *id);
+ int verify(chrn_id_hd *id, bool check_sector);
+ void data_transfer_read(chrn_id_hd id, int transfer_enable);
+ void data_transfer_write(chrn_id_hd id, int deldata, int redcur, int precomp, bool write_long);
+ void read_write_sectors();
+ void read_sectors_continue();
+ void write_sectors_continue();
+
+ void restore_drive();
+ void restore_continue();
+
+ void step_in_out();
+ void step_continue();
+
+ void poll_drives();
+
+ void drive_select(int driveparm);
+
+ void seek_read_id();
+ void seek_read_id_continue();
+
+ void format_track();
+ void format_track_continue();
+ void format_floppy_track(int flags);
+ void format_harddisk_track(int flags);
+
+ void read_track();
+ void read_track_continue();
+ void read_floppy_track(bool transfer_only_ids);
+ void read_harddisk_track(bool transfer_only_ids);
+
+ void process_after_callback();
+ void process_command(UINT8 opcode);
+
+ int m_selected_drive_type;
+ // We need to store the types, although this is not the case in the
+ // real hardware. The reason is that poll_drives wants to select the
+ // drives without knowing their kinds. In reality this does not matter,
+ // since we only check for the seek_complete line, but in our case,
+ // floppy and harddrive are pretty different, and we need to know which
+ // one to check.
+ int m_types[4];
+ int m_head_load_delay_enable;
+ int m_register_pointer;
+
+ UINT8 m_register_r[12];
+ UINT8 m_register_w[12];
+
+ /* timers to delay execution/completion of commands */
+ emu_timer *m_timer_data, *m_timer_rs, *m_timer_ws, *m_timer_seek, *m_timer_track;
+
+ /* Flag which determines whether to use realistic timing. */
+ bool m_use_real_timing;
+
+ /* Required to store the current iteration within restore. */
+ int m_seek_count;
+
+ /* Recent command. */
+ UINT8 m_command;
+
+ /* Stores the step direction. */
+ int m_step_direction;
+
+ /* Stores the buffered flag. */
+ bool m_buffered;
+
+ /* Stores the recent id field. */
+ chrn_id_hd m_recent_id;
+
+ /* Indicates whether an ID has been found. */
+ bool m_found_id;
+
+ /* Indicates whether we are already past the seek_id phase in read/write sector. */
+ bool m_after_seek;
+
+ /* Determines whether the command will be continued. */
+ bool m_to_be_continued;
+
+ bool m_full_track_layout;
+
+ // Link to attached drive (hard / floppy disk)
+ // Hard disks must be instances of mfmhd_device; floppy disks are the common drives.
+ // We expect the embedding board to replace the drive according to the
+ // select lines.
+ device_t *m_drive;
+};
+
+#define MCFG_SMC92X4_ADD(_tag, _intrf) \
+ MCFG_DEVICE_ADD(_tag, SMC92X4, 0) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#endif
diff --git a/src/mess/machine/sms.c b/src/mess/machine/sms.c
new file mode 100644
index 00000000000..7e170cf9aa6
--- /dev/null
+++ b/src/mess/machine/sms.c
@@ -0,0 +1,2322 @@
+#include "emu.h"
+#include "crsshair.h"
+#include "video/315_5124.h"
+#include "sound/2413intf.h"
+#include "imagedev/cartslot.h"
+#include "machine/eeprom.h"
+#include "includes/sms.h"
+
+#define VERBOSE 0
+#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
+
+#define CF_CODEMASTERS_MAPPER 0x001
+#define CF_KOREAN_MAPPER 0x002
+#define CF_KOREAN_ZEMINA_MAPPER 0x004
+#define CF_KOREAN_NOBANK_MAPPER 0x008
+#define CF_93C46_EEPROM 0x010
+#define CF_ONCART_RAM 0x020
+#define CF_GG_SMS_MODE 0x040
+#define CF_KOREAN_ZEMINA_NEMESIS 0x080
+#define CF_4PAK_MAPPER 0x100
+#define CF_JANGGUN_MAPPER 0x200
+#define CF_TVDRAW 0x400
+#define CF_MAPPER_BITS ( CF_CODEMASTERS_MAPPER | CF_KOREAN_MAPPER | CF_KOREAN_ZEMINA_MAPPER | \
+ CF_KOREAN_NOBANK_MAPPER | CF_4PAK_MAPPER | CF_JANGGUN_MAPPER )
+
+#define LGUN_RADIUS 6
+#define LGUN_X_INTERVAL 4
+
+
+static void setup_rom(address_space *space);
+
+
+static TIMER_CALLBACK( rapid_fire_callback )
+{
+ sms_state *state = machine.driver_data<sms_state>();
+ state->m_rapid_fire_state_1 ^= 0xff;
+ state->m_rapid_fire_state_2 ^= 0xff;
+}
+
+
+void sms_state::map_cart_16k( UINT16 address, UINT16 bank )
+{
+ switch ( address )
+ {
+ case 0x0000:
+ map_cart_8k( 0x0000, bank * 2 );
+ map_cart_8k( 0x2000, bank * 2 + 1 );
+ break;
+
+ case 0x0400:
+ map_cart_8k( 0x0400, bank * 2 );
+ map_cart_8k( 0x2000, bank * 2 + 1 );
+ break;
+
+ case 0x4000:
+ map_cart_8k( 0x4000, bank * 2 );
+ map_cart_8k( 0x6000, bank * 2 + 1 );
+ break;
+
+ case 0x8000:
+ map_cart_8k( 0x8000, bank * 2 );
+ map_cart_8k( 0xA000, bank * 2 + 1 );
+ break;
+
+ default:
+ fatalerror("map_cart_16k: Unsupported map address %04x passed\n", address);
+ break;
+ }
+}
+
+
+void sms_state::map_cart_8k( UINT16 address, UINT16 bank )
+{
+ UINT8 *bank_start = m_banking_none;
+
+ if ( m_cartridge[m_current_cartridge].ROM )
+ {
+ UINT16 rom_bank_count = m_cartridge[m_current_cartridge].size / 0x2000;
+ bank_start = m_cartridge[m_current_cartridge].ROM + ((rom_bank_count > 0) ? bank % rom_bank_count : 0) * 0x2000;
+ }
+
+ switch ( address )
+ {
+ case 0x0000:
+ m_banking_cart[1] = bank_start;
+ m_banking_cart[2] = bank_start + 0x400;
+ membank("bank1")->set_base(m_banking_cart[1]);
+ membank("bank2")->set_base(m_banking_cart[2]);
+ break;
+
+ case 0x0400:
+ m_banking_cart[2] = bank_start + 0x400;
+ membank("bank2")->set_base(m_banking_cart[2]);
+ break;
+
+ case 0x2000:
+ m_banking_cart[7] = bank_start;
+ membank("bank7")->set_base(m_banking_cart[7]);
+ break;
+
+ case 0x4000:
+ m_banking_cart[3] = bank_start;
+ membank("bank3")->set_base(m_banking_cart[3]);
+ break;
+
+ case 0x6000:
+ m_banking_cart[4] = bank_start;
+ membank("bank4")->set_base(m_banking_cart[4]);
+ break;
+
+ case 0x8000:
+ m_banking_cart[5] = bank_start;
+ membank("bank5")->set_base(m_banking_cart[5]);
+ break;
+
+ case 0xA000:
+ m_banking_cart[6] = bank_start;
+ membank("bank6")->set_base(m_banking_cart[6]);
+ break;
+
+ default:
+ fatalerror("map_cart_8k: Unsuppored map address %04x passed\n", address);
+ break;
+ }
+}
+
+
+void sms_state::map_bios_16k( UINT16 address, UINT16 bank)
+{
+ switch ( address )
+ {
+ case 0x0000:
+ map_bios_8k( 0x0000, bank * 2 );
+ map_bios_8k( 0x2000, bank * 2 + 1 );
+ break;
+
+ case 0x0400:
+ map_bios_8k( 0x0400, bank * 2 );
+ map_bios_8k( 0x2000, bank * 2 + 1 );
+ break;
+
+ case 0x4000:
+ map_bios_8k( 0x4000, bank * 2 );
+ map_bios_8k( 0x6000, bank * 2 + 1 );
+ break;
+
+ case 0x8000:
+ map_bios_8k( 0x8000, bank * 2 );
+ map_bios_8k( 0xA000, bank * 2 + 1 );
+ break;
+
+ default:
+ fatalerror("map_bios_16k: Unsupported map address %04x passed\n", address);
+ break;
+ }
+}
+
+
+void sms_state::map_bios_8k( UINT16 address, UINT16 bank )
+{
+ UINT8 *bank_start = m_banking_none;
+
+ if ( m_BIOS )
+ {
+ bank_start = m_BIOS + ((m_bios_page_count > 0) ? bank % ( m_bios_page_count << 1 ) : 0) * 0x2000;
+ }
+
+ switch ( address )
+ {
+ case 0x0000:
+ m_banking_bios[1] = bank_start;
+ membank("bank1")->set_base(m_banking_bios[1]);
+ break;
+
+ case 0x0400:
+ if ( m_has_bios_0400 )
+ {
+ break;
+ }
+ m_banking_bios[2] = bank_start + 0x400;
+ membank("bank2")->set_base(m_banking_bios[2]);
+ break;
+
+ case 0x2000:
+ if ( m_has_bios_0400 || m_has_bios_2000 )
+ {
+ break;
+ }
+ m_banking_bios[7] = bank_start;
+ membank("bank7")->set_base(m_banking_bios[7]);
+ break;
+
+ case 0x4000:
+ if ( m_has_bios_0400 || m_has_bios_2000 )
+ {
+ break;
+ }
+ m_banking_bios[3] = bank_start;
+ membank("bank3")->set_base(m_banking_bios[3]);
+ break;
+
+ case 0x6000:
+ if ( m_has_bios_0400 || m_has_bios_2000 )
+ {
+ break;
+ }
+ m_banking_bios[4] = bank_start;
+ membank("bank4")->set_base(m_banking_bios[4]);
+ break;
+
+ case 0x8000:
+ if ( m_has_bios_0400 || m_has_bios_2000 )
+ {
+ break;
+ }
+ m_banking_bios[5] = bank_start;
+ membank("bank5")->set_base(m_banking_bios[5]);
+ break;
+
+ case 0xA000:
+ if ( m_has_bios_0400 || m_has_bios_2000 )
+ {
+ break;
+ }
+ m_banking_bios[6] = bank_start;
+ membank("bank6")->set_base(m_banking_bios[6]);
+ break;
+
+ default:
+ fatalerror("map_cart_8k: Unsuppored map address %04x passed\n", address);
+ break;
+ }
+}
+
+
+WRITE8_MEMBER(sms_state::sms_input_write)
+{
+
+ switch (offset)
+ {
+ case 0:
+ switch (ioport("CTRLSEL")->read_safe(0x00) & 0x0f)
+ {
+ case 0x04: /* Sports Pad */
+ if (data != m_sports_pad_last_data_1)
+ {
+ UINT32 cpu_cycles = downcast<cpu_device *>(&space.device())->total_cycles();
+
+ m_sports_pad_last_data_1 = data;
+ if (cpu_cycles - m_last_sports_pad_time_1 > 512)
+ {
+ m_sports_pad_state_1 = 3;
+ m_sports_pad_1_x = ioport("SPORT0")->read();
+ m_sports_pad_1_y = ioport("SPORT1")->read();
+ }
+ m_last_sports_pad_time_1 = cpu_cycles;
+ m_sports_pad_state_1 = (m_sports_pad_state_1 + 1) & 3;
+ }
+ break;
+ }
+ break;
+
+ case 1:
+ switch (ioport("CTRLSEL")->read_safe(0x00) & 0xf0)
+ {
+ case 0x40: /* Sports Pad */
+ if (data != m_sports_pad_last_data_2)
+ {
+ UINT32 cpu_cycles = downcast<cpu_device *>(&space.device())->total_cycles();
+
+ m_sports_pad_last_data_2 = data;
+ if (cpu_cycles - m_last_sports_pad_time_2 > 2048)
+ {
+ m_sports_pad_state_2 = 3;
+ m_sports_pad_2_x = ioport("SPORT2")->read();
+ m_sports_pad_2_y = ioport("SPORT3")->read();
+ }
+ m_last_sports_pad_time_2 = cpu_cycles;
+ m_sports_pad_state_2 = (m_sports_pad_state_2 + 1) & 3;
+ }
+ break;
+ }
+ break;
+ }
+}
+
+/* FIXME: this function is a hack for Light Phaser emulation. Theoretically
+ sms_vdp_hcount_latch() should be used instead, but it returns incorrect
+ position for unknown reason (timing?) */
+static void sms_vdp_hcount_lphaser( running_machine &machine, int hpos )
+{
+ sms_state *state = machine.driver_data<sms_state>();
+ int hpos_tmp = hpos + state->m_lphaser_x_offs;
+ UINT8 tmp = ((hpos_tmp - 46) >> 1) & 0xff;
+
+ //printf ("sms_vdp_hcount_lphaser: hpos %3d hpos_tmp %3d => hcount %2X\n", hpos, hpos_tmp, tmp);
+ state->m_vdp->hcount_latch_write(*state->m_space, 0, tmp);
+}
+
+
+/*
+ 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 off to on, a value is latched for HCount register
+ and a flag is set. The emulation uses the flag to avoid sequential latches and
+ to signal that TH line is activated when the status of the input port is read.
+ When the status is 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 bit after the VINT line.
+ - 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.
+*/
+static int lgun_bright_aim_area( running_machine &machine, emu_timer *timer, int lgun_x, int lgun_y )
+{
+ sms_state *state = machine.driver_data<sms_state>();
+ const int r_x_r = LGUN_RADIUS * LGUN_RADIUS;
+ screen_device *screen = machine.first_screen();
+ const rectangle &visarea = screen->visible_area();
+ int beam_x = screen->hpos();
+ int beam_y = screen->vpos();
+ int dx, dy;
+ int result = 0;
+ int pos_changed = 0;
+ double dx_circ;
+
+ while (1)
+ {
+ dy = abs(beam_y - lgun_y);
+
+ if (dy > LGUN_RADIUS || beam_y < visarea.min_y || beam_y > visarea.max_y)
+ {
+ beam_y = lgun_y - LGUN_RADIUS;
+ if (beam_y < visarea.min_y)
+ beam_y = visarea.min_y;
+ dy = abs(beam_y - lgun_y);
+ pos_changed = 1;
+ }
+ /* 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_circ = ceil((float) sqrt((float) (r_x_r - (dy * dy))));
+ dx = abs(beam_x - lgun_x);
+
+ if (dx > dx_circ || beam_x < visarea.min_x || beam_x > visarea.max_x)
+ {
+ if (beam_x > lgun_x)
+ {
+ beam_x = 0;
+ beam_y++;
+ continue;
+ }
+ beam_x = lgun_x - dx_circ;
+ if (beam_x < visarea.min_x)
+ beam_x = visarea.min_x;
+ pos_changed = 1;
+ }
+
+ if (!pos_changed)
+ {
+ bitmap_rgb32 &bitmap = state->m_vdp->get_bitmap();
+
+ /* brightness of the lightgray color in the frame drawn by Light Phaser games */
+ const UINT8 sensor_min_brightness = 0x7f;
+
+ /* TODO: Check how Light Phaser behaves for border areas. For Gangster Town, should */
+ /* a shot at right border (HC~=0x90) really appear at active scr, near to left border? */
+ if (beam_x < SEGA315_5124_LBORDER_START + SEGA315_5124_LBORDER_WIDTH || beam_x >= SEGA315_5124_LBORDER_START + SEGA315_5124_LBORDER_WIDTH + 256)
+ return 0;
+
+ rgb_t color = bitmap.pix32(beam_y, beam_x);
+
+ /* reference: http://www.w3.org/TR/AERT#color-contrast */
+ UINT8 brightness = (RGB_RED(color) * 0.299) + (RGB_GREEN(color) * 0.587) + (RGB_BLUE(color) * 0.114);
+ //printf ("color brightness: %2X for x %d y %d\n", brightness, beam_x, beam_y);
+
+ result = (brightness >= sensor_min_brightness) ? 1 : 0;
+
+ /* next check at same line */
+ beam_x += LGUN_X_INTERVAL;
+ pos_changed = 1;
+ }
+ else
+ break;
+ }
+ timer->adjust(machine.first_screen()->time_until_pos(beam_y, beam_x));
+
+ return result;
+}
+
+static UINT8 sms_vdp_hcount( running_machine &machine )
+{
+ UINT8 tmp;
+ screen_device *screen = machine.first_screen();
+ int hpos = screen->hpos();
+
+ /* alternative method: pass HCounter test, but some others fail */
+ //int hpos_tmp = hpos;
+ //if ((hpos + 2) % 6 == 0) hpos_tmp--;
+ //tmp = ((hpos_tmp - 46) >> 1) & 0xff;
+
+ UINT64 calc_cycles;
+ attotime time_end;
+ int vpos = screen->vpos();
+ int max_hpos = screen->width() - 1;
+
+ if (hpos == max_hpos)
+ time_end = attotime::zero;
+ else
+ time_end = screen->time_until_pos(vpos, max_hpos);
+ calc_cycles = machine.device<cpu_device>("maincpu")->attotime_to_clocks(time_end);
+
+ /* equation got from SMSPower forum, posted by Flubba. */
+ tmp = ((590 - (calc_cycles * 3)) / 4) & 0xff;
+
+ //printf ("sms_vdp_hcount: hpos %3d => hcount %2X\n", hpos, tmp);
+ return tmp;
+}
+
+
+static void sms_vdp_hcount_latch( address_space *space )
+{
+ sms_state *state = space->machine().driver_data<sms_state>();
+ UINT8 value = sms_vdp_hcount(space->machine());
+
+ state->m_vdp->hcount_latch_write(*space, 0, value);
+}
+
+
+static UINT16 screen_hpos_nonscaled( screen_device &screen, int scaled_hpos )
+{
+ const rectangle &visarea = screen.visible_area();
+ int offset_x = (scaled_hpos * visarea.width()) / 255;
+ return visarea.min_x + offset_x;
+}
+
+
+static UINT16 screen_vpos_nonscaled( screen_device &screen, int scaled_vpos )
+{
+ const rectangle &visarea = screen.visible_area();
+ int offset_y = (scaled_vpos * (visarea.max_y - visarea.min_y)) / 255;
+ return visarea.min_y + offset_y;
+}
+
+
+static void lphaser1_sensor_check( running_machine &machine )
+{
+ sms_state *state = machine.driver_data<sms_state>();
+ const int x = screen_hpos_nonscaled(*machine.first_screen(), machine.root_device().ioport("LPHASER0")->read());
+ const int y = screen_vpos_nonscaled(*machine.first_screen(), machine.root_device().ioport("LPHASER1")->read());
+
+ if (lgun_bright_aim_area(machine, state->m_lphaser_1_timer, x, y))
+ {
+ if (state->m_lphaser_1_latch == 0)
+ {
+ state->m_lphaser_1_latch = 1;
+ sms_vdp_hcount_lphaser(machine, x);
+ }
+ }
+}
+
+static void lphaser2_sensor_check( running_machine &machine )
+{
+ sms_state *state = machine.driver_data<sms_state>();
+ const int x = screen_hpos_nonscaled(*machine.first_screen(), machine.root_device().ioport("LPHASER2")->read());
+ const int y = screen_vpos_nonscaled(*machine.first_screen(), machine.root_device().ioport("LPHASER3")->read());
+
+ if (lgun_bright_aim_area(machine, state->m_lphaser_2_timer, x, y))
+ {
+ if (state->m_lphaser_2_latch == 0)
+ {
+ state->m_lphaser_2_latch = 1;
+ sms_vdp_hcount_lphaser(machine, x);
+ }
+ }
+}
+
+
+// at each input port read we check if lightguns are enabled in one of the ports:
+// if so, we turn on crosshair and the lightgun timer
+static TIMER_CALLBACK( lightgun_tick )
+{
+ sms_state *state = machine.driver_data<sms_state>();
+
+ if ((state->ioport("CTRLSEL")->read_safe(0x00) & 0x0f) == 0x01)
+ {
+ /* enable crosshair */
+ crosshair_set_screen(machine, 0, CROSSHAIR_SCREEN_ALL);
+ if (!state->m_lphaser_1_timer->enabled())
+ lphaser1_sensor_check(machine);
+ }
+ else
+ {
+ /* disable crosshair */
+ crosshair_set_screen(machine, 0, CROSSHAIR_SCREEN_NONE);
+ state->m_lphaser_1_timer->enable(0);
+ }
+
+ if ((state->ioport("CTRLSEL")->read_safe(0x00) & 0xf0) == 0x10)
+ {
+ /* enable crosshair */
+ crosshair_set_screen(machine, 1, CROSSHAIR_SCREEN_ALL);
+ if (!state->m_lphaser_2_timer->enabled())
+ lphaser2_sensor_check(machine);
+ }
+ else
+ {
+ /* disable crosshair */
+ crosshair_set_screen(machine, 1, CROSSHAIR_SCREEN_NONE);
+ state->m_lphaser_2_timer->enable(0);
+ }
+}
+
+
+static TIMER_CALLBACK( lphaser_1_callback )
+{
+ lphaser1_sensor_check(machine);
+}
+
+
+static TIMER_CALLBACK( lphaser_2_callback )
+{
+ lphaser2_sensor_check(machine);
+}
+
+
+INPUT_CHANGED( lgun1_changed )
+{
+ sms_state *state = field.machine().driver_data<sms_state>();
+ if (!state->m_lphaser_1_timer ||
+ (field.machine().root_device().ioport("CTRLSEL")->read_safe(0x00) & 0x0f) != 0x01)
+ return;
+
+ if (newval != oldval)
+ lphaser1_sensor_check(field.machine());
+}
+
+INPUT_CHANGED( lgun2_changed )
+{
+ sms_state *state = field.machine().driver_data<sms_state>();
+ if (!state->m_lphaser_2_timer ||
+ (field.machine().root_device().ioport("CTRLSEL")->read_safe(0x00) & 0xf0) != 0x10)
+ return;
+
+ if (newval != oldval)
+ lphaser2_sensor_check(field.machine());
+}
+
+
+static void sms_get_inputs( address_space *space )
+{
+ sms_state *state = space->machine().driver_data<sms_state>();
+ UINT8 data = 0x00;
+ UINT32 cpu_cycles = downcast<cpu_device *>(&space->device())->total_cycles();
+ running_machine &machine = space->machine();
+
+ state->m_input_port0 = 0xff;
+ state->m_input_port1 = 0xff;
+
+ if (cpu_cycles - state->m_last_paddle_read_time > 256)
+ {
+ state->m_paddle_read_state ^= 0xff;
+ state->m_last_paddle_read_time = cpu_cycles;
+ }
+
+ /* Check if lightgun has been chosen as input: if so, enable crosshair */
+ machine.scheduler().timer_set(attotime::zero, FUNC(lightgun_tick));
+
+ /* Player 1 */
+ switch (machine.root_device().ioport("CTRLSEL")->read_safe(0x00) & 0x0f)
+ {
+ case 0x00: /* Joystick */
+ data = machine.root_device().ioport("PORT_DC")->read();
+ /* Check Rapid Fire setting for Button A */
+ if (!(data & 0x10) && (machine.root_device().ioport("RFU")->read() & 0x01))
+ data |= state->m_rapid_fire_state_1 & 0x10;
+
+ /* Check Rapid Fire setting for Button B */
+ if (!(data & 0x20) && (machine.root_device().ioport("RFU")->read() & 0x02))
+ data |= state->m_rapid_fire_state_1 & 0x20;
+
+ state->m_input_port0 = (state->m_input_port0 & 0xc0) | (data & 0x3f);
+ break;
+
+ case 0x01: /* Light Phaser */
+ data = (machine.root_device().ioport("CTRLIPT")->read() & 0x01) << 4;
+ if (!(data & 0x10))
+ {
+ if (machine.root_device().ioport("RFU")->read() & 0x01)
+ data |= state->m_rapid_fire_state_1 & 0x10;
+ }
+ /* just consider the button (trigger) bit */
+ data |= ~0x10;
+ state->m_input_port0 = (state->m_input_port0 & 0xc0) | (data & 0x3f);
+ break;
+
+ case 0x02: /* Paddle Control */
+ /* Get button A state */
+ data = machine.root_device().ioport("PADDLE0")->read();
+
+ if (state->m_paddle_read_state)
+ data = data >> 4;
+
+ state->m_input_port0 = (state->m_input_port0 & 0xc0) | (data & 0x0f) | (state->m_paddle_read_state & 0x20)
+ | ((machine.root_device().ioport("CTRLIPT")->read() & 0x02) << 3);
+ break;
+
+ case 0x04: /* Sega Sports Pad */
+ switch (state->m_sports_pad_state_1)
+ {
+ case 0:
+ data = (state->m_sports_pad_1_x >> 4) & 0x0f;
+ break;
+ case 1:
+ data = state->m_sports_pad_1_x & 0x0f;
+ break;
+ case 2:
+ data = (state->m_sports_pad_1_y >> 4) & 0x0f;
+ break;
+ case 3:
+ data = state->m_sports_pad_1_y & 0x0f;
+ break;
+ }
+ state->m_input_port0 = (state->m_input_port0 & 0xc0) | data | ((machine.root_device().ioport("CTRLIPT")->read() & 0x0c) << 2);
+ break;
+ }
+
+ /* Player 2 */
+ switch (machine.root_device().ioport("CTRLSEL")->read_safe(0x00) & 0xf0)
+ {
+ case 0x00: /* Joystick */
+ data = machine.root_device().ioport("PORT_DC")->read();
+ state->m_input_port0 = (state->m_input_port0 & 0x3f) | (data & 0xc0);
+
+ data = machine.root_device().ioport("PORT_DD")->read();
+ /* Check Rapid Fire setting for Button A */
+ if (!(data & 0x04) && (machine.root_device().ioport("RFU")->read() & 0x04))
+ data |= state->m_rapid_fire_state_2 & 0x04;
+
+ /* Check Rapid Fire setting for Button B */
+ if (!(data & 0x08) && (machine.root_device().ioport("RFU")->read() & 0x08))
+ data |= state->m_rapid_fire_state_2 & 0x08;
+
+ state->m_input_port1 = (state->m_input_port1 & 0xf0) | (data & 0x0f);
+ break;
+
+ case 0x10: /* Light Phaser */
+ data = (machine.root_device().ioport("CTRLIPT")->read() & 0x10) >> 2;
+ if (!(data & 0x04))
+ {
+ if (machine.root_device().ioport("RFU")->read() & 0x04)
+ data |= state->m_rapid_fire_state_2 & 0x04;
+ }
+ /* just consider the button (trigger) bit */
+ data |= ~0x04;
+ state->m_input_port1 = (state->m_input_port1 & 0xf0) | (data & 0x0f);
+ break;
+
+ case 0x20: /* Paddle Control */
+ /* Get button A state */
+ data = machine.root_device().ioport("PADDLE1")->read();
+ if (state->m_paddle_read_state)
+ data = data >> 4;
+
+ state->m_input_port0 = (state->m_input_port0 & 0x3f) | ((data & 0x03) << 6);
+ state->m_input_port1 = (state->m_input_port1 & 0xf0) | ((data & 0x0c) >> 2) | (state->m_paddle_read_state & 0x08)
+ | ((machine.root_device().ioport("CTRLIPT")->read() & 0x20) >> 3);
+ break;
+
+ case 0x40: /* Sega Sports Pad */
+ switch (state->m_sports_pad_state_2)
+ {
+ case 0:
+ data = state->m_sports_pad_2_x & 0x0f;
+ break;
+ case 1:
+ data = (state->m_sports_pad_2_x >> 4) & 0x0f;
+ break;
+ case 2:
+ data = state->m_sports_pad_2_y & 0x0f;
+ break;
+ case 3:
+ data = (state->m_sports_pad_2_y >> 4) & 0x0f;
+ break;
+ }
+ state->m_input_port0 = (state->m_input_port0 & 0x3f) | ((data & 0x03) << 6);
+ state->m_input_port1 = (state->m_input_port1 & 0xf0) | (data >> 2) | ((machine.root_device().ioport("CTRLIPT")->read() & 0xc0) >> 4);
+ break;
+ }
+}
+
+
+WRITE8_MEMBER(sms_state::sms_fm_detect_w)
+{
+
+ if (m_has_fm)
+ m_fm_detect = (data & 0x01);
+}
+
+
+READ8_MEMBER(sms_state::sms_fm_detect_r)
+{
+
+ if (m_has_fm)
+ {
+ return m_fm_detect;
+ }
+ else
+ {
+ if (m_bios_port & IO_CHIP)
+ {
+ return 0xff;
+ }
+ else
+ {
+ sms_get_inputs(&space);
+ return m_input_port0;
+ }
+ }
+}
+
+WRITE8_MEMBER(sms_state::sms_io_control_w)
+{
+ bool hcount_latch = false;
+
+ if (data & 0x08)
+ {
+ /* check if TH pin level is high (1) and was low last time */
+ if (data & 0x80 && !(m_ctrl_reg & 0x80))
+ {
+ hcount_latch = true;
+ }
+ sms_input_write(space, 0, (data & 0x20) >> 5);
+ }
+
+ if (data & 0x02)
+ {
+ if (data & 0x20 && !(m_ctrl_reg & 0x20))
+ {
+ hcount_latch = true;
+ }
+ sms_input_write(space, 1, (data & 0x80) >> 7);
+ }
+
+ if (hcount_latch)
+ {
+ sms_vdp_hcount_latch(&space);
+ }
+
+ m_ctrl_reg = data;
+}
+
+
+READ8_MEMBER(sms_state::sms_count_r)
+{
+
+ if (offset & 0x01)
+ return m_vdp->hcount_latch_read(*m_space, offset);
+ else
+ return m_vdp->vcount_read(*m_space, offset);
+}
+
+
+/*
+ Check if the pause button is pressed.
+ If the gamegear is in sms mode, check if the start button is pressed.
+ */
+WRITE_LINE_DEVICE_HANDLER( sms_pause_callback )
+{
+ sms_state *driver_state = device->machine().driver_data<sms_state>();
+
+ if (driver_state->m_is_gamegear && !(driver_state->m_cartridge[driver_state->m_current_cartridge].features & CF_GG_SMS_MODE))
+ return;
+
+ if (!(driver_state->ioport(driver_state->m_is_gamegear ? "START" : "PAUSE")->read() & 0x80))
+ {
+ if (!driver_state->m_paused)
+ {
+ cputag_set_input_line(device->machine(), "maincpu", INPUT_LINE_NMI, PULSE_LINE);
+ }
+ driver_state->m_paused = 1;
+ }
+ else
+ {
+ driver_state->m_paused = 0;
+ }
+
+ /* clear Light Phaser latch flags for next frame */
+ driver_state->m_lphaser_1_latch = 0;
+ driver_state->m_lphaser_2_latch = 0;
+}
+
+READ8_MEMBER(sms_state::sms_input_port_0_r)
+{
+
+ if (m_bios_port & IO_CHIP)
+ {
+ return 0xff;
+ }
+ else
+ {
+ sms_get_inputs(&space);
+ return m_input_port0;
+ }
+}
+
+
+READ8_MEMBER(sms_state::sms_input_port_1_r)
+{
+
+ if (m_bios_port & IO_CHIP)
+ return 0xff;
+
+ sms_get_inputs(&space);
+
+ /* Reset Button */
+ m_input_port1 = (m_input_port1 & 0xef) | (ioport("RESET")->read_safe(0x01) & 0x01) << 4;
+
+ /* Do region detection if TH of ports A and B are set to output (0) */
+ if (!(m_ctrl_reg & 0x0a))
+ {
+ /* Move bits 7,5 of IO control port into bits 7, 6 */
+ m_input_port1 = (m_input_port1 & 0x3f) | (m_ctrl_reg & 0x80) | (m_ctrl_reg & 0x20) << 1;
+
+ /* Inverse region detect value for Japanese machines */
+ if (m_is_region_japan)
+ m_input_port1 ^= 0xc0;
+ }
+ else
+ {
+ if (m_ctrl_reg & 0x02 && m_lphaser_1_latch)
+ {
+ m_input_port1 &= ~0x40;
+ m_lphaser_1_latch = 0;
+ }
+
+ if (m_ctrl_reg & 0x08 && m_lphaser_2_latch)
+ {
+ m_input_port1 &= ~0x80;
+ m_lphaser_2_latch = 0;
+ }
+ }
+
+ return m_input_port1;
+}
+
+
+
+WRITE8_MEMBER(sms_state::sms_ym2413_register_port_0_w)
+{
+
+ if (m_has_fm)
+ ym2413_w(m_ym, 0, (data & 0x3f));
+}
+
+
+WRITE8_MEMBER(sms_state::sms_ym2413_data_port_0_w)
+{
+
+ if (m_has_fm)
+ {
+ logerror("data_port_0_w %x %x\n", offset, data);
+ ym2413_w(m_ym, 1, data);
+ }
+}
+
+
+READ8_MEMBER(sms_state::gg_input_port_2_r)
+{
+
+ //logerror("joy 2 read, val: %02x, pc: %04x\n", ((m_is_region_japan ? 0x00 : 0x40) | (machine.root_device().ioport("START")->read() & 0x80)), activecpu_get_pc());
+ return ((m_is_region_japan ? 0x00 : 0x40) | (ioport("START")->read() & 0x80));
+}
+
+
+READ8_MEMBER(sms_state::sms_sscope_r)
+{
+ return m_sscope_state;
+}
+
+
+WRITE8_MEMBER(sms_state::sms_sscope_w)
+{
+ m_sscope_state = data;
+}
+
+
+READ8_MEMBER(sms_state::sms_mapper_r)
+{
+ return m_mapper[offset];
+}
+
+/* Terebi Oekaki */
+/* The following code comes from sg1000.c. We should eventually merge these TV Draw implementations */
+WRITE8_MEMBER(sms_state::sms_tvdraw_axis_w)
+{
+ UINT8 tvboard_on = ioport("TVDRAW")->read_safe(0x00);
+
+ if (data & 0x01)
+ {
+ m_cartridge[m_current_cartridge].m_tvdraw_data = tvboard_on ? ioport("TVDRAW_X")->read() : 0x80;
+
+ if (m_cartridge[m_current_cartridge].m_tvdraw_data < 4) m_cartridge[m_current_cartridge].m_tvdraw_data = 4;
+ if (m_cartridge[m_current_cartridge].m_tvdraw_data > 251) m_cartridge[m_current_cartridge].m_tvdraw_data = 251;
+ }
+ else
+ {
+ m_cartridge[m_current_cartridge].m_tvdraw_data = tvboard_on ? ioport("TVDRAW_Y")->read() + 0x20 : 0x80;
+ }
+}
+
+READ8_MEMBER(sms_state::sms_tvdraw_status_r)
+{
+ UINT8 tvboard_on = ioport("TVDRAW")->read_safe(0x00);
+ return tvboard_on ? ioport("TVDRAW_PEN")->read() : 0x01;
+}
+
+READ8_MEMBER(sms_state::sms_tvdraw_data_r)
+{
+ return m_cartridge[m_current_cartridge].m_tvdraw_data;
+}
+
+
+WRITE8_MEMBER(sms_state::sms_93c46_w)
+{
+
+ if ( m_cartridge[m_current_cartridge].m_93c46_enabled )
+ {
+ m_cartridge[m_current_cartridge].m_93c46_lines = data;
+
+ logerror( "sms_93c46_w: setting eeprom lines: DI=%s CLK=%s CS=%s\n", data & 0x01 ? "1" : "0", data & 0x02 ? "1" : "0", data & 0x04 ? "1" : "0" );
+ m_eeprom->write_bit( ( data & 0x01 ) ? ASSERT_LINE : CLEAR_LINE );
+ m_eeprom->set_cs_line( !( data & 0x04 ) ? ASSERT_LINE : CLEAR_LINE );
+ m_eeprom->set_clock_line( ( data & 0x02 ) ? ASSERT_LINE : CLEAR_LINE );
+ }
+}
+
+
+READ8_MEMBER(sms_state::sms_93c46_r)
+{
+ UINT8 data = m_banking_cart[5][0];
+
+ if ( m_cartridge[m_current_cartridge].m_93c46_enabled )
+ {
+ data = ( m_cartridge[m_current_cartridge].m_93c46_lines & 0xFC ) | 0x02;
+ data |= m_eeprom->read_bit() ? 1 : 0;
+ }
+
+ return data;
+}
+
+
+WRITE8_MEMBER(sms_state::sms_mapper_w)
+{
+ bool bios_selected = false;
+ bool cartridge_selected = false;
+
+ offset &= 3;
+
+ m_mapper[offset] = data;
+ m_mapper_ram[offset] = data;
+
+ if (m_bios_port & IO_BIOS_ROM || (m_is_gamegear && m_BIOS == NULL))
+ {
+ if (!(m_bios_port & IO_CARTRIDGE) || (m_is_gamegear && m_BIOS == NULL))
+ {
+ if (!m_cartridge[m_current_cartridge].ROM)
+ return;
+ cartridge_selected = true;
+ }
+ else
+ {
+ /* nothing to page in */
+ return;
+ }
+ }
+ else
+ {
+ if (!m_BIOS)
+ return;
+ bios_selected = true;
+ }
+
+ switch (offset)
+ {
+ case 0: /* Control */
+ /* Is it ram or rom? */
+ if (data & 0x08) /* it's ram */
+ {
+ if ( m_cartridge[m_current_cartridge].features & CF_93C46_EEPROM )
+ {
+ if ( data & 0x80 )
+ {
+ m_eeprom->reset();
+ logerror("sms_mapper_w: eeprom CS=1\n");
+ m_eeprom->set_cs_line( ASSERT_LINE );
+ }
+ logerror("sms_mapper_w: eeprom enabled\n");
+ m_cartridge[m_current_cartridge].m_93c46_enabled = true;
+ }
+ else
+ {
+ UINT8 *sram = NULL;
+ m_cartridge[m_current_cartridge].sram_save = 1; /* SRAM should be saved on exit. */
+ if (data & 0x04)
+ {
+ sram = m_cartridge[m_current_cartridge].cartSRAM + 0x4000;
+ }
+ else
+ {
+ sram = m_cartridge[m_current_cartridge].cartSRAM;
+ }
+ membank("bank5")->set_base(sram);
+ membank("bank6")->set_base(sram + 0x2000);
+ }
+ }
+ else /* it's rom */
+ {
+ if (m_bios_port & IO_BIOS_ROM || ! m_has_bios)
+ {
+ if ( ! ( m_cartridge[m_current_cartridge].features & ( CF_KOREAN_NOBANK_MAPPER | CF_KOREAN_ZEMINA_MAPPER ) ) )
+ {
+ if ( m_cartridge[m_current_cartridge].features & CF_93C46_EEPROM )
+ {
+ if ( data & 0x80 )
+ {
+ m_eeprom->reset();
+ logerror("sms_mapper_w: eeprom CS=1\n");
+ m_eeprom->set_cs_line( ASSERT_LINE );
+ }
+ logerror("sms_mapper_w: eeprom disabled\n");
+ m_cartridge[m_current_cartridge].m_93c46_enabled = false;
+ }
+ else
+ {
+ map_cart_16k( 0x8000, m_mapper[3] );
+ }
+ }
+ }
+ else
+ {
+ map_bios_16k( 0x8000, m_mapper[3] );
+ }
+ }
+ break;
+
+ case 1: /* Select 16k ROM bank for 0400-3FFF */
+ if ( cartridge_selected || m_is_gamegear )
+ {
+ if ( ! ( m_cartridge[m_current_cartridge].features & ( CF_KOREAN_NOBANK_MAPPER | CF_KOREAN_ZEMINA_MAPPER ) ) )
+ {
+ map_cart_16k( 0x400, data );
+ }
+ }
+ if ( bios_selected )
+ {
+ map_bios_16k( 0x400, data );
+ }
+ break;
+
+ case 2: /* Select 16k ROM bank for 4000-7FFF */
+ if ( cartridge_selected || m_is_gamegear )
+ {
+ if ( ! ( m_cartridge[m_current_cartridge].features & ( CF_KOREAN_NOBANK_MAPPER | CF_KOREAN_ZEMINA_MAPPER ) ) )
+ {
+ map_cart_16k( 0x4000, data );
+ }
+ }
+ if ( bios_selected )
+ {
+ map_bios_16k( 0x4000, data );
+ }
+ break;
+
+ case 3: /* Select 16k ROM bank for 8000-BFFF */
+ if ( cartridge_selected || m_is_gamegear )
+ {
+ if ( m_cartridge[m_current_cartridge].features & CF_CODEMASTERS_MAPPER)
+ {
+ return;
+ }
+
+ if ( ! ( m_mapper[0] & 0x08 ) ) // Is RAM disabled
+ {
+ if ( ! ( m_cartridge[m_current_cartridge].features & ( CF_KOREAN_NOBANK_MAPPER | CF_KOREAN_ZEMINA_MAPPER ) ) )
+ {
+ map_cart_16k( 0x8000, data );
+ }
+ }
+ }
+
+ if ( bios_selected )
+ {
+ if ( ! ( m_mapper[0] & 0x08 ) ) // Is RAM disabled
+ {
+ map_bios_16k( 0x8000, data );
+ }
+ }
+ break;
+ }
+}
+
+WRITE8_MEMBER(sms_state::sms_korean_zemina_banksw_w)
+{
+
+ if (m_cartridge[m_current_cartridge].features & CF_KOREAN_ZEMINA_MAPPER)
+ {
+ if (!m_cartridge[m_current_cartridge].ROM)
+ return;
+
+ switch (offset & 3)
+ {
+ case 0:
+ map_cart_8k( 0x8000, data );
+ break;
+ case 1:
+ map_cart_8k( 0xA000, data );
+ break;
+ case 2:
+ map_cart_8k( 0x4000, data );
+ break;
+ case 3:
+ map_cart_8k( 0x6000, data );
+ break;
+ }
+ LOG(("Zemina mapper write: offset %x data %x.\n", offset, data));
+ }
+}
+
+WRITE8_MEMBER(sms_state::sms_codemasters_page0_w)
+{
+
+ if (m_cartridge[m_current_cartridge].ROM && m_cartridge[m_current_cartridge].features & CF_CODEMASTERS_MAPPER)
+ {
+ map_cart_16k( 0x0000, data );
+ }
+}
+
+
+WRITE8_MEMBER(sms_state::sms_codemasters_page1_w)
+{
+
+ if (m_cartridge[m_current_cartridge].ROM && m_cartridge[m_current_cartridge].features & CF_CODEMASTERS_MAPPER)
+ {
+ /* Check if we need to switch in some RAM */
+ if (data & 0x80)
+ {
+ m_cartridge[m_current_cartridge].ram_page = data & 0x07;
+ membank("bank6")->set_base(m_cartridge[m_current_cartridge].cartRAM + m_cartridge[m_current_cartridge].ram_page * 0x2000);
+ }
+ else
+ {
+ map_cart_16k( 0x4000, data );
+ membank("bank6")->set_base(m_banking_cart[5] + 0x2000);
+ }
+ }
+}
+
+
+WRITE8_MEMBER(sms_state::sms_4pak_page0_w)
+{
+
+ m_cartridge[m_current_cartridge].m_4pak_page0 = data;
+
+ map_cart_16k( 0x0000, data );
+ map_cart_16k( 0x8000, ( m_cartridge[m_current_cartridge].m_4pak_page0 & 0x30 ) + m_cartridge[m_current_cartridge].m_4pak_page2 );
+}
+
+
+WRITE8_MEMBER(sms_state::sms_4pak_page1_w)
+{
+
+ m_cartridge[m_current_cartridge].m_4pak_page1 = data;
+
+ map_cart_16k( 0x4000, data );
+}
+
+
+WRITE8_MEMBER(sms_state::sms_4pak_page2_w)
+{
+
+ m_cartridge[m_current_cartridge].m_4pak_page2 = data;
+
+ map_cart_16k( 0x8000, ( m_cartridge[m_current_cartridge].m_4pak_page0 & 0x30 ) + m_cartridge[m_current_cartridge].m_4pak_page2 );
+}
+
+
+WRITE8_MEMBER(sms_state::sms_janggun_bank0_w)
+{
+
+ map_cart_8k( 0x4000, data );
+}
+
+
+WRITE8_MEMBER(sms_state::sms_janggun_bank1_w)
+{
+
+ map_cart_8k( 0x6000, data );
+}
+
+
+WRITE8_MEMBER(sms_state::sms_janggun_bank2_w)
+{
+
+ map_cart_8k( 0x8000, data );
+}
+
+
+WRITE8_MEMBER(sms_state::sms_janggun_bank3_w)
+{
+
+ map_cart_8k( 0xA000, data );
+}
+
+
+WRITE8_MEMBER(sms_state::sms_bios_w)
+{
+ m_bios_port = data;
+
+ logerror("bios write %02x, pc: %04x\n", data, cpu_get_pc(&space.device()));
+
+ setup_rom(&space);
+}
+
+
+WRITE8_MEMBER(sms_state::sms_cartram2_w)
+{
+
+ if (m_mapper[0] & 0x08)
+ {
+ logerror("write %02X to cartram at offset #%04X\n", data, offset + 0x2000);
+ if (m_mapper[0] & 0x04)
+ {
+ m_cartridge[m_current_cartridge].cartSRAM[offset + 0x6000] = data;
+ }
+ else
+ {
+ m_cartridge[m_current_cartridge].cartSRAM[offset + 0x2000] = data;
+ }
+ }
+
+ if (m_cartridge[m_current_cartridge].features & CF_CODEMASTERS_MAPPER)
+ {
+ m_cartridge[m_current_cartridge].cartRAM[m_cartridge[m_current_cartridge].ram_page * 0x2000 + offset] = data;
+ }
+
+ if (m_cartridge[m_current_cartridge].features & CF_KOREAN_MAPPER && offset == 0) /* Dodgeball King mapper */
+ {
+ map_cart_16k( 0x8000, data );
+ }
+}
+
+
+WRITE8_MEMBER(sms_state::sms_cartram_w)
+{
+ int page;
+
+ if (m_mapper[0] & 0x08)
+ {
+ logerror("write %02X to cartram at offset #%04X\n", data, offset);
+ if (m_mapper[0] & 0x04)
+ {
+ m_cartridge[m_current_cartridge].cartSRAM[offset + 0x4000] = data;
+ }
+ else
+ {
+ m_cartridge[m_current_cartridge].cartSRAM[offset] = data;
+ }
+ }
+ else
+ {
+ if (m_cartridge[m_current_cartridge].features & CF_CODEMASTERS_MAPPER && offset == 0) /* Codemasters mapper */
+ {
+ UINT8 rom_page_count = m_cartridge[m_current_cartridge].size / 0x4000;
+ page = (rom_page_count > 0) ? data % rom_page_count : 0;
+ if (!m_cartridge[m_current_cartridge].ROM)
+ return;
+ m_banking_cart[5] = m_cartridge[m_current_cartridge].ROM + page * 0x4000;
+ membank("bank5")->set_base(m_banking_cart[5]);
+ membank("bank6")->set_base(m_banking_cart[5] + 0x2000);
+ LOG(("rom 2 paged in %x (Codemasters mapper).\n", page));
+ }
+ else if (m_cartridge[m_current_cartridge].features & CF_ONCART_RAM)
+ {
+ m_cartridge[m_current_cartridge].cartRAM[offset & (m_cartridge[m_current_cartridge].ram_size - 1)] = data;
+ }
+ else
+ {
+ logerror("INVALID write %02X to cartram at offset #%04X\n", data, offset);
+ }
+ }
+}
+
+
+WRITE8_MEMBER(sms_state::gg_sio_w)
+{
+ logerror("*** write %02X to SIO register #%d\n", data, offset);
+
+ m_gg_sio[offset & 0x07] = data;
+ switch (offset & 7)
+ {
+ case 0x00: /* Parallel Data */
+ break;
+
+ case 0x01: /* Data Direction/ NMI Enable */
+ break;
+
+ case 0x02: /* Serial Output */
+ break;
+
+ case 0x03: /* Serial Input */
+ break;
+
+ case 0x04: /* Serial Control / Status */
+ break;
+ }
+}
+
+
+READ8_MEMBER(sms_state::gg_sio_r)
+{
+ logerror("*** read SIO register #%d\n", offset);
+
+ switch (offset & 7)
+ {
+ case 0x00: /* Parallel Data */
+ break;
+
+ case 0x01: /* Data Direction/ NMI Enable */
+ break;
+
+ case 0x02: /* Serial Output */
+ break;
+
+ case 0x03: /* Serial Input */
+ break;
+
+ case 0x04: /* Serial Control / Status */
+ break;
+ }
+
+ return m_gg_sio[offset];
+}
+
+static void sms_machine_stop( running_machine &machine )
+{
+ sms_state *state = machine.driver_data<sms_state>();
+
+ /* Does the cartridge have SRAM that should be saved? */
+ if (state->m_cartridge[state->m_current_cartridge].sram_save) {
+ device_image_interface *image = dynamic_cast<device_image_interface *>(machine.device("cart1"));
+ image->battery_save(state->m_cartridge[state->m_current_cartridge].cartSRAM, sizeof(UINT8) * NVRAM_SIZE );
+ }
+}
+
+
+static void setup_rom( address_space *space )
+{
+ sms_state *state = space->machine().driver_data<sms_state>();
+
+ /* 1. set up bank pointers to point to nothing */
+ state->membank("bank1")->set_base(state->m_banking_none);
+ state->membank("bank2")->set_base(state->m_banking_none);
+ state->membank("bank7")->set_base(state->m_banking_none);
+ state->membank("bank3")->set_base(state->m_banking_none);
+ state->membank("bank4")->set_base(state->m_banking_none);
+ state->membank("bank5")->set_base(state->m_banking_none);
+ state->membank("bank6")->set_base(state->m_banking_none);
+
+ /* 2. check and set up expansion port */
+ if (!(state->m_bios_port & IO_EXPANSION) && (state->m_bios_port & IO_CARTRIDGE) && (state->m_bios_port & IO_CARD))
+ {
+ /* TODO: Implement me */
+ logerror("Switching to unsupported expansion port.\n");
+ }
+
+ /* 3. check and set up card rom */
+ if (!(state->m_bios_port & IO_CARD) && (state->m_bios_port & IO_CARTRIDGE) && (state->m_bios_port & IO_EXPANSION))
+ {
+ /* TODO: Implement me */
+ logerror("Switching to unsupported card rom port.\n");
+ }
+
+ /* 4. check and set up cartridge rom */
+ /* if ((!(bios_port & IO_CARTRIDGE) && (bios_port & IO_EXPANSION) && (bios_port & IO_CARD)) || state->m_is_gamegear) { */
+ /* Out Run Europa initially writes a value to port 3E where IO_CARTRIDGE, IO_EXPANSION and IO_CARD are reset */
+ if ((!(state->m_bios_port & IO_CARTRIDGE)) || state->m_is_gamegear)
+ {
+ state->membank("bank1")->set_base(state->m_banking_cart[1]);
+ state->membank("bank2")->set_base(state->m_banking_cart[2]);
+ state->membank("bank7")->set_base(state->m_banking_cart[7]);
+ state->membank("bank3")->set_base(state->m_banking_cart[3]);
+ state->membank("bank4")->set_base(state->m_banking_cart[3] + 0x2000);
+ state->membank("bank5")->set_base(state->m_banking_cart[5]);
+ state->membank("bank6")->set_base(state->m_banking_cart[5] + 0x2000);
+ logerror("Switched in cartridge rom.\n");
+ }
+
+ /* 5. check and set up bios rom */
+ if (!(state->m_bios_port & IO_BIOS_ROM))
+ {
+ /* 0x0400 bioses */
+ if (state->m_has_bios_0400)
+ {
+ state->membank("bank1")->set_base(state->m_banking_bios[1]);
+ logerror("Switched in 0x0400 bios.\n");
+ }
+ /* 0x2000 bioses */
+ if (state->m_has_bios_2000)
+ {
+ state->membank("bank1")->set_base(state->m_banking_bios[1]);
+ state->membank("bank2")->set_base(state->m_banking_bios[2]);
+ logerror("Switched in 0x2000 bios.\n");
+ }
+ if (state->m_has_bios_full)
+ {
+ state->membank("bank1")->set_base(state->m_banking_bios[1]);
+ state->membank("bank2")->set_base(state->m_banking_bios[2]);
+ state->membank("bank7")->set_base(state->m_banking_bios[7]);
+ state->membank("bank3")->set_base(state->m_banking_bios[3]);
+ state->membank("bank4")->set_base(state->m_banking_bios[3] + 0x2000);
+ state->membank("bank5")->set_base(state->m_banking_bios[5]);
+ state->membank("bank6")->set_base(state->m_banking_bios[5] + 0x2000);
+ logerror("Switched in full bios.\n");
+ }
+ }
+
+ if (state->m_cartridge[state->m_current_cartridge].features & CF_ONCART_RAM)
+ {
+ state->membank("bank5")->set_base(state->m_cartridge[state->m_current_cartridge].cartRAM);
+ state->membank("bank6")->set_base(state->m_cartridge[state->m_current_cartridge].cartRAM);
+ }
+}
+
+
+static int sms_verify_cart( UINT8 *magic, int size )
+{
+ int retval;
+
+ 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;
+}
+
+#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.
+ */
+static int 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;
+}
+
+
+static int 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
+
+
+static int detect_tvdraw( UINT8 *rom )
+{
+ static const UINT8 terebi_oekaki[7] = { 0x61, 0x6e, 0x6e, 0x61, 0x6b, 0x6d, 0x6e }; // "annakmn"
+
+ if (!memcmp(&rom[0x13b3], terebi_oekaki, 7))
+ return 1;
+
+ return 0;
+}
+
+
+static int detect_lphaser_xoffset( running_machine &machine, UINT8 *rom )
+{
+ sms_state *state = machine.driver_data<sms_state>();
+
+ static const UINT8 signatures[6][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 },
+ };
+
+ if (!(state->m_bios_port & IO_CARTRIDGE) && state->m_cartridge[state->m_current_cartridge].size >= 0x8000)
+ {
+ if (!memcmp(&rom[0x7ff0], signatures[0], 16) || !memcmp(&rom[0x7ff0], signatures[1], 16))
+ return 40;
+
+ if (!memcmp(&rom[0x7ff0], signatures[2], 16))
+ return 49;
+
+ if (!memcmp(&rom[0x7ff0], signatures[3], 16))
+ return 47;
+
+ if (!memcmp(&rom[0x7ff0], signatures[4], 16))
+ return 44;
+
+ if (!memcmp(&rom[0x7ff0], signatures[5], 16))
+ return 53;
+
+ }
+ return 50;
+}
+
+
+DEVICE_START( sms_cart )
+{
+ sms_state *state = device->machine().driver_data<sms_state>();
+ int i;
+
+ for (i = 0; i < MAX_CARTRIDGES; i++)
+ {
+ state->m_cartridge[i].ROM = NULL;
+ state->m_cartridge[i].size = 0;
+ state->m_cartridge[i].features = 0;
+ state->m_cartridge[i].cartSRAM = NULL;
+ state->m_cartridge[i].sram_save = 0;
+ state->m_cartridge[i].cartRAM = NULL;
+ state->m_cartridge[i].ram_size = 0;
+ state->m_cartridge[i].ram_page = 0;
+ }
+ state->m_current_cartridge = 0;
+
+ state->m_bios_port = (IO_EXPANSION | IO_CARTRIDGE | IO_CARD);
+ if (!state->m_is_gamegear && !state->m_has_bios)
+ {
+ state->m_bios_port &= ~(IO_CARTRIDGE);
+ state->m_bios_port |= IO_BIOS_ROM;
+ }
+}
+
+
+DEVICE_IMAGE_LOAD( sms_cart )
+{
+ running_machine &machine = image.device().machine();
+ sms_state *state = machine.driver_data<sms_state>();
+ int size, index = 0, offset = 0;
+
+ if (strcmp(image.device().tag(), ":cart1") == 0)
+ index = 0;
+ if (strcmp(image.device().tag(), ":cart2") == 0)
+ index = 1;
+ if (strcmp(image.device().tag(), ":cart3") == 0)
+ index = 2;
+ if (strcmp(image.device().tag(), ":cart4") == 0)
+ index = 3;
+ if (strcmp(image.device().tag(), ":cart5") == 0)
+ index = 4;
+ if (strcmp(image.device().tag(), ":cart6") == 0)
+ index = 5;
+ if (strcmp(image.device().tag(), ":cart7") == 0)
+ index = 6;
+ if (strcmp(image.device().tag(), ":cart8") == 0)
+ index = 7;
+ if (strcmp(image.device().tag(), ":cart9") == 0)
+ index = 8;
+ if (strcmp(image.device().tag(), ":cart10") == 0)
+ index = 9;
+ if (strcmp(image.device().tag(), ":cart11") == 0)
+ index = 10;
+ if (strcmp(image.device().tag(), ":cart12") == 0)
+ index = 11;
+ if (strcmp(image.device().tag(), ":cart13") == 0)
+ index = 12;
+ if (strcmp(image.device().tag(), ":cart14") == 0)
+ index = 13;
+ if (strcmp(image.device().tag(), ":cart15") == 0)
+ index = 14;
+ if (strcmp(image.device().tag(), ":cart16") == 0)
+ index = 15;
+
+ state->m_cartridge[index].features = 0;
+
+ if (image.software_entry() == NULL)
+ {
+ size = image.length();
+ }
+ else
+ size = image.get_software_region_length("rom");
+
+ /* Check for 512-byte header */
+ if ((size / 512) & 1)
+ {
+ offset = 512;
+ size -= 512;
+ }
+
+ if (!size)
+ {
+ image.seterror(IMAGE_ERROR_UNSPECIFIED, "Invalid ROM image: ROM image is too small");
+ return IMAGE_INIT_FAIL;
+ }
+
+ /* Create a new memory region to hold the ROM. */
+ /* Make sure the region holds only complete (0x4000) rom banks */
+ state->m_cartridge[index].size = (size & 0x3fff) ? (((size >> 14) + 1) << 14) : size;
+ state->m_cartridge[index].ROM = auto_alloc_array(machine, UINT8, state->m_cartridge[index].size);
+ state->m_cartridge[index].cartSRAM = auto_alloc_array(machine, UINT8, NVRAM_SIZE);
+
+ /* Load ROM banks */
+ if (image.software_entry() == NULL)
+ {
+ image.fseek(offset, SEEK_SET);
+
+ if (image.fread( state->m_cartridge[index].ROM, size) != size)
+ return IMAGE_INIT_FAIL;
+ }
+ else
+ {
+ memcpy(state->m_cartridge[index].ROM, image.get_software_region("rom") + offset, size);
+
+ const char *pcb = image.get_feature("pcb");
+ const char *mapper = image.get_feature("mapper");
+ const char *pin_42 = image.get_feature("pin_42");
+ const char *eeprom = image.get_feature("eeprom");
+
+ // Check for special mappers (or lack of mappers)
+ if ( pcb && !strcmp(pcb, "korean_nobank"))
+ {
+ state->m_cartridge[index].features |= CF_KOREAN_NOBANK_MAPPER;
+ }
+
+ if ( mapper )
+ {
+ if ( ! strcmp( mapper, "codemasters" ) )
+ {
+ state->m_cartridge[index].features |= CF_CODEMASTERS_MAPPER;
+ }
+ else if ( ! strcmp( mapper, "korean" ) )
+ {
+ state->m_cartridge[index].features |= CF_KOREAN_MAPPER;
+ }
+ else if ( ! strcmp( mapper, "zemina" ) )
+ {
+ state->m_cartridge[index].features |= CF_KOREAN_ZEMINA_MAPPER;
+ }
+ else if ( ! strcmp( mapper, "nemesis" ) )
+ {
+ state->m_cartridge[index].features |= CF_KOREAN_ZEMINA_MAPPER;
+ state->m_cartridge[index].features |= CF_KOREAN_ZEMINA_NEMESIS;
+ }
+ else if ( ! strcmp( mapper, "4pak" ) )
+ {
+ state->m_cartridge[index].features |= CF_4PAK_MAPPER;
+ }
+ else if ( ! strcmp( mapper, "janggun" ) )
+ {
+ state->m_cartridge[index].features |= CF_JANGGUN_MAPPER;
+ }
+ }
+
+ // Check for gamegear cartridges with PIN 42 set to SMS mode
+ if ( pin_42 && ! strcmp(pin_42, "sms_mode"))
+ {
+ state->m_cartridge[index].features |= CF_GG_SMS_MODE;
+ }
+
+ // Check for presence of 93c46 eeprom
+ if ( eeprom && ! strcmp( eeprom, "93c46" ) )
+ {
+ state->m_cartridge[index].features |= CF_93C46_EEPROM;
+ }
+ }
+
+ /* check the image */
+ if (!state->m_has_bios)
+ {
+ if (sms_verify_cart(state->m_cartridge[index].ROM, size) == IMAGE_VERIFY_FAIL)
+ {
+ logerror("Warning loading image: sms_verify_cart failed\n");
+ }
+ }
+
+ // If no mapper bits are set attempt to autodetect the mapper
+ if ( ! ( state->m_cartridge[index].features & CF_MAPPER_BITS ) )
+ {
+ /* If no extrainfo information is available try to find special information out on our own */
+ /* Check for special cartridge features (new routine, courtesy of Omar Cornut, from MEKA) */
+ if (size >= 0x8000)
+ {
+ int c0002 = 0, c8000 = 0, cA000 = 0, cFFFF = 0, c3FFE = 0, c4000 = 0, c6000 = 0, i;
+ for (i = 0; i < 0x8000; i++)
+ {
+ if (state->m_cartridge[index].ROM[i] == 0x32) // Z80 opcode for: LD (xxxx), A
+ {
+ UINT16 addr = (state->m_cartridge[index].ROM[i + 2] << 8) | state->m_cartridge[index].ROM[i + 1];
+ if (addr == 0xFFFF)
+ { i += 2; cFFFF++; continue; }
+ if (addr == 0x0002 || addr == 0x0003 || addr == 0x0004)
+ { i += 2; c0002++; continue; }
+ if (addr == 0x8000)
+ { i += 2; c8000++; continue; }
+ if (addr == 0xA000)
+ { i += 2; cA000++; continue; }
+ if ( addr == 0x3FFE)
+ { i += 2; c3FFE++; continue; }
+ if ( addr == 0x4000 )
+ { i += 2; c4000++; continue; }
+ if ( addr == 0x6000 )
+ { i += 2; c6000++; continue; }
+ }
+ }
+
+ LOG(("Mapper test: c002 = %d, c8000 = %d, cA000 = %d, cFFFF = %d\n", c0002, c8000, cA000, cFFFF));
+
+ // 2 is a security measure, although tests on existing ROM showed it was not needed
+ if (c0002 > cFFFF + 2 || (c0002 > 0 && cFFFF == 0))
+ {
+ UINT8 *rom = state->m_cartridge[index].ROM;
+
+ state->m_cartridge[index].features |= CF_KOREAN_ZEMINA_MAPPER;
+ // Check for special bank 0 signature
+ if ( size == 0x20000 && rom[0] == 0x00 && rom[1] == 0x00 && rom[2] == 0x00 &&
+ rom[0x1e000] == 0xF3 && rom[0x1e001] == 0xED && rom[0x1e002] == 0x56 )
+ {
+ state->m_cartridge[index].features |= CF_KOREAN_ZEMINA_NEMESIS;
+ }
+ }
+ else if (c8000 > cFFFF + 2 || (c8000 > 0 && cFFFF == 0))
+ {
+ state->m_cartridge[index].features |= CF_CODEMASTERS_MAPPER;
+ }
+ else if (cA000 > cFFFF + 2 || (cA000 > 0 && cFFFF == 0))
+ {
+ state->m_cartridge[index].features |= CF_KOREAN_MAPPER;
+ }
+ else if ( c3FFE > cFFFF + 2 || (c3FFE > 0) )
+ {
+ state->m_cartridge[index].features |= CF_4PAK_MAPPER;
+ }
+ else if ( c4000 > 0 && c6000 > 0 && c8000 > 0 && cA000 > 0 )
+ {
+ state->m_cartridge[index].features |= CF_JANGGUN_MAPPER;
+ }
+ }
+ }
+
+ if (state->m_cartridge[index].features & CF_CODEMASTERS_MAPPER)
+ {
+ state->m_cartridge[index].ram_size = 0x10000;
+ state->m_cartridge[index].cartRAM = auto_alloc_array(machine, UINT8, state->m_cartridge[index].ram_size);
+ state->m_cartridge[index].ram_page = 0;
+ }
+
+ /* For Light Phaser games, we have to detect the x offset */
+ state->m_lphaser_x_offs = detect_lphaser_xoffset(machine, state->m_cartridge[index].ROM);
+
+ /* Terebi Oekaki (TV Draw) is a SG1000 game with special input device which is compatible with SG1000 Mark III */
+ if ((detect_tvdraw(state->m_cartridge[index].ROM)) && state->m_is_region_japan)
+ {
+ state->m_cartridge[index].features |= CF_TVDRAW;
+ }
+
+ if (state->m_cartridge[index].features & CF_JANGGUN_MAPPER)
+ {
+ // Reverse bytes when bit 6 in the mapper is set
+
+ if ( state->m_cartridge[index].size <= 0x40 * 0x4000 )
+ {
+ UINT8 *new_rom = auto_alloc_array(machine, UINT8, 0x80 * 0x4000);
+ UINT32 dest = 0;
+
+ while ( dest < 0x40 * 0x4000 )
+ {
+ memcpy( new_rom + dest, state->m_cartridge[index].ROM, state->m_cartridge[index].size );
+ dest += state->m_cartridge[index].size;
+ }
+
+ for ( dest = 0; dest < 0x40 * 0x4000; dest++ )
+ {
+ new_rom[ 0x40 * 0x4000 + dest ] = BITSWAP8( new_rom[ dest ], 0, 1, 2, 3, 4, 5, 6, 7);
+ }
+
+ state->m_cartridge[index].ROM = new_rom;
+ state->m_cartridge[index].size = 0x80 * 0x4000;
+ }
+ }
+
+ LOG(("Cart Features: %x\n", state->m_cartridge[index].features));
+
+ /* Load battery backed RAM, if available */
+ image.battery_load(state->m_cartridge[index].cartSRAM, sizeof(UINT8) * NVRAM_SIZE, 0x00);
+
+ return IMAGE_INIT_PASS;
+}
+
+
+static void setup_cart_banks( running_machine &machine )
+{
+ sms_state *state = machine.driver_data<sms_state>();
+ if (state->m_cartridge[state->m_current_cartridge].ROM)
+ {
+ UINT8 rom_page_count = state->m_cartridge[state->m_current_cartridge].size / 0x4000;
+ state->m_banking_cart[1] = state->m_cartridge[state->m_current_cartridge].ROM;
+ state->m_banking_cart[2] = state->m_cartridge[state->m_current_cartridge].ROM + 0x0400;
+ state->m_banking_cart[3] = state->m_cartridge[state->m_current_cartridge].ROM + ((1 < rom_page_count) ? 0x4000 : 0);
+ state->m_banking_cart[5] = state->m_cartridge[state->m_current_cartridge].ROM + ((2 < rom_page_count) ? 0x8000 : 0);
+ state->m_banking_cart[7] = state->m_cartridge[state->m_current_cartridge].ROM + 0x2000;
+ /* Codemasters mapper points to bank 0 for page 2 */
+ if ( state->m_cartridge[state->m_current_cartridge].features & CF_CODEMASTERS_MAPPER )
+ {
+ state->m_banking_cart[5] = state->m_cartridge[state->m_current_cartridge].ROM;
+ }
+ /* Nemesis starts with last 8kb bank in page 0 */
+ if (state->m_cartridge[state->m_current_cartridge].features & CF_KOREAN_ZEMINA_NEMESIS )
+ {
+ state->m_banking_cart[1] = state->m_cartridge[state->m_current_cartridge].ROM + ( rom_page_count - 1 ) * 0x4000 + 0x2000;
+ state->m_banking_cart[2] = state->m_cartridge[state->m_current_cartridge].ROM + ( rom_page_count - 1 ) * 0x4000 + 0x2000 + 0x400;
+ }
+ }
+ else
+ {
+ state->m_banking_cart[1] = state->m_banking_none;
+ state->m_banking_cart[2] = state->m_banking_none;
+ state->m_banking_cart[3] = state->m_banking_none;
+ state->m_banking_cart[5] = state->m_banking_none;
+ }
+}
+
+static void setup_banks( running_machine &machine )
+{
+ sms_state *state = machine.driver_data<sms_state>();
+ UINT8 *mem = machine.root_device().memregion("maincpu")->base();
+ state->m_banking_none = mem;
+ state->m_banking_bios[1] = state->m_banking_cart[1] = mem;
+ state->m_banking_bios[2] = state->m_banking_cart[2] = mem;
+ state->m_banking_bios[3] = state->m_banking_cart[3] = mem;
+ state->m_banking_bios[4] = state->m_banking_cart[4] = mem;
+ state->m_banking_bios[5] = state->m_banking_cart[5] = mem;
+ state->m_banking_bios[6] = state->m_banking_cart[6] = mem;
+ state->m_banking_bios[7] = state->m_banking_cart[7] = mem;
+
+ state->m_BIOS = machine.root_device().memregion("user1")->base();
+
+ state->m_bios_page_count = (state->m_BIOS ? state->memregion("user1")->bytes() / 0x4000 : 0);
+
+ setup_cart_banks(machine);
+
+ if (state->m_BIOS == NULL || state->m_BIOS[0] == 0x00)
+ {
+ state->m_BIOS = NULL;
+ state->m_bios_port |= IO_BIOS_ROM;
+ state->m_has_bios_0400 = 0;
+ state->m_has_bios_2000 = 0;
+ state->m_has_bios_full = 0;
+ state->m_has_bios = 0;
+ }
+
+ if (state->m_BIOS)
+ {
+ state->m_banking_bios[1] = state->m_BIOS;
+ state->m_banking_bios[2] = state->m_BIOS + 0x0400;
+ state->m_banking_bios[3] = state->m_BIOS + ((1 < state->m_bios_page_count) ? 0x4000 : 0);
+ state->m_banking_bios[5] = state->m_BIOS + ((2 < state->m_bios_page_count) ? 0x8000 : 0);
+ }
+}
+
+MACHINE_START( sms )
+{
+ sms_state *state = machine.driver_data<sms_state>();
+
+ machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(sms_machine_stop),&machine));
+ state->m_rapid_fire_timer = machine.scheduler().timer_alloc(FUNC(rapid_fire_callback));
+ state->m_rapid_fire_timer->adjust(attotime::from_hz(10), 0, attotime::from_hz(10));
+
+ state->m_lphaser_1_timer = machine.scheduler().timer_alloc(FUNC(lphaser_1_callback));
+ state->m_lphaser_2_timer = machine.scheduler().timer_alloc(FUNC(lphaser_2_callback));
+
+ state->m_main_cpu = machine.device("maincpu");
+ state->m_control_cpu = machine.device("control");
+ state->m_vdp = machine.device<sega315_5124_device>("sms_vdp");
+ state->m_eeprom = machine.device<eeprom_device>("eeprom");
+ state->m_ym = machine.device("ym2413");
+ state->m_main_scr = machine.device("screen");
+ state->m_left_lcd = machine.device("left_lcd");
+ state->m_right_lcd = machine.device("right_lcd");
+ state->m_space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ /* Check if lightgun has been chosen as input: if so, enable crosshair */
+ machine.scheduler().timer_set(attotime::zero, FUNC(lightgun_tick));
+}
+
+MACHINE_RESET( sms )
+{
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ sms_state *state = machine.driver_data<sms_state>();
+
+ state->m_ctrl_reg = 0xff;
+ if (state->m_has_fm)
+ state->m_fm_detect = 0x01;
+
+ state->m_mapper_ram = (UINT8*)space->get_write_ptr(0xdffc);
+
+ state->m_bios_port = 0;
+
+ if ( state->m_cartridge[state->m_current_cartridge].features & CF_CODEMASTERS_MAPPER )
+ {
+ /* Install special memory handlers */
+ space->install_write_handler(0x0000, 0x0000, write8_delegate(FUNC(sms_state::sms_codemasters_page0_w),state));
+ space->install_write_handler(0x4000, 0x4000, write8_delegate(FUNC(sms_state::sms_codemasters_page1_w),state));
+ }
+
+ if ( state->m_cartridge[state->m_current_cartridge].features & CF_KOREAN_ZEMINA_MAPPER )
+ {
+ space->install_write_handler(0x0000, 0x0003, write8_delegate(FUNC(sms_state::sms_korean_zemina_banksw_w),state));
+ }
+
+ if ( state->m_cartridge[state->m_current_cartridge].features & CF_JANGGUN_MAPPER )
+ {
+ space->install_write_handler(0x4000, 0x4000, write8_delegate(FUNC(sms_state::sms_janggun_bank0_w),state));
+ space->install_write_handler(0x6000, 0x6000, write8_delegate(FUNC(sms_state::sms_janggun_bank1_w),state));
+ space->install_write_handler(0x8000, 0x8000, write8_delegate(FUNC(sms_state::sms_janggun_bank2_w),state));
+ space->install_write_handler(0xA000, 0xA000,write8_delegate(FUNC(sms_state::sms_janggun_bank3_w),state));
+ }
+
+ if ( state->m_cartridge[state->m_current_cartridge].features & CF_4PAK_MAPPER )
+ {
+ space->install_write_handler(0x3ffe, 0x3ffe, write8_delegate(FUNC(sms_state::sms_4pak_page0_w),state));
+ space->install_write_handler(0x7fff, 0x7fff, write8_delegate(FUNC(sms_state::sms_4pak_page1_w),state));
+ space->install_write_handler(0xbfff, 0xbfff, write8_delegate(FUNC(sms_state::sms_4pak_page2_w),state));
+ }
+
+ if ( state->m_cartridge[state->m_current_cartridge].features & CF_TVDRAW )
+ {
+ space->install_write_handler(0x6000, 0x6000, write8_delegate(FUNC(sms_state::sms_tvdraw_axis_w),state));
+ space->install_read_handler(0x8000, 0x8000, read8_delegate(FUNC(sms_state::sms_tvdraw_status_r),state));
+ space->install_read_handler(0xa000, 0xa000, read8_delegate(FUNC(sms_state::sms_tvdraw_data_r),state));
+ space->nop_write(0xa000, 0xa000);
+ state->m_cartridge[state->m_current_cartridge].m_tvdraw_data = 0;
+ }
+
+ if ( state->m_cartridge[state->m_current_cartridge].features & CF_93C46_EEPROM )
+ {
+ space->install_write_handler(0x8000,0x8000, write8_delegate(FUNC(sms_state::sms_93c46_w),state));
+ space->install_read_handler(0x8000,0x8000, read8_delegate(FUNC(sms_state::sms_93c46_r),state));
+ }
+
+ if (state->m_cartridge[state->m_current_cartridge].features & CF_GG_SMS_MODE)
+ {
+ state->m_vdp->set_sega315_5124_compatibility_mode(true);
+ }
+
+ /* Initialize SIO stuff for GG */
+ state->m_gg_sio[0] = 0x7f;
+ state->m_gg_sio[1] = 0xff;
+ state->m_gg_sio[2] = 0x00;
+ state->m_gg_sio[3] = 0xff;
+ state->m_gg_sio[4] = 0x00;
+
+ state->m_store_control = 0;
+
+ setup_banks(machine);
+
+ setup_rom(space);
+
+ state->m_rapid_fire_state_1 = 0;
+ state->m_rapid_fire_state_2 = 0;
+
+ state->m_last_paddle_read_time = 0;
+ state->m_paddle_read_state = 0;
+
+ state->m_last_sports_pad_time_1 = 0;
+ state->m_last_sports_pad_time_2 = 0;
+ state->m_sports_pad_state_1 = 0;
+ state->m_sports_pad_state_2 = 0;
+ state->m_sports_pad_last_data_1 = 0;
+ state->m_sports_pad_last_data_2 = 0;
+ state->m_sports_pad_1_x = 0;
+ state->m_sports_pad_1_y = 0;
+ state->m_sports_pad_2_x = 0;
+ state->m_sports_pad_2_y = 0;
+
+ state->m_lphaser_1_latch = 0;
+ state->m_lphaser_2_latch = 0;
+
+ state->m_sscope_state = 0;
+}
+
+READ8_MEMBER(sms_state::sms_store_cart_select_r)
+{
+ return 0xff;
+}
+
+
+WRITE8_MEMBER(sms_state::sms_store_cart_select_w)
+{
+ UINT8 slot = data >> 4;
+ UINT8 slottype = data & 0x08;
+
+ logerror("switching in part of %s slot #%d\n", slottype ? "card" : "cartridge", slot );
+ /* cartridge? slot #0 */
+ if (slottype == 0)
+ m_current_cartridge = slot;
+
+ setup_cart_banks(machine());
+ membank("bank10")->set_base(m_banking_cart[3] + 0x2000);
+ setup_rom(&space);
+}
+
+
+READ8_MEMBER(sms_state::sms_store_select1)
+{
+ return 0xff;
+}
+
+
+READ8_MEMBER(sms_state::sms_store_select2)
+{
+ return 0xff;
+}
+
+
+READ8_MEMBER(sms_state::sms_store_control_r)
+{
+ return m_store_control;
+}
+
+
+WRITE8_MEMBER(sms_state::sms_store_control_w)
+{
+ logerror("0x%04X: sms_store_control write 0x%02X\n", cpu_get_pc(&space.device()), data);
+ if (data & 0x02)
+ {
+ machine().device<cpu_device>("maincpu")->resume(SUSPEND_REASON_HALT);
+ }
+ else
+ {
+ /* Pull reset line of CPU #0 low */
+ machine().device("maincpu")->reset();
+ machine().device<cpu_device>("maincpu")->suspend(SUSPEND_REASON_HALT, 1);
+ }
+ m_store_control = data;
+}
+
+WRITE_LINE_DEVICE_HANDLER( sms_store_int_callback )
+{
+ sms_state *driver_state = device->machine().driver_data<sms_state>();
+ device_set_input_line(driver_state->m_store_control & 0x01 ? driver_state->m_control_cpu : driver_state->m_main_cpu, 0, state);
+}
+
+
+static void sms_set_zero_flag( running_machine &machine )
+{
+ sms_state *state = machine.driver_data<sms_state>();
+ state->m_is_gamegear = 0;
+ state->m_is_region_japan = 0;
+ state->m_has_bios_0400 = 0;
+ state->m_has_bios_2000 = 0;
+ state->m_has_bios_full = 0;
+ state->m_has_bios = 0;
+ state->m_has_fm = 0;
+}
+
+DRIVER_INIT_MEMBER(sms_state,sg1000m3)
+{
+ sms_set_zero_flag(machine());
+ m_is_region_japan = 1;
+ m_has_fm = 1;
+}
+
+
+DRIVER_INIT_MEMBER(sms_state,sms1)
+{
+ sms_set_zero_flag(machine());
+ m_has_bios_full = 1;
+}
+
+
+DRIVER_INIT_MEMBER(sms_state,smsj)
+{
+ sms_set_zero_flag(machine());
+ m_is_region_japan = 1;
+ m_has_bios_2000 = 1;
+ m_has_fm = 1;
+}
+
+
+DRIVER_INIT_MEMBER(sms_state,sms2kr)
+{
+ sms_set_zero_flag(machine());
+ m_is_region_japan = 1;
+ m_has_bios_full = 1;
+ m_has_fm = 1;
+}
+
+
+DRIVER_INIT_MEMBER(sms_state,smssdisp)
+{
+ sms_set_zero_flag(machine());
+}
+
+
+DRIVER_INIT_MEMBER(sms_state,gamegear)
+{
+ sms_set_zero_flag(machine());
+ m_is_gamegear = 1;
+ m_has_bios_0400 = 1;
+}
+
+
+DRIVER_INIT_MEMBER(sms_state,gamegeaj)
+{
+ sms_set_zero_flag(machine());
+ m_is_region_japan = 1;
+ m_is_gamegear = 1;
+ m_has_bios_0400 = 1;
+}
+
+
+VIDEO_START( sms1 )
+{
+ sms_state *state = machine.driver_data<sms_state>();
+ screen_device *screen = machine.first_screen();
+
+ screen->register_screen_bitmap(state->m_prevleft_bitmap);
+ screen->register_screen_bitmap(state->m_prevright_bitmap);
+ state->save_item(NAME(state->m_prevleft_bitmap));
+ state->save_item(NAME(state->m_prevright_bitmap));
+}
+
+SCREEN_UPDATE_RGB32( sms1 )
+{
+ sms_state *state = screen.machine().driver_data<sms_state>();
+ UINT8 sscope = 0;
+ UINT8 sscope_binocular_hack;
+ UINT8 occluded_view = 0;
+
+ if (&screen != state->m_main_scr)
+ {
+ sscope = screen.machine().root_device().ioport("SEGASCOPE")->read_safe(0x00);
+ if (!sscope)
+ {
+ occluded_view = 1;
+ }
+ else if (&screen == state->m_left_lcd)
+ {
+ // with SegaScope, sscope_state 0 = left screen OFF, right screen ON
+ if (!(state->m_sscope_state & 0x01))
+ occluded_view = 1;
+ }
+ else // it's right LCD
+ {
+ // with SegaScope, sscope_state 1 = left screen ON, right screen OFF
+ if (state->m_sscope_state & 0x01)
+ occluded_view = 1;
+ }
+ }
+
+ if (!occluded_view)
+ {
+ state->m_vdp->screen_update(screen, bitmap, cliprect);
+
+ // HACK: fake 3D->2D handling (if enabled, it repeats each frame twice on the selected lens)
+ // save a copy of current bitmap for the binocular hack
+ if (sscope)
+ {
+ sscope_binocular_hack = screen.machine().root_device().ioport("SSCOPE_BINOCULAR")->read_safe(0x00);
+
+ if (&screen == state->m_left_lcd)
+ {
+ if (sscope_binocular_hack & 0x01)
+ copybitmap(state->m_prevleft_bitmap, bitmap, 0, 0, 0, 0, cliprect);
+ }
+ else // it's right LCD
+ {
+ if (sscope_binocular_hack & 0x02)
+ copybitmap(state->m_prevright_bitmap, bitmap, 0, 0, 0, 0, cliprect);
+ }
+ }
+ }
+ else
+ {
+ // HACK: fake 3D->2D handling (if enabled, it repeats each frame twice on the selected lens)
+ // use the copied bitmap for the binocular hack
+ if (sscope)
+ {
+ sscope_binocular_hack = screen.machine().root_device().ioport("SSCOPE_BINOCULAR")->read_safe(0x00);
+
+ if (&screen == state->m_left_lcd)
+ {
+ if (sscope_binocular_hack & 0x01)
+ {
+ copybitmap(bitmap, state->m_prevleft_bitmap, 0, 0, 0, 0, cliprect);
+ return 0;
+ }
+ }
+ else // it's right LCD
+ {
+ if (sscope_binocular_hack & 0x02)
+ {
+ copybitmap(bitmap, state->m_prevright_bitmap, 0, 0, 0, 0, cliprect);
+ return 0;
+ }
+ }
+ }
+ bitmap.fill(RGB_BLACK);
+ }
+
+ return 0;
+}
+
+SCREEN_UPDATE_RGB32( sms )
+{
+ sms_state *state = screen.machine().driver_data<sms_state>();
+ state->m_vdp->screen_update(screen, bitmap, cliprect);
+ return 0;
+}
+
+VIDEO_START( gamegear )
+{
+ sms_state *state = machine.driver_data<sms_state>();
+ screen_device *screen = machine.first_screen();
+
+ screen->register_screen_bitmap(state->m_prev_bitmap);
+ state->save_item(NAME(state->m_prev_bitmap));
+}
+
+SCREEN_UPDATE_RGB32( gamegear )
+{
+ sms_state *state = screen.machine().driver_data<sms_state>();
+ int width = screen.width();
+ int height = screen.height();
+ int x, y;
+
+ bitmap_rgb32 &vdp_bitmap = state->m_vdp->get_bitmap();
+
+ // HACK: fake LCD persistence effect
+ // (it would be better to generalize this in the core, to be used for all LCD systems)
+ for (y = 0; y < height; y++)
+ {
+ UINT32 *linedst = &bitmap.pix32(y);
+ UINT32 *line0 = &vdp_bitmap.pix32(y);
+ UINT32 *line1 = &state->m_prev_bitmap.pix32(y);
+ for (x = 0; x < 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);
+ linedst[x] = (r << 16) | (g << 8) | b;
+ }
+ }
+ copybitmap(state->m_prev_bitmap, vdp_bitmap, 0, 0, 0, 0, cliprect);
+
+ return 0;
+}
diff --git a/src/mess/machine/snescart.c b/src/mess/machine/snescart.c
new file mode 100644
index 00000000000..124a3258687
--- /dev/null
+++ b/src/mess/machine/snescart.c
@@ -0,0 +1,1488 @@
+/***************************************************************************
+
+ snescart.c
+
+ Machine file to handle cart loading in the Nintendo Super NES emulation.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "includes/snes.h"
+#include "imagedev/cartslot.h"
+#include "snescart.h"
+
+#define SNES_CART_DEBUG 0
+
+/****** Strings for Cart Header Logging ******/
+
+#define UNK "Unknown"
+
+/* Some known type of cart */
+static const char *const types[] =
+{
+ "ROM",
+ "ROM, DSP-1",
+ "ROM, DSP-2",
+ "ROM, DSP-3",
+ "ROM, DSP-4",
+ "ROM, Super FX / FX2",
+ "ROM, SA-1",
+ "ROM, S-DD1",
+ "ROM, OBC-1",
+ "ROM, S-RTC",
+ "ROM, Z80GB (Super Game Boy)",
+ "ROM, C4",
+ "ROM, Seta ST-010",
+ "ROM, Seta ST-011",
+ "ROM, Seta ST-018",
+ "ROM, SPC7110",
+ "ROM, SPC7110, RTC",
+ UNK, // to add: Satellaview BS-X detection
+};
+
+/* 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,
+};
+
+
+/* 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;
+}
+
+
+/***************************************************************************
+
+ SRAM handling
+
+***************************************************************************/
+
+/* Loads the battery backed RAM into the appropriate memory area */
+static void snes_load_sram(running_machine &machine)
+{
+ snes_state *state = machine.driver_data<snes_state>();
+ UINT8 ii;
+ UINT8 *battery_ram, *ptr;
+
+ battery_ram = (UINT8*)malloc(state->m_cart[0].sram_max);
+ ptr = battery_ram;
+ device_image_interface *image = dynamic_cast<device_image_interface *>(machine.device("cart"));
+ image->battery_load(battery_ram, state->m_cart[0].sram_max, 0xff);
+
+ if (state->m_cart[0].mode == SNES_MODE_20)
+ {
+ UINT32 size = state->m_cart[0].small_sram ? 0x8000 : 0x10000;
+
+ /* There could be some larger image needing banks 0x70 to 0x7f at address 0x8000 for ROM
+ * mirroring. These should be treated separately or data would be overwritten by SRAM */
+ for (ii = 0; ii < 16; ii++)
+ {
+ /* loading */
+ memmove(&snes_ram[0x700000 + (ii * 0x010000)], ptr, size);
+ /* mirroring */
+ memcpy(&snes_ram[0xf00000 + (ii * 0x010000)], &snes_ram[0x700000 + (ii * 0x010000)], size);
+ ptr += size;
+ }
+ }
+ else if (state->m_cart[0].mode == SNES_MODE_21)
+ {
+ for (ii = 0; ii < 16; ii++)
+ {
+ /* loading */
+ memmove(&snes_ram[0x306000 + (ii * 0x010000)], ptr, 0x2000);
+ /* mirroring */
+ memcpy(&snes_ram[0xb06000 + (ii * 0x010000)], &snes_ram[0x306000 + (ii * 0x010000)], 0x2000);
+ ptr += 0x2000;
+ }
+ }
+ else if (state->m_cart[0].mode == SNES_MODE_25)
+ {
+ for (ii = 0; ii < 16; ii++)
+ {
+ memmove(&snes_ram[0xb06000 + (ii * 0x010000)], ptr, 0x2000);
+ ptr += 0x2000;
+ }
+ }
+
+ free(battery_ram);
+}
+
+/* Saves the battery backed RAM from the appropriate memory area */
+static void snes_save_sram(running_machine &machine)
+{
+ snes_state *state = machine.driver_data<snes_state>();
+ UINT8 ii;
+ UINT8 *battery_ram, *ptr;
+
+ battery_ram = (UINT8*)malloc(state->m_cart[0].sram_max);
+ ptr = battery_ram;
+
+ if (state->m_cart[0].mode == SNES_MODE_20)
+ {
+ UINT32 size = state->m_cart[0].small_sram ? 0x8000 : 0x10000;
+
+ for (ii = 0; ii < 16; ii++)
+ {
+ memmove(ptr, &snes_ram[0x700000 + (ii * 0x010000)], size);
+ ptr += size;
+ }
+ }
+ else if (state->m_cart[0].mode == SNES_MODE_21)
+ {
+ for (ii = 0; ii < 16; ii++)
+ {
+ memmove(ptr, &snes_ram[0x306000 + (ii * 0x010000)], 0x2000);
+ ptr += 0x2000;
+ }
+ }
+ else if (state->m_cart[0].mode == SNES_MODE_25)
+ {
+ for (ii = 0; ii < 16; ii++)
+ {
+ memmove(ptr, &snes_ram[0xb06000 + (ii * 0x010000)], 0x2000);
+ ptr += 0x2000;
+ }
+ }
+ device_image_interface *image = dynamic_cast<device_image_interface *>(machine.device("cart"));
+ image->battery_save(battery_ram, state->m_cart[0].sram_max);
+
+ free(battery_ram);
+}
+
+static void snes_machine_stop(running_machine &machine)
+{
+ snes_state *state = machine.driver_data<snes_state>();
+
+ /* Save SRAM */
+ if (state->m_cart[0].sram > 0)
+ snes_save_sram(machine);
+}
+
+MACHINE_START( snes_mess )
+{
+ machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(snes_machine_stop),&machine));
+ MACHINE_START_CALL(snes);
+}
+
+
+static void sufami_load_sram(running_machine &machine, const char *cart_tag)
+{
+ UINT8 ii;
+ UINT8 *battery_ram, *ptr;
+ int st_sram_offset = 0;
+
+ battery_ram = (UINT8*)malloc(0x20000);
+ ptr = battery_ram;
+ device_image_interface *image = dynamic_cast<device_image_interface *>(machine.device(cart_tag));
+ image->battery_load(battery_ram, 0x20000, 0);
+
+ if (strcmp(cart_tag, ":slot_a") == 0)
+ st_sram_offset = 0x608000;
+
+ if (strcmp(cart_tag, ":slot_b") == 0)
+ st_sram_offset = 0x708000;
+
+ /* Cart RAM is at 0x60-0x63:0x8000-0xffff (+0x10 for slot2) */
+ for (ii = 0; ii < 4; ii++)
+ {
+ /* loading */
+ memcpy(&snes_ram[st_sram_offset + (ii * 0x010000)], ptr + (ii * 0x8000), 0x8000);
+ /* mirroring */
+ memcpy(&snes_ram[0x800000 + st_sram_offset + (ii * 0x010000)], &snes_ram[st_sram_offset + (ii * 0x010000)], 0x8000);
+ }
+
+ free(battery_ram);
+}
+
+static void sufami_machine_stop(running_machine &machine)
+{
+ snes_state *state = machine.driver_data<snes_state>();
+ UINT8 ii;
+ UINT8 *battery_ram, *ptr;
+
+ battery_ram = (UINT8*)malloc(0x20000);
+ ptr = battery_ram;
+
+ if (state->m_cart[0].slot_in_use)
+ {
+ for (ii = 0; ii < 4; ii++)
+ {
+ memmove(ptr + ii * 0x8000, &snes_ram[0x608000 + (ii * 0x010000)], 0x8000);
+ }
+ device_image_interface *image = dynamic_cast<device_image_interface *>(machine.device("slot_a"));
+ image->battery_save(battery_ram, 0x20000);
+ }
+
+ if (state->m_cart[1].slot_in_use)
+ {
+ for (ii = 0; ii < 4; ii++)
+ {
+ memmove(ptr + ii * 0x8000, &snes_ram[0x708000 + (ii * 0x010000)], 0x8000);
+ }
+ device_image_interface *image = dynamic_cast<device_image_interface *>(machine.device("slot_b"));
+ image->battery_save(battery_ram, 0x20000);
+ }
+
+ free(battery_ram);
+}
+
+MACHINE_START( snesst )
+{
+ machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(sufami_machine_stop),&machine));
+ MACHINE_START_CALL(snes);
+}
+
+
+/***************************************************************************
+
+ Cart handling
+
+***************************************************************************/
+
+/* 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.cinnamonpirate.com/ */
+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;
+}
+
+/* Here we add a couple of cart utilities, to avoid duplicating the code in each DEVICE_IMAGE_LOAD */
+static UINT32 snes_skip_header( device_image_interface &image, UINT32 snes_rom_size )
+{
+ UINT8 header[512];
+ UINT32 offset = 512;
+
+ /* Check for a header (512 bytes) */
+ if (image.software_entry() == NULL)
+ image.fread( header, 512);
+ else
+ memcpy(header, image.get_software_region("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)) == (((snes_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 ((snes_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 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( device_image_interface &image, UINT8 *buffer, UINT32 offset, int cartid )
+{
+ snes_state *state = image.device().machine().driver_data<snes_state>();
+ UINT8 valid_mode20, valid_mode21, valid_mode25;
+ UINT32 retvalue;
+
+ /* Now to determine if this is a lo-ROM, a hi-ROM or an extended lo/hi-ROM */
+ valid_mode20 = snes_validate_infoblock(buffer, 0x007fc0);
+ valid_mode21 = snes_validate_infoblock(buffer, 0x00ffc0);
+ 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))
+ {
+ if ((buffer[0x007fd5] == 0x32) || ((state->m_cart_size - offset) > 0x401000))
+ state->m_cart[cartid].mode = SNES_MODE_22; // ExLoRom
+ else
+ state->m_cart[cartid].mode = SNES_MODE_20; // LoRom
+
+ retvalue = 0x007fc0;
+
+ /* a few games require 512k, however we store twice as much to be sure to cover the various mirrors */
+ state->m_cart[cartid].sram_max = 0x100000;
+ }
+ else if (valid_mode21 >= valid_mode25)
+ {
+ state->m_cart[cartid].mode = SNES_MODE_21; // HiRom
+ retvalue = 0x00ffc0;
+ state->m_cart[cartid].sram_max = 0x20000;
+ }
+ else
+ {
+ state->m_cart[cartid].mode = SNES_MODE_25; // ExHiRom
+ retvalue = 0x40ffc0;
+ state->m_cart[cartid].sram_max = 0x20000;
+ }
+
+ logerror( "\t HiROM/LoROM id: %s (LoROM: %d , HiROM: %d, ExHiROM: %d)\n",
+ (state->m_cart[cartid].mode == SNES_MODE_20) ? "LoROM" :
+ (state->m_cart[cartid].mode == SNES_MODE_21) ? "HiROM" :
+ (state->m_cart[cartid].mode == SNES_MODE_22) ? "ExLoROM" :
+ (state->m_cart[cartid].mode == SNES_MODE_25) ? "ExHiROM" : "Other (BSX or ST)",
+ valid_mode20, valid_mode21, valid_mode25);
+
+ return retvalue;
+}
+
+static int snes_find_addon_chip( running_machine &machine )
+{
+ snes_state *state = machine.driver_data<snes_state>();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ int supported_type = 1;
+ int dsp_prg_offset = 0;
+
+ /* Info mostly taken from http://snesemu.black-ship.net/misc/-from%20nsrt.edgeemu.com-chipinfo.htm */
+ switch (snes_r_bank1(space, 0x00ffd6))
+ {
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ state->m_has_addon_chip = HAS_NONE;
+ break;
+
+ case 0x03:
+ if (snes_r_bank1(space, 0x00ffd5) == 0x30)
+ {
+ state->m_has_addon_chip = HAS_DSP4;
+ dsp_prg_offset = SNES_DSP4_OFFSET;
+ }
+ else
+ {
+ state->m_has_addon_chip = HAS_DSP1;
+ dsp_prg_offset = SNES_DSP1B_OFFSET;
+ }
+ break;
+
+ case 0x04:
+ state->m_has_addon_chip = HAS_DSP1;
+ dsp_prg_offset = SNES_DSP1B_OFFSET;
+ break;
+
+ case 0x05:
+ if (snes_r_bank1(space, 0x00ffd5) == 0x20)
+ {
+ state->m_has_addon_chip = HAS_DSP2;
+ dsp_prg_offset = SNES_DSP2_OFFSET;
+ }
+ /* DSP-3 is hard to detect. We exploit the fact that the only game has been manufactured by Bandai */
+ else if ((snes_r_bank1(space, 0x00ffd5) == 0x30) && (snes_r_bank1(space, 0x00ffda) == 0xb2))
+ {
+ state->m_has_addon_chip = HAS_DSP3;
+ dsp_prg_offset = SNES_DSP3_OFFSET;
+ }
+ else
+ {
+ state->m_has_addon_chip = HAS_DSP1;
+ dsp_prg_offset = SNES_DSP1B_OFFSET;
+ }
+ break;
+
+ case 0x13: // Mario Chip 1
+ case 0x14: // GSU-x
+ case 0x15: // GSU-x
+ case 0x1a: // GSU-1 (21 MHz at start)
+ if (snes_r_bank1(space, 0x00ffd5) == 0x20)
+ state->m_has_addon_chip = HAS_SUPERFX;
+ break;
+
+ case 0x25:
+ state->m_has_addon_chip = HAS_OBC1;
+ break;
+
+ case 0x32: // needed by a Sample game (according to ZSNES)
+ case 0x34:
+ case 0x35:
+ if (snes_r_bank1(space, 0x00ffd5) == 0x23)
+ {
+ state->m_has_addon_chip = HAS_SA1;
+ supported_type = 0;
+ mame_printf_error("This is a SA-1 type game, currently unsupported by the driver\n");
+ }
+ break;
+
+ case 0x43:
+ case 0x45:
+ if (snes_r_bank1(space, 0x00ffd5) == 0x32)
+ {
+ state->m_has_addon_chip = HAS_SDD1;
+ }
+ break;
+
+ case 0x55:
+ if (snes_r_bank1(space, 0x00ffd5) == 0x35)
+ {
+ state->m_has_addon_chip = HAS_RTC;
+ }
+ break;
+
+ case 0xe3:
+ state->m_has_addon_chip = HAS_Z80GB;
+ supported_type = 0;
+ break;
+
+ case 0xf3:
+ state->m_has_addon_chip = HAS_CX4;
+ break;
+
+ case 0xf5:
+ if (snes_r_bank1(space, 0x00ffd5) == 0x30)
+ {
+ state->m_has_addon_chip = HAS_ST018;
+ supported_type = 0;
+ }
+ else if (snes_r_bank1(space, 0x00ffd5) == 0x3a)
+ {
+ state->m_has_addon_chip = HAS_SPC7110;
+ }
+ break;
+
+ case 0xf6:
+ /* These Seta ST-01X chips have both 0x30 at 0x00ffd5,
+ they only differ for the 'size' at 0x00ffd7 */
+ if (snes_r_bank1(space, 0x00ffd7) < 0x0a)
+ state->m_has_addon_chip = HAS_ST011;
+ else
+ state->m_has_addon_chip = HAS_ST010;
+
+ // if we are loading the game in a driver without the ST01X DSP, revert to HAS_NONE to avoid crash
+ if (!state->m_upd96050)
+ state->m_has_addon_chip = HAS_NONE;
+ break;
+
+ case 0xf9:
+ if (snes_r_bank1(space, 0x00ffd5) == 0x3a)
+ {
+ state->m_has_addon_chip = HAS_SPC7110_RTC;
+ supported_type = 0;
+ }
+ break;
+
+ default:
+ state->m_has_addon_chip = HAS_UNK;
+ supported_type = 0;
+ break;
+ }
+
+ if ((state->m_has_addon_chip >= HAS_DSP1) && (state->m_has_addon_chip <= HAS_DSP4))
+ {
+ UINT8 *dspsrc = (UINT8 *)(*machine.root_device().memregion("addons"));
+ UINT32 *dspprg = (UINT32 *)(*machine.root_device().memregion("dspprg"));
+ UINT16 *dspdata = (UINT16 *)(*machine.root_device().memregion("dspdata"));
+
+ // copy DSP program
+ for (int i = 0; i < 0x2000; i+= 4)
+ {
+ *dspprg = dspsrc[dsp_prg_offset+0+i]<<24 | dspsrc[dsp_prg_offset+1+i]<<16 | dspsrc[dsp_prg_offset+2+i]<<8;
+ dspprg++;
+ }
+
+ // copy DSP data
+ for (int i = 0; i < 0x800; i+= 2)
+ {
+ *dspdata++ = dspsrc[dsp_prg_offset+0x2000+i]<<8 | dspsrc[dsp_prg_offset+0x2001+i];
+ }
+ }
+
+ if ((state->m_has_addon_chip == HAS_ST010) || (state->m_has_addon_chip == HAS_ST011))
+ {
+ UINT8 *dspsrc = (UINT8 *)(*machine.root_device().memregion("addons"));
+ UINT32 *dspprg = (UINT32 *)(*machine.root_device().memregion("dspprg"));
+ UINT16 *dspdata = (UINT16 *)(*machine.root_device().memregion("dspdata"));
+
+ // copy DSP program
+ for (int i = 0; i < 0x10000; i+= 4)
+ {
+ *dspprg = dspsrc[0+i]<<24 | dspsrc[1+i]<<16 | dspsrc[2+i]<<8;
+ dspprg++;
+ }
+
+ // copy DSP data
+ for (int i = 0; i < 0x1000; i+= 2)
+ {
+ *dspdata++ = dspsrc[0x10000+i]<<8 | dspsrc[0x10001+i];
+ }
+ }
+
+ return supported_type;
+}
+
+static void snes_cart_log_info( running_machine &machine, int total_blocks, int supported )
+{
+ snes_state *state = machine.driver_data<snes_state>();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ char title[21], rom_id[4], company_id[2];
+ int i, company, has_ram = 0, has_sram = 0;
+
+ /* Company */
+ for (i = 0; i < 2; i++)
+ company_id[i] = snes_r_bank1(space, 0x00ffb0 + i);
+ company = (char_to_int_conv(company_id[0]) << 4) + char_to_int_conv(company_id[1]);
+ if (company == 0)
+ company = snes_r_bank1(space, 0x00ffda);
+
+ /* ROM ID */
+ for( i = 0; i < 4; i++ )
+ rom_id[i] = snes_r_bank1(space, 0x00ffb2 + i);
+
+ /* Title */
+ for( i = 0; i < 21; i++ )
+ title[i] = snes_r_bank1(space, 0x00ffc0 + i);
+
+ /* RAM */
+ if (((snes_r_bank1(space, 0x00ffd6) & 0xf) == 1) ||
+ ((snes_r_bank1(space, 0x00ffd6) & 0xf) == 2) ||
+ ((snes_r_bank1(space, 0x00ffd6) & 0xf) == 4) ||
+ ((snes_r_bank1(space, 0x00ffd6) & 0xf) == 5))
+ has_ram = 1;
+
+ /* SRAM */
+ if (((snes_r_bank1(space, 0x00ffd6) & 0xf) == 2) ||
+ ((snes_r_bank1(space, 0x00ffd6) & 0xf) == 5) ||
+ ((snes_r_bank1(space, 0x00ffd6) & 0xf) == 6))
+ has_sram = 1;
+
+ logerror( "ROM DETAILS\n" );
+ logerror( "===========\n\n" );
+ logerror( "\tTotal blocks: %d (%dmb)\n", total_blocks, total_blocks / (state->m_cart[0].mode & 5 ? 32 : 16) );
+ logerror( "\tROM bank size: %s \n",
+ (state->m_cart[0].mode == SNES_MODE_20) ? "LoROM" :
+ (state->m_cart[0].mode == SNES_MODE_21) ? "HiROM" :
+ (state->m_cart[0].mode == SNES_MODE_22) ? "ExLoROM" :
+ (state->m_cart[0].mode == SNES_MODE_25) ? "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", ((snes_r_bank1(space, 0x00ffd5) & 0xf0)) ? "FastROM" : "SlowROM", (snes_r_bank1(space, 0x00ffd5) & 0xf0) >> 4 );
+ logerror( "\tBank size: %s [%d]\n", (snes_r_bank1(space, 0x00ffd5) & 0xf) ? "HiROM" : "LoROM", snes_r_bank1(space, 0x00ffd5) & 0xf );
+
+ logerror( "\tType: %s", types[state->m_has_addon_chip]);
+ if (has_ram)
+ logerror( ", RAM");
+ if (has_sram)
+ logerror( ", SRAM");
+ logerror( " [%d]\n", snes_r_bank1(space, 0x00ffd6) );
+
+ logerror( "\tSize: %d megabits [%d]\n", 1 << (snes_r_bank1(space, 0x00ffd7) - 7), snes_r_bank1(space, 0x00ffd7) );
+ logerror( "\tSRAM: %d kilobits [%d]\n", state->m_cart[0].sram * 8, snes_ram[0xffd8] );
+ logerror( "\tCountry: %s [%d]\n", countries[snes_r_bank1(space, 0x00ffd9)], snes_r_bank1(space, 0x00ffd9) );
+ logerror( "\tLicense: %s [%X]\n", companies[snes_r_bank1(space, 0x00ffda)], snes_r_bank1(space, 0x00ffda) );
+ logerror( "\tVersion: 1.%d\n", snes_r_bank1(space, 0x00ffdb) );
+ logerror( "\tInv Checksum: %X %X\n", snes_r_bank1(space, 0x00ffdd), snes_r_bank1(space, 0x00ffdc) );
+ logerror( "\tChecksum: %X %X\n", snes_r_bank1(space, 0x00ffdf), snes_r_bank1(space, 0x00ffde) );
+ logerror( "\tNMI Address: %2X%2Xh\n", snes_r_bank1(space, 0x00fffb), snes_r_bank1(space, 0x00fffa) );
+ logerror( "\tStart Address: %2X%2Xh\n\n", snes_r_bank1(space, 0x00fffd), snes_r_bank1(space, 0x00fffc) );
+
+ logerror( "\tMode: %d\n", state->m_cart[0].mode);
+
+ if (!supported)
+ logerror("WARNING: This cart type \"%s\" is not supported yet!\n", types[state->m_has_addon_chip]);
+}
+
+static DEVICE_IMAGE_LOAD( snes_cart )
+{
+ int supported_type = 1;
+ running_machine &machine = image.device().machine();
+ snes_state *state = machine.driver_data<snes_state>();
+ address_space *space = machine.device( "maincpu")->memory().space( AS_PROGRAM );
+ int total_blocks, read_blocks, has_bsx_slot = 0, st_bios = 0;
+ UINT32 offset, int_header_offs;
+ UINT8 *ROM = state->memregion("cart")->base();
+
+ if (image.software_entry() == NULL)
+ state->m_cart_size = image.length();
+ else
+ state->m_cart_size = image.get_software_region_length("rom");
+
+ /* Check for a header (512 bytes), and skip it if found */
+ offset = snes_skip_header(image, state->m_cart_size);
+
+ if (image.software_entry() == NULL)
+ {
+ image.fseek(offset, SEEK_SET);
+ image.fread( ROM, state->m_cart_size - offset);
+ }
+ else
+ memcpy(ROM, image.get_software_region("rom") + offset, state->m_cart_size - offset);
+
+ if (SNES_CART_DEBUG) mame_printf_error("size %08X\n", state->m_cart_size - offset);
+
+ /* First, look if the cart is HiROM or LoROM (and set snes_cart accordingly) */
+ int_header_offs = snes_find_hilo_mode(image, ROM, offset, 0);
+
+ /* Then, detect BS-X carts */
+ // Detect presence of BS-X Flash Cart
+ if ((ROM[int_header_offs + 0x13] == 0x00 || ROM[int_header_offs + 0x13] == 0xff) &&
+ ROM[int_header_offs + 0x14] == 0x00)
+ {
+ UINT8 n15 = ROM[int_header_offs + 0x15];
+ if (n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc)
+ {
+ if (ROM[int_header_offs + 0x1a] == 0x33 || ROM[int_header_offs + 0x1a] == 0xff)
+ {
+ // BS-X Flash Cart
+ state->m_cart[0].mode = SNES_MODE_BSX;
+ }
+ }
+ }
+
+ // Detect presence of BS-X flash cartridge connector
+ if ((ROM[int_header_offs - 14] == 'Z') && (ROM[int_header_offs - 11] == 'J'))
+ {
+ UINT8 n13 = ROM[int_header_offs - 13];
+ if ((n13 >= 'A' && n13 <= 'Z') || (n13 >= '0' && n13 <= '9'))
+ {
+ if (ROM[int_header_offs + 0x1a] == 0x33 ||
+ (ROM[int_header_offs - 10] == 0x00 && ROM[int_header_offs - 4] == 0x00))
+ {
+ has_bsx_slot = 1;
+ }
+ }
+ }
+
+ // If there is a BS-X connector, detect if it is the Base Cart or a compatible slotted cart
+ if (has_bsx_slot)
+ {
+ if (!memcmp(ROM + int_header_offs, "Satellaview BS-X ", 21))
+ {
+ //BS-X Base Cart
+ state->m_cart[0].mode = SNES_MODE_BSX;
+ // handle RAM
+ }
+ else
+ {
+ state->m_cart[0].mode = (int_header_offs ==0x007fc0) ? SNES_MODE_BSLO : SNES_MODE_BSHI;
+ // handle RAM?
+ }
+ }
+
+ /* Then, detect Sufami Turbo carts */
+ if (!memcmp(ROM, "BANDAI SFC-ADX", 14))
+ {
+ state->m_cart[0].mode = SNES_MODE_ST;
+ if (!memcmp(ROM + 16, "SFC-ADX BACKUP", 14))
+ st_bios = 1;
+ }
+
+ if (SNES_CART_DEBUG) mame_printf_error("mode %d\n", state->m_cart[0].mode);
+
+ /* FIXME: Insert crc check here? */
+
+ /* How many blocks of data are available to be loaded? */
+ total_blocks = ((state->m_cart_size - offset) / (state->m_cart[0].mode & 0xa5 ? 0x8000 : 0x10000));
+ read_blocks = 0;
+
+ if (SNES_CART_DEBUG) mame_printf_error("blocks %d\n", total_blocks);
+
+ /* Loading all the data blocks from cart, we only partially cover banks 0x00 to 0x7f. Therefore, we
+ * have to mirror the blocks until we reach the end. E.g. for a 11Mbits image (44 blocks), we proceed
+ * as follows:
+ * 11 Mbits = 8 Mbits (blocks 1->32) + 2 Mbits (blocks 33->40) + 1 Mbit (blocks 41->44).
+ * Hence, we fill memory up to 16 Mbits (banks 0x00 to 0x3f) mirroring as follows
+ * 8 Mbits (blocks 1->32) + 2 Mbits (blocks 33->40) + 1 Mbit (blocks 41->44) + 1 Mbit (blocks 41->44)
+ * + 2 Mbits (blocks 33->40) + 1 Mbit (blocks 41->44) + 1 Mbit (blocks 41->44)
+ * and we repeat the same blocks in the second half of the banks (banks 0x40 to 0x7f).
+ * This is likely what happens in the real SNES as well, because the unit cannot be aware of the exact
+ * size of data in the cart (procedure confirmed by byuu)
+ */
+ switch (state->m_cart[0].mode)
+ {
+ case SNES_MODE_21:
+ /* HiROM carts load data in banks 0xc0 to 0xff. Each bank is fully mirrored in banks 0x40 to 0x7f
+ * (actually up to 0x7d, because 0x7e and 0x7f are overwritten by WRAM). The top half (address
+ * range 0x8000 - 0xffff) of each bank is also mirrored in banks 0x00 to 0x3f and 0x80 to 0xbf.
+ */
+ /* SPC7110 games needs this different loading routine */
+ if ((ROM[0x00ffd6] == 0xf9 || ROM[0x00ffd6] == 0xf5) && (ROM[0x00ffd5] == 0x3a))
+ {
+ while (read_blocks < 16 && read_blocks < total_blocks)
+ {
+ /* Loading data */
+ memcpy(&snes_ram[0xc00000 + read_blocks * 0x10000], &ROM[0x000000 + read_blocks * 0x10000], 0x10000);
+ /* Mirroring */
+ memcpy(&snes_ram[0x008000 + read_blocks * 0x10000], &snes_ram[0xc08000 + read_blocks * 0x10000], 0x8000);
+ memcpy(&snes_ram[0x808000 + read_blocks * 0x10000], &snes_ram[0xc08000 + read_blocks * 0x10000], 0x8000);
+ read_blocks++;
+ }
+ }
+ else
+ {
+ while (read_blocks < 64 && read_blocks < total_blocks)
+ {
+ /* Loading data */
+ memcpy(&snes_ram[0xc00000 + read_blocks * 0x10000], &ROM[0x000000 + read_blocks * 0x10000], 0x10000);
+ /* Mirroring */
+ memcpy(&snes_ram[0x008000 + read_blocks * 0x10000], &snes_ram[0xc08000 + read_blocks * 0x10000], 0x8000);
+ memcpy(&snes_ram[0x400000 + read_blocks * 0x10000], &snes_ram[0xc00000 + read_blocks * 0x10000], 0x10000);
+ memcpy(&snes_ram[0x808000 + read_blocks * 0x10000], &snes_ram[0xc08000 + read_blocks * 0x10000], 0x8000);
+ read_blocks++;
+ }
+ /* Filling banks up to 0xff and their mirrors */
+ while (read_blocks % 64)
+ {
+ int j = 0, repeat_blocks;
+ while ((read_blocks % (64 >> j)) && j < 6)
+ j++;
+ repeat_blocks = read_blocks % (64 >> (j - 1));
+
+ memcpy(&snes_ram[0xc00000 + read_blocks * 0x10000], &snes_ram[0xc00000 + (read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000);
+ memcpy(&snes_ram[read_blocks * 0x10000], &snes_ram[(read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000);
+ memcpy(&snes_ram[0x400000 + read_blocks * 0x10000], &snes_ram[0x400000 + (read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000);
+ memcpy(&snes_ram[0x800000 + read_blocks * 0x10000], &snes_ram[0x800000 + (read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000);
+ read_blocks += repeat_blocks;
+ }
+ }
+ break;
+
+ case SNES_MODE_25:
+ /* Extendend HiROM carts start to load data in banks 0xc0 to 0xff. However, they exceed the
+ * available space in these banks, and continue loading at banks 0x40 to 0x7f. The top half
+ * (address range 0x8000 - 0xffff) of each bank is also mirrored either to banks 0x00 to 0x3f
+ * (for data in banks 0x40 to 0x7f) or to banks 0x80 to 0xbf (for data in banks 0xc0 to 0xff).
+ * Notice that banks 0x7e and 0x7f are overwritten by WRAM, but they could contain data at
+ * address > 0x8000 because the mirrors at 0x3e and 0x3f are not overwritten.
+ */
+ /* Reading the first 64 blocks */
+ while (read_blocks < 64 && read_blocks < total_blocks)
+ {
+ /* Loading data */
+ memcpy(&snes_ram[0xc00000 + read_blocks * 0x10000], &ROM[0x000000 + read_blocks * 0x10000], 0x10000);
+ /* Mirroring */
+ memcpy( &snes_ram[0x808000 + read_blocks * 0x10000], &snes_ram[0xc08000 + read_blocks * 0x10000], 0x8000);
+ read_blocks++;
+ }
+ /* ExHiROMs are supposed to be larger than 32Mbits! */
+ if (read_blocks < 64)
+ {
+ logerror("This image has been identified as ExHiROM, but it's too small!\n");
+ logerror("Please verify if it's corrupted. If it's not please report this as a bug.\n");
+ return IMAGE_INIT_FAIL;
+ }
+ /* Scaling down the counter */
+ read_blocks -= 64;
+ /* Reading the next blocks */
+ while (read_blocks < 64 && read_blocks < (total_blocks - 64))
+ {
+ /* Loading data */
+ memcpy(&snes_ram[0x400000 + read_blocks * 0x10000], &ROM[0x400000 + read_blocks * 0x10000], 0x10000);
+ /* Mirroring */
+ memcpy(&snes_ram[0x8000 + read_blocks * 0x10000], &snes_ram[0x408000 + read_blocks * 0x10000], 0x8000);
+ read_blocks++;
+ }
+ /* Filling banks up to 0x7f and their mirrors */
+ while (read_blocks % 64)
+ {
+ int j = 0, repeat_blocks;
+ while ((read_blocks % (64 >> j)) && j < 6)
+ j++;
+ repeat_blocks = read_blocks % (64 >> (j - 1));
+
+ memcpy(&snes_ram[0x400000 + read_blocks * 0x10000], &snes_ram[0x400000 + (read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000);
+ memcpy(&snes_ram[read_blocks * 0x10000], &snes_ram[(read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000);
+ read_blocks += repeat_blocks;
+ }
+ break;
+
+ case SNES_MODE_22:
+ /* "Extendend LoROM" carts have their data loaded in banks 0x00 to 0x3f at address 0x8000.
+ * These are then mirrored in banks 0x40 to 0x7f, both at address 0x0000 and at address
+ * 0x8000, in banks 0x80 to 0xbf at address 0x8000 and in banks 0xc0 to 0xff, both at address
+ * 0x0000 and at address 0x8000. Notice that SDD-1 games (Star Ocean and Street Fighter Zero 2)
+ * use SNES_MODE_22
+ */
+ while (read_blocks < 64 && read_blocks < total_blocks)
+ {
+ /* Loading and mirroring data */
+ memcpy(&snes_ram[0x008000 + read_blocks * 0x10000], &ROM[0x000000 + read_blocks * 0x8000], 0x8000);
+ memcpy(&snes_ram[0x808000 + read_blocks * 0x10000], &ROM[0x000000 + read_blocks * 0x8000], 0x8000);
+ memcpy(&snes_ram[0x400000 + read_blocks * 0x10000], &ROM[0x000000 + read_blocks * 0x10000], 0x10000);
+ memcpy(&snes_ram[0xc00000 + read_blocks * 0x10000], &ROM[0x000000 + read_blocks * 0x10000], 0x10000);
+ read_blocks++;
+ }
+ /* Filling banks up to 0x3f and their mirrors */
+ while (read_blocks % 64)
+ {
+ int j = 0, repeat_blocks;
+ while ((read_blocks % (64 >> j)) && j < 6)
+ j++;
+ repeat_blocks = read_blocks % (64 >> (j - 1));
+
+ memcpy(&snes_ram[read_blocks * 0x10000], &snes_ram[(read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000);
+ memcpy(&snes_ram[0x800000 + read_blocks * 0x10000], &snes_ram[0x800000 + (read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000);
+ memcpy(&snes_ram[0x400000 + read_blocks * 0x10000], &snes_ram[0x400000 + (read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000);
+ memcpy(&snes_ram[0xc00000 + read_blocks * 0x10000], &snes_ram[0xc00000 + (read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000);
+ read_blocks += repeat_blocks;
+ }
+ break;
+
+ case SNES_MODE_ST:
+ if (!st_bios)
+ {
+ mame_printf_error("This is a Sufami Turbo data cart and cannot be loaded for snes/snespal in MESS.\n");
+ mame_printf_error("Please use snesst driver to load it, instead.\n");
+ return IMAGE_INIT_FAIL;
+ }
+ else
+ {
+ // The Base ST cart consists of 8 * 0x8000 block which have to be loaded (and mirrored)
+ // at 0x00-0x1f:0x8000-0xffff and 0x80-0x9f:0x8000-0xffff
+ int i = 0;
+ for (i = 0; i < 8; i++)
+ {
+ /* Loading data */
+ memcpy(&snes_ram[0x008000 + i * 0x10000], &ROM[0x000000 + i * 0x8000], 0x8000);
+ /* Mirroring */
+ memcpy(&snes_ram[0x808000 + i * 0x10000], &snes_ram[0x8000 + (i * 0x10000)], 0x8000);
+
+ /* Additional mirrors (to fill snes_ram up to 0x1fffff) */
+ int j = 0;
+ for (j = 1; j < 4; j++)
+ {
+ memcpy(&snes_ram[0x008000 + i * 0x10000 + j * 0x80000], &snes_ram[0x8000 + (i * 0x10000)], 0x8000);
+ memcpy(&snes_ram[0x808000 + i * 0x10000 + j * 0x80000], &snes_ram[0x8000 + (i * 0x10000)], 0x8000);
+ }
+ }
+ }
+ break;
+
+ case SNES_MODE_BSX:
+ case SNES_MODE_BSLO:
+ case SNES_MODE_BSHI:
+ /* not handled yet */
+ mame_printf_error("This is a BS-X Satellaview image: MESS does not support these yet, sorry.\n");
+#if 0
+ // shall we force incompatibility of flash carts without a base unit?
+ if (!has_bsx_slot)
+ {
+ mame_printf_error("This is a BS-X flash cart and cannot be loaded in snes/snespal.\n");
+// mame_printf_error("Please use snesbsx driver to load it, instead.\n");
+ return IMAGE_INIT_FAIL;
+ }
+#endif
+ break;
+
+ default:
+ case SNES_MODE_20:
+ /* LoROM carts load data in banks 0x00 to 0x7f at address 0x8000 (actually up to 0x7d, because 0x7e and
+ * 0x7f are overwritten by WRAM). Each block is also mirrored in banks 0x80 to 0xff (up to 0xff for real)
+ */
+ /* SuperFX games needs this different loading routine */
+ if (((ROM[0x007fd6] >= 0x13 && ROM[0x007fd6] <= 0x15) || ROM[0x007fd6] == 0x1a) && (ROM[0x007fd5] == 0x20))
+ {
+ while (read_blocks < 64 && read_blocks < total_blocks)
+ {
+ /* Loading data primary: banks 0-3f from 8000-ffff*/
+ memcpy(&snes_ram[0x008000 + read_blocks * 0x10000], &ROM[0x000000 + read_blocks * 0x8000], 0x8000);
+ /* Mirroring at banks 80-bf from 8000-ffff */
+ memcpy(&snes_ram[0x808000 + read_blocks * 0x10000], &snes_ram[0x8000 + (read_blocks * 0x10000)], 0x8000);
+ /* Mirroring at banks 40-5f and c0-df */
+ memcpy(&snes_ram[0x400000 + read_blocks * 0x8000], &snes_ram[0x8000 + (read_blocks * 0x10000)], total_blocks * 0x8000);
+ memcpy(&snes_ram[0xc00000 + read_blocks * 0x8000], &snes_ram[0x8000 + (read_blocks * 0x10000)], total_blocks * 0x8000);
+
+ read_blocks++;
+ }
+ /* SuperFX games are supposed to contain 64 blocks! */
+ if (read_blocks < total_blocks)
+ {
+ logerror("This image has been identified as a SuperFX game, but it's too large!\n");
+ logerror("Please verify if it's corrupted. If it's not please report this as a bug.\n");
+ return IMAGE_INIT_FAIL;
+ }
+ }
+ else
+ {
+ while (read_blocks < 128 && read_blocks < total_blocks)
+ {
+ /* Loading data */
+ memcpy(&snes_ram[0x008000 + read_blocks * 0x10000], &ROM[0x000000 + read_blocks * 0x8000], 0x8000);
+ /* Mirroring */
+ memcpy(&snes_ram[0x808000 + read_blocks * 0x10000], &snes_ram[0x8000 + (read_blocks * 0x10000)], 0x8000);
+ read_blocks++;
+ }
+ /* Filling banks up to 0x7f and their mirrors */
+ while (read_blocks % 128)
+ {
+ int j = 0, repeat_blocks;
+ while ((read_blocks % (128 >> j)) && j < 7)
+ j++;
+ repeat_blocks = read_blocks % (128 >> (j - 1));
+
+ memcpy( &snes_ram[read_blocks * 0x10000], &snes_ram[(read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000);
+ memcpy( &snes_ram[0x800000 + read_blocks * 0x10000], &snes_ram[(read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000);
+ read_blocks += repeat_blocks;
+ }
+ }
+ break;
+ }
+
+ /* Detect special chips */
+ supported_type = snes_find_addon_chip(machine);
+
+ /* Find the amount of cart ram (even if we call it sram...) */
+ if (image.software_entry() == NULL)
+ {
+ if ((state->m_has_addon_chip != HAS_SUPERFX))
+ state->m_cart[0].sram = snes_r_bank1(space, 0x00ffd8);
+ else
+ state->m_cart[0].sram = (snes_r_bank1(space, 0x00ffbd) & 0x07);
+
+ if (state->m_cart[0].sram > 0)
+ {
+ state->m_cart[0].sram = (1024 << state->m_cart[0].sram);
+ if (state->m_cart[0].sram > state->m_cart[0].sram_max)
+ state->m_cart[0].sram = state->m_cart[0].sram_max;
+ }
+// printf("size %x\n", state->m_cart[0].sram);
+ }
+ else
+ {
+ // if we are loading from softlist, take sram from the xml
+ state->m_cart[0].sram = image.get_software_region("sram") ? image.get_software_region_length("sram") : 0;
+
+ if (state->m_cart[0].sram > 0)
+ {
+ if (state->m_cart[0].sram > state->m_cart[0].sram_max)
+ fatalerror("Found more SRAM than max allowed (found: %x, max: %x), check xml file!\n", state->m_cart[0].sram, state->m_cart[0].sram_max);
+ }
+ // TODO: Eventually sram handlers should point to the allocated cart:sram region!
+ // For now, we only use the region as a placeholder to carry size info...
+// printf("size %x\n", state->m_cart[0].sram);
+ }
+
+ /* adjust size for very large carts */
+ if (state->m_cart[0].mode == SNES_MODE_20 && ((state->m_cart_size - offset) > 0x200000 || state->m_cart[0].sram > (32 * 1024)))
+ state->m_cart[0].small_sram = 1;
+ else
+ state->m_cart[0].small_sram = 0;
+
+ /* Log snes_cart information */
+ snes_cart_log_info(machine, total_blocks, supported_type);
+
+ /* Load SRAM */
+ snes_load_sram(machine);
+
+ /* All done */
+ return IMAGE_INIT_PASS;
+}
+
+static DEVICE_IMAGE_LOAD( sufami_cart )
+{
+ running_machine &machine = image.device().machine();
+ snes_state *state = machine.driver_data<snes_state>();
+ int total_blocks, read_blocks;
+ int st_bios = 0, slot_id = 0;
+ UINT32 offset, st_data_offset = 0;
+ UINT8 *ROM = image.device().machine().root_device().memregion(image.device().tag())->base();
+
+ snes_ram = state->memregion("maincpu")->base();
+
+ if (strcmp(image.device().tag(), ":slot_a") == 0)
+ {
+ st_data_offset = 0x200000;
+ slot_id = 0;
+ }
+
+ if (strcmp(image.device().tag(), ":slot_b") == 0)
+ {
+ st_data_offset = 0x400000;
+ slot_id = 1;
+ }
+
+ if (image.software_entry() == NULL)
+ state->m_cart_size = image.length();
+ else
+ state->m_cart_size = image.get_software_region_length("rom");
+
+ /* Check for a header (512 bytes), and skip it if found */
+ offset = snes_skip_header(image, state->m_cart_size);
+
+ if (image.software_entry() == NULL)
+ {
+ image.fseek(offset, SEEK_SET);
+ image.fread( ROM, state->m_cart_size - offset);
+ }
+ else
+ memcpy(ROM, image.get_software_region("rom") + offset, state->m_cart_size - offset);
+
+ if (SNES_CART_DEBUG) mame_printf_error("size %08X\n", state->m_cart_size - offset);
+
+ /* Detect Sufami Turbo carts */
+ if (!memcmp(ROM, "BANDAI SFC-ADX", 14))
+ {
+ state->m_cart[slot_id].mode = SNES_MODE_ST;
+ if (!memcmp(ROM + 16, "SFC-ADX BACKUP", 14))
+ st_bios = 1;
+ }
+ else
+ {
+ mame_printf_error("This is not a Sufami Turbo data pack.\n");
+ mame_printf_error("This image cannot be loaded in snesst (Use snes or snespal drivers, instead).\n");
+ return IMAGE_INIT_FAIL;
+ }
+
+ if (st_bios == 1)
+ {
+ mame_printf_error("This is the Sufami Turbo BIOS and not a Sufami Turbo data pack.\n");
+ mame_printf_error("This image cannot be loaded in snesst.\n");
+ return IMAGE_INIT_FAIL;
+ }
+
+ /* FIXME: Insert crc check here? */
+
+ /* How many blocks of data are available to be loaded? */
+ total_blocks = (state->m_cart_size - offset) / 0x8000;
+ read_blocks = 0;
+
+ if (SNES_CART_DEBUG)
+ mame_printf_error("blocks %d\n", total_blocks);
+
+ // actually load the cart
+ while (read_blocks < 32 && read_blocks < total_blocks)
+ {
+ /* Loading data */
+ // CART (either A or B)
+ memcpy(&snes_ram[0x008000 + st_data_offset + read_blocks * 0x10000], &ROM[0x000000 + read_blocks * 0x8000], 0x8000);
+ /* Mirroring */
+ memcpy(&snes_ram[0x808000 + st_data_offset + read_blocks * 0x10000], &snes_ram[0x8000 + st_data_offset + (read_blocks * 0x10000)], 0x8000);
+
+ read_blocks++;
+ }
+
+ /* Filling banks up to 0x1f and their mirrors */
+ while (read_blocks % 32)
+ {
+ int j = 0, repeat_blocks;
+ while ((read_blocks % (32 >> j)) && j < 5)
+ j++;
+ repeat_blocks = read_blocks % (32 >> (j - 1));
+
+ memcpy(&snes_ram[st_data_offset + read_blocks * 0x10000], &snes_ram[st_data_offset + (read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000);
+ memcpy(&snes_ram[0x800000 + st_data_offset + read_blocks * 0x10000], &snes_ram[st_data_offset + (read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000);
+ read_blocks += repeat_blocks;
+ }
+
+ sufami_load_sram(machine, image.device().tag());
+
+ state->m_cart[slot_id].slot_in_use = 1; // aknowledge the cart in this slot, for saving sram at exit
+
+ auto_free(image.device().machine(), ROM);
+
+ return IMAGE_INIT_PASS;
+}
+
+static DEVICE_IMAGE_LOAD( bsx_cart )
+{
+ running_machine &machine = image.device().machine();
+ snes_state *state = machine.driver_data<snes_state>();
+ int total_blocks, read_blocks;
+ int has_bsx_slot = 0;
+ UINT32 offset, int_header_offs;
+ UINT8 *ROM = state->memregion("cart")->base();
+
+ if (image.software_entry() == NULL)
+ state->m_cart_size = image.length();
+ else
+ state->m_cart_size = image.get_software_region_length("rom");
+
+ /* Check for a header (512 bytes), and skip it if found */
+ offset = snes_skip_header(image, state->m_cart_size);
+
+ if (image.software_entry() == NULL)
+ {
+ image.fseek(offset, SEEK_SET);
+ image.fread( ROM, state->m_cart_size - offset);
+ }
+ else
+ memcpy(ROM, image.get_software_region("rom") + offset, state->m_cart_size - offset);
+
+ if (SNES_CART_DEBUG) mame_printf_error("size %08X\n", state->m_cart_size - offset);
+
+ /* First, look if the cart is HiROM or LoROM (and set snes_cart accordingly) */
+ int_header_offs = snes_find_hilo_mode(image, ROM, offset, 0);
+
+ // Detect presence of BS-X flash cartridge connector
+ if ((ROM[int_header_offs - 14] == 'Z') && (ROM[int_header_offs - 11] == 'J'))
+ {
+ UINT8 n13 = ROM[int_header_offs - 13];
+ if ((n13 >= 'A' && n13 <= 'Z') || (n13 >= '0' && n13 <= '9'))
+ {
+ if (ROM[int_header_offs + 0x1a] == 0x33 ||
+ (ROM[int_header_offs - 10] == 0x00 && ROM[int_header_offs - 4] == 0x00))
+ {
+ has_bsx_slot = 1;
+ }
+ }
+ }
+
+ // If there is a BS-X connector, detect if it is the Base Cart or a compatible slotted cart
+ if (has_bsx_slot)
+ {
+ if (!memcmp(ROM + int_header_offs, "Satellaview BS-X ", 21))
+ {
+ //BS-X Base Cart
+ state->m_cart[0].mode = SNES_MODE_BSX;
+ // handle RAM
+ }
+ else
+ {
+ state->m_cart[0].mode = (int_header_offs ==0x007fc0) ? SNES_MODE_BSLO : SNES_MODE_BSHI;
+ // handle RAM?
+ }
+ }
+ else
+ {
+ mame_printf_error("This is not a BS-X compatible cart.\n");
+ mame_printf_error("This image cannot be loaded in the first cartslot of snesbsx.\n");
+ return IMAGE_INIT_FAIL;
+ }
+
+
+ /* FIXME: Insert crc check here? */
+
+ /* How many blocks of data are available to be loaded? */
+ total_blocks = (state->m_cart_size - offset) / 0x8000;
+ read_blocks = 0;
+
+ if (SNES_CART_DEBUG) mame_printf_error("blocks %d\n", total_blocks);
+
+ // actually load the cart
+ while (read_blocks < 64 && read_blocks < total_blocks)
+ {
+ /* Loading data */
+ memcpy(&snes_ram[0x008000 + read_blocks * 0x10000], &ROM[0x000000 + read_blocks * 0x8000], 0x8000);
+ /* Mirroring */
+ memcpy(&snes_ram[0x808000 + read_blocks * 0x10000], &snes_ram[0x8000 + (read_blocks * 0x10000)], 0x8000);
+
+ read_blocks++;
+ }
+
+ /* Filling banks up to 0x3f and their mirrors */
+ while (read_blocks % 64)
+ {
+ int j = 0, repeat_blocks;
+ while ((read_blocks % (64 >> j)) && j < 6)
+ j++;
+ repeat_blocks = read_blocks % (64 >> (j - 1));
+
+ memcpy(&snes_ram[read_blocks * 0x10000], &snes_ram[(read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000);
+ memcpy(&snes_ram[0x800000 + read_blocks * 0x10000], &snes_ram[(read_blocks - repeat_blocks) * 0x10000], repeat_blocks * 0x10000);
+ read_blocks += repeat_blocks;
+ }
+
+ return IMAGE_INIT_PASS;
+}
+
+static DEVICE_IMAGE_LOAD( bsx2slot_cart )
+{
+ running_machine &machine = image.device().machine();
+ snes_state *state = machine.driver_data<snes_state>();
+ UINT32 offset, int_header_offs;
+ UINT8 *ROM = state->memregion("flash")->base();
+
+ if (image.software_entry() == NULL)
+ state->m_cart_size = image.length();
+ else
+ state->m_cart_size = image.get_software_region_length("rom");
+
+ /* Check for a header (512 bytes), and skip it if found */
+ offset = snes_skip_header(image, state->m_cart_size);
+
+ if (image.software_entry() == NULL)
+ {
+ image.fseek(offset, SEEK_SET);
+ image.fread( ROM, state->m_cart_size - offset);
+ }
+ else
+ memcpy(ROM, image.get_software_region("rom") + offset, state->m_cart_size - offset);
+
+ if (SNES_CART_DEBUG) mame_printf_error("size %08X\n", state->m_cart_size - offset);
+
+ /* First, look if the cart is HiROM or LoROM (and set snes_cart accordingly) */
+ int_header_offs = snes_find_hilo_mode(image, ROM, offset, 1);
+
+ // Detect presence of BS-X Flash Cart
+ if ((ROM[int_header_offs + 0x13] == 0x00 || ROM[int_header_offs + 0x13] == 0xff) &&
+ ROM[int_header_offs + 0x14] == 0x00)
+ {
+ UINT8 n15 = ROM[int_header_offs + 0x15];
+ if (n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc)
+ {
+ if (ROM[int_header_offs + 0x1a] == 0x33 || ROM[int_header_offs + 0x1a] == 0xff)
+ {
+ // BS-X Flash Cart
+ state->m_cart[1].mode = SNES_MODE_BSX;
+ }
+ }
+ }
+
+ if (state->m_cart[1].mode != SNES_MODE_BSX)
+ {
+ mame_printf_error("This is not a BS-X flash cart.\n");
+ mame_printf_error("This image cannot be loaded in the second cartslot of snesbsx.\n");
+ return IMAGE_INIT_FAIL;
+ }
+
+ // actually load the cart
+ return IMAGE_INIT_PASS;
+}
+
+MACHINE_CONFIG_FRAGMENT( snes_cartslot )
+ MCFG_CARTSLOT_ADD("cart")
+ MCFG_CARTSLOT_EXTENSION_LIST("sfc,smc,fig,swc,bin")
+ MCFG_CARTSLOT_NOT_MANDATORY
+ MCFG_CARTSLOT_INTERFACE("snes_cart")
+ MCFG_CARTSLOT_LOAD(snes_cart)
+ MCFG_SOFTWARE_LIST_ADD("cart_list","snes")
+MACHINE_CONFIG_END
+
+// This (hackily) emulates a SNES unit with a Sufami Turbo Unit cart inserted:
+// hence, the user can mount two data cart in the two slots available on the ST Unit
+MACHINE_CONFIG_FRAGMENT( sufami_cartslot )
+ MCFG_CARTSLOT_ADD("slot_a")
+ MCFG_CARTSLOT_EXTENSION_LIST("st,sfc")
+ MCFG_CARTSLOT_NOT_MANDATORY
+ MCFG_CARTSLOT_INTERFACE("sufami_cart")
+ MCFG_CARTSLOT_LOAD(sufami_cart)
+
+ MCFG_CARTSLOT_ADD("slot_b")
+ MCFG_CARTSLOT_EXTENSION_LIST("st,sfc")
+ MCFG_CARTSLOT_NOT_MANDATORY
+ MCFG_CARTSLOT_INTERFACE("sufami_cart")
+ MCFG_CARTSLOT_LOAD(sufami_cart)
+
+// MCFG_SOFTWARE_LIST_ADD("cart_list","snes")
+MACHINE_CONFIG_END
+
+// This (hackily) emulates a SNES unit where you want to load a BS-X compatible cart:
+// hence, the user can mount a SNES cart in the first slot (either a BS-X BIOS cart, or a
+// BS-X compatible one, e.g. Same Game), and there is a second slot for the 8M data pack
+// (in a real SNES this would have been inserted in the smaller slot on the cart itself)
+MACHINE_CONFIG_FRAGMENT( bsx_cartslot )
+ MCFG_CARTSLOT_ADD("cart")
+ MCFG_CARTSLOT_EXTENSION_LIST("sfc,smc,fig,swc,bin")
+ MCFG_CARTSLOT_NOT_MANDATORY
+ MCFG_CARTSLOT_INTERFACE("snes_cart")
+ MCFG_CARTSLOT_LOAD(bsx_cart)
+
+ MCFG_CARTSLOT_ADD("slot2")
+ MCFG_CARTSLOT_EXTENSION_LIST("bs,sfc")
+ MCFG_CARTSLOT_NOT_MANDATORY
+ MCFG_CARTSLOT_INTERFACE("bsx_cart")
+ MCFG_CARTSLOT_LOAD(bsx2slot_cart)
+
+// MCFG_SOFTWARE_LIST_ADD("cart_list","snes")
+MACHINE_CONFIG_END
+
+DRIVER_INIT_MEMBER(snes_state,snes_mess)
+{
+ snes_ram = machine().root_device().memregion("maincpu")->base();
+ memset(snes_ram, 0, 0x1000000);
+}
+
+DRIVER_INIT_MEMBER(snes_state,snesst)
+{
+ UINT8 *STBIOS = memregion("sufami")->base();
+ int i, j;
+
+ m_cart[0].slot_in_use = 0;
+ m_cart[1].slot_in_use = 0;
+
+ DRIVER_INIT_CALL(snes_mess);
+
+ // the Base ST cart consists of 8 * 0x8000 block which have to be loaded (and mirrored)
+ // at 0x00-0x1f:0x8000-0xffff and 0x80-0x9f:0x8000-0xffff
+ for (i = 0; i < 8; i++)
+ {
+ /* Loading data */
+ memcpy(&snes_ram[0x008000 + i * 0x10000], &STBIOS[0x000000 + i * 0x8000], 0x8000);
+ /* Mirroring */
+ memcpy(&snes_ram[0x808000 + i * 0x10000], &snes_ram[0x8000 + (i * 0x10000)], 0x8000);
+
+ /* Additional mirrors (to fill snes_ram up to 0x1fffff) */
+ for (j = 1; j < 4; j++)
+ {
+ memcpy(&snes_ram[0x008000 + i * 0x10000 + j * 0x80000], &snes_ram[0x8000 + (i * 0x10000)], 0x8000);
+ memcpy(&snes_ram[0x808000 + i * 0x10000 + j * 0x80000], &snes_ram[0x8000 + (i * 0x10000)], 0x8000);
+ }
+ }
+
+}
diff --git a/src/mess/machine/snescart.h b/src/mess/machine/snescart.h
new file mode 100644
index 00000000000..085c8c0e78a
--- /dev/null
+++ b/src/mess/machine/snescart.h
@@ -0,0 +1,19 @@
+/*
+ snescart.h
+
+*/
+
+#ifndef _SNESCART_H
+#define _SNESCART_H
+
+#include "imagedev/cartslot.h"
+
+MACHINE_START( snes_mess );
+MACHINE_START( snesst );
+
+MACHINE_CONFIG_EXTERN( snes_cartslot );
+MACHINE_CONFIG_EXTERN( sufami_cartslot );
+MACHINE_CONFIG_EXTERN( bsx_cartslot );
+
+#endif /* _SNESCART_H */
+
diff --git a/src/mess/machine/softbox.c b/src/mess/machine/softbox.c
new file mode 100644
index 00000000000..0aa67eb3260
--- /dev/null
+++ b/src/mess/machine/softbox.c
@@ -0,0 +1,203 @@
+/**********************************************************************
+
+ SSE SoftBox emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "softbox.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define Z80_TAG "z80"
+#define I8251_TAG "i8251"
+#define I8255_0_TAG "ic17"
+#define I8255_1_TAG "ic16"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type SOFTBOX = &device_creator<softbox_device>;
+
+
+//-------------------------------------------------
+// ROM( softbox )
+//-------------------------------------------------
+
+ROM_START( softbox )
+ ROM_REGION( 0x1000, Z80_TAG, 0 )
+ ROM_LOAD( "379.ic3", 0x000, 0x800, CRC(7b5a737c) SHA1(2348590884b026b7647f6864af8c9ba1c6f8746b) ) // Revision 27-Oct-81
+ ROM_LOAD( "380.ic4", 0x800, 0x800, CRC(65a13029) SHA1(46de02e6f04be298047efeb412e00a5714dc21b3) ) // Revision 27-Oct-81
+ ROM_LOAD( "389.ic3", 0x000, 0x800, CRC(d66e581a) SHA1(2403e25c140c41b0e6d6975d39c9cd9d6f335048) ) // Revision 09-June-1983
+ ROM_LOAD( "390.ic4", 0x800, 0x800, CRC(abe6cb30) SHA1(4b26d5db36f828e01268f718799f145d09b449ad) ) // Revision 09-June-1983
+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, 0x0fff) AM_ROM AM_REGION(Z80_TAG, 0)
+ AM_RANGE(0x1000, 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(0x, 0x) AM_DEVREADWRITE(I8251_TAG, i8251_device, data_r, data_w)
+ //AM_RANGE(0x, 0x) AM_DEVREADWRITE(I8251_TAG, i8251_device, status_r, control_w)
+ //AM_RANGE(0x, 0x) AM_DEVREADWRITE(I8255_0_TAG, i8255_device, read, write)
+ //AM_RANGE(0x, 0x) AM_DEVREADWRITE(I8255_1_TAG, i8255_device, read, write)
+ADDRESS_MAP_END
+
+
+//-------------------------------------------------
+// I8255A_INTERFACE( ppi0_intf )
+//-------------------------------------------------
+
+static const i8251_interface usart_intf =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// I8255A_INTERFACE( ppi0_intf )
+//-------------------------------------------------
+
+static I8255A_INTERFACE( ppi0_intf )
+{
+ DEVCB_NULL, // Port A read
+ DEVCB_NULL, // Port A write
+ DEVCB_NULL, // Port B read
+ DEVCB_NULL, // Port B write
+ DEVCB_NULL, // Port C read
+ DEVCB_NULL // Port C write
+};
+
+
+//-------------------------------------------------
+// I8255A_INTERFACE( ppi1_intf )
+//-------------------------------------------------
+
+static I8255A_INTERFACE( ppi1_intf )
+{
+ DEVCB_NULL, // Port A read
+ DEVCB_NULL, // Port A write
+ DEVCB_NULL, // Port B read
+ DEVCB_NULL, // Port B write
+ DEVCB_NULL, // Port C read
+ DEVCB_NULL // Port C write
+};
+
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( softbox )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( softbox )
+ MCFG_CPU_ADD(Z80_TAG, Z80, 4000000) // ???
+ MCFG_CPU_PROGRAM_MAP(softbox_mem)
+ MCFG_CPU_IO_MAP(softbox_io)
+
+ MCFG_I8251_ADD(I8251_TAG, usart_intf)
+ MCFG_I8255A_ADD(I8255_0_TAG, ppi0_intf)
+ MCFG_I8255A_ADD(I8255_1_TAG, ppi1_intf)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor softbox_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_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, "SoftBox", tag, owner, clock),
+ device_ieee488_interface(mconfig, *this),
+ m_maincpu(*this, Z80_TAG)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void softbox_device::device_start()
+{
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void softbox_device::device_reset()
+{
+}
+
+
+//-------------------------------------------------
+// ieee488_atn - attention
+//-------------------------------------------------
+
+void softbox_device::ieee488_atn(int state)
+{
+}
+
+
+//-------------------------------------------------
+// ieee488_ifc - interface clear
+//-------------------------------------------------
+
+void softbox_device::ieee488_ifc(int state)
+{
+}
diff --git a/src/mess/machine/softbox.h b/src/mess/machine/softbox.h
new file mode 100644
index 00000000000..bdbf093b002
--- /dev/null
+++ b/src/mess/machine/softbox.h
@@ -0,0 +1,63 @@
+/**********************************************************************
+
+ SSE SoftBox emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __SOFTBOX__
+#define __SOFTBOX__
+
+
+#include "emu.h"
+#include "cpu/z80/z80.h"
+#include "machine/i8251.h"
+#include "machine/i8255.h"
+#include "machine/ieee488.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;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "softbox"; }
+
+ // device_ieee488_interface overrides
+ void ieee488_atn(int state);
+ void ieee488_ifc(int state);
+
+private:
+ required_device<cpu_device> m_maincpu;
+};
+
+
+// device type definition
+extern const device_type SOFTBOX;
+
+
+
+#endif
diff --git a/src/mess/machine/sorcerer.c b/src/mess/machine/sorcerer.c
new file mode 100644
index 00000000000..91b1a457cc0
--- /dev/null
+++ b/src/mess/machine/sorcerer.c
@@ -0,0 +1,426 @@
+/******************************************************************************
+
+ Exidy Sorcerer machine functions
+
+*******************************************************************************/
+
+#include "includes/sorcerer.h"
+
+#if SORCERER_USING_RS232
+
+/* The serial code (which was never connected to the outside) is disabled for now. */
+
+/* timer for sorcerer serial chip transmit and receive */
+
+static TIMER_CALLBACK(sorcerer_serial_tc)
+{
+ sorcerer_state *state = machine.driver_data<sorcerer_state>();
+ /* if rs232 is enabled, uart is connected to clock defined by bit6 of port fe.
+ Transmit and receive clocks are connected to the same clock */
+
+ /* if rs232 is disabled, receive clock is linked to cassette hardware */
+ if (state->m_fe & 0x80)
+ {
+ /* connect to rs232 */
+ }
+}
+#endif
+
+
+/* timer to read cassette waveforms */
+
+
+static cassette_image_device *cassette_device_image(running_machine &machine)
+{
+ sorcerer_state *state = machine.driver_data<sorcerer_state>();
+ if (state->m_fe & 0x20)
+ return machine.device<cassette_image_device>(CASSETTE2_TAG);
+ else
+ return machine.device<cassette_image_device>(CASSETTE_TAG);
+}
+
+
+
+static TIMER_CALLBACK(sorcerer_cassette_tc)
+{
+ sorcerer_state *state = machine.driver_data<sorcerer_state>();
+ UINT8 cass_ws = 0;
+ switch (state->m_fe & 0xc0) /*/ bit 7 low indicates cassette */
+ {
+ case 0x00: /* Cassette 300 baud */
+
+ /* loading a tape - this is basically the same as the super80.
+ We convert the 1200/2400 Hz signal to a 0 or 1, and send it to the uart. */
+
+ state->m_cass_data.input.length++;
+
+ cass_ws = ((cassette_device_image(machine))->input() > +0.02) ? 1 : 0;
+
+ if (cass_ws != state->m_cass_data.input.level)
+ {
+ state->m_cass_data.input.level = cass_ws;
+ state->m_cass_data.input.bit = ((state->m_cass_data.input.length < 0x6) || (state->m_cass_data.input.length > 0x20)) ? 1 : 0;
+ state->m_cass_data.input.length = 0;
+ ay31015_set_input_pin( state->m_uart, AY31015_SI, state->m_cass_data.input.bit );
+ }
+
+ /* saving a tape - convert the serial stream from the uart, into 1200 and 2400 Hz frequencies.
+ Synchronisation of the frequency pulses to the uart is extremely important. */
+
+ state->m_cass_data.output.length++;
+ if (!(state->m_cass_data.output.length & 0x1f))
+ {
+ cass_ws = ay31015_get_output_pin( state->m_uart, AY31015_SO );
+ if (cass_ws != state->m_cass_data.output.bit)
+ {
+ state->m_cass_data.output.bit = cass_ws;
+ state->m_cass_data.output.length = 0;
+ }
+ }
+
+ if (!(state->m_cass_data.output.length & 3))
+ {
+ if (!((state->m_cass_data.output.bit == 0) && (state->m_cass_data.output.length & 4)))
+ {
+ state->m_cass_data.output.level ^= 1; // toggle output state, except on 2nd half of low bit
+ cassette_device_image(machine)->output(state->m_cass_data.output.level ? -1.0 : +1.0);
+ }
+ }
+ return;
+
+ case 0x40: /* Cassette 1200 baud */
+ /* loading a tape */
+ state->m_cass_data.input.length++;
+
+ cass_ws = ((cassette_device_image(machine))->input() > +0.02) ? 1 : 0;
+
+ if (cass_ws != state->m_cass_data.input.level || state->m_cass_data.input.length == 10)
+ {
+ state->m_cass_data.input.bit = ((state->m_cass_data.input.length < 10) || (state->m_cass_data.input.length > 0x20)) ? 1 : 0;
+ if ( cass_ws != state->m_cass_data.input.level )
+ {
+ state->m_cass_data.input.length = 0;
+ state->m_cass_data.input.level = cass_ws;
+ }
+ ay31015_set_input_pin( state->m_uart, AY31015_SI, state->m_cass_data.input.bit );
+ }
+
+ /* saving a tape - convert the serial stream from the uart, into 600 and 1200 Hz frequencies. */
+
+ state->m_cass_data.output.length++;
+ if (!(state->m_cass_data.output.length & 7))
+ {
+ cass_ws = ay31015_get_output_pin( state->m_uart, AY31015_SO );
+ if (cass_ws != state->m_cass_data.output.bit)
+ {
+ state->m_cass_data.output.bit = cass_ws;
+ state->m_cass_data.output.length = 0;
+ }
+ }
+
+ if (!(state->m_cass_data.output.length & 7))
+ {
+ if (!((state->m_cass_data.output.bit == 0) && (state->m_cass_data.output.length & 8)))
+ {
+ state->m_cass_data.output.level ^= 1; // toggle output state, except on 2nd half of low bit
+ cassette_device_image(machine)->output(state->m_cass_data.output.level ? -1.0 : +1.0);
+ }
+ }
+ return;
+ }
+}
+
+
+/* after the first 4 bytes have been read from ROM, switch the ram back in */
+static TIMER_CALLBACK( sorcerer_reset )
+{
+ sorcerer_state *state = machine.driver_data<sorcerer_state>();
+ state->membank("boot")->set_entry(0);
+}
+
+WRITE8_MEMBER(sorcerer_state::sorcerer_fc_w)
+{
+ ay31015_set_transmit_data( m_uart, data );
+}
+
+
+WRITE8_MEMBER(sorcerer_state::sorcerer_fd_w)
+{
+ /* Translate data to control signals */
+
+ ay31015_set_input_pin( m_uart, AY31015_CS, 0 );
+ ay31015_set_input_pin( m_uart, AY31015_NB1, data & 1);
+ ay31015_set_input_pin( m_uart, AY31015_NB2, (BIT(data, 1)) ? 1 : 0 );
+ ay31015_set_input_pin( m_uart, AY31015_TSB, (BIT(data, 2)) ? 1 : 0 );
+ ay31015_set_input_pin( m_uart, AY31015_EPS, (BIT(data, 3)) ? 1 : 0 );
+ ay31015_set_input_pin( m_uart, AY31015_NP, (BIT(data, 4)) ? 1 : 0 );
+ ay31015_set_input_pin( m_uart, AY31015_CS, 1 );
+}
+
+WRITE8_MEMBER(sorcerer_state::sorcerer_fe_w)
+{
+ UINT8 changed_bits = (m_fe ^ data) & 0xf0;
+ m_fe = data;
+
+ /* bits 0..3 */
+ m_keyboard_line = data & 0x0f;
+
+ if (!changed_bits) return;
+
+ /* bits 4..5 */
+ /* does user want to hear the sound? */
+
+ if (!BIT(data, 7)) // cassette operations
+ {
+#if SORCERER_USING_RS232
+ m_serial_timer->adjust(attotime::zero);
+#endif
+
+ bool sound = BIT(m_iop_config->read(), 3);
+
+ m_cass1->change_state(
+ (BIT(data,4) & sound) ? CASSETTE_SPEAKER_ENABLED : CASSETTE_SPEAKER_MUTED, CASSETTE_MASK_SPEAKER);
+
+ m_cass2->change_state(
+ (BIT(data,5) & sound) ? CASSETTE_SPEAKER_ENABLED : CASSETTE_SPEAKER_MUTED, CASSETTE_MASK_SPEAKER);
+
+ /* cassette 1 motor */
+ m_cass1->change_state(
+ (BIT(data,4)) ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR);
+
+ /* cassette 2 motor */
+ m_cass2->change_state(
+ (BIT(data,5)) ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR);
+
+ if (data & 0x30)
+ m_cassette_timer->adjust(attotime::zero, 0, attotime::from_hz(19200));
+ else
+ m_cassette_timer->adjust(attotime::zero);
+ }
+#if SORCERER_USING_RS232
+ else
+ {
+ m_serial_timer->adjust(attotime::zero, 0, attotime::from_hz(19200));
+ m_cassette_timer->adjust(attotime::zero);
+ }
+#endif
+
+ // bit 6 baud rate */
+ if (BIT(changed_bits, 6))
+ {
+ ay31015_set_receiver_clock( m_uart, (BIT(data, 6)) ? 19200.0 : 4800.0);
+ ay31015_set_transmitter_clock( m_uart, (BIT(data, 6)) ? 19200.0 : 4800.0);
+ }
+}
+
+WRITE8_MEMBER(sorcerer_state::sorcerer_ff_w)
+{
+ /* reading the config switch */
+ switch (m_iop_config->read() & 0x06)
+ {
+ case 0: /* speaker */
+ m_dac->write_unsigned8(data);
+ break;
+
+ case 2: /* Centronics 7-bit printer */
+ /* bit 7 = strobe, bit 6..0 = data */
+ m_centronics->strobe_w((~data>>7) & 0x01);
+ m_centronics->write(space, 0, data & 0x7f);
+ break;
+
+ case 4: /* 8-bit parallel output */
+ /* hardware strobe driven from port select, bit 7..0 = data */
+ m_centronics->strobe_w(1);
+ m_centronics->write(space, 0, data);
+ m_centronics->strobe_w(0);
+ break;
+ }
+}
+
+READ8_MEMBER(sorcerer_state::sorcerer_fc_r)
+{
+ UINT8 data = ay31015_get_received_data( m_uart );
+ ay31015_set_input_pin( m_uart, AY31015_RDAV, 0 );
+ ay31015_set_input_pin( m_uart, AY31015_RDAV, 1 );
+ return data;
+}
+
+READ8_MEMBER(sorcerer_state::sorcerer_fd_r)
+{
+ /* set unused bits high */
+ UINT8 data = 0xe0;
+
+ ay31015_set_input_pin( m_uart, AY31015_SWE, 0 );
+ data |= ay31015_get_output_pin( m_uart, AY31015_TBMT ) ? 0x01 : 0;
+ data |= ay31015_get_output_pin( m_uart, AY31015_DAV ) ? 0x02 : 0;
+ data |= ay31015_get_output_pin( m_uart, AY31015_OR ) ? 0x04 : 0;
+ data |= ay31015_get_output_pin( m_uart, AY31015_FE ) ? 0x08 : 0;
+ data |= ay31015_get_output_pin( m_uart, AY31015_PE ) ? 0x10 : 0;
+ ay31015_set_input_pin( m_uart, AY31015_SWE, 1 );
+
+ return data;
+}
+
+READ8_MEMBER(sorcerer_state::sorcerer_fe_r)
+{
+ /* bits 6..7
+ - hardware handshakes from user port
+ - not emulated
+ - tied high, allowing PARIN and PAROUT bios routines to run */
+
+ UINT8 data = 0xc0;
+ char kbdrow[6];
+
+ sprintf(kbdrow,"X%X",m_keyboard_line);
+
+ /* bit 5 - vsync */
+ data |= m_iop_vs->read();
+
+ /* bits 4..0 - keyboard data */
+ data |= ioport(kbdrow)->read();
+
+ return data;
+}
+
+READ8_MEMBER(sorcerer_state::sorcerer_ff_r)
+{
+ /* The use of the parallel port as a general purpose port is not emulated.
+ Currently the only use is to read the printer status in the Centronics CENDRV bios routine.
+ This uses bit 7. The other bits have been set high (=nothing plugged in).
+ This fixes those games that use a joystick. */
+
+ UINT8 data=0x7f;
+
+ /* bit 7 = printer busy 0 = printer is not busy */
+
+ data |= m_centronics->busy_r() << 7;
+
+ return data;
+}
+
+/******************************************************************************
+ Snapshot Handling
+******************************************************************************/
+
+SNAPSHOT_LOAD(sorcerer)
+{
+ device_t *cpu = image.device().machine().device("maincpu");
+ UINT8 *RAM = image.device().machine().root_device().memregion(cpu->tag())->base();
+ address_space *space = cpu->memory().space(AS_PROGRAM);
+ UINT8 header[28];
+ unsigned char s_byte;
+
+ /* check size */
+ if (snapshot_size != 0x1001c)
+ {
+ image.seterror(IMAGE_ERROR_INVALIDIMAGE, "Snapshot must be 65564 bytes");
+ image.message("Snapshot must be 65564 bytes");
+ return IMAGE_INIT_FAIL;
+ }
+
+ /* get the header */
+ image.fread( &header, sizeof(header));
+
+ /* write it to ram */
+ for (int i = 0; i < 0xc000; i++)
+ {
+ image.fread( &s_byte, 1);
+ space->write_byte(i, s_byte);
+ }
+ image.fread( RAM+0xc000, 0x4000);
+
+ /* patch CPU registers */
+ cpu_set_reg(cpu, Z80_I, header[0]);
+ cpu_set_reg(cpu, Z80_HL2, header[1] | (header[2] << 8));
+ cpu_set_reg(cpu, Z80_DE2, header[3] | (header[4] << 8));
+ cpu_set_reg(cpu, Z80_BC2, header[5] | (header[6] << 8));
+ cpu_set_reg(cpu, Z80_AF2, header[7] | (header[8] << 8));
+ cpu_set_reg(cpu, Z80_HL, header[9] | (header[10] << 8));
+ cpu_set_reg(cpu, Z80_DE, header[11] | (header[12] << 8));
+ cpu_set_reg(cpu, Z80_BC, header[13] | (header[14] << 8));
+ cpu_set_reg(cpu, Z80_IY, header[15] | (header[16] << 8));
+ cpu_set_reg(cpu, Z80_IX, header[17] | (header[18] << 8));
+ cpu_set_reg(cpu, Z80_IFF1, header[19]&2 ? 1 : 0);
+ cpu_set_reg(cpu, Z80_IFF2, header[19]&4 ? 1 : 0);
+ cpu_set_reg(cpu, Z80_R, header[20]);
+ cpu_set_reg(cpu, Z80_AF, header[21] | (header[22] << 8));
+ cpu_set_reg(cpu, STATE_GENSP, header[23] | (header[24] << 8));
+ cpu_set_reg(cpu, Z80_IM, header[25]);
+ cpu_set_reg(cpu, STATE_GENPC, header[26] | (header[27] << 8));
+
+ return IMAGE_INIT_PASS;
+}
+
+MACHINE_START( sorcerer )
+{
+ sorcerer_state *state = machine.driver_data<sorcerer_state>();
+ state->m_cassette_timer = machine.scheduler().timer_alloc(FUNC(sorcerer_cassette_tc));
+#if SORCERER_USING_RS232
+ state->m_serial_timer = machine.scheduler().timer_alloc(FUNC(sorcerer_serial_tc));
+#endif
+
+ UINT16 endmem = 0xbfff;
+
+ address_space *space = state->m_maincpu->memory().space(AS_PROGRAM);
+ /* configure RAM */
+ switch (state->m_ram->size())
+ {
+ case 8*1024:
+ space->unmap_readwrite(0x2000, endmem);
+ break;
+
+ case 16*1024:
+ space->unmap_readwrite(0x4000, endmem);
+ break;
+
+ case 32*1024:
+ space->unmap_readwrite(0x8000, endmem);
+ break;
+ }
+}
+
+MACHINE_START( sorcererd )
+{
+ sorcerer_state *state = machine.driver_data<sorcerer_state>();
+ state->m_cassette_timer = machine.scheduler().timer_alloc(FUNC(sorcerer_cassette_tc));
+#if SORCERER_USING_RS232
+ state->m_serial_timer = machine.scheduler().timer_alloc(FUNC(sorcerer_serial_tc));
+#endif
+
+ UINT16 endmem = 0xbbff;
+
+ address_space *space = state->m_maincpu->memory().space(AS_PROGRAM);
+ /* configure RAM */
+ switch (state->m_ram->size())
+ {
+ case 8*1024:
+ space->unmap_readwrite(0x2000, endmem);
+ break;
+
+ case 16*1024:
+ space->unmap_readwrite(0x4000, endmem);
+ break;
+
+ case 32*1024:
+ space->unmap_readwrite(0x8000, endmem);
+ break;
+ }
+}
+
+MACHINE_RESET( sorcerer )
+{
+ sorcerer_state *state = machine.driver_data<sorcerer_state>();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ /* Initialize cassette interface */
+ state->m_cass_data.output.length = 0;
+ state->m_cass_data.output.level = 1;
+ state->m_cass_data.input.length = 0;
+ state->m_cass_data.input.bit = 1;
+
+ state->m_fe = 0xff;
+ state->sorcerer_fe_w(*space, 0, 0, 0xff);
+
+ state->membank("boot")->set_entry(1);
+ machine.scheduler().timer_set(attotime::from_usec(10), FUNC(sorcerer_reset));
+}
diff --git a/src/mess/machine/southbridge.c b/src/mess/machine/southbridge.c
new file mode 100644
index 00000000000..865d54bcc74
--- /dev/null
+++ b/src/mess/machine/southbridge.c
@@ -0,0 +1,479 @@
+/***************************************************************************
+
+ Southbridge implementation
+
+***************************************************************************/
+
+#include "emu.h"
+#include "cpu/i386/i386.h"
+#include "machine/southbridge.h"
+#include "machine/pc_keyboards.h"
+#include "machine/8237dma.h"
+
+const struct pic8259_interface at_pic8259_master_config =
+{
+ DEVCB_CPU_INPUT_LINE(":maincpu", 0),
+ DEVCB_LINE_VCC,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, southbridge_device, get_slave_ack)
+};
+
+const struct pic8259_interface at_pic8259_slave_config =
+{
+ DEVCB_DEVICE_LINE("pic8259_master", pic8259_ir2_w),
+ DEVCB_LINE_GND,
+ DEVCB_NULL
+};
+
+const struct pit8253_config at_pit8254_config =
+{
+ {
+ {
+ 4772720/4, /* heartbeat IRQ */
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, southbridge_device, at_pit8254_out0_changed)
+ }, {
+ 4772720/4, /* dram refresh */
+ DEVCB_NULL,
+ DEVCB_NULL
+ }, {
+ 4772720/4, /* pio port c pin 4, and speaker polling enough */
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, southbridge_device, at_pit8254_out2_changed)
+ }
+ }
+};
+
+I8237_INTERFACE( at_dma8237_1_config )
+{
+ DEVCB_DEVICE_LINE("dma8237_2",i8237_dreq0_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, southbridge_device, at_dma8237_out_eop),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, southbridge_device, pc_dma_read_byte),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, southbridge_device, pc_dma_write_byte),
+ { DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, southbridge_device, pc_dma8237_0_dack_r), DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, southbridge_device, pc_dma8237_1_dack_r), DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, southbridge_device, pc_dma8237_2_dack_r), DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, southbridge_device, pc_dma8237_3_dack_r) },
+ { DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, southbridge_device, pc_dma8237_0_dack_w), DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, southbridge_device, pc_dma8237_1_dack_w), DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, southbridge_device, pc_dma8237_2_dack_w), DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, southbridge_device, pc_dma8237_3_dack_w) },
+ { DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, southbridge_device, pc_dack0_w), DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, southbridge_device, pc_dack1_w), DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, southbridge_device, pc_dack2_w), DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, southbridge_device, pc_dack3_w) }
+};
+
+
+I8237_INTERFACE( at_dma8237_2_config )
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, southbridge_device, pc_dma_hrq_changed),
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, southbridge_device, pc_dma_read_word),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, southbridge_device, pc_dma_write_word),
+ { DEVCB_NULL, DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, southbridge_device, pc_dma8237_5_dack_r), DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, southbridge_device, pc_dma8237_6_dack_r), DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, southbridge_device, pc_dma8237_7_dack_r) },
+ { DEVCB_NULL, DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, southbridge_device, pc_dma8237_5_dack_w), DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, southbridge_device, pc_dma8237_6_dack_w), DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, southbridge_device, pc_dma8237_7_dack_w) },
+ { DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, southbridge_device, pc_dack4_w), DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, southbridge_device, pc_dack5_w), DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, southbridge_device, pc_dack6_w), DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, southbridge_device, pc_dack7_w) }
+};
+
+const struct mc146818_interface at_mc146818_config =
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, southbridge_device, at_mc146818_irq)
+};
+
+static const at_keyboard_controller_interface keyboard_controller_intf =
+{
+ DEVCB_CPU_INPUT_LINE(":maincpu", INPUT_LINE_RESET),
+ DEVCB_CPU_INPUT_LINE(":maincpu", INPUT_LINE_A20),
+ DEVCB_DEVICE_LINE("pic8259_master", pic8259_ir1_w),
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER("pc_kbdc", pc_kbdc_device, clock_write_from_mb),
+ DEVCB_DEVICE_LINE_MEMBER("pc_kbdc", pc_kbdc_device, data_write_from_mb)
+};
+
+static const pc_kbdc_interface pc_kbdc_intf =
+{
+ DEVCB_DEVICE_LINE_MEMBER("keybc", at_keyboard_controller_device, keyboard_clock_w),
+ DEVCB_DEVICE_LINE_MEMBER("keybc", at_keyboard_controller_device, keyboard_data_w)
+};
+
+static const isa16bus_interface isabus_intf =
+{
+ // interrupts
+ DEVCB_DEVICE_LINE("pic8259_slave", pic8259_ir2_w), // in place of irq 2 on at irq 9 is used
+ DEVCB_DEVICE_LINE("pic8259_master", pic8259_ir3_w),
+ DEVCB_DEVICE_LINE("pic8259_master", pic8259_ir4_w),
+ DEVCB_DEVICE_LINE("pic8259_master", pic8259_ir5_w),
+ DEVCB_DEVICE_LINE("pic8259_master", pic8259_ir6_w),
+ DEVCB_DEVICE_LINE("pic8259_master", pic8259_ir7_w),
+
+ DEVCB_DEVICE_LINE("pic8259_slave", pic8259_ir3_w),
+ DEVCB_DEVICE_LINE("pic8259_slave", pic8259_ir4_w),
+ DEVCB_DEVICE_LINE("pic8259_slave", pic8259_ir5_w),
+ DEVCB_DEVICE_LINE("pic8259_slave", pic8259_ir6_w),
+ DEVCB_DEVICE_LINE("pic8259_slave", pic8259_ir7_w),
+
+ // dma request
+ DEVCB_DEVICE_LINE("dma8237_1", i8237_dreq0_w),
+ DEVCB_DEVICE_LINE("dma8237_1", i8237_dreq1_w),
+ DEVCB_DEVICE_LINE("dma8237_1", i8237_dreq2_w),
+ DEVCB_DEVICE_LINE("dma8237_1", i8237_dreq3_w),
+
+ DEVCB_DEVICE_LINE("dma8237_2", i8237_dreq1_w),
+ DEVCB_DEVICE_LINE("dma8237_2", i8237_dreq2_w),
+ DEVCB_DEVICE_LINE("dma8237_2", i8237_dreq3_w),
+};
+
+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("ide", ISA16_IDE)
+ SLOT_INTERFACE("ide_cd", ISA16_IDE_CD)
+SLOT_INTERFACE_END
+
+static MACHINE_CONFIG_FRAGMENT( southbridge )
+ MCFG_PIT8254_ADD( "pit8254", at_pit8254_config )
+
+ MCFG_I8237_ADD( "dma8237_1", XTAL_14_31818MHz/3, at_dma8237_1_config )
+ MCFG_I8237_ADD( "dma8237_2", XTAL_14_31818MHz/3, at_dma8237_2_config )
+
+ MCFG_PIC8259_ADD( "pic8259_master", at_pic8259_master_config )
+ MCFG_PIC8259_ADD( "pic8259_slave", at_pic8259_slave_config )
+
+ MCFG_AT_KEYBOARD_CONTROLLER_ADD("keybc", XTAL_12MHz, keyboard_controller_intf)
+ MCFG_PC_KBDC_ADD("pc_kbdc", pc_kbdc_intf)
+ MCFG_PC_KBDC_SLOT_ADD("pc_kbdc", "kbd", pc_at_keyboards, STR_KBD_MICROSOFT_NATURAL, NULL)
+
+ MCFG_MC146818_IRQ_ADD( "rtc", MC146818_STANDARD, at_mc146818_config )
+
+ /* sound hardware */
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+ MCFG_SOUND_ADD(SPEAKER_TAG, SPEAKER_SOUND, 0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+
+ MCFG_ISA16_BUS_ADD("isabus", ":maincpu", isabus_intf)
+ // on board devices
+ MCFG_ISA16_SLOT_ADD("isabus","board1", pc_isa_onboard, "fdcsmc", NULL, true)
+ MCFG_ISA16_SLOT_ADD("isabus","board2", pc_isa_onboard, "comat", NULL, true)
+ MCFG_ISA16_SLOT_ADD("isabus","board3", pc_isa_onboard, "ide", NULL, true)
+ MCFG_ISA16_SLOT_ADD("isabus","board4", pc_isa_onboard, "lpt", NULL, 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)
+ : device_t(mconfig, type, name, tag, owner, clock),
+ 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_TAG),
+ m_mc146818(*this, "rtc"),
+ m_pc_kbdc(*this, "pc_kbdc")
+{
+}
+/**********************************************************
+ *
+ * Init functions
+ *
+ **********************************************************/
+/*
+IRQ_CALLBACK(southbridge_device::at_irq_callback)
+{
+ device_t *pic = device->machine().device(":pcibus:1:i82371ab:pic8259_master");
+ //return pic8259_acknowledge(m_pic8259_master);
+ return pic8259_acknowledge(pic);
+}
+*/
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void southbridge_device::device_start()
+{
+ address_space* spaceio = machine().device(":maincpu")->memory().space(AS_IO);
+
+ spaceio->install_legacy_readwrite_handler(*m_dma8237_1, 0x0000, 0x001f, FUNC(i8237_r), FUNC(i8237_w), 0xffffffff);
+ spaceio->install_legacy_readwrite_handler(*m_pic8259_master, 0x0020, 0x003f, FUNC(pic8259_r), FUNC(pic8259_w), 0xffffffff);
+ spaceio->install_legacy_readwrite_handler(*m_pit8254, 0x0040, 0x005f, FUNC(pit8253_r), FUNC(pit8253_w), 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(mc146818_device::read),&(*m_mc146818)), write8_delegate(FUNC(mc146818_device::write),&(*m_mc146818)), 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_legacy_readwrite_handler(*m_pic8259_slave, 0x00a0, 0x00bf, FUNC(pic8259_r), FUNC(pic8259_w), 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->nop_readwrite(0x00e0, 0x00ef);
+
+
+ m_at_offset1 = 0xff;
+ //device_set_irq_callback(machine().device(":maincpu"), at_irq_callback);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void southbridge_device::device_reset()
+{
+ m_poll_delay = 4;
+ m_at_spkrdata = 0;
+ m_at_speaker_input = 0;
+}
+
+
+/*************************************************************
+ *
+ * pic8259 configuration
+ *
+ *************************************************************/
+READ8_MEMBER( southbridge_device::get_slave_ack )
+{
+ if (offset==2) // IRQ = 2
+ return pic8259_acknowledge(m_pic8259_slave);
+
+ return 0x00;
+}
+
+/*************************************************************************
+ *
+ * PC Speaker related
+ *
+ *************************************************************************/
+
+void southbridge_device::at_speaker_set_spkrdata(UINT8 data)
+{
+ m_at_spkrdata = data ? 1 : 0;
+ speaker_level_w( m_speaker, m_at_spkrdata & m_at_speaker_input);
+}
+
+void southbridge_device::at_speaker_set_input(UINT8 data)
+{
+ m_at_speaker_input = data ? 1 : 0;
+ speaker_level_w( m_speaker, m_at_spkrdata & m_at_speaker_input);
+}
+
+
+
+/*************************************************************
+ *
+ * pit8254 configuration
+ *
+ *************************************************************/
+
+WRITE_LINE_MEMBER( southbridge_device::at_pit8254_out0_changed )
+{
+ if (m_pic8259_master)
+ pic8259_ir0_w(m_pic8259_master, state);
+}
+
+
+WRITE_LINE_MEMBER( southbridge_device::at_pit8254_out2_changed )
+{
+ at_speaker_set_input( state );
+}
+
+/*************************************************************************
+ *
+ * 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 )
+{
+ device_set_input_line(m_maincpu, INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE);
+
+ /* Assert HLDA */
+ i8237_hlda_w( m_dma8237_2, state );
+}
+
+READ8_MEMBER(southbridge_device::pc_dma_read_byte)
+{
+ UINT8 result;
+ offs_t page_offset = (((offs_t) m_dma_offset[0][m_dma_channel]) << 16) & 0xFF0000;
+
+ result = space.read_byte(page_offset + offset);
+ return result;
+}
+
+
+WRITE8_MEMBER(southbridge_device::pc_dma_write_byte)
+{
+ offs_t page_offset = (((offs_t) m_dma_offset[0][m_dma_channel]) << 16) & 0xFF0000;
+
+ space.write_byte(page_offset + offset, data);
+}
+
+
+READ8_MEMBER(southbridge_device::pc_dma_read_word)
+{
+ UINT16 result;
+ offs_t page_offset = (((offs_t) m_dma_offset[1][m_dma_channel & 3]) << 16) & 0xFF0000;
+
+ result = space.read_word(page_offset + ( offset << 1 ) );
+ m_dma_high_byte = result & 0xFF00;
+
+ return result & 0xFF;
+}
+
+
+WRITE8_MEMBER(southbridge_device::pc_dma_write_word)
+{
+ offs_t page_offset = (((offs_t) m_dma_offset[1][m_dma_channel & 3]) << 16) & 0xFF0000;
+
+ 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_isabus->eop_w(state == ASSERT_LINE ? 0 : 1 ); }
+
+WRITE_LINE_MEMBER( southbridge_device::pc_dack0_w ) { if (!state) m_dma_channel = 0; }
+WRITE_LINE_MEMBER( southbridge_device::pc_dack1_w ) { if (!state) m_dma_channel = 1; }
+WRITE_LINE_MEMBER( southbridge_device::pc_dack2_w ) { if (!state) m_dma_channel = 2; }
+WRITE_LINE_MEMBER( southbridge_device::pc_dack3_w ) { if (!state) m_dma_channel = 3; }
+WRITE_LINE_MEMBER( southbridge_device::pc_dack4_w ) { i8237_hlda_w( m_dma8237_1, state ? 0 : 1); } // it's inverted
+WRITE_LINE_MEMBER( southbridge_device::pc_dack5_w ) { if (!state) m_dma_channel = 5; }
+WRITE_LINE_MEMBER( southbridge_device::pc_dack6_w ) { if (!state) m_dma_channel = 6; }
+WRITE_LINE_MEMBER( southbridge_device::pc_dack7_w ) { if (!state) m_dma_channel = 7; }
+
+READ8_MEMBER( southbridge_device::at_portb_r )
+{
+ UINT8 data = m_at_speaker;
+ data &= ~0xc0; /* AT BIOS don't likes this being set */
+
+ /* This needs fixing/updating not sure what this is meant to fix */
+ if ( --m_poll_delay < 0 )
+ {
+ m_poll_delay = 3;
+ m_at_offset1 ^= 0x10;
+ }
+ data = (data & ~0x10) | ( m_at_offset1 & 0x10 );
+
+ if ( pit8253_get_output(m_pit8254, 2 ) )
+ data |= 0x20;
+ else
+ data &= ~0x20; /* ps2m30 wants this */
+
+ return data;
+}
+
+WRITE8_MEMBER( southbridge_device::at_portb_w )
+{
+ m_at_speaker = data;
+ pit8253_gate2_w(m_pit8254, 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));
+}
+
+WRITE_LINE_MEMBER( southbridge_device::at_mc146818_irq )
+{
+ pic8259_ir0_w(m_pic8259_slave, (state) ? 0 : 1);
+}
+
+READ8_MEMBER( southbridge_device::at_dma8237_2_r )
+{
+ return i8237_r( m_dma8237_2, offset / 2);
+}
+
+WRITE8_MEMBER( southbridge_device::at_dma8237_2_w )
+{
+ i8237_w( m_dma8237_2, 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_mc146818->write(space,0,data);
+ }
+ else {
+ m_mc146818->write(space,offset,data);
+ }
+}
diff --git a/src/mess/machine/southbridge.h b/src/mess/machine/southbridge.h
new file mode 100644
index 00000000000..cae2b981915
--- /dev/null
+++ b/src/mess/machine/southbridge.h
@@ -0,0 +1,147 @@
+#pragma once
+
+#ifndef __SOUTHBRIDGE_H__
+#define __SOUTHBRIDGE_H__
+
+#include "emu.h"
+
+#include "machine/ins8250.h"
+#include "machine/mc146818.h"
+#include "machine/pic8259.h"
+#include "machine/pit8253.h"
+#include "video/isa_cga.h"
+#include "video/isa_ega.h"
+#include "video/isa_svga_cirrus.h"
+#include "video/isa_svga_s3.h"
+#include "video/isa_svga_tseng.h"
+
+#include "machine/idectrl.h"
+#include "machine/isa_aha1542.h"
+#include "machine/at_keybc.h"
+#include "includes/ps2.h"
+
+#include "imagedev/harddriv.h"
+#include "machine/pci.h"
+#include "machine/kb_keytro.h"
+
+#include "sound/dac.h"
+#include "sound/speaker.h"
+#include "machine/ram.h"
+#include "machine/nvram.h"
+#include "machine/isa.h"
+
+#include "machine/isa_adlib.h"
+#include "machine/isa_com.h"
+#include "machine/isa_fdc.h"
+#include "machine/isa_gblaster.h"
+#include "machine/isa_hdc.h"
+#include "machine/isa_sblaster.h"
+#include "machine/isa_gus.h"
+#include "machine/3c503.h"
+#include "machine/ne1000.h"
+#include "machine/ne2000.h"
+#include "video/isa_mda.h"
+#include "machine/isa_mpu401.h"
+#include "machine/isa_ibm_mfc.h"
+
+#include "machine/isa_ide.h"
+#include "machine/isa_ide_cd.h"
+
+#include "machine/pc_lpt.h"
+#include "machine/pc_kbdc.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);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+public:
+
+ //static IRQ_CALLBACK(at_irq_callback);
+ required_device<cpu_device> m_maincpu;
+ required_device<device_t> m_pic8259_master;
+ required_device<device_t> m_pic8259_slave;
+ required_device<device_t> m_dma8237_1;
+ required_device<device_t> m_dma8237_2;
+ required_device<device_t> m_pit8254;
+ required_device<at_keyboard_controller_device> m_keybc;
+ required_device<isa16_device> m_isabus;
+ required_device<device_t> m_speaker;
+ required_device<mc146818_device> m_mc146818;
+ required_device<pc_kbdc_device> m_pc_kbdc;
+ 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_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_READ32_MEMBER(ide_r);
+ DECLARE_WRITE32_MEMBER(ide_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_WRITE_LINE_MEMBER(at_mc146818_irq);
+ 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:
+ int m_poll_delay;
+ UINT8 m_at_spkrdata;
+ UINT8 m_at_speaker_input;
+ int m_dma_channel;
+ UINT8 m_dma_offset[2][4];
+ UINT8 m_at_pages[0x10];
+ UINT16 m_dma_high_byte;
+ UINT8 m_at_speaker;
+ UINT8 m_at_offset1;
+ void at_speaker_set_spkrdata(UINT8 data);
+ void at_speaker_set_input(UINT8 data);
+
+ UINT8 m_channel_check;
+ UINT8 m_nmi_enabled;
+};
+
+#endif /* __SOUTHBRIDGE_H__ */
diff --git a/src/mess/machine/special.c b/src/mess/machine/special.c
new file mode 100644
index 00000000000..2270a07c306
--- /dev/null
+++ b/src/mess/machine/special.c
@@ -0,0 +1,395 @@
+/***************************************************************************
+
+ Specialist machine driver by Miodrag Milanovic
+
+ 20/03/2008 Cassette support
+ 15/03/2008 Preliminary driver.
+
+****************************************************************************/
+
+
+
+#include "includes/special.h"
+
+
+/* Driver initialization */
+DRIVER_INIT_MEMBER(special_state,special)
+{
+ /* set initialy ROM to be visible on first bank */
+ UINT8 *RAM = machine().root_device().memregion("maincpu")->base();
+ memset(RAM,0x0000,0x3000); // make first page empty by default
+ membank("bank1")->configure_entries(1, 2, RAM, 0x0000);
+ membank("bank1")->configure_entries(0, 2, RAM, 0xc000);
+}
+
+READ8_MEMBER( special_state::specialist_8255_porta_r )
+{
+ if (ioport("LINE0")->read()!=0xff) return 0xfe;
+ if (ioport("LINE1")->read()!=0xff) return 0xfd;
+ if (ioport("LINE2")->read()!=0xff) return 0xfb;
+ if (ioport("LINE3")->read()!=0xff) return 0xf7;
+ if (ioport("LINE4")->read()!=0xff) return 0xef;
+ if (ioport("LINE5")->read()!=0xff) return 0xdf;
+ if (ioport("LINE6")->read()!=0xff) return 0xbf;
+ if (ioport("LINE7")->read()!=0xff) return 0x7f;
+ return 0xff;
+}
+
+READ8_MEMBER( special_state::specialist_8255_portb_r )
+{
+ UINT8 dat = 0;
+ double level;
+
+ if ((m_specialist_8255_porta & 0x01)==0) dat ^= (ioport("LINE0")->read() ^ 0xff);
+ if ((m_specialist_8255_porta & 0x02)==0) dat ^= (ioport("LINE1")->read() ^ 0xff);
+ if ((m_specialist_8255_porta & 0x04)==0) dat ^= (ioport("LINE2")->read() ^ 0xff);
+ if ((m_specialist_8255_porta & 0x08)==0) dat ^= (ioport("LINE3")->read() ^ 0xff);
+ if ((m_specialist_8255_porta & 0x10)==0) dat ^= (ioport("LINE4")->read() ^ 0xff);
+ if ((m_specialist_8255_porta & 0x20)==0) dat ^= (ioport("LINE5")->read() ^ 0xff);
+ if ((m_specialist_8255_porta & 0x40)==0) dat ^= (ioport("LINE6")->read() ^ 0xff);
+ if ((m_specialist_8255_porta & 0x80)==0) dat ^= (ioport("LINE7")->read() ^ 0xff);
+ if ((m_specialist_8255_portc & 0x01)==0) dat ^= (ioport("LINE8")->read() ^ 0xff);
+ if ((m_specialist_8255_portc & 0x02)==0) dat ^= (ioport("LINE9")->read() ^ 0xff);
+ if ((m_specialist_8255_portc & 0x04)==0) dat ^= (ioport("LINE10")->read() ^ 0xff);
+ if ((m_specialist_8255_portc & 0x08)==0) dat ^= (ioport("LINE11")->read() ^ 0xff);
+
+ dat = (dat << 2) ^0xff;
+ if (ioport("LINE12")->read()!=0xff) dat ^= 0x02;
+
+ level = m_cass->input();
+ if (level >= 0)
+ dat ^= 0x01;
+
+ return dat;
+}
+
+READ8_MEMBER( special_state::specialist_8255_portc_r )
+{
+ if (ioport("LINE8")->read()!=0xff) return 0x0e;
+ if (ioport("LINE9")->read()!=0xff) return 0x0d;
+ if (ioport("LINE10")->read()!=0xff) return 0x0b;
+ if (ioport("LINE11")->read()!=0xff) return 0x07;
+ return 0x0f;
+}
+
+WRITE8_MEMBER( special_state::specialist_8255_porta_w )
+{
+ m_specialist_8255_porta = data;
+}
+
+WRITE8_MEMBER( special_state::specialist_8255_portb_w )
+{
+ m_specialist_8255_portb = data;
+}
+
+WRITE8_MEMBER( special_state::specialist_8255_portc_w )
+{
+ m_specialist_8255_portc = data;
+
+ m_cass->output(BIT(data, 7) ? 1 : -1);
+
+ m_dac->write_unsigned8(BIT(data, 5)); //beeper
+}
+
+I8255_INTERFACE( specialist_ppi8255_interface )
+{
+ DEVCB_DRIVER_MEMBER(special_state, specialist_8255_porta_r),
+ DEVCB_DRIVER_MEMBER(special_state, specialist_8255_porta_w),
+ DEVCB_DRIVER_MEMBER(special_state, specialist_8255_portb_r),
+ DEVCB_DRIVER_MEMBER(special_state, specialist_8255_portb_w),
+ DEVCB_DRIVER_MEMBER(special_state, specialist_8255_portc_r),
+ DEVCB_DRIVER_MEMBER(special_state, specialist_8255_portc_w)
+};
+
+static TIMER_CALLBACK( special_reset )
+{
+ special_state *state = machine.driver_data<special_state>();
+ state->membank("bank1")->set_entry(0);
+}
+
+
+MACHINE_RESET( special )
+{
+ special_state *state = machine.driver_data<special_state>();
+ machine.scheduler().timer_set(attotime::from_usec(10), FUNC(special_reset));
+ state->membank("bank1")->set_entry(1);
+}
+
+
+/*
+ Specialist MX
+*/
+WRITE8_MEMBER( special_state::video_memory_w )
+{
+ m_ram->pointer()[0x9000 + offset] = data;
+ m_specimx_colorram[offset] = m_specimx_color;
+}
+
+WRITE8_MEMBER( special_state::specimx_video_color_w )
+{
+ m_specimx_color = data;
+}
+
+READ8_MEMBER( special_state::specimx_video_color_r )
+{
+ return m_specimx_color;
+}
+
+void special_state::specimx_set_bank(offs_t i, UINT8 data)
+{
+ address_space *space = m_maincpu->memory().space(AS_PROGRAM);
+ UINT8 *ram = m_ram->pointer();
+
+ space->install_write_bank(0xc000, 0xffbf, "bank3");
+ space->install_write_bank(0xffc0, 0xffdf, "bank4");
+ membank("bank4")->set_base(ram + 0xffc0);
+ switch(i)
+ {
+ case 0 :
+ space->install_write_bank(0x0000, 0x8fff, "bank1");
+ space->install_write_handler(0x9000, 0xbfff, write8_delegate(FUNC(special_state::video_memory_w), this));
+
+ membank("bank1")->set_base(ram);
+ membank("bank2")->set_base(ram + 0x9000);
+ membank("bank3")->set_base(ram + 0xc000);
+ break;
+ case 1 :
+ space->install_write_bank(0x0000, 0x8fff, "bank1");
+ space->install_write_bank(0x9000, 0xbfff, "bank2");
+
+ membank("bank1")->set_base(ram + 0x10000);
+ membank("bank2")->set_base(ram + 0x19000);
+ membank("bank3")->set_base(ram + 0x1c000);
+ break;
+ case 2 :
+ space->unmap_write(0x0000, 0x8fff);
+ space->unmap_write(0x9000, 0xbfff);
+
+ membank("bank1")->set_base(machine().root_device().memregion("maincpu")->base() + 0x10000);
+ membank("bank2")->set_base(machine().root_device().memregion("maincpu")->base() + 0x19000);
+
+ if (data & 0x80)
+ membank("bank3")->set_base(ram + 0x1c000);
+ else
+ membank("bank3")->set_base(ram + 0xc000);
+
+ break;
+ }
+}
+
+WRITE8_MEMBER( special_state::specimx_select_bank )
+{
+ specimx_set_bank(offset, data);
+}
+
+WRITE_LINE_MEMBER( special_state::specimx_pit8253_out0_changed )
+{
+ specimx_set_input( m_specimx_audio, 0, state );
+}
+
+WRITE_LINE_MEMBER( special_state::specimx_pit8253_out1_changed )
+{
+ specimx_set_input( m_specimx_audio, 1, state );
+}
+
+WRITE_LINE_MEMBER( special_state::specimx_pit8253_out2_changed )
+{
+ specimx_set_input( m_specimx_audio, 2, state );
+}
+
+
+
+const struct pit8253_config specimx_pit8253_intf =
+{
+ {
+ {
+ 2000000,
+ DEVCB_NULL,
+ DEVCB_DRIVER_LINE_MEMBER(special_state, specimx_pit8253_out0_changed)
+ },
+ {
+ 2000000,
+ DEVCB_NULL,
+ DEVCB_DRIVER_LINE_MEMBER(special_state, specimx_pit8253_out1_changed)
+ },
+ {
+ 2000000,
+ DEVCB_NULL,
+ DEVCB_DRIVER_LINE_MEMBER(special_state, specimx_pit8253_out2_changed)
+ }
+ }
+};
+
+MACHINE_START( specimx )
+{
+ special_state *state = machine.driver_data<special_state>();
+ state->m_specimx_audio = machine.device("custom");
+}
+
+static TIMER_CALLBACK( setup_pit8253_gates )
+{
+ device_t *pit8253 = machine.device("pit8253");
+
+ pit8253_gate0_w(pit8253, 0);
+ pit8253_gate1_w(pit8253, 0);
+ pit8253_gate2_w(pit8253, 0);
+}
+
+MACHINE_RESET( specimx )
+{
+ special_state *state = machine.driver_data<special_state>();
+ state->specimx_set_bank(2, 0); // Initiali load ROM disk
+ state->m_specimx_color = 0x70;
+ machine.scheduler().timer_set(attotime::zero, FUNC(setup_pit8253_gates));
+ device_t *fdc = machine.device("wd1793");
+ wd17xx_set_pause_time(fdc,12);
+ wd17xx_dden_w(fdc, 0);
+}
+
+READ8_MEMBER( special_state::specimx_disk_ctrl_r )
+{
+ return 0xff;
+}
+
+WRITE8_MEMBER( special_state::specimx_disk_ctrl_w )
+{
+ switch(offset)
+ {
+ case 2 :
+ wd17xx_set_side(m_fdc, data & 1);
+ break;
+ case 3 :
+ wd17xx_set_drive(m_fdc, data & 1);
+ break;
+ }
+}
+
+/*
+ Erik
+*/
+
+void special_state::erik_set_bank()
+{
+ UINT8 bank1 = m_RR_register & 3;
+ UINT8 bank2 = (m_RR_register >> 2) & 3;
+ UINT8 bank3 = (m_RR_register >> 4) & 3;
+ UINT8 bank4 = (m_RR_register >> 6) & 3;
+ UINT8 *mem = memregion("maincpu")->base();
+ UINT8 *ram = m_ram->pointer();
+ address_space *space = m_maincpu->memory().space(AS_PROGRAM);
+
+ space->install_write_bank(0x0000, 0x3fff, "bank1");
+ space->install_write_bank(0x4000, 0x8fff, "bank2");
+ space->install_write_bank(0x9000, 0xbfff, "bank3");
+ space->install_write_bank(0xc000, 0xefff, "bank4");
+ space->install_write_bank(0xf000, 0xf7ff, "bank5");
+ space->install_write_bank(0xf800, 0xffff, "bank6");
+
+ switch(bank1)
+ {
+ case 1:
+ case 2:
+ case 3:
+ membank("bank1")->set_base(ram + 0x10000*(bank1-1));
+ break;
+ case 0:
+ space->unmap_write(0x0000, 0x3fff);
+ membank("bank1")->set_base(mem + 0x10000);
+ break;
+ }
+ switch(bank2)
+ {
+ case 1:
+ case 2:
+ case 3:
+ membank("bank2")->set_base(ram + 0x10000*(bank2-1) + 0x4000);
+ break;
+ case 0:
+ space->unmap_write(0x4000, 0x8fff);
+ membank("bank2")->set_base(mem + 0x14000);
+ break;
+ }
+ switch(bank3)
+ {
+ case 1:
+ case 2:
+ case 3:
+ membank("bank3")->set_base(ram + 0x10000*(bank3-1) + 0x9000);
+ break;
+ case 0:
+ space->unmap_write(0x9000, 0xbfff);
+ membank("bank3")->set_base(mem + 0x19000);
+ break;
+ }
+ switch(bank4)
+ {
+ case 1:
+ case 2:
+ case 3:
+ membank("bank4")->set_base(ram + 0x10000*(bank4-1) + 0x0c000);
+ membank("bank5")->set_base(ram + 0x10000*(bank4-1) + 0x0f000);
+ membank("bank6")->set_base(ram + 0x10000*(bank4-1) + 0x0f800);
+ break;
+ case 0:
+ space->unmap_write(0xc000, 0xefff);
+ membank("bank4")->set_base(mem + 0x1c000);
+ space->unmap_write(0xf000, 0xf7ff);
+ space->nop_read(0xf000, 0xf7ff);
+ space->install_readwrite_handler(0xf800, 0xf803, 0, 0x7fc, read8_delegate(FUNC(i8255_device::read), (i8255_device*)m_ppi), write8_delegate(FUNC(i8255_device::write), (i8255_device*)m_ppi));
+ break;
+ }
+}
+
+DRIVER_INIT_MEMBER(special_state,erik)
+{
+ m_erik_color_1 = 0;
+ m_erik_color_2 = 0;
+ m_erik_background = 0;
+}
+
+MACHINE_RESET( erik )
+{
+ special_state *state = machine.driver_data<special_state>();
+ state->m_RR_register = 0x00;
+ state->m_RC_register = 0x00;
+ state->erik_set_bank();
+}
+
+READ8_MEMBER( special_state::erik_rr_reg_r )
+{
+ return m_RR_register;
+}
+
+WRITE8_MEMBER( special_state::erik_rr_reg_w )
+{
+ m_RR_register = data;
+ erik_set_bank();
+}
+
+READ8_MEMBER( special_state::erik_rc_reg_r )
+{
+ return m_RC_register;
+}
+
+WRITE8_MEMBER( special_state::erik_rc_reg_w )
+{
+ m_RC_register = data;
+ m_erik_color_1 = m_RC_register & 7;
+ m_erik_color_2 = (m_RC_register >> 3) & 7;
+ m_erik_background = BIT(m_RC_register, 6) + BIT(m_RC_register, 7) * 4;
+}
+
+READ8_MEMBER( special_state::erik_disk_reg_r )
+{
+ return 0xff;
+}
+
+WRITE8_MEMBER( special_state::erik_disk_reg_w )
+{
+ wd17xx_set_side (m_fdc,data & 1);
+ wd17xx_set_drive(m_fdc,(data >> 1) & 1);
+ wd17xx_dden_w(m_fdc, BIT(data, 2));
+ floppy_mon_w(floppy_get_device(machine(), BIT(data, 1)), 0);
+ floppy_mon_w(floppy_get_device(machine(), BIT(data, 1) ^ 1), 1);
+ floppy_drive_set_ready_state(floppy_get_device(machine(), BIT(data, 1)), 1, 1);
+}
diff --git a/src/mess/machine/sst39vfx.c b/src/mess/machine/sst39vfx.c
new file mode 100644
index 00000000000..3fc1d32afd0
--- /dev/null
+++ b/src/mess/machine/sst39vfx.c
@@ -0,0 +1,223 @@
+/*
+
+ SST Multi-Purpose Flash (MPF)
+
+ (c) 2001-2007 Tim Schuerewegen
+
+ SST39VF020 - 256 KByte
+ SST39VF400A - 512 Kbyte
+
+*/
+
+#include "sst39vfx.h"
+
+#define LOG_LEVEL 1
+#define _logerror(level,x) do { if (LOG_LEVEL > level) logerror x; } while (0)
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _sst39vfx_t sst39vfx_t;
+struct _sst39vfx_t
+{
+ UINT8 *data;
+ UINT32 size;
+ UINT8 swap;
+};
+
+enum
+{
+ TYPE_SST39VF020,
+ TYPE_SST39VF400A
+};
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+INLINE sst39vfx_t *get_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == SST39VF020 || device->type() == SST39VF400A);
+
+ return (sst39vfx_t *) downcast<legacy_device_base *>(device)->token();
+}
+
+INLINE const sst39vfx_config *get_config(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == SST39VF020 || device->type() == SST39VF400A);
+
+ return (const sst39vfx_config *) downcast<const legacy_device_base *>(device)->inline_config();
+}
+
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+static void common_start(device_t *device, int device_type)
+{
+ sst39vfx_t *flash = get_token(device);
+ const sst39vfx_config *config = get_config(device);
+
+ _logerror( 0, ("sst39vfx_init (%d)\n", device_type));
+ memset(flash, 0, sizeof(sst39vfx_t));
+ switch (device_type)
+ {
+ case TYPE_SST39VF020 : flash->size = 256 * 1024; break;
+ case TYPE_SST39VF400A : flash->size = 512 * 1024; break;
+ }
+ flash->data = auto_alloc_array(device->machine(), UINT8, flash->size);
+#ifdef LSB_FIRST
+ if (config->cpu_endianess != ENDIANNESS_LITTLE) flash->swap = config->cpu_datawidth / 8; else flash->swap = 0;
+#else
+ if (config->cpu_endianess != ENDIANNESS_BIG) flash->swap = config->cpu_datawidth / 8; else flash->swap = 0;
+#endif
+
+ state_save_register_item_pointer(device->machine(), "sst39vfx", device->tag(), 0, flash->data, flash->size);
+ state_save_register_item(device->machine(), "sst39vfx", device->tag(), 0, flash->swap);
+}
+
+
+static DEVICE_START( sst39vf020 )
+{
+ common_start(device, TYPE_SST39VF020);
+}
+
+static DEVICE_START( sst39vf400a )
+{
+ common_start(device, TYPE_SST39VF400A);
+}
+
+UINT8* sst39vfx_get_base( device_t *device)
+{
+ sst39vfx_t *flash = get_token(device);
+ return flash->data;
+}
+
+UINT32 sst39vfx_get_size( device_t *device)
+{
+ sst39vfx_t *flash = get_token(device);
+ return flash->size;
+}
+
+/*
+#define OFFSET_SWAP(offset,width) (offset & (~(width - 1))) | (width - 1 - (offset & (width - 1)))
+*/
+
+#ifdef UNUSED_FUNCTION
+READ8_HANDLER( sst39vfx_r )
+{
+ _logerror( 1, ("sst39vfx_r (%08X)\n", offset));
+ if (flash->swap) offset = OFFSET_SWAP( offset, flash->swap);
+ return flash->data[offset];
+}
+
+WRITE8_HANDLER( sst39vfx_w )
+{
+ _logerror( 1, ("sst39vfx_w (%08X/%02X)\n", offset, data));
+ if (flash->swap) offset = OFFSET_SWAP( offset, flash->swap);
+ flash->data[offset] = data;
+}
+#endif
+
+static void sst39vfx_swap( device_t *device)
+{
+ int i, j;
+ UINT8 *base, temp[8];
+ sst39vfx_t *flash = get_token(device);
+
+ base = flash->data;
+ for (i=0;i<flash->size;i+=flash->swap)
+ {
+ memcpy( temp, base, flash->swap);
+ for (j=flash->swap-1;j>=0;j--) *base++ = temp[j];
+ }
+}
+
+void sst39vfx_load(device_t *device, emu_file *file)
+{
+ sst39vfx_t *flash = get_token(device);
+
+ _logerror( 0, ("sst39vfx_load (%p)\n", file));
+ file->read(flash->data, flash->size);
+ if (flash->swap) sst39vfx_swap(device);
+}
+
+void sst39vfx_save(device_t *device, emu_file *file)
+{
+ sst39vfx_t *flash = get_token(device);
+
+ _logerror( 0, ("sst39vfx_save (%p)\n", file));
+ if (flash->swap) sst39vfx_swap(device);
+ file->write(flash->data, flash->size);
+ if (flash->swap) sst39vfx_swap(device);
+}
+
+#if 0
+NVRAM_HANDLER( sst39vfx )
+{
+ _logerror( 0, ("nvram_handler_sst39vfx (%p/%d)\n", file, read_or_write));
+ if (read_or_write)
+ {
+ sst39vfx_save( file);
+ }
+ else
+ {
+ if (file)
+ {
+ sst39vfx_load( file);
+ }
+ else
+ {
+ memset( flash->data, 0xFF, flash->size);
+ }
+ }
+}
+#endif
+
+
+/*-------------------------------------------------
+ DEVICE_GET_INFO( sst39vf020 )
+-------------------------------------------------*/
+
+DEVICE_GET_INFO( sst39vf020 )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(sst39vfx_t); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = sizeof(sst39vfx_config); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(sst39vf020); break;
+ case DEVINFO_FCT_STOP: /* Nothing */ break;
+ case DEVINFO_FCT_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "SST39VF020"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "SST39VFxx"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: /* Nothing */ break;
+ }
+}
+
+DEVICE_GET_INFO( sst39vf400a )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "SST39VF400A"); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(sst39vf400a); break;
+
+ default: DEVICE_GET_INFO_CALL(sst39vf020); break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(SST39VF020, sst39vf020);
+DEFINE_LEGACY_DEVICE(SST39VF400A, sst39vf400a);
diff --git a/src/mess/machine/sst39vfx.h b/src/mess/machine/sst39vfx.h
new file mode 100644
index 00000000000..79535ee53e4
--- /dev/null
+++ b/src/mess/machine/sst39vfx.h
@@ -0,0 +1,72 @@
+/*
+
+ SST Multi-Purpose Flash (MPF)
+
+ (c) 2001-2007 Tim Schuerewegen
+
+ SST39VF020 - 256 KByte
+ SST39VF400A - 512 Kbyte
+
+*/
+
+#ifndef _SST39VFX_H_
+#define _SST39VFX_H_
+
+#include "emu.h"
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _sst39vfx_config sst39vfx_config;
+struct _sst39vfx_config
+{
+ int cpu_datawidth;
+ int cpu_endianess;
+};
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+DECLARE_LEGACY_DEVICE(SST39VF020, sst39vf020);
+
+#define MCFG_SST39VF020_ADD(_tag,_cpu_datawidth,_cpu_endianess) \
+ MCFG_DEVICE_ADD(_tag, SST39VF020, 0) \
+ MCFG_DEVICE_CONFIG_DATA32(sst39vfx_config, cpu_datawidth, _cpu_datawidth) \
+ MCFG_DEVICE_CONFIG_DATA32(sst39vfx_config, cpu_endianess, _cpu_endianess)
+
+#define MCFG_SST39VF020_REMOVE(_tag) \
+ MCFG_DEVICE_REMOVE(_tag)
+
+DECLARE_LEGACY_DEVICE(SST39VF400A, sst39vf400a);
+
+#define MCFG_SST39VF400A_ADD(_tag,_cpu_datawidth,_cpu_endianess) \
+ MCFG_DEVICE_ADD(_tag, SST39VF400A, 0) \
+ MCFG_DEVICE_CONFIG_DATA32(sst39vfx_config, cpu_datawidth, _cpu_datawidth) \
+ MCFG_DEVICE_CONFIG_DATA32(sst39vfx_config, cpu_endianess, _cpu_endianess)
+
+#define MCFG_SST39VF400A_REMOVE(_tag) \
+ MCFG_DEVICE_REMOVE(_tag)
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+// get base/size
+UINT8* sst39vfx_get_base( device_t *device );
+UINT32 sst39vfx_get_size( device_t *device );
+
+// read/write handler
+#if 0
+READ8_HANDLER( sst39vfx_r );
+WRITE8_HANDLER( sst39vfx_w );
+#endif
+
+// load/save
+void sst39vfx_load(device_t *device, emu_file *file);
+void sst39vfx_save(device_t *device, emu_file *file);
+
+// non-volatile ram handler
+//NVRAM_HANDLER( sst39vfx );
+
+#endif
diff --git a/src/mess/machine/strata.c b/src/mess/machine/strata.c
new file mode 100644
index 00000000000..ad458d9d473
--- /dev/null
+++ b/src/mess/machine/strata.c
@@ -0,0 +1,695 @@
+/*
+ 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
+*/
+
+#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 ADDRESS_MASK 0x7fffff
+#define BLOCK_ADDRESS_MASK 0x7e0000
+#define BLOCK_ADDRESS_SHIFT 17
+#define BYTE_ADDRESS_MASK 0x01ffff
+
+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
+};
+typedef struct
+{
+ fm_mode_t mode; // current operation mode
+ int hard_unlock; // 1 if RP* pin is at Vhh (not fully implemented)
+ int status; // current status
+ int master_lock; // master lock flag
+ offs_t wrbuf_base; // start address in write buffer command
+ int wrbuf_len; // count converted into byte length in write buffer command
+ int wrbuf_count; // current count in write buffer command
+ UINT8 *wrbuf; // write buffer used by write buffer command
+ UINT8 *data_ptr; // main FEEPROM area
+ UINT8 *blocklock; // block lock flags
+ UINT8 *prot_regs; // protection registers
+} strata_t;
+
+/* accessors for individual block lock flags */
+#define READ_BLOCKLOCK(strata, block) (((strata)->blocklock[(block) >> 3] >> ((block) & 7)) & 1)
+#define SET_BLOCKLOCK(strata, block) ((strata)->blocklock[(block) >> 3] |= 1 << ((block) & 7))
+#define CLEAR_BLOCKLOCK(strata, block) ((strata)->blocklock[(block) >> 3] &= ~(1 << ((block) & 7)))
+
+/*
+ Initialize one FEEPROM chip: may be called at driver init or image load
+ time (or machine init time if you don't use MESS image core)
+*/
+
+INLINE strata_t *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == STRATAFLASH);
+
+ return (strata_t *)downcast<legacy_device_base *>(device)->token();
+}
+
+static DEVICE_START( strataflash )
+{
+ strata_t *strata = get_safe_token(device);
+ int i;
+
+ strata->mode = FM_NORMAL;
+ strata->status = 0x80;
+ strata->master_lock = 0;
+ strata->data_ptr = auto_alloc_array(device->machine(), UINT8, FEEPROM_SIZE + WRBUF_SIZE + PROT_REGS_SIZE + BLOCKLOCK_SIZE);
+ strata->wrbuf = strata->data_ptr + FEEPROM_SIZE;
+ strata->prot_regs = strata->wrbuf + WRBUF_SIZE;
+ strata->blocklock = strata->prot_regs + PROT_REGS_SIZE;
+ /* clear various FEEPROM areas */
+ memset(strata->prot_regs, 0xff, 18);
+ memset(strata->data_ptr, 0xff, FEEPROM_SIZE);
+ memset(strata->blocklock, 0x00, BLOCKLOCK_SIZE);
+ /* set-up factory-programmed protection register segment */
+ strata->prot_regs[BYTE_XOR_LE(0)] &= 0xfe;
+ for (i=2; i<10; i++)
+ strata->prot_regs[i] = device->machine().rand();
+}
+
+DEVICE_GET_INFO( strataflash )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(strata_t); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(strataflash); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "Intel 28F640J5"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "Intel 28F640J5"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright MESS Team"); break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(STRATAFLASH, strataflash);
+
+/*
+ load the FEEPROM contents from file
+*/
+int strataflash_load(device_t *device, emu_file *file)
+{
+ strata_t *strata = get_safe_token(device);
+ 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;
+ strata->master_lock = buf & 1;
+
+ /* main FEEPROM area */
+ if (file->read(strata->data_ptr, FEEPROM_SIZE) != FEEPROM_SIZE)
+ return 1;
+ for (i = 0; i < FEEPROM_SIZE; i += 2)
+ {
+ UINT16 *ptr = (UINT16 *) (&strata->data_ptr[i]);
+ *ptr = LITTLE_ENDIANIZE_INT16(*ptr);
+ }
+
+ /* protection registers */
+ if (file->read(strata->prot_regs, PROT_REGS_SIZE) != PROT_REGS_SIZE)
+ return 1;
+ for (i = 0; i < PROT_REGS_SIZE; i += 2)
+ {
+ UINT16 *ptr = (UINT16 *) (&strata->prot_regs[i]);
+ *ptr = LITTLE_ENDIANIZE_INT16(*ptr);
+ }
+
+ /* block lock flags */
+ if (file->read(strata->blocklock, BLOCKLOCK_SIZE) != BLOCKLOCK_SIZE)
+ return 1;
+
+ return 0;
+}
+
+/*
+ save the FEEPROM contents to file
+*/
+int strataflash_save(device_t *device, emu_file *file)
+{
+ strata_t *strata = get_safe_token(device);
+ 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 = strata->master_lock;
+ if (file->write(& buf, 1) != 1)
+ return 1;
+
+ /* main FEEPROM area */
+ for (i = 0; i < FEEPROM_SIZE; i += 2)
+ {
+ UINT16 *ptr = (UINT16 *) (&strata->data_ptr[i]);
+ *ptr = LITTLE_ENDIANIZE_INT16(*ptr);
+ }
+ if (file->write(strata->data_ptr, FEEPROM_SIZE) != FEEPROM_SIZE)
+ return 1;
+ for (i = 0; i < FEEPROM_SIZE; i += 2)
+ {
+ UINT16 *ptr = (UINT16 *) (&strata->data_ptr[i]);
+ *ptr = LITTLE_ENDIANIZE_INT16(*ptr);
+ }
+
+ /* protection registers */
+ for (i = 0; i < PROT_REGS_SIZE; i += 2)
+ {
+ UINT16 *ptr = (UINT16 *) (&strata->prot_regs[i]);
+ *ptr = LITTLE_ENDIANIZE_INT16(*ptr);
+ }
+ if (file->write(strata->prot_regs, PROT_REGS_SIZE) != PROT_REGS_SIZE)
+ return 1;
+ for (i = 0; i < PROT_REGS_SIZE; i += 2)
+ {
+ UINT16 *ptr = (UINT16 *) (&strata->prot_regs[i]);
+ *ptr = LITTLE_ENDIANIZE_INT16(*ptr);
+ }
+
+ /* block lock flags */
+ if (file->write(strata->blocklock, BLOCKLOCK_SIZE) != BLOCKLOCK_SIZE)
+ return 1;
+
+ return 0;
+}
+
+/* bus width for 8/16-bit handlers */
+typedef enum bus_width_t
+{
+ bw_8,
+ bw_16
+} bus_width_t;
+
+/*
+ read a 8/16-bit word from FEEPROM
+*/
+static int strataflash_r(device_t *device, offs_t offset, bus_width_t bus_width)
+{
+ strata_t *strata = get_safe_token(device);
+
+ switch (bus_width)
+ {
+ case bw_8:
+ offset &= ADDRESS_MASK;
+ break;
+ case bw_16:
+ offset &= ADDRESS_MASK & ~1;
+ }
+
+ switch (strata->mode)
+ {
+ default:
+ case FM_NORMAL:
+ switch (bus_width)
+ {
+ case bw_8:
+ return strata->data_ptr[BYTE_XOR_LE(offset)];
+ case bw_16:
+ return *(UINT16*)(strata->data_ptr+offset);
+ }
+ break;
+ case FM_READSTATUS:
+ return strata->status;
+ case FM_WRBUFPART1:
+ return 0x80;
+ case FM_READID:
+ if ((offset >= 0x100) && (offset < 0x112))
+ { /* protection registers */
+ switch (bus_width)
+ {
+ case bw_8:
+ return strata->prot_regs[BYTE_XOR_LE(offset)];
+ case bw_16:
+ return *(UINT16*)(strata->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(strata, offset >> BLOCK_ADDRESS_SHIFT);
+ }
+ return 0; // default case
+ case 3: // master lock config
+ if (strata->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(strata, offset >> BLOCK_ADDRESS_SHIFT);
+ }
+ return 0; // default case
+#if 0
+ case 0x03: // master lock config
+ if (strata->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;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ write a 8/16-bit word to FEEPROM
+*/
+static void strataflash_w(device_t *device, offs_t offset, int data, bus_width_t bus_width)
+{
+ strata_t *strata = get_safe_token(device);
+
+ switch (bus_width)
+ {
+ case bw_8:
+ offset &= ADDRESS_MASK;
+ break;
+ case bw_16:
+ offset &= ADDRESS_MASK & ~1;
+ }
+
+ switch (strata->mode)
+ {
+ case FM_NORMAL:
+ case FM_READID:
+ case FM_READQUERY:
+ case FM_READSTATUS:
+ switch (data)
+ {
+ case 0xff: // read array
+ strata->mode = FM_NORMAL;
+ break;
+ case 0x90: // read identifier codes
+ strata->mode = FM_READID;
+ break;
+ case 0x98: // read query
+ strata->mode = FM_READQUERY;
+ break;
+ case 0x70: // read status register
+ strata->mode = FM_READSTATUS;
+ break;
+ case 0x50: // clear status register
+ strata->mode = FM_READSTATUS;
+ strata->status &= 0xC5;
+ break;
+ case 0xe8: // write to buffer
+ strata->mode = FM_WRBUFPART1;
+ strata->wrbuf_base = offset & BLOCK_ADDRESS_MASK;
+ /*strata->status &= 0xC5;*/
+ break;
+ case 0x40:
+ case 0x10: // program
+ strata->mode = FM_WRITEPART1;
+ strata->status &= 0xC5;
+ break;
+ case 0x20: // block erase
+ strata->mode = FM_CLEARPART1;
+ strata->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
+ strata->mode = FM_CONFPART1;
+ strata->status &= 0xC5;
+ break;
+ case 0x60: // set master lock
+ strata->mode = FM_SETLOCK;
+ strata->status &= 0xC5;
+ break;
+ case 0xc0: // protection program
+ strata->mode = FM_WRPROTPART1;
+ strata->status &= 0xC5;
+ break;
+ default:
+ logerror("Unknown flash mode byte %x\n", data);
+ break;
+ }
+ break;
+ case FM_WRBUFPART1:
+ strata->mode = FM_WRBUFPART2;
+ if (((offset & BLOCK_ADDRESS_MASK) != strata->wrbuf_base) || (data >= 0x20))
+ {
+ strata->status |= 0x30;
+ strata->wrbuf_len = 0;
+ strata->wrbuf_count = data;
+ }
+ else
+ {
+ switch (bus_width)
+ {
+ case bw_8:
+ strata->wrbuf_len = data+1;
+ break;
+ case bw_16:
+ strata->wrbuf_len = (data+1) << 1;
+ break;
+ }
+ strata->wrbuf_count = data;
+ }
+ break;
+ case FM_WRBUFPART2:
+ strata->mode = FM_WRBUFPART3;
+ if (((offset & BLOCK_ADDRESS_MASK) != strata->wrbuf_base)
+ || (((offset & BYTE_ADDRESS_MASK) + strata->wrbuf_len) > BLOCK_SIZE))
+ {
+ strata->status |= 0x30;
+ strata->wrbuf_len = 0;
+ strata->wrbuf_base = 0;
+ }
+ else
+ strata->wrbuf_base = offset;
+ memset(strata->wrbuf, 0xff, strata->wrbuf_len); /* right??? */
+ case FM_WRBUFPART3:
+ if ((offset < strata->wrbuf_base) || (offset >= (strata->wrbuf_base + strata->wrbuf_len)))
+ strata->status |= 0x30;
+ else
+ {
+ switch (bus_width)
+ {
+ case bw_8:
+ strata->wrbuf[offset-strata->wrbuf_base] = data;
+ break;
+ case bw_16:
+ strata->wrbuf[offset-strata->wrbuf_base] = data & 0xff;
+ strata->wrbuf[offset-strata->wrbuf_base+1] = data >> 8;
+ break;
+ }
+ }
+ if (strata->wrbuf_count == 0)
+ strata->mode = FM_WRBUFPART4;
+ else
+ strata->wrbuf_count--;
+ break;
+ case FM_WRBUFPART4:
+ if (((offset & BLOCK_ADDRESS_MASK) != (strata->wrbuf_base & BLOCK_ADDRESS_MASK)) || (data != 0xd0))
+ {
+ strata->status |= 0x30;
+ }
+ else if (READ_BLOCKLOCK(strata, offset >> BLOCK_ADDRESS_SHIFT) && !strata->hard_unlock)
+ {
+ strata->status |= 0x12;
+ }
+ else if (!(strata->status & 0x30))
+ {
+ int i;
+ for (i=0; i<strata->wrbuf_len; i++)
+ strata->data_ptr[BYTE_XOR_LE(strata->wrbuf_base+i)] &= strata->wrbuf[i];
+ strata->mode = FM_READSTATUS;
+ }
+ break;
+ case FM_WRITEPART1:
+ if (READ_BLOCKLOCK(strata, offset >> BLOCK_ADDRESS_SHIFT) && !strata->hard_unlock)
+ {
+ strata->status |= 0x12;
+ }
+ else
+ {
+ switch (bus_width)
+ {
+ case bw_8:
+ strata->data_ptr[BYTE_XOR_LE(offset)] &= data;
+ break;
+ case bw_16:
+ *(UINT16*)(strata->data_ptr+offset) &= data;
+ break;
+ }
+ }
+ strata->mode = FM_READSTATUS;
+ break;
+ case FM_CLEARPART1:
+ if (data == 0xd0)
+ {
+ // clear the 128k block containing the current address
+ // to all 0xffs
+ if (READ_BLOCKLOCK(strata, offset >> BLOCK_ADDRESS_SHIFT) && !strata->hard_unlock)
+ {
+ strata->status |= 0x22;
+ }
+ else
+ {
+ offset &= BLOCK_ADDRESS_MASK;
+ memset(&strata->data_ptr[offset], 0xff, BLOCK_SIZE);
+ }
+ strata->mode = FM_READSTATUS;
+ }
+ break;
+ case FM_SETLOCK:
+ switch (data)
+ {
+ case 0xf1:
+ if (!strata->hard_unlock)
+ strata->status |= 0x12;
+ else
+ strata->master_lock = 1;
+ break;
+ case 0x01:
+ if (strata->master_lock && !strata->hard_unlock)
+ strata->status |= 0x12;
+ else
+ SET_BLOCKLOCK(strata, offset >> BLOCK_ADDRESS_SHIFT);
+ break;
+ case 0xd0:
+ if (strata->master_lock && !strata->hard_unlock)
+ strata->status |= 0x22;
+ else
+ CLEAR_BLOCKLOCK(strata, offset >> BLOCK_ADDRESS_SHIFT);
+ break;
+ case 0x03: // Set Read configuration
+ /* ignore command */
+ break;
+ default:
+ strata->status |= 0x30;
+ break;
+ }
+ strata->mode = FM_READSTATUS;
+ break;
+ case FM_CONFPART1:
+ /* configuration register is not emulated because the sts pin is not */
+ //strata->configuration = data;
+ strata->mode = FM_READSTATUS; /* right??? */
+ break;
+ case FM_WRPROTPART1:
+ if ((offset < 0x100) || (offset >= 0x112))
+ strata->status |= 0x10;
+ else if ((offset >= 0x102) && !((strata->prot_regs[BYTE_XOR_LE(0)] >> ((offset - 0x102) >> 3)) & 1))
+ strata->status |= 0x12;
+ else
+ {
+ switch (bus_width)
+ {
+ case bw_8:
+ strata->prot_regs[BYTE_XOR_LE(offset-0x100)] &= data;
+ break;
+ case bw_16:
+ *(UINT16*)(strata->prot_regs+(offset-0x100)) &= data;
+ break;
+ }
+ }
+ strata->mode = FM_READSTATUS; /* right??? */
+ break;
+ }
+}
+
+/*
+ read a 8-bit word from FEEPROM
+*/
+UINT8 strataflash_8_r(device_t *device, offs_t offset)
+{
+ return strataflash_r(device, offset, bw_8);
+}
+
+/*
+ write a 8-bit word to FEEPROM
+*/
+void strataflash_8_w(device_t *device, offs_t offset, UINT8 data)
+{
+ strataflash_w(device, offset, data, bw_8);
+}
+
+/*
+ read a 16-bit word from FEEPROM
+*/
+UINT16 strataflash_16_r(device_t *device, offs_t offset)
+{
+ return strataflash_r(device, offset, bw_16);
+}
+
+/*
+ write a 16-bit word to FEEPROM
+*/
+void strataflash_16_w(device_t *device, offs_t offset, UINT16 data)
+{
+ strataflash_w(device, offset, data, bw_16);
+}
diff --git a/src/mess/machine/strata.h b/src/mess/machine/strata.h
new file mode 100644
index 00000000000..b4ada71c80c
--- /dev/null
+++ b/src/mess/machine/strata.h
@@ -0,0 +1,15 @@
+/*
+ strata.h: header file for strata.c
+*/
+
+DECLARE_LEGACY_DEVICE(STRATAFLASH, strataflash);
+
+#define MCFG_STRATAFLASH_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, STRATAFLASH, 0)
+
+int strataflash_load(device_t *device, emu_file *file);
+int strataflash_save(device_t *device, emu_file *file);
+UINT8 strataflash_8_r(device_t *device, UINT32 address);
+void strataflash_8_w(device_t *device, UINT32 address, UINT8 data);
+UINT16 strataflash_16_r(device_t *device, offs_t offset);
+void strataflash_16_w(device_t *device, offs_t offset, UINT16 data);
diff --git a/src/mess/machine/super80.c b/src/mess/machine/super80.c
new file mode 100644
index 00000000000..7e8bf324d64
--- /dev/null
+++ b/src/mess/machine/super80.c
@@ -0,0 +1,227 @@
+/* Super80.c written by Robbbert, 2005-2009. See driver source for documentation. */
+
+#include "emu.h"
+#include "includes/super80.h"
+
+
+/**************************** PIO ******************************************************************************/
+
+
+WRITE8_MEMBER( super80_state::pio_port_a_w )
+{
+ m_keylatch = data;
+};
+
+static READ8_DEVICE_HANDLER( pio_port_b_r ) // cannot be modernised yet as super80 hangs at start
+{
+ super80_state *state = device->machine().driver_data<super80_state>();
+ char kbdrow[6];
+ UINT8 i;
+ UINT8 data = 0xff;
+
+ for (i = 0; i < 8; i++)
+ {
+ sprintf(kbdrow,"X%d",i);
+ if (!BIT(state->m_keylatch, i)) data &= state->ioport(kbdrow)->read();
+ }
+
+ return data;
+};
+
+Z80PIO_INTERFACE( super80_pio_intf )
+{
+ DEVCB_CPU_INPUT_LINE("maincpu", INPUT_LINE_IRQ0),
+ DEVCB_NULL,
+ DEVCB_DRIVER_MEMBER(super80_state, pio_port_a_w),
+ DEVCB_NULL, /* portA ready active callback (not used in super80) */
+ DEVCB_HANDLER(pio_port_b_r),
+ DEVCB_NULL,
+ DEVCB_NULL /* portB ready active callback (not used in super80) */
+};
+
+
+/**************************** CASSETTE ROUTINES *****************************************************************/
+
+static void super80_cassette_motor( running_machine &machine, UINT8 data )
+{
+ super80_state *state = machine.driver_data<super80_state>();
+ if (data)
+ state->m_cass->change_state(CASSETTE_MOTOR_DISABLED,CASSETTE_MASK_MOTOR);
+ else
+ state->m_cass->change_state(CASSETTE_MOTOR_ENABLED,CASSETTE_MASK_MOTOR);
+
+ /* does user want to hear the sound? */
+ if BIT(machine.root_device().ioport("CONFIG")->read(), 3)
+ state->m_cass->change_state(CASSETTE_SPEAKER_ENABLED,CASSETTE_MASK_SPEAKER);
+ else
+ state->m_cass->change_state(CASSETTE_SPEAKER_MUTED,CASSETTE_MASK_SPEAKER);
+}
+
+/********************************************* TIMER ************************************************/
+
+
+ /* this timer runs at 200khz and does 2 jobs:
+ 1. Scan the keyboard and present the results to the pio
+ 2. Emulate the 2 chips in the cassette input circuit
+
+ Reasons why it is necessary:
+ 1. The real z80pio is driven by the cpu clock and is capable of independent actions.
+ MAME does not support this at all. If the interrupt key sequence is entered, the
+ computer can be reset out of a hung state by the operator.
+ 2. This "emulates" U79 CD4046BCN PLL chip and U1 LM311P op-amp. U79 converts a frequency to a voltage,
+ and U1 amplifies that voltage to digital levels. U1 has a trimpot connected, to set the midpoint.
+
+ The MDS homebrew input circuit consists of 2 op-amps followed by a D-flipflop.
+ My "read-any-system" cassette circuit was a CA3140 op-amp, the smarts being done in software.
+
+ bit 0 = original system (U79 and U1)
+ bit 1 = MDS fast system
+ bit 2 = CA3140 */
+
+static TIMER_CALLBACK( super80_timer )
+{
+ super80_state *state = machine.driver_data<super80_state>();
+ UINT8 cass_ws=0;
+
+ state->m_cass_data[1]++;
+ cass_ws = ((state->m_cass)->input() > +0.03) ? 4 : 0;
+
+ if (cass_ws != state->m_cass_data[0])
+ {
+ if (cass_ws) state->m_cass_data[3] ^= 2; // the MDS flipflop
+ state->m_cass_data[0] = cass_ws;
+ state->m_cass_data[2] = ((state->m_cass_data[1] < 0x40) ? 1 : 0) | cass_ws | state->m_cass_data[3];
+ state->m_cass_data[1] = 0;
+ }
+
+ state->m_pio->port_b_write(pio_port_b_r(state->m_pio,0));
+}
+
+/* after the first 4 bytes have been read from ROM, switch the ram back in */
+static TIMER_CALLBACK( super80_reset )
+{
+ super80_state *state = machine.driver_data<super80_state>();
+ state->membank("boot")->set_entry(0);
+}
+
+static TIMER_CALLBACK( super80_halfspeed )
+{
+ UINT8 go_fast = 0;
+ super80_state *state = machine.driver_data<super80_state>();
+ if ( (!BIT(state->m_shared, 2)) | (!BIT(machine.root_device().ioport("CONFIG")->read(), 1)) ) /* bit 2 of port F0 is low, OR user turned on config switch */
+ go_fast++;
+
+ /* code to slow down computer to 1 MHz by halting cpu on every second frame */
+ if (!go_fast)
+ {
+ if (!state->m_int_sw)
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_HALT, ASSERT_LINE); // if going, stop it
+
+ state->m_int_sw++;
+ if (state->m_int_sw > 1)
+ {
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_HALT, CLEAR_LINE); // if stopped, start it
+ state->m_int_sw = 0;
+ }
+ }
+ else
+ {
+ if (state->m_int_sw < 8) // @2MHz, reset just once
+ {
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_HALT, CLEAR_LINE);
+ state->m_int_sw = 8; // ...not every time
+ }
+ }
+}
+
+/*************************************** PRINTER ********************************************************/
+
+/* The Super80 had an optional I/O card that plugged into the S-100 slot. The card had facility for running
+ an 8-bit Centronics printer, and a serial device at 300, 600, or 1200 baud. The I/O address range
+ was selectable via 4 dipswitches. The serial parameters (baud rate, parity, stop bits, etc) was
+ chosen with more dipswitches. Regretably, no parameters could be set by software. Currently, the
+ Centronics printer is emulated; the serial side of things may be done later, as will the dipswitches.
+
+ The most commonly used I/O range is DC-DE (DC = centronics, DD = serial data, DE = serial control
+ All the home-brew roms use this, except for super80e which uses BC-BE. */
+
+/**************************** I/O PORTS *****************************************************************/
+
+READ8_MEMBER( super80_state::super80_dc_r )
+{
+ UINT8 data=0x7f;
+
+ /* bit 7 = printer busy 0 = printer is not busy */
+
+ data |= m_centronics->busy_r() << 7;
+
+ return data;
+}
+
+READ8_MEMBER( super80_state::super80_f2_r )
+{
+ UINT8 data = ioport("DSW")->read() & 0xf0; // dip switches on pcb
+ data |= m_cass_data[2]; // bit 0 = output of U1, bit 1 = MDS cass state, bit 2 = current wave_state
+ data |= 0x08; // bit 3 - not used
+ return data;
+}
+
+WRITE8_MEMBER( super80_state::super80_dc_w )
+{
+ /* hardware strobe driven from port select, bit 7..0 = data */
+ m_centronics->strobe_w( 1);
+ m_centronics->write(space, 0, data);
+ m_centronics->strobe_w(0);
+}
+
+
+WRITE8_MEMBER( super80_state::super80_f0_w )
+{
+ UINT8 bits = data ^ m_last_data;
+ m_shared = data;
+ speaker_level_w(m_speaker, BIT(data, 3)); /* bit 3 - speaker */
+ if (BIT(bits, 1)) super80_cassette_motor(machine(), BIT(data, 1)); /* bit 1 - cassette motor */
+ m_cass->output( BIT(data, 0) ? -1.0 : +1.0); /* bit 0 - cass out */
+
+ m_last_data = data;
+}
+
+WRITE8_MEMBER( super80_state::super80r_f0_w )
+{
+ UINT8 bits = data ^ m_last_data;
+ m_shared = data | 0x14;
+ speaker_level_w(m_speaker, BIT(data, 3)); /* bit 3 - speaker */
+ if (BIT(bits, 1)) super80_cassette_motor(machine(), BIT(data, 1)); /* bit 1 - cassette motor */
+ m_cass->output( BIT(data, 0) ? -1.0 : +1.0); /* bit 0 - cass out */
+
+ m_last_data = data;
+}
+
+/**************************** BASIC MACHINE CONSTRUCTION ***********************************************************/
+
+void super80_state::machine_reset()
+{
+ m_shared=0xff;
+ machine().scheduler().timer_set(attotime::from_usec(10), FUNC(super80_reset));
+ membank("boot")->set_entry(1);
+}
+
+static void driver_init_common( running_machine &machine )
+{
+ super80_state *state = machine.driver_data<super80_state>();
+ UINT8 *RAM = state->memregion("maincpu")->base();
+ state->membank("boot")->configure_entries(0, 2, &RAM[0x0000], 0xc000);
+ machine.scheduler().timer_pulse(attotime::from_hz(200000), FUNC(super80_timer)); /* timer for keyboard and cassette */
+}
+
+DRIVER_INIT_MEMBER(super80_state,super80)
+{
+ machine().scheduler().timer_pulse(attotime::from_hz(100), FUNC(super80_halfspeed)); /* timer for 1MHz slowdown */
+ driver_init_common(machine());
+}
+
+DRIVER_INIT_MEMBER(super80_state,super80v)
+{
+ driver_init_common(machine());
+}
+
diff --git a/src/mess/machine/svi318.c b/src/mess/machine/svi318.c
new file mode 100644
index 00000000000..dde43107f98
--- /dev/null
+++ b/src/mess/machine/svi318.c
@@ -0,0 +1,915 @@
+/*
+** Spectravideo SVI-318 and SVI-328
+**
+** Sean Young, Tomas Karlsson
+**
+*/
+
+#include "emu.h"
+#include "video/mc6845.h"
+#include "includes/svi318.h"
+#include "cpu/z80/z80.h"
+#include "video/tms9928a.h"
+#include "machine/i8255.h"
+#include "machine/ins8250.h"
+#include "machine/wd17xx.h"
+#include "machine/ctronics.h"
+#include "imagedev/flopdrv.h"
+#include "imagedev/cassette.h"
+#include "formats/svi_cas.h"
+#include "sound/dac.h"
+#include "sound/ay8910.h"
+#include "machine/ram.h"
+
+enum {
+ SVI_INTERNAL = 0,
+ SVI_CART = 1,
+ SVI_EXPRAM2 = 2,
+ SVI_EXPRAM3 = 3
+};
+
+
+static void svi318_set_banks(running_machine &machine);
+
+
+/* Serial ports */
+
+static WRITE_LINE_DEVICE_HANDLER( svi318_ins8250_interrupt )
+{
+ svi318_state *drvstate = device->machine().driver_data<svi318_state>();
+ if (drvstate->m_svi.bankLow != SVI_CART)
+ {
+ cputag_set_input_line(device->machine(), "maincpu", 0, (state ? HOLD_LINE : CLEAR_LINE));
+ }
+}
+#if 0
+static INS8250_REFRESH_CONNECT( svi318_com_refresh_connected )
+{
+ /* Motorola MC14412 modem */
+ ins8250_handshake_in(device, UART8250_HANDSHAKE_IN_CTS|UART8250_HANDSHAKE_IN_DSR|UART8250_INPUTS_RING_INDICATOR|UART8250_INPUTS_DATA_CARRIER_DETECT);
+}
+#endif
+const ins8250_interface svi318_ins8250_interface[2]=
+{
+ {
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_LINE(svi318_ins8250_interrupt),
+ DEVCB_NULL,
+ DEVCB_NULL
+ },
+ {
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_LINE(svi318_ins8250_interrupt),
+ DEVCB_NULL,
+ DEVCB_NULL
+ }
+};
+
+
+/* Cartridge */
+
+static int svi318_verify_cart (UINT8 magic[2])
+{
+ /* read the first two bytes */
+ if ( (magic[0] == 0xf3) && (magic[1] == 0x31) )
+ return IMAGE_VERIFY_PASS;
+ else
+ return IMAGE_VERIFY_FAIL;
+}
+
+DEVICE_START( svi318_cart )
+{
+ svi318_state *state = device->machine().driver_data<svi318_state>();
+ state->m_pcart = NULL;
+ state->m_pcart_rom_size = 0;
+}
+
+DEVICE_IMAGE_LOAD( svi318_cart )
+{
+ svi318_state *state = image.device().machine().driver_data<svi318_state>();
+ UINT8 *p = state->memregion("user1")->base();
+ UINT32 size;
+
+ if (image.software_entry() == NULL)
+ size = image.length();
+ else
+ size = image.get_software_region_length("rom");
+
+ if (size > 0x8000)
+ logerror("Cart image %s larger than expected. Please report the issue.\n", image.filename());
+
+ if (image.software_entry() == NULL)
+ {
+ if (image.fread(p, size) != size)
+ {
+ logerror("Can't read file %s\n", image.filename());
+ return IMAGE_INIT_FAIL;
+ }
+ }
+ else
+ memcpy(p, image.get_software_region("rom"), size);
+
+ if (svi318_verify_cart(p) == IMAGE_VERIFY_FAIL)
+ return IMAGE_INIT_FAIL;
+
+ state->m_pcart = p;
+ state->m_pcart_rom_size = size;
+
+ return IMAGE_INIT_PASS;
+}
+
+DEVICE_IMAGE_UNLOAD( svi318_cart )
+{
+ svi318_state *state = image.device().machine().driver_data<svi318_state>();
+ state->m_pcart = NULL;
+ state->m_pcart_rom_size = 0;
+}
+
+/* PPI */
+
+/*
+ PPI Port A Input (address 98H)
+ Bit Name Description
+ 1 TA Joystick 1, /SENSE
+ 2 TB Joystick 1, EOC
+ 3 TC Joystick 2, /SENSE
+ 4 TD Joystick 2, EOC
+ 5 TRIGGER1 Joystick 1, Trigger
+ 6 TRIGGER2 Joystick 2, Trigger
+ 7 /READY Cassette, Ready
+ 8 CASR Cassette, Read data
+*/
+
+static READ8_DEVICE_HANDLER ( svi318_ppi_port_a_r )
+{
+ int data = 0x0f;
+
+ if ((device->machine().device<cassette_image_device>(CASSETTE_TAG))->input() > 0.0038)
+ data |= 0x80;
+ if (!svi318_cassette_present(device->machine(), 0))
+ data |= 0x40;
+ data |= device->machine().root_device().ioport("BUTTONS")->read() & 0x30;
+
+ return data;
+}
+
+/*
+ PPI Port B Input (address 99H)
+ Bit Name Description
+ 1 IN0 Keyboard, Column status of selected line
+ 2 IN1 Keyboard, Column status of selected line
+ 3 IN2 Keyboard, Column status of selected line
+ 4 IN3 Keyboard, Column status of selected line
+ 5 IN4 Keyboard, Column status of selected line
+ 6 IN5 Keyboard, Column status of selected line
+ 7 IN6 Keyboard, Column status of selected line
+ 8 IN7 Keyboard, Column status of selected line
+*/
+
+static READ8_DEVICE_HANDLER ( svi318_ppi_port_b_r )
+{
+ svi318_state *state = device->machine().driver_data<svi318_state>();
+ int row;
+ static const char *const keynames[] = {
+ "LINE0", "LINE1", "LINE2", "LINE3", "LINE4", "LINE5",
+ "LINE6", "LINE7", "LINE8", "LINE9", "LINE10"
+ };
+
+ row = state->m_svi.keyboard_row;
+ if (row <= 10)
+ return device->machine().root_device().ioport(keynames[row])->read();
+
+ return 0xff;
+}
+
+/*
+ PPI Port C Output (address 97H)
+ Bit Name Description
+ 1 KB0 Keyboard, Line select 0
+ 2 KB1 Keyboard, Line select 1
+ 3 KB2 Keyboard, Line select 2
+ 4 KB3 Keyboard, Line select 3
+ 5 CASON Cassette, Motor relay control (0=on, 1=off)
+ 6 CASW Cassette, Write data
+ 7 CASAUD Cassette, Audio out (pulse)
+ 8 SOUND Keyboard, Click sound bit (pulse)
+*/
+
+static WRITE8_DEVICE_HANDLER ( svi318_ppi_port_c_w )
+{
+ svi318_state *state = device->machine().driver_data<svi318_state>();
+ int val;
+
+ /* key click */
+ val = (data & 0x80) ? 0x3e : 0;
+ val += (data & 0x40) ? 0x3e : 0;
+ device->machine().device<dac_device>("dac")->write_signed8(val);
+
+ /* cassette motor on/off */
+ if (svi318_cassette_present(device->machine(), 0))
+ {
+
+ device->machine().device<cassette_image_device>(CASSETTE_TAG)->change_state(
+ (data & 0x10) ? CASSETTE_MOTOR_DISABLED : CASSETTE_MOTOR_ENABLED,
+ CASSETTE_MOTOR_DISABLED);
+ }
+
+ /* cassette signal write */
+ device->machine().device<cassette_image_device>(CASSETTE_TAG)->output((data & 0x20) ? -1.0 : +1.0);
+
+ state->m_svi.keyboard_row = data & 0x0F;
+}
+
+I8255_INTERFACE( svi318_ppi8255_interface )
+{
+ DEVCB_HANDLER(svi318_ppi_port_a_r),
+ DEVCB_NULL,
+ DEVCB_HANDLER(svi318_ppi_port_b_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(svi318_ppi_port_c_w)
+};
+
+WRITE8_MEMBER(svi318_state::svi318_ppi_w)
+{
+ i8255_device *ppi = machine().device<i8255_device>("ppi8255");
+ ppi->write(space, offset + 2, data);
+}
+
+
+/* PSG */
+
+/*
+ PSG Port A Input
+ Bit Name Description
+ 1 FWD1 Joystick 1, Forward
+ 2 BACK1 Joystick 1, Back
+ 3 LEFT1 Joystick 1, Left
+ 4 RIGHT1 Joystick 1, Right
+ 5 FWD2 Joystick 2, Forward
+ 6 BACK2 Joystick 2, Back
+ 7 LEFT2 Joystick 2, Left
+ 8 RIGHT2 Joystick 2, Right
+*/
+
+READ8_MEMBER(svi318_state::svi318_psg_port_a_r)
+{
+ return ioport("JOYSTICKS")->read();
+}
+
+/*
+ PSG Port B Output
+ Bit Name Description
+ 1 /CART Memory bank 11, ROM 0000-7FFF (Cartridge /CCS1, /CCS2)
+ 2 /BK21 Memory bank 21, RAM 0000-7FFF
+ 3 /BK22 Memory bank 22, RAM 8000-FFFF
+ 4 /BK31 Memory bank 31, RAM 0000-7FFF
+ 5 /BK32 Memory bank 32, RAM 8000-7FFF
+ 6 CAPS Caps-Lock diod
+ 7 /ROMEN0 Memory bank 12, ROM 8000-BFFF* (Cartridge /CCS3)
+ 8 /ROMEN1 Memory bank 12, ROM C000-FFFF* (Cartridge /CCS4)
+
+ * The /CART signal must be active for any effect and all banks
+ with RAM are disabled.
+*/
+
+WRITE8_MEMBER(svi318_state::svi318_psg_port_b_w)
+{
+ if ( (m_svi.bank_switch ^ data) & 0x20)
+ set_led_status (machine(), 0, !(data & 0x20) );
+
+ m_svi.bank_switch = data;
+ svi318_set_banks(machine());
+}
+
+/* Disk drives */
+
+static WRITE_LINE_DEVICE_HANDLER( svi_fdc_intrq_w )
+{
+ svi318_state *drvstate = device->machine().driver_data<svi318_state>();
+ drvstate->m_fdc.irq = state;
+}
+
+static WRITE_LINE_DEVICE_HANDLER( svi_fdc_drq_w )
+{
+ svi318_state *drvstate = device->machine().driver_data<svi318_state>();
+ drvstate->m_fdc.drq = state;
+}
+
+const wd17xx_interface svi_wd17xx_interface =
+{
+ DEVCB_NULL,
+ DEVCB_LINE(svi_fdc_intrq_w),
+ DEVCB_LINE(svi_fdc_drq_w),
+ {FLOPPY_0, FLOPPY_1, NULL, NULL}
+};
+
+WRITE8_MEMBER(svi318_state::svi318_fdc_drive_motor_w)
+{
+ device_t *fdc = machine().device("wd179x");
+ switch (data & 3)
+ {
+ case 1:
+ wd17xx_set_drive(fdc,0);
+ m_fdc.driveselect = 0;
+ break;
+ case 2:
+ wd17xx_set_drive(fdc,1);
+ m_fdc.driveselect = 1;
+ break;
+ }
+}
+
+WRITE8_MEMBER(svi318_state::svi318_fdc_density_side_w)
+{
+ device_t *fdc = machine().device("wd179x");
+
+ wd17xx_dden_w(fdc, BIT(data, 0));
+ wd17xx_set_side(fdc, BIT(data, 1));
+}
+
+READ8_MEMBER(svi318_state::svi318_fdc_irqdrq_r)
+{
+ UINT8 result = 0;
+
+ result |= m_fdc.drq << 6;
+ result |= m_fdc.irq << 7;
+
+ return result;
+}
+
+MC6845_UPDATE_ROW( svi806_crtc6845_update_row )
+{
+ svi318_state *state = device->machine().driver_data<svi318_state>();
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+ int i;
+
+ for( i = 0; i < x_count; i++ )
+ {
+ int j;
+ UINT8 data = state->m_svi.svi806_gfx[ state->m_svi.svi806_ram->u8(( ma + i ) & 0x7FF) * 16 + ra ];
+
+ if ( i == cursor_x )
+ {
+ data = 0xFF;
+ }
+
+ for( j=0; j < 8; j++ )
+ {
+ bitmap.pix32(y, i * 8 + j ) = palette[TMS9928A_PALETTE_SIZE + ( ( data & 0x80 ) ? 1 : 0 )];
+ data = data << 1;
+ }
+ }
+}
+
+
+/* 80 column card init */
+static void svi318_80col_init(running_machine &machine)
+{
+ svi318_state *state = machine.driver_data<svi318_state>();
+ /* 2K RAM, but allocating 4KB to make banking easier */
+ /* The upper 2KB will be set to FFs and will never be written to */
+ state->m_svi.svi806_ram = machine.memory().region_alloc("gfx2", 0x1000, 1, ENDIANNESS_LITTLE );
+ memset( state->m_svi.svi806_ram->base(), 0x00, 0x800 );
+ memset( state->m_svi.svi806_ram->base() + 0x800, 0xFF, 0x800 );
+ state->m_svi.svi806_gfx = state->memregion("gfx1")->base();
+}
+
+
+WRITE8_MEMBER(svi318_state::svi806_ram_enable_w)
+{
+ m_svi.svi806_ram_enabled = ( data & 0x01 );
+ svi318_set_banks(machine());
+}
+
+VIDEO_START( svi328_806 )
+{
+}
+
+MACHINE_RESET( svi328_806 )
+{
+ svi318_state *state = machine.driver_data<svi318_state>();
+ MACHINE_RESET_CALL(svi318);
+
+ svi318_80col_init(machine);
+ state->m_svi.svi806_present = 1;
+ svi318_set_banks(machine);
+
+ /* Set SVI-806 80 column card palette */
+ palette_set_color_rgb( machine, TMS9928A_PALETTE_SIZE, 0, 0, 0 ); /* Monochrome black */
+ palette_set_color_rgb( machine, TMS9928A_PALETTE_SIZE+1, 0, 224, 0 ); /* Monochrome green */
+}
+
+/* Init functions */
+
+void svi318_vdp_interrupt(running_machine &machine, int i)
+{
+ cputag_set_input_line(machine, "maincpu", 0, (i ? HOLD_LINE : CLEAR_LINE));
+}
+
+
+static const UINT8 cc_op[0x100] = {
+ 4+1,10+1, 7+1, 6+1, 4+1, 4+1, 7+1, 4+1, 4+1,11+1, 7+1, 6+1, 4+1, 4+1, 7+1, 4+1,
+ 8+1,10+1, 7+1, 6+1, 4+1, 4+1, 7+1, 4+1,12+1,11+1, 7+1, 6+1, 4+1, 4+1, 7+1, 4+1,
+ 7+1,10+1,16+1, 6+1, 4+1, 4+1, 7+1, 4+1, 7+1,11+1,16+1, 6+1, 4+1, 4+1, 7+1, 4+1,
+ 7+1,10+1,13+1, 6+1,11+1,11+1,10+1, 4+1, 7+1,11+1,13+1, 6+1, 4+1, 4+1, 7+1, 4+1,
+ 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1,
+ 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1,
+ 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1,
+ 7+1, 7+1, 7+1, 7+1, 7+1, 7+1, 4+1, 7+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1,
+ 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1,
+ 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1,
+ 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1,
+ 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 4+1, 7+1, 4+1,
+ 5+1,10+1,10+1,10+1,10+1,11+1, 7+1,11+1, 5+1,10+1,10+1, 0+1,10+1,17+1, 7+1,11+1,
+ 5+1,10+1,10+1,11+1,10+1,11+1, 7+1,11+1, 5+1, 4+1,10+1,11+1,10+1, 0+1, 7+1,11+1,
+ 5+1,10+1,10+1,19+1,10+1,11+1, 7+1,11+1, 5+1, 4+1,10+1, 4+1,10+1, 0+1, 7+1,11+1,
+ 5+1,10+1,10+1, 4+1,10+1,11+1, 7+1,11+1, 5+1, 6+1,10+1, 4+1,10+1, 0+1, 7+1,11+1
+};
+
+static const UINT8 cc_cb[0x100] = {
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,12+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,12+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,12+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,12+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,12+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,12+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,12+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,12+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,15+2, 8+2
+};
+
+static const UINT8 cc_ed[0x100] = {
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
+12+2,12+2,15+2,20+2, 8+2,14+2, 8+2, 9+2,12+2,12+2,15+2,20+2, 8+2,14+2, 8+2, 9+2,
+12+2,12+2,15+2,20+2, 8+2,14+2, 8+2, 9+2,12+2,12+2,15+2,20+2, 8+2,14+2, 8+2, 9+2,
+12+2,12+2,15+2,20+2, 8+2,14+2, 8+2,18+2,12+2,12+2,15+2,20+2, 8+2,14+2, 8+2,18+2,
+12+2,12+2,15+2,20+2, 8+2,14+2, 8+2, 8+2,12+2,12+2,15+2,20+2, 8+2,14+2, 8+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
+16+2,16+2,16+2,16+2, 8+2, 8+2, 8+2, 8+2,16+2,16+2,16+2,16+2, 8+2, 8+2, 8+2, 8+2,
+16+2,16+2,16+2,16+2, 8+2, 8+2, 8+2, 8+2,16+2,16+2,16+2,16+2, 8+2, 8+2, 8+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2,
+ 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2, 8+2
+};
+
+static const UINT8 cc_xy[0x100] = {
+ 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2,15+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2,
+ 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2,15+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2,
+ 4+2,14+2,20+2,10+2, 9+2, 9+2, 9+2, 4+2, 4+2,15+2,20+2,10+2, 9+2, 9+2, 9+2, 4+2,
+ 4+2, 4+2, 4+2, 4+2,23+2,23+2,19+2, 4+2, 4+2,15+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2,
+ 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2, 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2,
+ 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2, 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2,
+ 9+2, 9+2, 9+2, 9+2, 9+2, 9+2,19+2, 9+2, 9+2, 9+2, 9+2, 9+2, 9+2, 9+2,19+2, 9+2,
+19+2,19+2,19+2,19+2,19+2,19+2, 4+2,19+2, 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2,
+ 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2, 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2,
+ 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2, 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2,
+ 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2, 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2,
+ 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2, 4+2, 4+2, 4+2, 4+2, 9+2, 9+2,19+2, 4+2,
+ 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 0+2, 4+2, 4+2, 4+2, 4+2,
+ 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2,
+ 4+2,14+2, 4+2,23+2, 4+2,15+2, 4+2, 4+2, 4+2, 8+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2,
+ 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2,10+2, 4+2, 4+2, 4+2, 4+2, 4+2, 4+2
+};
+
+static const UINT8 cc_xycb[0x100] = {
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
+20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,
+20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,
+20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,
+20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,20+2,
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,
+23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2,23+2
+};
+
+/* 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+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, 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+1
+};
+
+
+DRIVER_INIT_MEMBER(svi318_state,svi318)
+{
+ /* z80 stuff */
+ z80_set_cycle_tables( machine().device("maincpu"), cc_op, cc_cb, cc_ed, cc_xy, cc_xycb, cc_ex );
+
+ memset(&m_svi, 0, sizeof (m_svi) );
+
+ if ( ! strcmp( machine().system().name, "svi318" ) || ! strcmp( machine().system().name, "svi318n" ) )
+ {
+ m_svi.svi318 = 1;
+ }
+
+ device_set_input_line_vector(machine().device("maincpu"), 0, 0xff);
+
+ /* memory */
+ m_svi.empty_bank = auto_alloc_array(machine(), UINT8, 0x8000);
+ memset (m_svi.empty_bank, 0xff, 0x8000);
+}
+
+MACHINE_START( svi318_ntsc )
+{
+}
+
+MACHINE_START( svi318_pal )
+{
+}
+
+static void svi318_load_proc(device_image_interface &image)
+{
+ svi318_state *state = image.device().machine().driver_data<svi318_state>();
+ int size;
+ int id = floppy_get_drive(&image.device());
+
+ size = image.length();
+ switch (size)
+ {
+ case 172032: /* SVI-328 SSDD */
+ state->m_fdc.heads[id] = 1;
+ break;
+ case 346112: /* SVI-328 DSDD */
+ state->m_fdc.heads[id] = 2;
+ break;
+ case 348160: /* SVI-728 DSDD CP/M */
+ state->m_fdc.heads[id] = 2;
+ break;
+ }
+}
+
+MACHINE_RESET( svi318 )
+{
+ svi318_state *state = machine.driver_data<svi318_state>();
+ int drive;
+
+ state->m_svi.bank_switch = 0xff;
+ svi318_set_banks(machine);
+
+ for(drive=0;drive<2;drive++)
+ {
+ floppy_install_load_proc(floppy_get_device(machine, drive), svi318_load_proc);
+ }
+}
+
+/* Memory */
+
+WRITE8_MEMBER(svi318_state::svi318_writemem1)
+{
+ if ( m_svi.bankLow_read_only )
+ return;
+
+ m_svi.bankLow_ptr[offset] = data;
+}
+
+WRITE8_MEMBER(svi318_state::svi318_writemem2)
+{
+ if ( m_svi.bankHigh1_read_only)
+ return;
+
+ m_svi.bankHigh1_ptr[offset] = data;
+}
+
+WRITE8_MEMBER(svi318_state::svi318_writemem3)
+{
+ if ( m_svi.bankHigh2_read_only)
+ return;
+
+ m_svi.bankHigh2_ptr[offset] = data;
+}
+
+WRITE8_MEMBER(svi318_state::svi318_writemem4)
+{
+ if ( m_svi.svi806_ram_enabled )
+ {
+ if ( offset < 0x800 )
+ {
+ m_svi.svi806_ram->u8(offset) = data;
+ }
+ }
+ else
+ {
+ if ( m_svi.bankHigh2_read_only )
+ return;
+
+ m_svi.bankHigh2_ptr[ 0x3000 + offset] = data;
+ }
+}
+
+static void svi318_set_banks(running_machine &machine)
+{
+ svi318_state *state = machine.driver_data<svi318_state>();
+ const UINT8 v = state->m_svi.bank_switch;
+ UINT8 *ram = machine.device<ram_device>(RAM_TAG)->pointer();
+ UINT32 ram_size = machine.device<ram_device>(RAM_TAG)->size();
+
+ state->m_svi.bankLow = ( v & 1 ) ? ( ( v & 2 ) ? ( ( v & 8 ) ? SVI_INTERNAL : SVI_EXPRAM3 ) : SVI_EXPRAM2 ) : SVI_CART;
+ state->m_svi.bankHigh1 = ( v & 4 ) ? ( ( v & 16 ) ? SVI_INTERNAL : SVI_EXPRAM3 ) : SVI_EXPRAM2;
+
+ state->m_svi.bankLow_ptr = state->m_svi.empty_bank;
+ state->m_svi.bankLow_read_only = 1;
+
+ switch( state->m_svi.bankLow )
+ {
+ case SVI_INTERNAL:
+ state->m_svi.bankLow_ptr = state->memregion("maincpu")->base();
+ break;
+ case SVI_CART:
+ if ( state->m_pcart )
+ {
+ state->m_svi.bankLow_ptr = state->m_pcart;
+ }
+ break;
+ case SVI_EXPRAM2:
+ if ( ram_size >= 64 * 1024 )
+ {
+ state->m_svi.bankLow_ptr = ram + ram_size - 64 * 1024;
+ state->m_svi.bankLow_read_only = 0;
+ }
+ break;
+ case SVI_EXPRAM3:
+ if ( ram_size > 128 * 1024 )
+ {
+ state->m_svi.bankLow_ptr = ram + ram_size - 128 * 1024;
+ state->m_svi.bankLow_read_only = 0;
+ }
+ break;
+ }
+
+ state->m_svi.bankHigh1_ptr = state->m_svi.bankHigh2_ptr = state->m_svi.empty_bank;
+ state->m_svi.bankHigh1_read_only = state->m_svi.bankHigh2_read_only = 1;
+
+ switch( state->m_svi.bankHigh1 )
+ {
+ case SVI_INTERNAL:
+ if ( ram_size == 16 * 1024 )
+ {
+ state->m_svi.bankHigh2_ptr = ram;
+ state->m_svi.bankHigh2_read_only = 0;
+ }
+ else
+ {
+ state->m_svi.bankHigh1_ptr = ram;
+ state->m_svi.bankHigh1_read_only = 0;
+ state->m_svi.bankHigh2_ptr = ram + 0x4000;
+ state->m_svi.bankHigh2_read_only = 0;
+ }
+ break;
+ case SVI_EXPRAM2:
+ if ( ram_size > 64 * 1024 )
+ {
+ state->m_svi.bankHigh1_ptr = ram + ram_size - 64 * 1024 + 32 * 1024;
+ state->m_svi.bankHigh1_read_only = 0;
+ state->m_svi.bankHigh2_ptr = ram + ram_size - 64 * 1024 + 48 * 1024;
+ state->m_svi.bankHigh2_read_only = 0;
+ }
+ break;
+ case SVI_EXPRAM3:
+ if ( ram_size > 128 * 1024 )
+ {
+ state->m_svi.bankHigh1_ptr = ram + ram_size - 128 * 1024 + 32 * 1024;
+ state->m_svi.bankHigh1_read_only = 0;
+ state->m_svi.bankHigh2_ptr = ram + ram_size - 128 * 1024 + 48 * 1024;
+ state->m_svi.bankHigh2_read_only = 0;
+ }
+ break;
+ }
+
+ /* Check for special CART based banking */
+ if ( state->m_svi.bankLow == SVI_CART && ( v & 0xc0 ) != 0xc0 )
+ {
+ state->m_svi.bankHigh1_ptr = state->m_svi.empty_bank;
+ state->m_svi.bankHigh1_read_only = 1;
+ state->m_svi.bankHigh2_ptr = state->m_svi.empty_bank;
+ state->m_svi.bankHigh2_read_only = 1;
+ if ( state->m_pcart && ! ( v & 0x80 ) )
+ {
+ state->m_svi.bankHigh2_ptr = state->m_pcart + 0x4000;
+ }
+ if ( state->m_pcart && ! ( v & 0x40 ) )
+ {
+ state->m_svi.bankHigh1_ptr = state->m_pcart;
+ }
+ }
+
+ state->membank("bank1")->set_base(state->m_svi.bankLow_ptr );
+ state->membank("bank2")->set_base(state->m_svi.bankHigh1_ptr );
+ state->membank("bank3")->set_base(state->m_svi.bankHigh2_ptr );
+
+ /* SVI-806 80 column card specific banking */
+ if ( state->m_svi.svi806_present )
+ {
+ if ( state->m_svi.svi806_ram_enabled )
+ {
+ state->membank("bank4")->set_base(state->m_svi.svi806_ram );
+ }
+ else
+ {
+ state->membank("bank4")->set_base(state->m_svi.bankHigh2_ptr + 0x3000 );
+ }
+ }
+}
+
+/* Cassette */
+
+int svi318_cassette_present(running_machine &machine, int id)
+{
+ device_image_interface *image = dynamic_cast<device_image_interface *>(machine.device<cassette_image_device>(CASSETTE_TAG));
+
+ if ( image == NULL )
+ return FALSE;
+ return image->exists();
+}
+
+/* External I/O */
+
+READ8_MEMBER(svi318_state::svi318_io_ext_r)
+{
+ UINT8 data = 0xff;
+ device_t *device;
+ ins8250_device *uart;
+ centronics_device *centronics = machine().device<centronics_device>("centronics");
+
+ if (m_svi.bankLow == SVI_CART)
+ {
+ return 0xff;
+ }
+
+ switch( offset )
+ {
+ case 0x12:
+ data = 0xfe | centronics->busy_r();
+ break;
+
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x24:
+ case 0x25:
+ case 0x26:
+ case 0x27:
+ uart = machine().device<ins8250_device>("ins8250_0");
+ data = uart->ins8250_r(space, offset & 7);
+ break;
+
+ case 0x28:
+ case 0x29:
+ case 0x2A:
+ case 0x2B:
+ case 0x2C:
+ case 0x2D:
+ case 0x2E:
+ case 0x2F:
+ uart = machine().device<ins8250_device>("ins8250_1");
+ data = uart->ins8250_r(space, offset & 7);
+ break;
+
+ case 0x30:
+ device = machine().device("wd179x");
+ data = wd17xx_status_r(device, 0);
+ break;
+ case 0x31:
+ device = machine().device("wd179x");
+ data = wd17xx_track_r(device, 0);
+ break;
+ case 0x32:
+ device = machine().device("wd179x");
+ data = wd17xx_sector_r(device, 0);
+ break;
+ case 0x33:
+ device = machine().device("wd179x");
+ data = wd17xx_data_r(device, 0);
+ break;
+ case 0x34:
+ data = svi318_fdc_irqdrq_r(space, 0);
+ break;
+ case 0x51:
+ device = machine().device("crtc");
+ data = downcast<mc6845_device *>(device)->register_r( space, offset );
+ break;
+ }
+
+ return data;
+}
+
+WRITE8_MEMBER(svi318_state::svi318_io_ext_w)
+{
+ device_t *device;
+ ins8250_device *uart;
+ centronics_device *centronics = machine().device<centronics_device>("centronics");
+
+ if (m_svi.bankLow == SVI_CART)
+ {
+ return;
+ }
+
+ switch( offset )
+ {
+ case 0x10:
+ centronics->write(space, 0, data);
+ break;
+
+ case 0x11:
+ centronics->strobe_w(BIT(data, 0));
+ break;
+
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x24:
+ case 0x25:
+ case 0x26:
+ case 0x27:
+ uart = machine().device<ins8250_device>("ins8250_0");
+ uart->ins8250_w(space, offset & 7, data);
+ break;
+
+ case 0x28:
+ case 0x29:
+ case 0x2A:
+ case 0x2B:
+ case 0x2C:
+ case 0x2D:
+ case 0x2E:
+ case 0x2F:
+ uart = machine().device<ins8250_device>("ins8250_1");
+ uart->ins8250_w(space, offset & 7, data);
+ break;
+
+ case 0x30:
+ device = machine().device("wd179x");
+ wd17xx_command_w(device, 0, data);
+ break;
+ case 0x31:
+ device = machine().device("wd179x");
+ wd17xx_track_w(device, 0, data);
+ break;
+ case 0x32:
+ device = machine().device("wd179x");
+ wd17xx_sector_w(device, 0, data);
+ break;
+ case 0x33:
+ device = machine().device("wd179x");
+ wd17xx_data_w(device, 0, data);
+ break;
+ case 0x34:
+ svi318_fdc_drive_motor_w(space, 0, data);
+ break;
+ case 0x38:
+ svi318_fdc_density_side_w(space, 0, data);
+ break;
+
+ case 0x50:
+ device = machine().device("crtc");
+ downcast<mc6845_device *>(device)->address_w(space, offset, data);
+ break;
+ case 0x51:
+ device = machine().device("crtc");
+ downcast<mc6845_device *>(device)->register_w(space, offset, data);
+ break;
+
+ case 0x58:
+ svi806_ram_enable_w(space, 0, data);
+ break;
+ }
+}
diff --git a/src/mess/machine/sym1.c b/src/mess/machine/sym1.c
new file mode 100644
index 00000000000..ec9b3fbaad7
--- /dev/null
+++ b/src/mess/machine/sym1.c
@@ -0,0 +1,310 @@
+/******************************************************************************
+ Synertek Systems Corp. SYM-1
+
+ Early driver by PeT mess@utanet.at May 2000
+ Rewritten by Dirk Best October 2007
+
+******************************************************************************/
+
+
+#include "emu.h"
+#include "includes/sym1.h"
+
+/* M6502 CPU */
+#include "cpu/m6502/m6502.h"
+
+/* Peripheral chips */
+#include "machine/6522via.h"
+#include "machine/6532riot.h"
+#include "machine/74145.h"
+#include "sound/speaker.h"
+#include "machine/ram.h"
+
+#define LED_REFRESH_DELAY attotime::from_usec(70)
+
+
+
+
+
+/******************************************************************************
+ 6532 RIOT
+******************************************************************************/
+
+
+static WRITE_LINE_DEVICE_HANDLER( sym1_74145_output_0_w )
+{
+ sym1_state *drvstate = device->machine().driver_data<sym1_state>();
+ if (state) drvstate->m_led_update->adjust(LED_REFRESH_DELAY);
+}
+
+
+static WRITE_LINE_DEVICE_HANDLER( sym1_74145_output_1_w )
+{
+ sym1_state *drvstate = device->machine().driver_data<sym1_state>();
+ if (state) drvstate->m_led_update->adjust(LED_REFRESH_DELAY, 1);
+}
+
+
+static WRITE_LINE_DEVICE_HANDLER( sym1_74145_output_2_w )
+{
+ sym1_state *drvstate = device->machine().driver_data<sym1_state>();
+ if (state) drvstate->m_led_update->adjust(LED_REFRESH_DELAY, 2);
+}
+
+
+static WRITE_LINE_DEVICE_HANDLER( sym1_74145_output_3_w )
+{
+ sym1_state *drvstate = device->machine().driver_data<sym1_state>();
+ if (state) drvstate->m_led_update->adjust(LED_REFRESH_DELAY, 3);
+}
+
+
+static WRITE_LINE_DEVICE_HANDLER( sym1_74145_output_4_w )
+{
+ sym1_state *drvstate = device->machine().driver_data<sym1_state>();
+ if (state) drvstate->m_led_update->adjust(LED_REFRESH_DELAY, 4);
+}
+
+
+static WRITE_LINE_DEVICE_HANDLER( sym1_74145_output_5_w )
+{
+ sym1_state *drvstate = device->machine().driver_data<sym1_state>();
+ if (state) drvstate->m_led_update->adjust(LED_REFRESH_DELAY, 5);
+}
+
+
+static TIMER_CALLBACK( led_refresh )
+{
+ sym1_state *state = machine.driver_data<sym1_state>();
+ output_set_digit_value(param, state->m_riot_port_a);
+}
+
+
+static READ8_DEVICE_HANDLER(sym1_riot_a_r)
+{
+ sym1_state *state = device->machine().driver_data<sym1_state>();
+ int data = 0x7f;
+
+ /* scan keypad rows */
+ if (!(state->m_riot_port_a & 0x80)) data &= device->machine().root_device().ioport("ROW-0")->read();
+ if (!(state->m_riot_port_b & 0x01)) data &= device->machine().root_device().ioport("ROW-1")->read();
+ if (!(state->m_riot_port_b & 0x02)) data &= device->machine().root_device().ioport("ROW-2")->read();
+ if (!(state->m_riot_port_b & 0x04)) data &= device->machine().root_device().ioport("ROW-3")->read();
+
+ /* determine column */
+ if ( ((state->m_riot_port_a ^ 0xff) & (state->ioport("ROW-0")->read() ^ 0xff)) & 0x7f )
+ data &= ~0x80;
+
+ return data;
+}
+
+
+static READ8_DEVICE_HANDLER(sym1_riot_b_r)
+{
+ sym1_state *state = device->machine().driver_data<sym1_state>();
+ int data = 0xff;
+
+ /* determine column */
+ if ( ((state->m_riot_port_a ^ 0xff) & (device->machine().root_device().ioport("ROW-1")->read() ^ 0xff)) & 0x7f )
+ data &= ~0x01;
+
+ if ( ((state->m_riot_port_a ^ 0xff) & (device->machine().root_device().ioport("ROW-2")->read() ^ 0xff)) & 0x3f )
+ data &= ~0x02;
+
+ if ( ((state->m_riot_port_a ^ 0xff) & (state->ioport("ROW-3")->read() ^ 0xff)) & 0x1f )
+ data &= ~0x04;
+
+ data &= ~0x80; // else hangs 8b02
+
+ return data;
+}
+
+
+static WRITE8_DEVICE_HANDLER(sym1_riot_a_w)
+{
+ sym1_state *state = device->machine().driver_data<sym1_state>();
+ logerror("%x: riot_a_w 0x%02x\n", cpu_get_pc( device->machine().device("maincpu") ), data);
+
+ /* save for later use */
+ state->m_riot_port_a = data;
+}
+
+
+static WRITE8_DEVICE_HANDLER(sym1_riot_b_w)
+{
+ sym1_state *state = device->machine().driver_data<sym1_state>();
+ logerror("%x: riot_b_w 0x%02x\n", cpu_get_pc( device->machine().device("maincpu") ), data);
+
+ /* save for later use */
+ state->m_riot_port_b = data;
+
+ /* first 4 pins are connected to the 74145 */
+ device->machine().device<ttl74145_device>("ttl74145")->write(data & 0x0f);
+}
+
+
+const riot6532_interface sym1_r6532_interface =
+{
+ DEVCB_HANDLER(sym1_riot_a_r),
+ DEVCB_HANDLER(sym1_riot_b_r),
+ DEVCB_HANDLER(sym1_riot_a_w),
+ DEVCB_HANDLER(sym1_riot_b_w)
+};
+
+
+const ttl74145_interface sym1_ttl74145_intf =
+{
+ DEVCB_LINE(sym1_74145_output_0_w), /* connected to DS0 */
+ DEVCB_LINE(sym1_74145_output_1_w), /* connected to DS1 */
+ DEVCB_LINE(sym1_74145_output_2_w), /* connected to DS2 */
+ DEVCB_LINE(sym1_74145_output_3_w), /* connected to DS3 */
+ DEVCB_LINE(sym1_74145_output_4_w), /* connected to DS4 */
+ DEVCB_LINE(sym1_74145_output_5_w), /* connected to DS5 */
+ DEVCB_DEVICE_LINE(SPEAKER_TAG, speaker_level_w),
+ DEVCB_NULL, /* not connected */
+ DEVCB_NULL, /* not connected */
+ DEVCB_NULL /* not connected */
+};
+
+
+/******************************************************************************
+ 6522 VIA
+******************************************************************************/
+
+
+static void sym1_irq(device_t *device, int level)
+{
+ cputag_set_input_line(device->machine(), "maincpu", M6502_IRQ_LINE, level);
+}
+
+
+static READ8_DEVICE_HANDLER( sym1_via0_b_r )
+{
+ return 0xff;
+}
+
+
+static WRITE8_DEVICE_HANDLER( sym1_via0_b_w )
+{
+ logerror("%s: via0_b_w 0x%02x\n", device->machine().describe_context(), data);
+}
+
+
+/* PA0: Write protect R6532 RAM
+ * PA1: Write protect RAM 0x400-0x7ff
+ * PA2: Write protect RAM 0x800-0xbff
+ * PA3: Write protect RAM 0xc00-0xfff
+ */
+static WRITE8_DEVICE_HANDLER( sym1_via2_a_w )
+{
+ address_space *cpu0space = device->machine().device( "maincpu")->memory().space( AS_PROGRAM );
+
+ logerror("SYM1 VIA2 W 0x%02x\n", data);
+
+ if ((device->machine().root_device().ioport("WP")->read() & 0x01) && !(data & 0x01)) {
+ cpu0space->nop_write(0xa600, 0xa67f);
+ } else {
+ cpu0space->install_write_bank(0xa600, 0xa67f, "bank5");
+ }
+ if ((device->machine().root_device().ioport("WP")->read() & 0x02) && !(data & 0x02)) {
+ cpu0space->nop_write(0x0400, 0x07ff);
+ } else {
+ cpu0space->install_write_bank(0x0400, 0x07ff, "bank2");
+ }
+ if ((device->machine().root_device().ioport("WP")->read() & 0x04) && !(data & 0x04)) {
+ cpu0space->nop_write(0x0800, 0x0bff);
+ } else {
+ cpu0space->install_write_bank(0x0800, 0x0bff, "bank3");
+ }
+ if ((device->machine().root_device().ioport("WP")->read() & 0x08) && !(data & 0x08)) {
+ cpu0space->nop_write(0x0c00, 0x0fff);
+ } else {
+ cpu0space->install_write_bank(0x0c00, 0x0fff, "bank4");
+ }
+}
+
+
+const via6522_interface sym1_via0 =
+{
+ DEVCB_NULL, /* VIA Port A Input */
+ DEVCB_HANDLER(sym1_via0_b_r), /* VIA Port B Input */
+ DEVCB_NULL, /* VIA Port CA1 Input */
+ DEVCB_NULL, /* VIA Port CB1 Input */
+ DEVCB_NULL, /* VIA Port CA2 Input */
+ DEVCB_NULL, /* VIA Port CB2 Input */
+ DEVCB_NULL, /* VIA Port A Output */
+ DEVCB_HANDLER(sym1_via0_b_w), /* VIA Port B Output */
+ DEVCB_NULL, /* VIA Port CA1 Output */
+ DEVCB_NULL, /* VIA Port CB1 Output */
+ DEVCB_NULL, /* VIA Port CA2 Output */
+ DEVCB_NULL, /* VIA Port CB2 Output */
+ DEVCB_LINE(sym1_irq) /* VIA IRQ Callback */
+};
+
+
+const via6522_interface sym1_via1 =
+{
+ DEVCB_NULL, /* VIA Port A Input */
+ DEVCB_NULL, /* VIA Port B Input */
+ DEVCB_NULL, /* VIA Port CA1 Input */
+ DEVCB_NULL, /* VIA Port CB1 Input */
+ DEVCB_NULL, /* VIA Port CA2 Input */
+ DEVCB_NULL, /* VIA Port CB2 Input */
+ DEVCB_NULL, /* VIA Port A Output */
+ DEVCB_NULL, /* VIA Port B Output */
+ DEVCB_NULL, /* VIA Port CA1 Output */
+ DEVCB_NULL, /* VIA Port CB1 Output */
+ DEVCB_NULL, /* VIA Port CA2 Output */
+ DEVCB_NULL, /* VIA Port CB2 Output */
+ DEVCB_LINE(sym1_irq) /* VIA IRQ Callback */
+};
+
+
+const via6522_interface sym1_via2 =
+{
+ DEVCB_NULL, /* VIA Port A Input */
+ DEVCB_NULL, /* VIA Port B Input */
+ DEVCB_NULL, /* VIA Port CA1 Input */
+ DEVCB_NULL, /* VIA Port CB1 Input */
+ DEVCB_NULL, /* VIA Port CA2 Input */
+ DEVCB_NULL, /* VIA Port CB2 Input */
+ DEVCB_HANDLER(sym1_via2_a_w), /* VIA Port A Output */
+ DEVCB_NULL, /* VIA Port B Output */
+ DEVCB_NULL, /* VIA Port CA1 Output */
+ DEVCB_NULL, /* VIA Port CB1 Output */
+ DEVCB_NULL, /* VIA Port CA2 Output */
+ DEVCB_NULL, /* VIA Port CB2 Output */
+ DEVCB_LINE(sym1_irq) /* VIA IRQ Callback */
+};
+
+
+
+/******************************************************************************
+ Driver init and reset
+******************************************************************************/
+
+
+DRIVER_INIT_MEMBER(sym1_state,sym1)
+{
+ /* wipe expansion memory banks that are not installed */
+ if (machine().device<ram_device>(RAM_TAG)->size() < 4*1024)
+ {
+ machine().device( "maincpu")->memory().space( AS_PROGRAM )->nop_readwrite(
+ machine().device<ram_device>(RAM_TAG)->size(), 0x0fff);
+ }
+
+ /* allocate a timer to refresh the led display */
+ m_led_update = machine().scheduler().timer_alloc(FUNC(led_refresh));
+}
+
+
+MACHINE_RESET( sym1 )
+{
+ sym1_state *state = machine.driver_data<sym1_state>();
+ /* make 0xf800 to 0xffff point to the last half of the monitor ROM
+ so that the CPU can find its reset vectors */
+ machine.device( "maincpu")->memory().space( AS_PROGRAM )->install_read_bank(0xf800, 0xffff, "bank1");
+ machine.device( "maincpu")->memory().space( AS_PROGRAM )->nop_write(0xf800, 0xffff);
+ state->membank("bank1")->set_base(state->m_monitor + 0x800);
+ machine.device("maincpu")->reset();
+}
diff --git a/src/mess/machine/tandy1t.c b/src/mess/machine/tandy1t.c
new file mode 100644
index 00000000000..20d9727fb06
--- /dev/null
+++ b/src/mess/machine/tandy1t.c
@@ -0,0 +1,401 @@
+#include "emu.h"
+
+#include "machine/pckeybrd.h"
+
+#include "machine/pcshare.h"
+#include "includes/pc.h"
+#include "machine/pit8253.h"
+#include "includes/tandy1t.h"
+
+
+/* tandy 1000 eeprom
+ hx and later
+ clock, and data out lines at 0x37c
+ data in at 0x62 bit 4 (0x10)
+
+ 8x read 16 bit word at x
+ 30 cx 30 4x 16bit 00 write 16bit at x
+*/
+static struct
+{
+ int state;
+ int clock;
+ UINT8 oper;
+ UINT16 data;
+ struct
+ {
+ UINT8 low, high;
+ } ee[0x40]; /* only 0 to 4 used in hx, addressing seems to allow this */
+} eeprom={0};
+
+NVRAM_HANDLER( tandy1000 )
+{
+ if (file==NULL)
+ {
+ // init only
+ }
+ else if (read_or_write)
+ {
+ file->write(eeprom.ee, sizeof(eeprom.ee));
+ }
+ else
+ {
+ file->read(eeprom.ee, sizeof(eeprom.ee));
+ }
+}
+
+static int tandy1000_read_eeprom(void)
+{
+ if ((eeprom.state>=100)&&(eeprom.state<=199))
+ return eeprom.data&0x8000;
+ return 1;
+}
+
+static void tandy1000_write_eeprom(UINT8 data)
+{
+ if (!eeprom.clock && (data&4) )
+ {
+// logerror("!!!tandy1000 eeprom %.2x %.2x\n",eeprom.state, data);
+ switch (eeprom.state)
+ {
+ case 0:
+ if ((data&3)==0) eeprom.state++;
+ break;
+ case 1:
+ if ((data&3)==2) eeprom.state++;
+ break;
+ case 2:
+ if ((data&3)==3) eeprom.state++;
+ break;
+ case 3:
+ eeprom.oper=data&1;
+ eeprom.state++;
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ eeprom.oper=(eeprom.oper<<1)|(data&1);
+ eeprom.state++;
+ break;
+ case 10:
+ eeprom.oper=(eeprom.oper<<1)|(data&1);
+ logerror("!!!tandy1000 eeprom %.2x\n",eeprom.oper);
+ if ((eeprom.oper&0xc0)==0x80)
+ {
+ eeprom.state=100;
+ eeprom.data=eeprom.ee[eeprom.oper&0x3f].low
+ |(eeprom.ee[eeprom.oper&0x3f].high<<8);
+ logerror("!!!tandy1000 eeprom read %.2x,%.4x\n",eeprom.oper,eeprom.data);
+ }
+ else if ((eeprom.oper&0xc0)==0x40)
+ {
+ eeprom.state=200;
+ }
+ else
+ eeprom.state=0;
+ break;
+
+ /* read 16 bit */
+ case 100:
+ eeprom.state++;
+ break;
+ case 101:
+ case 102:
+ case 103:
+ case 104:
+ case 105:
+ case 106:
+ case 107:
+ case 108:
+ case 109:
+ case 110:
+ case 111:
+ case 112:
+ case 113:
+ case 114:
+ case 115:
+ eeprom.data<<=1;
+ eeprom.state++;
+ break;
+ case 116:
+ eeprom.data<<=1;
+ eeprom.state=0;
+ break;
+
+ /* write 16 bit */
+ case 200:
+ case 201:
+ case 202:
+ case 203:
+ case 204:
+ case 205:
+ case 206:
+ case 207:
+ case 208:
+ case 209:
+ case 210:
+ case 211:
+ case 212:
+ case 213:
+ case 214:
+ eeprom.data=(eeprom.data<<1)|(data&1);
+ eeprom.state++;
+ break;
+ case 215:
+ eeprom.data=(eeprom.data<<1)|(data&1);
+ logerror("tandy1000 %.2x %.4x written\n",eeprom.oper,eeprom.data);
+ eeprom.ee[eeprom.oper&0x3f].low=eeprom.data&0xff;
+ eeprom.ee[eeprom.oper&0x3f].high=eeprom.data>>8;
+ eeprom.state=0;
+ break;
+ }
+ }
+ eeprom.clock=data&4;
+}
+
+static struct
+{
+ UINT8 data[8];
+
+ UINT8 bios_bank; /* I/O port FFEAh */
+} tandy={ {0}};
+
+WRITE8_HANDLER ( pc_t1t_p37x_w )
+{
+// DBG_LOG(2,"T1T_p37x_w",("%.5x #%d $%02x\n", cpu_get_pc( &space->device()),offset, data));
+ if (offset!=4)
+ logerror("T1T_p37x_w %.5x #%d $%02x\n", cpu_get_pc( &space->device()),offset, data);
+ tandy.data[offset]=data;
+ switch( offset )
+ {
+ case 4:
+ tandy1000_write_eeprom(data);
+ break;
+ }
+}
+
+ READ8_HANDLER ( pc_t1t_p37x_r )
+{
+ int data = tandy.data[offset];
+// DBG_LOG(1,"T1T_p37x_r",("%.5x #%d $%02x\n", cpu_get_pc( &space->device()), offset, data));
+ return data;
+}
+
+/* this is for tandy1000hx
+ hopefully this works for all x models
+ must not be a ppi8255 chip
+ (think custom chip)
+ port c:
+ bit 4 input eeprom data in
+ bit 3 output turbo mode
+*/
+static struct
+{
+ UINT8 portb, portc;
+} tandy_ppi= { 0 };
+
+WRITE8_HANDLER ( tandy1000_pio_w )
+{
+ switch (offset)
+ {
+ case 1:
+ tandy_ppi.portb = data;
+ pit8253_gate2_w(space->machine().device("pit8253"), BIT(data, 0));
+ pc_speaker_set_spkrdata( space->machine(), data & 0x02 );
+ pc_keyb_set_clock(data&0x40);
+ if ( data & 0x80 )
+ {
+ pc_keyb_clear();
+ }
+ break;
+ case 2:
+ tandy_ppi.portc = data;
+ if (data & 8)
+ space->machine().device("maincpu")->set_clock_scale(1);
+ else
+ space->machine().device("maincpu")->set_clock_scale(4.77/8);
+ break;
+ }
+}
+
+ READ8_HANDLER(tandy1000_pio_r)
+{
+ int data=0xff;
+ switch (offset)
+ {
+ case 0:
+ data = pc_keyb_read();
+ break;
+ case 1:
+ data=tandy_ppi.portb;
+ break;
+ case 2:
+// if (tandy1000hx) {
+// data=tandy_ppi.portc; // causes problems (setuphx)
+ if (!tandy1000_read_eeprom()) data&=~0x10;
+// }
+ break;
+ }
+ return data;
+}
+
+
+static void tandy1000_set_bios_bank( running_machine &machine )
+{
+ machine.root_device().membank( "bank11" )->set_base( machine.root_device().memregion("maincpu")->base() + ( tandy.bios_bank & 0x07 ) * 0x10000 );
+}
+
+
+MACHINE_RESET( tandy1000rl )
+{
+ MACHINE_RESET_CALL( pc );
+ tandy.bios_bank = 6;
+ tandy1000_set_bios_bank( machine );
+}
+
+
+READ8_HANDLER( tandy1000_bank_r )
+{
+ UINT8 data = 0xFF;
+
+ logerror( "%s: tandy1000_bank_r: offset = %x\n", space->machine().describe_context(), offset );
+
+ switch( offset )
+ {
+ case 0x00: /* FFEA */
+ data = tandy.bios_bank;
+ break;
+ }
+
+ return data;
+}
+
+
+WRITE8_HANDLER( tandy1000_bank_w )
+{
+ logerror( "%s: tandy1000_bank_w: offset = %x, data = %02x\n", space->machine().describe_context(), offset, data );
+
+ switch( offset )
+ {
+ case 0x00: /* FFEA */
+ tandy.bios_bank = data;
+ tandy1000_set_bios_bank(space->machine());
+ break;
+ }
+}
+
+
+
+INPUT_PORTS_START( t1000_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("Cursor Up") PORT_CODE(KEYCODE_UP) /* 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("Cursor Left") PORT_CODE(KEYCODE_LEFT) /* 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("Print") /* 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) PORT_TOGGLE/* 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) PORT_TOGGLE/* Num Lock 45 C5 */
+ PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Hold") PORT_CODE(KEYCODE_SCRLOCK) /* 46 C6 */
+ PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 7 \\") PORT_CODE(KEYCODE_7_PAD) /* Keypad 7 47 C7 */
+ PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 8 ~") PORT_CODE(KEYCODE_8_PAD) /* Keypad 8 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("Cursor Down") PORT_CODE(KEYCODE_DOWN) /* 4A CA */
+ PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 4 |") PORT_CODE(KEYCODE_4_PAD) /* Keypad 4 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") PORT_CODE(KEYCODE_6_PAD) /* Keypad 6 4D CD */
+ PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Cursor Right") PORT_CODE(KEYCODE_RIGHT) /* 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 `") PORT_CODE(KEYCODE_2_PAD) /* Keypad 2 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") PORT_CODE(KEYCODE_0_PAD) /* Keypad 0 52 D2 */
+ PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP - (Del)") PORT_CODE(KEYCODE_MINUS_PAD) /* - Delete 53 D3 */
+ PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Break") PORT_CODE(KEYCODE_STOP) /* Break 54 D4 */
+ PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("+ Insert") PORT_CODE(KEYCODE_PLUS_PAD) /* + Insert 55 D5 */
+ PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(".") PORT_CODE(KEYCODE_DEL_PAD) /* . 56 D6 */
+ PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Enter") PORT_CODE(KEYCODE_ENTER_PAD) /* Enter 57 D7 */
+ PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Home") PORT_CODE(KEYCODE_HOME) /* HOME 58 D8 */
+ PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F11") PORT_CODE(KEYCODE_F11) /* F11 59 D9 */
+ PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F12") PORT_CODE(KEYCODE_F12) /* F12 5a Da */
+
+ PORT_START("pc_keyboard_6")
+ PORT_BIT ( 0xffff, 0x0000, IPT_UNUSED )
+
+ PORT_START("pc_keyboard_7")
+ PORT_BIT ( 0xffff, 0x0000, IPT_UNUSED )
+INPUT_PORTS_END
diff --git a/src/mess/machine/tandy2kb.c b/src/mess/machine/tandy2kb.c
new file mode 100644
index 00000000000..2060ca6c096
--- /dev/null
+++ b/src/mess/machine/tandy2kb.c
@@ -0,0 +1,424 @@
+/**********************************************************************
+
+ Tandy 2000 keyboard emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#include "tandy2kb.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define I8048_TAG "m1"
+
+enum
+{
+ LED_1 = 0,
+ LED_2
+};
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type TANDY2K_KEYBOARD = &device_creator<tandy2k_keyboard_device>;
+
+
+
+//-------------------------------------------------
+// ROM( tandy2k_keyboard )
+//-------------------------------------------------
+
+ROM_START( tandy2k_keyboard )
+ ROM_REGION( 0x400, I8048_TAG, 0 )
+ ROM_LOAD( "keyboard.m1", 0x0000, 0x0400, NO_DUMP )
+ROM_END
+
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *tandy2k_keyboard_device::device_rom_region() const
+{
+ return ROM_NAME( tandy2k_keyboard );
+}
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( kb_io )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( tandy2k_keyboard_io, AS_IO, 8, tandy2k_keyboard_device )
+ AM_RANGE(MCS48_PORT_P1, MCS48_PORT_P1) AM_WRITE(kb_p1_w)
+ AM_RANGE(MCS48_PORT_P2, MCS48_PORT_P2) AM_WRITE(kb_p2_w)
+ AM_RANGE(MCS48_PORT_BUS, MCS48_PORT_BUS) AM_READ(kb_p1_r)
+ADDRESS_MAP_END
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( tandy2k_keyboard )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( tandy2k_keyboard )
+ MCFG_CPU_ADD(I8048_TAG, I8048, 1000000) // ?
+ MCFG_CPU_IO_MAP(tandy2k_keyboard_io)
+ MCFG_DEVICE_DISABLE() // TODO
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor tandy2k_keyboard_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( tandy2k_keyboard );
+}
+
+
+//-------------------------------------------------
+// INPUT_PORTS( tandy2k_keyboard )
+//-------------------------------------------------
+
+INPUT_PORTS_START( tandy2k_keyboard )
+ PORT_START("Y0")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("Y1")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("Y2")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("Y3")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("Y4")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("Y5")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("Y6")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("Y7")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("Y8")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("Y9")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("Y10")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("Y11")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD )
+INPUT_PORTS_END
+
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+ioport_constructor tandy2k_keyboard_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( tandy2k_keyboard );
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// tandy2k_keyboard_device - constructor
+//-------------------------------------------------
+
+tandy2k_keyboard_device::tandy2k_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, TANDY2K_KEYBOARD, "Tandy 2000 Keyboard", tag, owner, clock),
+ m_maincpu(*this, I8048_TAG),
+ m_keylatch(0xffff),
+ m_clock(0),
+ m_data(0)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void tandy2k_keyboard_device::device_start()
+{
+ // resolve callbacks
+ m_out_clock_func.resolve(m_out_clock_cb, *this);
+ m_out_data_func.resolve(m_out_data_cb, *this);
+
+ // state saving
+ save_item(NAME(m_keylatch));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void tandy2k_keyboard_device::device_reset()
+{
+}
+
+
+//-------------------------------------------------
+// power_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( tandy2k_keyboard_device::power_w )
+{
+ // TODO
+}
+
+
+//-------------------------------------------------
+// reset_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( tandy2k_keyboard_device::reset_w )
+{
+ if (!state)
+ {
+ device_reset();
+ }
+}
+
+
+//-------------------------------------------------
+// busy_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( tandy2k_keyboard_device::busy_w )
+{
+ m_maincpu->set_input_line(MCS48_INPUT_IRQ, state ? CLEAR_LINE : ASSERT_LINE);
+}
+
+
+//-------------------------------------------------
+// data_r -
+//-------------------------------------------------
+
+READ_LINE_MEMBER( tandy2k_keyboard_device::data_r )
+{
+ return m_data;
+}
+
+
+//-------------------------------------------------
+// kb_p1_r -
+//-------------------------------------------------
+
+READ8_MEMBER( tandy2k_keyboard_device::kb_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_keylatch, 0)) data &= ioport("Y0")->read();
+ if (!BIT(m_keylatch, 1)) data &= ioport("Y1")->read();
+ if (!BIT(m_keylatch, 2)) data &= ioport("Y2")->read();
+ if (!BIT(m_keylatch, 3)) data &= ioport("Y3")->read();
+ if (!BIT(m_keylatch, 4)) data &= ioport("Y4")->read();
+ if (!BIT(m_keylatch, 5)) data &= ioport("Y5")->read();
+ if (!BIT(m_keylatch, 6)) data &= ioport("Y6")->read();
+ if (!BIT(m_keylatch, 7)) data &= ioport("Y7")->read();
+ if (!BIT(m_keylatch, 8)) data &= ioport("Y8")->read();
+ if (!BIT(m_keylatch, 9)) data &= ioport("Y9")->read();
+ if (!BIT(m_keylatch, 10)) data &= ioport("Y10")->read();
+ if (!BIT(m_keylatch, 11)) data &= ioport("Y11")->read();
+
+ return ~data;
+}
+
+
+//-------------------------------------------------
+// kb_p1_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( tandy2k_keyboard_device::kb_p1_w )
+{
+ /*
+
+ bit description
+
+ 0 Y0
+ 1 Y1
+ 2 Y2
+ 3 Y3
+ 4 Y4
+ 5 Y5
+ 6 Y6
+ 7 Y7
+
+ */
+
+ // keyboard row
+ m_keylatch = (m_keylatch & 0xff00) | data;
+}
+
+
+//-------------------------------------------------
+// kb_p2_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( tandy2k_keyboard_device::kb_p2_w )
+{
+ /*
+
+ bit description
+
+ 0 Y8
+ 1 Y9
+ 2 Y10
+ 3 Y11
+ 4 LED 2
+ 5 LED 1
+ 6 CLOCK
+ 7 DATA
+
+ */
+
+ // keyboard row
+ m_keylatch = ((data & 0x0f) << 8) | (m_keylatch & 0xff);
+
+ // led output
+ output_set_led_value(LED_2, !BIT(data, 4));
+ output_set_led_value(LED_1, !BIT(data, 5));
+
+ // keyboard clock
+ int clock = BIT(data, 6);
+
+ if (m_clock != clock)
+ {
+ m_clock = clock;
+
+ m_out_clock_func(m_clock);
+ }
+
+ // keyboard data
+ int kbddat = BIT(data, 7);
+
+ if (m_data != kbddat)
+ {
+ m_data = kbddat;
+
+ m_out_data_func(m_data);
+ }
+}
diff --git a/src/mess/machine/tandy2kb.h b/src/mess/machine/tandy2kb.h
new file mode 100644
index 00000000000..1988f0ccc81
--- /dev/null
+++ b/src/mess/machine/tandy2kb.h
@@ -0,0 +1,104 @@
+/**********************************************************************
+
+ Tandy 2000 keyboard emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#pragma once
+
+#ifndef __TANDY2K_KEYBOARD__
+#define __TANDY2K_KEYBOARD__
+
+
+#include "emu.h"
+#include "cpu/mcs48/mcs48.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define TANDY2K_KEYBOARD_TAG "tandy2kb"
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_TANDY2K_KEYBOARD_ADD(_config) \
+ MCFG_DEVICE_ADD(TANDY2K_KEYBOARD_TAG, TANDY2K_KEYBOARD, 0) \
+ MCFG_DEVICE_CONFIG(_config)
+
+
+#define TANDY2K_KEYBOARD_INTERFACE(_name) \
+ const tandy2k_keyboard_interface (_name) =
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> tandy2k_keyboard_interface
+
+struct tandy2k_keyboard_interface
+{
+ devcb_write_line m_out_clock_cb;
+ devcb_write_line m_out_data_cb;
+};
+
+
+// ======================> tandy2k_keyboard_device
+
+class tandy2k_keyboard_device : public device_t,
+ public tandy2k_keyboard_interface
+{
+public:
+ // construction/destruction
+ tandy2k_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_WRITE_LINE_MEMBER( power_w );
+ DECLARE_WRITE_LINE_MEMBER( reset_w );
+ DECLARE_WRITE_LINE_MEMBER( busy_w );
+ DECLARE_READ_LINE_MEMBER( data_r );
+
+ // not really public
+ DECLARE_READ8_MEMBER( kb_p1_r );
+ DECLARE_WRITE8_MEMBER( kb_p1_w );
+ DECLARE_WRITE8_MEMBER( kb_p2_w );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "tandy2kb"; }
+
+private:
+ devcb_resolved_write_line m_out_clock_func;
+ devcb_resolved_write_line m_out_data_func;
+
+ required_device<cpu_device> m_maincpu;
+
+ UINT16 m_keylatch;
+
+ int m_clock;
+ int m_data;
+};
+
+
+// device type definition
+extern const device_type TANDY2K_KEYBOARD;
+
+
+
+#endif
diff --git a/src/mess/machine/teleprinter.c b/src/mess/machine/teleprinter.c
new file mode 100644
index 00000000000..2e4e281226f
--- /dev/null
+++ b/src/mess/machine/teleprinter.c
@@ -0,0 +1,237 @@
+#include "machine/teleprinter.h"
+
+static const UINT8 teleprinter_font[128*8] =
+{
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x07,0x07,0x07,0x07,0x00,0x00,0x00,0x00,
+ 0x38,0x38,0x38,0x38,0x00,0x00,0x00,0x00,
+ 0x3f,0x3f,0x3f,0x3f,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x07,
+ 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,
+ 0x38,0x38,0x38,0x38,0x07,0x07,0x07,0x07,
+ 0x3f,0x3f,0x3f,0x3f,0x07,0x07,0x07,0x07,
+ 0x00,0x00,0x00,0x00,0x38,0x38,0x38,0x38,
+ 0x07,0x07,0x07,0x07,0x38,0x38,0x38,0x38,
+ 0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,
+ 0x3f,0x3f,0x3f,0x3f,0x38,0x38,0x38,0x38,
+ 0x00,0x00,0x00,0x00,0x3f,0x3f,0x3f,0x3f,
+ 0x07,0x07,0x07,0x07,0x3f,0x3f,0x3f,0x3f,
+ 0x38,0x38,0x38,0x38,0x3f,0x3f,0x3f,0x3f,
+ 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,
+ 0x00,0x00,0x00,0x00,0x2a,0x15,0x2a,0x15,
+ 0x2a,0x15,0x2a,0x15,0x00,0x00,0x00,0x00,
+ 0x3f,0x3f,0x3f,0x3f,0x2a,0x15,0x2a,0x15,
+ 0x2a,0x15,0x2a,0x15,0x3f,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,
+ 0x08,0x08,0x08,0x08,0x08,0x00,0x08,0x00,
+ 0x14,0x14,0x14,0x00,0x00,0x00,0x00,0x00,
+ 0x14,0x14,0x3e,0x14,0x3e,0x14,0x14,0x00,
+ 0x08,0x3c,0x0a,0x1c,0x28,0x1e,0x08,0x00,
+ 0x06,0x26,0x10,0x08,0x04,0x32,0x30,0x00,
+ 0x08,0x14,0x14,0x0c,0x2a,0x12,0x2c,0x00,
+ 0x08,0x08,0x04,0x00,0x00,0x00,0x00,0x00,
+ 0x10,0x08,0x04,0x04,0x04,0x08,0x10,0x00,
+ 0x04,0x08,0x10,0x10,0x10,0x08,0x04,0x00,
+ 0x00,0x08,0x2a,0x1c,0x2a,0x08,0x00,0x00,
+ 0x00,0x08,0x08,0x3e,0x08,0x08,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x08,0x08,0x04,0x00,
+ 0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,
+ 0x00,0x20,0x10,0x08,0x04,0x02,0x00,0x00,
+ 0x1c,0x22,0x32,0x2a,0x26,0x22,0x1c,0x00,
+ 0x08,0x0c,0x08,0x08,0x08,0x08,0x1c,0x00,
+ 0x1c,0x22,0x20,0x18,0x04,0x02,0x3e,0x00,
+ 0x3e,0x20,0x10,0x18,0x20,0x22,0x1c,0x00,
+ 0x10,0x18,0x14,0x12,0x3e,0x10,0x10,0x00,
+ 0x3e,0x02,0x1e,0x20,0x20,0x22,0x1c,0x00,
+ 0x10,0x08,0x04,0x1c,0x22,0x22,0x1c,0x00,
+ 0x3e,0x20,0x10,0x08,0x04,0x04,0x04,0x00,
+ 0x1c,0x22,0x22,0x1c,0x22,0x22,0x1c,0x00,
+ 0x1c,0x22,0x22,0x1c,0x10,0x08,0x04,0x00,
+ 0x00,0x00,0x00,0x08,0x00,0x08,0x00,0x00,
+ 0x00,0x00,0x08,0x00,0x08,0x08,0x04,0x00,
+ 0x10,0x08,0x04,0x02,0x04,0x08,0x10,0x00,
+ 0x00,0x00,0x3e,0x00,0x3e,0x00,0x00,0x00,
+ 0x04,0x08,0x10,0x20,0x10,0x08,0x04,0x00,
+ 0x1c,0x22,0x20,0x10,0x08,0x00,0x08,0x00,
+ 0x1c,0x22,0x32,0x2a,0x3a,0x02,0x3c,0x00,
+ 0x08,0x14,0x22,0x22,0x3e,0x22,0x22,0x00,
+ 0x1e,0x22,0x22,0x1e,0x22,0x22,0x1e,0x00,
+ 0x1c,0x22,0x02,0x02,0x02,0x22,0x1c,0x00,
+ 0x1e,0x24,0x24,0x24,0x24,0x24,0x1e,0x00,
+ 0x3e,0x02,0x02,0x1e,0x02,0x02,0x3e,0x00,
+ 0x3e,0x02,0x02,0x1e,0x02,0x02,0x02,0x00,
+ 0x1c,0x22,0x02,0x02,0x32,0x22,0x3c,0x00,
+ 0x22,0x22,0x22,0x3e,0x22,0x22,0x22,0x00,
+ 0x1c,0x08,0x08,0x08,0x08,0x08,0x1c,0x00,
+ 0x38,0x10,0x10,0x10,0x10,0x12,0x0c,0x00,
+ 0x22,0x12,0x0a,0x06,0x0a,0x12,0x22,0x00,
+ 0x02,0x02,0x02,0x02,0x02,0x02,0x3e,0x00,
+ 0x22,0x36,0x2a,0x2a,0x22,0x22,0x22,0x00,
+ 0x22,0x22,0x26,0x2a,0x32,0x22,0x22,0x00,
+ 0x1c,0x22,0x22,0x22,0x22,0x22,0x1c,0x00,
+ 0x1e,0x22,0x22,0x1e,0x02,0x02,0x02,0x00,
+ 0x1c,0x22,0x22,0x22,0x2a,0x12,0x2c,0x00,
+ 0x1e,0x22,0x22,0x1e,0x0a,0x12,0x22,0x00,
+ 0x1c,0x22,0x02,0x1c,0x20,0x22,0x1c,0x00,
+ 0x3e,0x08,0x08,0x08,0x08,0x08,0x08,0x00,
+ 0x22,0x22,0x22,0x22,0x22,0x22,0x1c,0x00,
+ 0x22,0x22,0x22,0x14,0x14,0x08,0x08,0x00,
+ 0x22,0x22,0x22,0x2a,0x2a,0x2a,0x14,0x00,
+ 0x22,0x22,0x14,0x08,0x14,0x22,0x22,0x00,
+ 0x22,0x22,0x22,0x14,0x08,0x08,0x08,0x00,
+ 0x3e,0x20,0x10,0x08,0x04,0x02,0x3e,0x00,
+ 0x0e,0x02,0x02,0x02,0x02,0x02,0x0e,0x00,
+ 0x00,0x02,0x04,0x08,0x10,0x20,0x00,0x00,
+ 0x38,0x20,0x20,0x20,0x20,0x20,0x38,0x00,
+ 0x08,0x1c,0x2a,0x08,0x08,0x08,0x08,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x00,
+ 0x04,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x1c,0x20,0x3c,0x22,0x3c,0x00,
+ 0x02,0x02,0x1e,0x22,0x22,0x22,0x1e,0x00,
+ 0x00,0x00,0x3c,0x02,0x02,0x02,0x3c,0x00,
+ 0x20,0x20,0x3c,0x22,0x22,0x22,0x3c,0x00,
+ 0x00,0x00,0x1c,0x22,0x3e,0x02,0x1c,0x00,
+ 0x18,0x04,0x0e,0x04,0x04,0x04,0x04,0x00,
+ 0x00,0x00,0x3c,0x22,0x22,0x3c,0x20,0x18,
+ 0x02,0x02,0x1e,0x22,0x22,0x22,0x22,0x00,
+ 0x08,0x00,0x0c,0x08,0x08,0x08,0x1c,0x00,
+ 0x10,0x00,0x18,0x10,0x10,0x10,0x12,0x0c,
+ 0x02,0x02,0x22,0x12,0x0e,0x16,0x22,0x00,
+ 0x08,0x08,0x08,0x08,0x08,0x08,0x10,0x00,
+ 0x00,0x00,0x16,0x2a,0x2a,0x2a,0x2a,0x00,
+ 0x00,0x00,0x1a,0x26,0x22,0x22,0x22,0x00,
+ 0x00,0x00,0x1c,0x22,0x22,0x22,0x1c,0x00,
+ 0x00,0x00,0x1e,0x22,0x22,0x1e,0x02,0x02,
+ 0x00,0x00,0x3c,0x22,0x22,0x3c,0x20,0x20,
+ 0x00,0x00,0x34,0x0c,0x04,0x04,0x04,0x00,
+ 0x00,0x00,0x3c,0x02,0x1c,0x20,0x1e,0x00,
+ 0x08,0x08,0x1c,0x08,0x08,0x08,0x10,0x00,
+ 0x00,0x00,0x22,0x22,0x22,0x32,0x2c,0x00,
+ 0x00,0x00,0x22,0x22,0x22,0x14,0x08,0x00,
+ 0x00,0x00,0x22,0x22,0x2a,0x2a,0x14,0x00,
+ 0x00,0x00,0x22,0x14,0x08,0x14,0x22,0x00,
+ 0x00,0x00,0x22,0x22,0x14,0x08,0x04,0x02,
+ 0x00,0x00,0x3e,0x10,0x08,0x04,0x3e,0x00,
+ 0x10,0x08,0x08,0x04,0x08,0x08,0x10,0x00,
+ 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x00,
+ 0x04,0x08,0x08,0x10,0x08,0x08,0x04,0x00,
+ 0x3e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x2a,0x15,0x2a,0x15,0x2a,0x15,0x2a,0x15
+};
+
+teleprinter_device::teleprinter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : generic_terminal_device(mconfig, TELEPRINTER, "Teleprinter", tag, owner, clock)
+{
+}
+
+void teleprinter_device::scroll_line()
+{
+ memcpy(m_buffer,m_buffer+TELEPRINTER_WIDTH,(TELEPRINTER_HEIGHT-1)*TELEPRINTER_WIDTH);
+ memset(m_buffer + TELEPRINTER_WIDTH*(TELEPRINTER_HEIGHT-1),0x20,TELEPRINTER_WIDTH);
+}
+
+void teleprinter_device::write_char(UINT8 data) {
+ m_buffer[(TELEPRINTER_HEIGHT-1)*TELEPRINTER_WIDTH+m_x_pos] = data;
+ m_x_pos++;
+ if (m_x_pos >= TELEPRINTER_WIDTH)
+ {
+ m_x_pos = 0;
+ scroll_line();
+ }
+}
+
+void teleprinter_device::clear() {
+ memset(m_buffer,0,TELEPRINTER_WIDTH*TELEPRINTER_HEIGHT);
+ m_x_pos = 0;
+}
+
+void teleprinter_device::term_write(UINT8 data)
+{
+ switch(data) {
+ case 10: m_x_pos = 0;
+ scroll_line();
+ break;
+ case 13: m_x_pos = 0; break;
+ case 9: m_x_pos = (m_x_pos & 0xf8) + 8;
+ if (m_x_pos >= TELEPRINTER_WIDTH)
+ m_x_pos = TELEPRINTER_WIDTH-1;
+
+ break;
+ case 16: break;
+ default: write_char(data); break;
+ }
+}
+
+/***************************************************************************
+ VIDEO HARDWARE
+***************************************************************************/
+UINT32 teleprinter_device::tp_update(screen_device &device, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ UINT8 code;
+ int y, c, x, b;
+
+ for (y = 0; y < TELEPRINTER_HEIGHT; y++)
+ {
+ for (c = 0; c < 8; c++)
+ {
+ int horpos = 0;
+ for (x = 0; x < TELEPRINTER_WIDTH; x++)
+ {
+ code = teleprinter_font[(m_buffer[y*TELEPRINTER_WIDTH + x] & 0x7f) *8 + c];
+ for (b = 0; b < 8; b++)
+ {
+ bitmap.pix32(y*8 + c, horpos++) = (code >> b) & 0x01 ? 0 : 0x00ffffff;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static ASCII_KEYBOARD_INTERFACE( keyboard_intf )
+{
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, generic_terminal_device, kbd_put)
+};
+
+/***************************************************************************
+ VIDEO HARDWARE
+***************************************************************************/
+MACHINE_CONFIG_FRAGMENT( generic_teleprinter )
+ MCFG_SCREEN_ADD(TELEPRINTER_SCREEN_TAG, RASTER)
+ MCFG_SCREEN_REFRESH_RATE(50)
+ MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */
+ MCFG_SCREEN_SIZE(TELEPRINTER_WIDTH*8, TELEPRINTER_HEIGHT*8)
+ MCFG_SCREEN_VISIBLE_AREA(0, TELEPRINTER_WIDTH*8-1, 0, TELEPRINTER_HEIGHT*8-1)
+ MCFG_SCREEN_UPDATE_DEVICE(DEVICE_SELF, teleprinter_device, tp_update)
+ MCFG_ASCII_KEYBOARD_ADD(KEYBOARD_TAG, keyboard_intf)
+MACHINE_CONFIG_END
+
+machine_config_constructor teleprinter_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME(generic_teleprinter);
+}
+
+/*-------------------------------------------------
+ DEVICE_RESET( teleprinter )
+-------------------------------------------------*/
+
+void teleprinter_device::device_reset()
+{
+ clear();
+ generic_terminal_device::device_reset();
+}
+
+const device_type TELEPRINTER = &device_creator<teleprinter_device>;
diff --git a/src/mess/machine/teleprinter.h b/src/mess/machine/teleprinter.h
new file mode 100644
index 00000000000..574bc9fa81a
--- /dev/null
+++ b/src/mess/machine/teleprinter.h
@@ -0,0 +1,45 @@
+#ifndef __TELEPRINTER_H__
+#define __TELEPRINTER_H__
+
+#include "machine/terminal.h"
+
+#define TELEPRINTER_WIDTH 80
+#define TELEPRINTER_HEIGHT 50
+
+#define GENERIC_TELEPRINTER_INTERFACE GENERIC_TERMINAL_INTERFACE
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+#define TELEPRINTER_TAG "teleprinter"
+#define TELEPRINTER_SCREEN_TAG "tty_screen"
+
+#define MCFG_GENERIC_TELEPRINTER_ADD(_tag, _intrf) \
+ MCFG_DEVICE_ADD(_tag, TELEPRINTER, 0) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#define MCFG_GENERIC_TELEPRINTER_REMOVE(_tag) \
+ MCFG_DEVICE_REMOVE(_tag)
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+class teleprinter_device : public generic_terminal_device
+{
+public:
+ teleprinter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ UINT32 tp_update(screen_device &device, bitmap_rgb32 &bitmap, const rectangle &cliprect);
+protected:
+ virtual void term_write(UINT8 data);
+ virtual void device_reset();
+ machine_config_constructor device_mconfig_additions() const;
+private:
+ void scroll_line();
+ void write_char(UINT8 data);
+ void clear();
+};
+
+extern const device_type TELEPRINTER;
+
+#endif /* __TELEPRINTER_H__ */
diff --git a/src/mess/machine/terminal.c b/src/mess/machine/terminal.c
new file mode 100644
index 00000000000..1d0e1489b4e
--- /dev/null
+++ b/src/mess/machine/terminal.c
@@ -0,0 +1,548 @@
+#include "machine/terminal.h"
+
+/***************************************************************************
+ 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)
+ : device_t(mconfig, type, name, tag, owner, clock)
+{
+}
+
+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)
+{
+}
+
+void generic_terminal_device::scroll_line()
+{
+ memcpy(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 = ioport("TERM_CONF")->read();
+ UINT16 cursor = m_y_pos * TERMINAL_WIDTH + m_x_pos;
+ UINT8 y,ra,chr,gfx;
+ UINT16 sy=0,ma=0,x;
+ UINT32 font_color;
+ switch (options & 0x30)
+ {
+ case 0x10:
+ font_color = 0x00ff7e00;
+ break;
+ case 0x20:
+ font_color = 0x00ffffff;
+ break;
+ default:
+ font_color = 0x0000ff00;
+ break;
+ }
+
+ 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;
+}
+
+void generic_terminal_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+}
+
+WRITE8_MEMBER( generic_terminal_device::kbd_put )
+{
+ if (data)
+ send_key(data);
+}
+
+static ASCII_KEYBOARD_INTERFACE( keyboard_intf )
+{
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, generic_terminal_device, kbd_put)
+};
+
+/***************************************************************************
+ 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_ASCII_KEYBOARD_ADD(KEYBOARD_TAG, keyboard_intf)
+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_func.resolve(m_keyboard_cb, *this);
+ m_timer = timer_alloc();
+}
+
+void generic_terminal_device::device_config_complete()
+{
+ const _terminal_interface *intf = reinterpret_cast<const _terminal_interface *>(static_config());
+ if(intf != NULL)
+ {
+ *static_cast<_terminal_interface *>(this) = *intf;
+ }
+ else
+ {
+ memset(&m_keyboard_cb, 0, sizeof(m_keyboard_cb));
+ }
+}
+
+void generic_terminal_device::device_reset()
+{
+ clear();
+ //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
+
+*/
+static 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<generic_terminal_device>;
+
+static INPUT_PORTS_START(serial_terminal)
+ PORT_INCLUDE(generic_terminal)
+ PORT_START("TERM_FRAME")
+ PORT_CONFNAME(0x0f, 0x06, "Baud") PORT_CHANGED_MEMBER(DEVICE_SELF, serial_terminal_device, update_frame, 0)
+ PORT_CONFSETTING( 0x00, "150")
+ PORT_CONFSETTING( 0x01, "300")
+ PORT_CONFSETTING( 0x02, "600")
+ PORT_CONFSETTING( 0x03, "1200")
+ PORT_CONFSETTING( 0x04, "2400")
+ PORT_CONFSETTING( 0x05, "4800")
+ PORT_CONFSETTING( 0x06, "9600")
+ PORT_CONFSETTING( 0x07, "14400")
+ PORT_CONFSETTING( 0x08, "19200")
+ PORT_CONFSETTING( 0x09, "28800")
+ PORT_CONFSETTING( 0x0a, "38400")
+ PORT_CONFSETTING( 0x0b, "57600")
+ PORT_CONFSETTING( 0x0c, "115200")
+ PORT_CONFNAME(0x30, 0x00, "Format") PORT_CHANGED_MEMBER(DEVICE_SELF, serial_terminal_device, update_frame, 0)
+ PORT_CONFSETTING( 0x00, "8N1")
+ PORT_CONFSETTING( 0x10, "7E1")
+INPUT_PORTS_END
+
+ioport_constructor serial_terminal_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME(serial_terminal);
+}
+
+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),
+ device_serial_interface(mconfig, *this),
+ device_serial_port_interface(mconfig, *this)
+{
+}
+
+void serial_terminal_device::device_config_complete()
+{
+ const serial_terminal_interface *intf = reinterpret_cast<const serial_terminal_interface *>(static_config());
+ if(intf != NULL)
+ {
+ *static_cast<serial_terminal_interface *>(this) = *intf;
+ }
+ else
+ {
+ memset(&m_out_tx_cb, 0, sizeof(m_out_tx_cb));
+ }
+ m_shortname = "serial_terminal";
+}
+
+static int rates[] = {150, 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600, 115200};
+
+void serial_terminal_device::device_start()
+{
+ int baud = clock();
+ if(!baud) baud = 9600;
+ m_owner = dynamic_cast<serial_port_device *>(owner());
+ m_out_tx_func.resolve(m_out_tx_cb, *this);
+ m_slot = m_owner && 1;
+ m_timer = timer_alloc();
+ set_rcv_rate(baud);
+ set_tra_rate(baud);
+ set_data_frame(8, 1, SERIAL_PARITY_NONE);
+}
+
+INPUT_CHANGED_MEMBER(serial_terminal_device::update_frame)
+{
+ UINT8 val = ioport("TERM_FRAME")->read();
+ set_tra_rate(rates[val & 0x0f]);
+ set_rcv_rate(rates[val & 0x0f]);
+
+ switch(val & 0x30)
+ {
+ case 0x10:
+ set_data_frame(7, 1, SERIAL_PARITY_EVEN);
+ break;
+ case 0x00:
+ default:
+ set_data_frame(8, 1, SERIAL_PARITY_NONE);
+ break;
+ }
+}
+
+void serial_terminal_device::device_reset()
+{
+ generic_terminal_device::device_reset();
+ m_rbit = 1;
+ if(m_slot)
+ m_owner->out_rx(m_rbit);
+ else
+ m_out_tx_func(m_rbit);
+}
+
+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()
+{
+ m_rbit = transmit_register_get_data_bit();
+ if(m_slot)
+ m_owner->out_rx(m_rbit);
+ else
+ m_out_tx_func(m_rbit);
+}
+
+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());
+}
+
+READ_LINE_MEMBER(serial_terminal_device::tx_r)
+{
+ return m_rbit;
+}
+
+const device_type SERIAL_TERMINAL = &device_creator<serial_terminal_device>;
diff --git a/src/mess/machine/terminal.h b/src/mess/machine/terminal.h
new file mode 100644
index 00000000000..95e1825fee4
--- /dev/null
+++ b/src/mess/machine/terminal.h
@@ -0,0 +1,119 @@
+#ifndef __TERMINAL_H__
+#define __TERMINAL_H__
+
+#include "emu.h"
+#include "machine/serial.h"
+#include "machine/keyboard.h"
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _terminal_interface terminal_interface;
+struct _terminal_interface
+{
+ devcb_write8 m_keyboard_cb;
+};
+
+#define GENERIC_TERMINAL_INTERFACE(name) const terminal_interface (name) =
+
+struct serial_terminal_interface
+{
+ devcb_write_line m_out_tx_cb;
+};
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+#define TERMINAL_TAG "terminal"
+#define TERMINAL_SCREEN_TAG "terminal_screen"
+
+#define MCFG_GENERIC_TERMINAL_ADD(_tag, _intrf) \
+ MCFG_DEVICE_ADD(_tag, GENERIC_TERMINAL, 0) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#define MCFG_GENERIC_TERMINAL_REMOVE(_tag) \
+ MCFG_DEVICE_REMOVE(_tag)
+
+#define MCFG_SERIAL_TERMINAL_ADD(_tag, _intrf, _clock) \
+ MCFG_DEVICE_ADD(_tag, SERIAL_TERMINAL, _clock) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+#define TERMINAL_WIDTH 80
+#define TERMINAL_HEIGHT 24
+
+class generic_terminal_device :
+ public device_t,
+ public _terminal_interface
+{
+public:
+ generic_terminal_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
+ generic_terminal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ 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:
+ virtual void term_write(UINT8 data);
+ 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();
+ virtual void send_key(UINT8 code) { m_keyboard_func(0, code); }
+ UINT8 m_buffer[TERMINAL_WIDTH*50]; // make big enough for teleprinter
+ UINT8 m_x_pos;
+ emu_timer *m_timer;
+private:
+ void scroll_line();
+ void write_char(UINT8 data);
+ void clear();
+
+ UINT8 m_framecnt;
+ UINT8 m_y_pos;
+
+ devcb_resolved_write8 m_keyboard_func;
+};
+
+extern const device_type GENERIC_TERMINAL;
+
+class serial_terminal_device :
+ public generic_terminal_device,
+ public device_serial_interface,
+ public device_serial_port_interface,
+ public serial_terminal_interface
+{
+public:
+ serial_terminal_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ DECLARE_WRITE_LINE_MEMBER(rx_w) { m_tbit = state; check_for_start(state); }
+ DECLARE_READ_LINE_MEMBER(tx_r);
+ virtual ioport_constructor device_input_ports() const;
+
+ DECLARE_INPUT_CHANGED_MEMBER(update_frame);
+protected:
+ virtual void device_start();
+ virtual void device_config_complete();
+ virtual void device_reset();
+ virtual void tra_callback();
+ virtual void tra_complete();
+ virtual void rcv_complete();
+ virtual void input_callback(UINT8 state) { m_input_state = state; }
+ virtual void send_key(UINT8 code);
+private:
+ serial_port_device *m_owner;
+ bool m_slot;
+ UINT8 m_curr_key;
+ bool m_key_valid;
+ devcb_resolved_write_line m_out_tx_func;
+};
+
+extern const device_type SERIAL_TERMINAL;
+
+#endif /* __TERMINAL_H__ */
diff --git a/src/mess/machine/tf20.c b/src/mess/machine/tf20.c
new file mode 100644
index 00000000000..846f31507a0
--- /dev/null
+++ b/src/mess/machine/tf20.c
@@ -0,0 +1,388 @@
+/***************************************************************************
+
+ Epson TF-20
+
+ Dual floppy drive with HX-20 factory option
+
+
+ Status: Boots from system disk, missing ??PD7201 emulation
+
+***************************************************************************/
+
+#include "emu.h"
+#include "tf20.h"
+#include "cpu/z80/z80.h"
+#include "machine/ram.h"
+#include "machine/upd7201.h"
+#include "machine/upd765.h"
+#include "imagedev/flopdrv.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define XTAL_CR1 XTAL_8MHz
+#define XTAL_CR2 XTAL_4_9152MHz
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _tf20_state tf20_state;
+struct _tf20_state
+{
+ ram_device *ram;
+ device_t *upd765a;
+ upd7201_device *upd7201;
+ device_t *floppy_0;
+ device_t *floppy_1;
+};
+
+
+/*****************************************************************************
+ INLINE FUNCTIONS
+*****************************************************************************/
+
+INLINE tf20_state *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == TF20);
+
+ return (tf20_state *)downcast<legacy_device_base *>(device)->token();
+}
+
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+/* serial clock, 38400 baud by default */
+static TIMER_DEVICE_CALLBACK( serial_clock )
+{
+ tf20_state *tf20 = get_safe_token(timer.owner());
+
+ tf20->upd7201->rxca_w(ASSERT_LINE);
+ tf20->upd7201->txca_w(ASSERT_LINE);
+ tf20->upd7201->rxcb_w(ASSERT_LINE);
+ tf20->upd7201->txcb_w(ASSERT_LINE);
+}
+
+/* a read from this location disables the rom */
+static READ8_HANDLER( tf20_rom_disable )
+{
+ tf20_state *tf20 = get_safe_token(space->device().owner());
+ address_space *prg = space->device().memory().space(AS_PROGRAM);
+
+ /* switch in ram */
+ prg->install_ram(0x0000, 0x7fff, tf20->ram->pointer());
+
+ return 0xff;
+}
+
+static READ8_HANDLER( tf20_dip_r )
+{
+ logerror("%s: tf20_dip_r\n", space->machine().describe_context());
+
+ return space->machine().root_device().ioport("tf20_dip")->read();
+}
+
+static TIMER_CALLBACK( tf20_upd765_tc_reset )
+{
+ upd765_tc_w((device_t *)ptr, CLEAR_LINE);
+}
+
+static READ8_DEVICE_HANDLER( tf20_upd765_tc_r )
+{
+ logerror("%s: tf20_upd765_tc_r\n", device->machine().describe_context());
+
+ /* toggle tc on read */
+ upd765_tc_w(device, ASSERT_LINE);
+ device->machine().scheduler().timer_set(attotime::zero, FUNC(tf20_upd765_tc_reset), 0, device);
+
+ return 0xff;
+}
+
+static WRITE8_HANDLER( tf20_fdc_control_w )
+{
+ tf20_state *tf20 = get_safe_token(space->device().owner());
+ logerror("%s: tf20_fdc_control_w %02x\n", space->machine().describe_context(), data);
+
+ /* bit 0, motor on signal */
+ floppy_mon_w(tf20->floppy_0, !BIT(data, 0));
+ floppy_mon_w(tf20->floppy_1, !BIT(data, 0));
+}
+
+static IRQ_CALLBACK( tf20_irq_ack )
+{
+ return 0x00;
+}
+
+
+/***************************************************************************
+ EXTERNAL INTERFACE
+***************************************************************************/
+
+/* serial output signal (to the host computer) */
+READ_LINE_DEVICE_HANDLER( tf20_rxs_r )
+{
+ tf20_state *tf20 = get_safe_token(device);
+ logerror("%s: tf20_rxs_r\n", device->machine().describe_context());
+
+ return tf20->upd7201->txda_r();
+}
+
+READ_LINE_DEVICE_HANDLER( tf20_pins_r )
+{
+ tf20_state *tf20 = get_safe_token(device);
+ logerror("%s: tf20_pins_r\n", device->machine().describe_context());
+
+ return tf20->upd7201->dtra_r();
+}
+
+/* serial input signal (from host computer) */
+WRITE_LINE_DEVICE_HANDLER( tf20_txs_w )
+{
+ tf20_state *tf20 = get_safe_token(device);
+ logerror("%s: tf20_txs_w %u\n", device->machine().describe_context(), state);
+
+ tf20->upd7201->rxda_w(state);
+}
+
+WRITE_LINE_DEVICE_HANDLER( tf20_pouts_w )
+{
+ tf20_state *tf20 = get_safe_token(device);
+ logerror("%s: tf20_pouts_w %u\n", device->machine().describe_context(), state);
+
+ tf20->upd7201->ctsa_w(state);
+}
+
+#ifdef UNUSED_FUNCTION
+/* serial output signal (to another terminal) */
+WRITE_LINE_DEVICE_HANDLER( tf20_txc_w )
+{
+ tf20_state *tf20 = get_safe_token(device);
+ logerror("%s: tf20_txc_w %u\n", device->machine().describe_context(), state);
+
+ tf20->upd7201->rxda_w(state);
+}
+
+/* serial input signal (from another terminal) */
+READ_LINE_DEVICE_HANDLER( tf20_rxc_r )
+{
+ tf20_state *tf20 = get_safe_token(device);
+ logerror("%s: tf20_rxc_r\n", device->machine().describe_context());
+
+ return tf20->upd7201->txda_r();
+}
+
+WRITE_LINE_DEVICE_HANDLER( tf20_poutc_w )
+{
+ tf20_state *tf20 = get_safe_token(device);
+ logerror("%s: tf20_poutc_w %u\n", device->machine().describe_context(), state);
+
+ tf20->upd7201->ctsa_w(state);
+}
+
+READ_LINE_DEVICE_HANDLER( tf20_pinc_r )
+{
+ tf20_state *tf20 = get_safe_token(device);
+ logerror("%s: tf20_pinc_r\n", device->machine().describe_context());
+
+ return tf20->upd7201->dtra_r();
+}
+#endif
+
+
+/*****************************************************************************
+ ADDRESS MAPS
+*****************************************************************************/
+
+static ADDRESS_MAP_START( tf20_mem, AS_PROGRAM, 8, tf20_device )
+ AM_RANGE(0x0000, 0x7fff) AM_RAMBANK("bank21")
+ AM_RANGE(0x8000, 0xffff) AM_RAMBANK("bank22")
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( tf20_io, AS_IO, 8, 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_LEGACY(tf20_rom_disable)
+ AM_RANGE(0xf7, 0xf7) AM_READ_LEGACY(tf20_dip_r)
+ AM_RANGE(0xf8, 0xf8) AM_DEVREAD_LEGACY("5a", tf20_upd765_tc_r) AM_WRITE_LEGACY(tf20_fdc_control_w)
+ AM_RANGE(0xfa, 0xfa) AM_DEVREAD_LEGACY("5a", upd765_status_r)
+ AM_RANGE(0xfb, 0xfb) AM_DEVREADWRITE_LEGACY("5a", upd765_data_r, upd765_data_w)
+ADDRESS_MAP_END
+
+
+/***************************************************************************
+ INPUT PORTS
+***************************************************************************/
+
+INPUT_PORTS_START( tf20 )
+ PORT_START("tf20_dip")
+ PORT_DIPNAME(0x0f, 0x0f, "Drive extension")
+ PORT_DIPLOCATION("TF-20 TFX:8,7,6,5")
+ PORT_DIPSETTING(0x0f, "A & B Drive")
+ PORT_DIPSETTING(0x07, "C & D Drive")
+INPUT_PORTS_END
+
+
+/*****************************************************************************
+ MACHINE CONFIG
+*****************************************************************************/
+
+static UPD7201_INTERFACE( tf20_upd7201_intf )
+{
+ DEVCB_NULL, /* interrupt: nc */
+ {
+ {
+ XTAL_CR2 / 128, /* receive clock: 38400 baud (default) */
+ XTAL_CR2 / 128, /* transmit clock: 38400 baud (default) */
+ DEVCB_NULL, /* receive DRQ */
+ DEVCB_NULL, /* transmit DRQ */
+ DEVCB_NULL, /* receive data */
+ DEVCB_NULL, /* transmit data */
+ DEVCB_NULL, /* clear to send */
+ DEVCB_LINE_GND, /* data carrier detect */
+ DEVCB_NULL, /* ready to send */
+ DEVCB_NULL, /* data terminal ready */
+ DEVCB_NULL, /* wait */
+ DEVCB_NULL /* sync output: nc */
+ }, {
+ XTAL_CR2 / 128, /* receive clock: 38400 baud (default) */
+ XTAL_CR2 / 128, /* transmit clock: 38400 baud (default) */
+ DEVCB_NULL, /* receive DRQ: nc */
+ DEVCB_NULL, /* transmit DRQ */
+ DEVCB_NULL, /* receive data */
+ DEVCB_NULL, /* transmit data */
+ DEVCB_LINE_GND, /* clear to send */
+ DEVCB_LINE_GND, /* data carrier detect */
+ DEVCB_NULL, /* ready to send */
+ DEVCB_NULL, /* data terminal ready: nc */
+ DEVCB_NULL, /* wait */
+ DEVCB_NULL /* sync output: nc */
+ }
+ }
+};
+
+static const upd765_interface tf20_upd765a_intf =
+{
+ DEVCB_CPU_INPUT_LINE("tf20", INPUT_LINE_IRQ0),
+ DEVCB_NULL,
+ NULL,
+ UPD765_RDY_PIN_NOT_CONNECTED,
+ {FLOPPY_0, FLOPPY_1, NULL, NULL}
+};
+
+static const floppy_interface tf20_floppy_interface =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ FLOPPY_STANDARD_5_25_DSDD_40,
+ LEGACY_FLOPPY_OPTIONS_NAME(default),
+ NULL,
+ NULL
+};
+
+static MACHINE_CONFIG_FRAGMENT( tf20 )
+ MCFG_CPU_ADD("tf20", Z80, XTAL_CR1 / 2) /* uPD780C */
+ MCFG_CPU_PROGRAM_MAP(tf20_mem)
+ MCFG_CPU_IO_MAP(tf20_io)
+
+ /* 64k internal ram */
+ MCFG_RAM_ADD("ram")
+ MCFG_RAM_DEFAULT_SIZE("64k")
+
+ /* upd765a floppy controller */
+ MCFG_UPD765A_ADD("5a", tf20_upd765a_intf)
+
+ /* upd7201 serial interface */
+ MCFG_UPD7201_ADD("3a", XTAL_CR1 / 2, tf20_upd7201_intf)
+ MCFG_TIMER_ADD_PERIODIC("serial_timer", serial_clock, attotime::from_hz(XTAL_CR2 / 128))
+
+ /* 2 floppy drives */
+ MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(tf20_floppy_interface)
+MACHINE_CONFIG_END
+
+
+/***************************************************************************
+ ROM DEFINITIONS
+***************************************************************************/
+
+ROM_START( tf20 )
+ ROM_REGION(0x0800, "tf20", 0)
+ ROM_LOAD("tfx.15e", 0x0000, 0x0800, CRC(af34f084) SHA1(c9bdf393f757ba5d8f838108ceb2b079be1d616e))
+ROM_END
+
+
+/*****************************************************************************
+ DEVICE INTERFACE
+*****************************************************************************/
+
+static DEVICE_START( tf20 )
+{
+ tf20_state *tf20 = get_safe_token(device);
+ device_t *cpu = device->subdevice("tf20");
+ address_space *prg = cpu->memory().space(AS_PROGRAM);
+
+ device_set_irq_callback(cpu, tf20_irq_ack);
+
+ /* ram device */
+ tf20->ram = device->subdevice<ram_device>("ram");
+
+ /* make sure its already running */
+ if (!tf20->ram->started())
+ throw device_missing_dependencies();
+
+ /* locate child devices */
+ tf20->upd765a = device->subdevice("5a");
+ tf20->upd7201 = downcast<upd7201_device *>(device->subdevice("3a"));
+ tf20->floppy_0 = device->subdevice(FLOPPY_0);
+ tf20->floppy_1 = device->subdevice(FLOPPY_1);
+
+ /* enable second half of ram */
+ prg->install_ram(0x8000, 0xffff, tf20->ram->pointer() + 0x8000);
+}
+
+static DEVICE_RESET( tf20 )
+{
+ device_t *cpu = device->subdevice("tf20");
+ address_space *prg = cpu->memory().space(AS_PROGRAM);
+
+ /* enable rom */
+ prg->install_rom(0x0000, 0x07ff, 0, 0x7800, cpu->region()->base());
+}
+
+DEVICE_GET_INFO( tf20 )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(tf20_state); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+
+ /* --- the following bits of info are returned as pointers --- */
+ case DEVINFO_PTR_MACHINE_CONFIG: info->machine_config = MACHINE_CONFIG_NAME(tf20); break;
+ case DEVINFO_PTR_ROM_REGION: info->romregion = ROM_NAME(tf20); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(tf20); break;
+ case DEVINFO_FCT_STOP: /* Nothing */ break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(tf20); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "TF-20"); break;
+ case DEVINFO_STR_SHORTNAME: strcpy(info->s, "tf20"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "Floppy drive"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright MESS Team"); break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(TF20, tf20);
diff --git a/src/mess/machine/tf20.h b/src/mess/machine/tf20.h
new file mode 100644
index 00000000000..f083e848a84
--- /dev/null
+++ b/src/mess/machine/tf20.h
@@ -0,0 +1,58 @@
+/***************************************************************************
+
+ Epson TF-20
+
+ Dual floppy drive with HX-20 factory option
+
+***************************************************************************/
+
+#ifndef __TF20_H__
+#define __TF20_H__
+
+#include "devcb.h"
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+#if 0
+typedef struct _tf20_interface tf20_interface;
+struct _tf20_interface
+{
+};
+#endif
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* serial interface in (to the host computer) */
+WRITE_LINE_DEVICE_HANDLER( tf20_txs_w );
+READ_LINE_DEVICE_HANDLER( tf20_rxs_r );
+WRITE_LINE_DEVICE_HANDLER( tf20_pouts_w );
+READ_LINE_DEVICE_HANDLER( tf20_pins_r );
+
+#ifdef UNUSED_FUNCTION
+/* serial interface out (to another terminal) */
+WRITE_LINE_DEVICE_HANDLER( tf20_txc_r );
+READ_LINE_DEVICE_HANDLER( tf20_rxc_w );
+WRITE_LINE_DEVICE_HANDLER( tf20_poutc_r );
+READ_LINE_DEVICE_HANDLER( tf20_pinc_w );
+#endif
+
+INPUT_PORTS_EXTERN( tf20 );
+
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+DECLARE_LEGACY_DEVICE(TF20, tf20);
+
+#define MCFG_TF20_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, TF20, 0) \
+
+
+#endif /* __TF20_H__ */
diff --git a/src/mess/machine/thomflop.c b/src/mess/machine/thomflop.c
new file mode 100644
index 00000000000..114bde783bc
--- /dev/null
+++ b/src/mess/machine/thomflop.c
@@ -0,0 +1,1951 @@
+/**********************************************************************
+
+ Copyright (C) Antoine Mine' 2006
+
+ Thomson 8-bit computers
+
+**********************************************************************/
+
+#include "includes/thomson.h"
+#include "machine/wd17xx.h"
+
+
+#define VERBOSE 0 /* 0, 1 or 2 */
+
+#define PRINT(x) mame_printf_info x
+
+#define LOG(x) do { if (VERBOSE > 0) logerror x; } while (0)
+#define VLOG(x) do { if (VERBOSE > 1) logerror x; } while (0)
+
+
+
+
+/******************* 3''1/2 & 5''1/4 disk format ********************/
+
+/*
+ single density sector format:
+
+ data bytes
+
+ id field 00 6 byte synchro
+ FE 1 id field mark
+ 1 track
+ 1 side
+ 1 sector
+ 00 1 log sector size (0->128, 1->256, 2->512,...)
+ 2 CRC (unemulated)
+ FF 12 spaces
+ data field 00 6 bytes synchro
+ FB 1 data field mark
+ E5 128 actual data (set to E5 when formatting)
+ 2 CRC (unemulated)
+ FF 22 ? spaces
+
+
+
+ double density sector format:
+
+ data bytes
+
+ id field 00 12 bit synchro
+ A1 3 byte synchro
+ FE 1 id field mark
+ 1 track
+ 1 side
+ 1 sector
+ 01 1 log sector size (0->128, 1->256, 2->512,...)
+ 2 CRC (unemulated)
+ 4E/F7 22 spaces
+ data field 00 12 bit synchro
+ A1 3 bytes synchro
+ FB 1 data field mark
+ E5 256 actual data (set to E5 when formatting)
+ 2 CRC (unemulated)
+ 4E/F7 74 ? spaces
+
+ => at most 392 bytes / sector
+ => at most 6272 bytes / track
+
+ Notes:
+ - the BIOS puts 4E bytes as spaces after id and data fields
+ - some protected games expect F7 bytes (instead of 4E) after id fields
+*/
+
+#define THOM_SIZE_ID 32
+#define THOM_SIZE_DATA_LO (128+80)
+#define THOM_SIZE_DATA_HI (256+80)
+#define THOM_SIZE_SYNCHRO 12
+
+static int motor_on;
+
+
+/* build an identifier, with header & space */
+static int thom_floppy_make_addr( chrn_id id, UINT8* dst, int sector_size )
+{
+ if ( sector_size == 128 )
+ {
+ /* single density */
+ memset( dst, 0x00, 6 ); /* synchro bytes */
+ dst[ 7 ] = 0xfe; /* address field mark */
+ dst[ 8 ] = id.C;
+ dst[ 9 ] = id.H;
+ dst[ 10 ] = id.N;
+ dst[ 11 ] = id.R;
+ dst[ 12 ] = 0; /* TODO: CRC */
+ dst[ 13 ] = 0; /* TODO: CRC */
+ memset( dst + 14, 0xff, 12 ); /* end mark */
+ return 36;
+ }
+ else
+ {
+ /* double density */
+ memset( dst, 0xa1, 3 ); /* synchro bytes */
+ dst[ 3 ] = 0xfe; /* address field mark */
+ dst[ 4 ] = id.C;
+ dst[ 5 ] = id.H;
+ dst[ 6 ] = id.N;
+ dst[ 7 ] = id.R;
+ dst[ 8 ] = 0; /* TODO: CRC */
+ dst[ 9 ] = 0; /* TODO: CRC */
+ memset( dst + 10, 0xf7, 22 ); /* end mark */
+ return 32;
+ }
+}
+
+
+
+/* build a sector, with header & space */
+static int thom_floppy_make_sector( device_t* img, chrn_id id, UINT8* dst, int sector_size )
+{
+ if ( sector_size == 128 )
+ {
+ /* single density */
+ memset( dst, 0x00, 6 ); /* synchro bytes */
+ dst[ 6 ] = 0xfb; /* data field mark */
+ floppy_drive_read_sector_data
+ ( img, id.H, id.data_id, dst + 7, sector_size );
+ dst[ sector_size + 7 ] = 0; /* TODO: CRC */
+ dst[ sector_size + 8 ] = 0; /* TODO: CRC */
+ memset( dst + sector_size + 9, 0xff, 22 ); /* end mark */
+ return sector_size + 31;
+ }
+ else
+ {
+ /* double density */
+ memset( dst, 0xa1, 3 ); /* synchro bytes */
+ dst[ 3 ] = 0xfb; /* data field mark */
+ floppy_drive_read_sector_data
+ ( img, id.H, id.data_id, dst + 4, sector_size );
+ dst[ sector_size + 4 ] = 0; /* TODO: CRC */
+ dst[ sector_size + 5 ] = 0; /* TODO: CRC */
+ memset( dst + sector_size + 6, 0xF7, 74 ); /* end mark */
+ return sector_size + 80;
+ }
+}
+
+
+
+/* build a whole track */
+static int thom_floppy_make_track( device_t* img, UINT8* dst, int sector_size, int side )
+{
+ UINT8 space = ( sector_size == 128 ) ? 0xff : 0;
+ UINT8* org = dst;
+ chrn_id id;
+ int nb;
+
+ /* go to start of track */
+ while ( ! floppy_drive_get_flag_state( img, FLOPPY_DRIVE_INDEX ) )
+ {
+ if ( ! floppy_drive_get_next_id( img, side, &id ) )
+ return 0;
+ }
+
+ /* for each sector... */
+ for ( nb = 0; nb < 16; nb++ )
+ {
+ if ( ! floppy_drive_get_next_id( img, side, &id ) )
+ break;
+
+ memset( dst, space, THOM_SIZE_SYNCHRO ); dst += THOM_SIZE_SYNCHRO;
+ dst += thom_floppy_make_addr( id, dst, sector_size );
+ memset( dst, space, THOM_SIZE_SYNCHRO ); dst += THOM_SIZE_SYNCHRO;
+ dst += thom_floppy_make_sector( img, id, dst, sector_size );
+
+ if ( floppy_drive_get_flag_state( img, FLOPPY_DRIVE_INDEX ) )
+ break;
+ }
+ return dst - org;
+}
+
+
+
+/******************* QDD disk format ********************/
+
+/*
+ sector format:
+
+ data bytes
+
+ id field 16 17 synchro
+ A5 1 id field mark
+ 1 sector (1-400) hi byte
+ 1 sector (1-400) low byte
+ 1 check-sum (sum modulo 256 of 3 last bytes)
+
+ data field 16 10 synchro
+ 5A 1 data field mark
+ FF 128 actual data (set to FF when formatting)
+ 1 check-sum (sum modulo 256 of 129 last bytes)
+
+
+ there are 400 sectors numbered from 1
+*/
+
+#define THOM_QDD_SYNCH_DISK 100
+#define THOM_QDD_SYNCH_ADDR 17
+#define THOM_QDD_SYNCH_DATA 10
+
+#define THOM_QDD_SIZE_ID ( 4 + THOM_QDD_SYNCH_ADDR )
+#define THOM_QDD_SIZE_DATA ( 130 + THOM_QDD_SYNCH_DATA )
+
+
+/* build an identifier, with header */
+static int thom_qdd_make_addr( int sector, UINT8* dst )
+{
+ dst[ 0 ] = 0xa5;
+ dst[ 1 ] = sector >> 8;
+ dst[ 2 ] = sector & 0xff;
+ dst[ 3 ] = dst[ 0 ] + dst[ 1 ] + dst[ 2 ];
+ return 4;
+}
+
+
+
+/* build a sector, with header */
+static int thom_qdd_make_sector( device_t* img, int sector, UINT8* dst )
+{
+ int i;
+ dst[ 0 ] = 0x5a;
+ floppy_drive_read_sector_data ( img, 0, sector, dst + 1, 128 );
+ dst[ 129 ] = 0;
+ for ( i = 0; i < 129; i++ )
+ dst[ 129 ] += dst[ i ];
+ return 130;
+}
+
+
+
+/* build a whole disk */
+static int thom_qdd_make_disk ( device_t* img, UINT8* dst )
+{
+ UINT8* org = dst;
+ int i;
+
+ memset( dst, 0x16, THOM_QDD_SYNCH_DISK ); dst += THOM_QDD_SYNCH_DISK;
+
+ for ( i = 1; i <= 400; i++ )
+ {
+ memset( dst, 0x16, THOM_QDD_SYNCH_ADDR ); dst += THOM_QDD_SYNCH_ADDR;
+ dst += thom_qdd_make_addr( i, dst );
+ memset( dst, 0x16, THOM_QDD_SYNCH_DATA ); dst += THOM_QDD_SYNCH_DATA;
+ dst += thom_qdd_make_sector( img, i, dst );
+ }
+
+ memset( dst, 0x16, THOM_QDD_SYNCH_DISK ); dst += THOM_QDD_SYNCH_DISK;
+
+ return dst - org;
+}
+
+
+
+/*********************** CD 90-640 controller ************************/
+
+/* 5''1/4 two-sided double-density
+ used in TO7, TO7/70, MO5 computers
+ based on a WD2793 (or lower ?) chip
+*/
+
+
+
+static UINT8 to7_5p14_select;
+
+
+
+static READ8_HANDLER ( to7_5p14_r )
+{
+ device_t *fdc = space->machine().device("wd2793");
+
+ if ( offset < 4 )
+ return wd17xx_r( fdc, offset );
+ else if ( offset == 8 )
+ return to7_5p14_select;
+ else
+ logerror ( "%f $%04x to7_5p14_r: invalid read offset %i\n", space->machine().time().as_double(), cpu_get_previouspc(space->machine().device("maincpu")), offset );
+ return 0;
+}
+
+
+
+static WRITE8_HANDLER( to7_5p14_w )
+{
+ device_t *fdc = space->machine().device("wd2793");
+ if ( offset < 4 )
+ wd17xx_w( fdc, offset, data );
+ else if ( offset == 8 )
+ {
+ /* drive select */
+ int drive = -1, side = 0;
+
+ switch ( data & 7 )
+ {
+ case 0: break;
+ case 2: drive = 0; side = 0; break;
+ case 3: drive = 1; side = 1; break;
+ case 4: drive = 2; side = 0; break;
+ case 5: drive = 3; side = 1; break;
+ default:
+ logerror( "%f $%04x to7_5p14_w: invalid drive select pattern $%02X\n", space->machine().time().as_double(), cpu_get_previouspc(space->machine().device("maincpu")), data );
+ }
+
+ wd17xx_dden_w(fdc, BIT(data, 7));
+
+ to7_5p14_select = data;
+
+ if ( drive != -1 )
+ {
+ thom_floppy_active( space->machine(), 0 );
+ wd17xx_set_drive( fdc, drive );
+ wd17xx_set_side( fdc, side );
+ LOG(( "%f $%04x to7_5p14_w: $%02X set drive=%i side=%i density=%s\n",
+ space->machine().time().as_double(), cpu_get_previouspc(space->machine().device("maincpu")),
+ data, drive, side, (BIT(data, 7) ? "FM" : "MFM")));
+ }
+ }
+ else
+ logerror ( "%f $%04x to7_5p14_w: invalid write offset %i (data=$%02X)\n",
+ space->machine().time().as_double(), cpu_get_previouspc(space->machine().device("maincpu")), offset, data );
+}
+
+
+
+static void to7_5p14_reset( running_machine &machine )
+{
+ device_t *fdc = machine.device("wd2793");
+ LOG(( "to7_5p14_reset: CD 90-640 controller\n" ));
+ wd17xx_reset(fdc);
+}
+
+
+
+static void to7_5p14_init( running_machine &machine )
+{
+ LOG(( "to7_5p14_init: CD 90-640 controller\n" ));
+ state_save_register_global( machine, to7_5p14_select );
+}
+
+
+
+/*********************** CD 90-015 controller ************************/
+
+/* 5''1/4 one-sided single-density (up to 4 one-sided drives)
+ used in TO7, TO7/70, MO5 computers
+ based on HD 46503 S chip, but we actually use a MC 6843 instead
+ (seems they are clone)
+*/
+
+
+
+static UINT8 to7_5p14sd_select;
+
+
+
+static READ8_HANDLER ( to7_5p14sd_r )
+{
+ if ( offset < 8 )
+ return mc6843_r( space->machine().device("mc6843"), offset );
+ else if ( offset >= 8 && offset <= 9 )
+ return to7_5p14sd_select;
+ else
+ logerror ( "%f $%04x to7_5p14sd_r: invalid read offset %i\n", space->machine().time().as_double(), cpu_get_previouspc(space->machine().device("maincpu")), offset );
+ return 0;
+}
+
+
+
+static WRITE8_HANDLER( to7_5p14sd_w )
+{
+ if ( offset < 8 )
+ mc6843_w( space->machine().device("mc6843"), offset, data );
+ else if ( offset >= 8 && offset <= 9 )
+ {
+ /* drive select */
+ int drive = -1, side = 0;
+
+ if ( data & 1 )
+ {
+ drive = 0;
+ side = 0;
+ }
+ else if ( data & 2 )
+ {
+ drive = 1;
+ side = 1;
+ }
+ else if ( data & 4 )
+ {
+ drive = 2;
+ side = 0;
+ }
+ else if ( data & 8 )
+ {
+ drive = 3;
+ side = 1;
+ }
+
+ to7_5p14sd_select = data;
+
+ if ( drive != -1 )
+ {
+ thom_floppy_active( space->machine(), 0 );
+ mc6843_set_drive( space->machine().device("mc6843"), drive );
+ mc6843_set_side( space->machine().device("mc6843"), side );
+ LOG(( "%f $%04x to7_5p14sd_w: $%02X set drive=%i side=%i\n",
+ space->machine().time().as_double(), cpu_get_previouspc(space->machine().device("maincpu")), data, drive, side ));
+ }
+ }
+ else
+ logerror ( "%f $%04x to7_5p14sd_w: invalid write offset %i (data=$%02X)\n",
+ space->machine().time().as_double(), cpu_get_previouspc(space->machine().device("maincpu")), offset, data );
+}
+
+static void to7_5p14_index_pulse_callback( device_t *controller,device_t *image, int state )
+{
+ mc6843_set_index_pulse( image->machine().device("mc6843"), state );
+}
+
+static void to7_5p14sd_reset( running_machine &machine )
+{
+ int i;
+ LOG(( "to7_5p14sd_reset: CD 90-015 controller\n" ));
+ for ( i = 0; i < floppy_get_count( machine ); i++ )
+ {
+ device_t * img = floppy_get_device( machine, i );
+ if (img) {
+ floppy_drive_set_ready_state( img, FLOPPY_DRIVE_READY, 0 );
+ floppy_drive_set_rpm( img, 300. );
+ floppy_drive_seek( img, - floppy_drive_get_current_track( img ) );
+ }
+ }
+}
+
+
+
+const mc6843_interface to7_6843_itf = { NULL };
+
+
+
+static void to7_5p14sd_init( running_machine &machine )
+{
+ LOG(( "to7_5p14sd_init: CD 90-015 controller\n" ));
+ state_save_register_global( machine, to7_5p14sd_select );
+}
+
+
+/*********************** CQ 90-028 controller ************************/
+
+/* QDD 2''8 controller
+ used in TO7, TO7/70, MO5 computers
+ it is based on a MC6852 SSDA
+
+ Note: the MC6852 is only partially emulated, most features are not used in
+ the controller and are ignored.
+*/
+
+
+
+/* MC6852 status */
+#define QDD_S_RDA 0x01 /* receiver data available */
+#define QDD_S_TDRA 0x02 /* transitter data register available */
+#define QDD_S_NDCD 0x04 /* data carrier detect, negated (unused) */
+#define QDD_S_NCTS 0x08 /* clear-to-send, negated write-protect */
+#define QDD_S_TUF 0x10 /* transmitter underflow (unused) */
+#define QDD_S_OVR 0x20 /* receiver overrun (unused) */
+#define QDD_S_PE 0x40 /* receiver parity error (unused) */
+#define QDD_S_IRQ 0x80 /* interrupt request */
+#define QDD_S_ERR (QDD_S_TUF | QDD_S_OVR | QDD_S_PE | QDD_S_NDCD | QDD_S_NCTS)
+
+
+/* MC6852 control */
+#define QDD_C1_RIE 0x20 /* interrupt on reveive */
+#define QDD_C1_TIE 0x10 /* interrupt on transmit */
+#define QDD_C1_CLRSYNC 0x08 /* clear receiver sync char (unused) */
+#define QDD_C1_STRIPSYNC 0x04 /* strips sync from received (unused) */
+#define QDD_C1_TRESET 0x02 /* transmitter reset */
+#define QDD_C1_RRESET 0x01 /* receiver reset */
+#define QDD_C2_EIE 0x80 /* interrupt on error */
+#define QDD_C2_TSYNC 0x40 /* underflow = ff if 0 / sync if 1 (unused) */
+#define QDD_C2_BLEN 0x04 /* transfer byte length (unused) */
+#define QDD_C3_CLRTUF 0x08 /* clear underflow */
+#define QDD_C3_CLRCTS 0x04 /* clear CTS */
+#define QDD_C3_SYNCLEN 0x02 /* sync byte length (unused) */
+#define QDD_C3_SYNCMODE 0x01 /* external / internal sync mode (unused) */
+
+
+/* a track is actually the whole disk = 400 128-byte sectors + headers */
+#define QDD_MAXBUF ( THOM_QDD_SIZE_ID + THOM_QDD_SIZE_DATA ) * 512
+
+
+static struct _to7qdd
+{
+ /* MC6852 registers */
+ UINT8 status;
+ UINT8 ctrl1;
+ UINT8 ctrl2;
+ UINT8 ctrl3;
+
+ /* extra registers */
+ UINT8 drive;
+
+ /* internal state */
+ UINT8 data[QDD_MAXBUF]; /* enough for a whole track */
+ UINT32 data_idx; /* byte position in track */
+ UINT32 start_idx; /* start of write position */
+ UINT32 data_size; /* track length */
+ UINT8 data_crc; /* checksum when writing */
+ UINT8 index_pulse; /* one pulse per track */
+
+} * to7qdd;
+
+
+
+static void to7_qdd_index_pulse_cb ( device_t *controller,device_t *image, int state )
+{
+ to7qdd->index_pulse = state;
+
+ if ( state )
+ {
+ /* rewind to disk start */
+ to7qdd->data_idx = 0;
+ to7qdd->start_idx = 0;
+ to7qdd->data_size = 0;
+ }
+
+ VLOG(( "%f to7_qdd_pulse_cb: state=%i\n", image->machine().time().as_double(), state ));
+}
+
+
+
+static device_t * to7_qdd_image ( running_machine &machine )
+{
+ return floppy_get_device( machine, 0 );
+}
+
+
+
+/* update MC6852 status register */
+static void to7_qdd_stat_update( running_machine &machine )
+{
+ /* byte-ready */
+ to7qdd->status |= QDD_S_RDA | QDD_S_TDRA;
+ if ( ! to7qdd->drive )
+ to7qdd->status |= QDD_S_PE;
+
+ /* write-protect */
+ if (floppy_wpt_r(to7_qdd_image(machine)) == CLEAR_LINE)
+ to7qdd->status |= QDD_S_NCTS;
+
+ /* sticky reset conditions */
+ if ( to7qdd->ctrl1 & QDD_C1_RRESET )
+ to7qdd->status &= ~(QDD_S_PE | QDD_S_RDA | QDD_S_OVR);
+ if ( to7qdd->ctrl1 & QDD_C1_TRESET )
+ to7qdd->status &= ~(QDD_S_TDRA | QDD_S_TUF);
+
+ /* irq update */
+
+ if ( ( (to7qdd->ctrl1 & QDD_C1_RIE) && !(to7qdd->status & QDD_S_RDA ) ) ||
+ ( (to7qdd->ctrl1 & QDD_C1_TIE) && !(to7qdd->status & QDD_S_TDRA) ) ||
+ ( (to7qdd->ctrl2 & QDD_C2_EIE) && !(to7qdd->status & QDD_S_ERR ) ) )
+ to7qdd->status &= ~QDD_S_IRQ;
+
+ if ( ( (to7qdd->ctrl1 & QDD_C1_RIE) && (to7qdd->status & QDD_S_RDA ) ) ||
+ ( (to7qdd->ctrl1 & QDD_C1_TIE) && (to7qdd->status & QDD_S_TDRA) ) ||
+ ( (to7qdd->ctrl2 & QDD_C2_EIE) && (to7qdd->status & QDD_S_ERR ) ) )
+ to7qdd->status |= QDD_S_IRQ;
+}
+
+
+
+static UINT8 to7_qdd_read_byte( running_machine &machine )
+{
+ UINT8 data;
+
+ /* rebuild disk if needed */
+ if ( !to7qdd->data_size )
+ {
+ to7qdd->data_size = thom_qdd_make_disk( to7_qdd_image(machine), to7qdd->data );
+ assert( to7qdd->data_idx < sizeof( to7qdd->data ) );
+ }
+
+ if ( to7qdd->data_idx >= to7qdd->data_size )
+ data = 0;
+ else
+ data = to7qdd->data[ to7qdd->data_idx ];
+
+ VLOG(( "%f $%04x to7_qdd_read_byte: RDATA off=%i/%i data=$%02X\n",
+ machine.time().as_double(), cpu_get_previouspc(machine.device("maincpu")),
+ to7qdd->data_idx, to7qdd->data_size, data ));
+
+ to7qdd->data_idx++;
+ to7qdd->start_idx = to7qdd->data_idx;
+
+ return data;
+}
+
+
+
+/* This is quite complex: bytes are written one at a time by the CPU and we
+ must detect the following patterns:
+ * CPU write id field and data field => format
+ * CPU write data field after it has read an id field => sector write
+ */
+static void to7_qdd_write_byte( running_machine &machine, UINT8 data )
+{
+ int i;
+
+ /* rebuild disk if needed */
+ if ( !to7qdd->data_size )
+ {
+ to7qdd->data_size = thom_qdd_make_disk( to7_qdd_image(machine), to7qdd->data );
+ assert( to7qdd->data_idx < sizeof( to7qdd->data ) );
+ }
+
+ if ( ( to7qdd->start_idx != to7qdd->data_idx || /* field in construction */
+ data==0xA5 || data==0x5A ) && /* first byte of tentative field */
+ to7qdd->data_idx <to7qdd->data_size )
+ {
+
+ /* this is the first byte of the field */
+ if ( to7qdd->start_idx == to7qdd->data_idx )
+ to7qdd->data_crc = 0;
+
+ /* accumulate bytes */
+ to7qdd->data[ to7qdd->data_idx ] = data;
+ to7qdd->data_idx++;
+
+ VLOG (( "%f $%04x to7_qdd_write_byte: got $%02X offs=%i-%i\n",
+ machine.time().as_double(), cpu_get_previouspc(machine.device("maincpu")), data,
+ to7qdd->start_idx, to7qdd->data_idx ));
+
+ /* end of tentative id field */
+ if ( to7qdd->data_idx == to7qdd->start_idx + 4 &&
+ to7qdd->data[ to7qdd->start_idx ] == 0xA5 &&
+ to7qdd->data[ to7qdd->start_idx + 3 ] == to7qdd->data_crc )
+ {
+
+ /* got an id field => format */
+ int sector = (int) to7qdd->data[ to7qdd->start_idx + 1 ] * 256 + (int) to7qdd->data[ to7qdd->start_idx + 2 ];
+ UINT8 filler = 0xff;
+
+ LOG(( "%f $%04x to7_qdd_write_byte: got id field for sector=%i\n",
+ machine.time().as_double(), cpu_get_previouspc(machine.device("maincpu")), sector ));
+
+ floppy_drive_format_sector( to7_qdd_image(machine),
+ 0, sector, 0, 0, sector, 128, filler );
+ thom_floppy_active( machine, 1 );
+ to7qdd->start_idx = to7qdd->data_idx;
+ }
+
+ /* end of tentative data field */
+ else if ( to7qdd->data_idx == to7qdd->start_idx + 130 &&
+ to7qdd->data[ to7qdd->start_idx ] == 0x5A &&
+ to7qdd->data[ to7qdd->start_idx + 129 ] == to7qdd->data_crc )
+ {
+
+ /* look backwards for previous id field */
+ for ( i = to7qdd->start_idx - 3; i >= 0; i-- )
+ {
+ if ( to7qdd->data[ i ] == 0xA5 &&
+ ( ( to7qdd->data[ i ] + to7qdd->data[ i + 1 ] +
+ to7qdd->data[ i + 2 ] ) & 0xff
+ ) == to7qdd->data[ i + 3 ] )
+ break;
+ }
+
+ if ( i >= 0 )
+ {
+ /* got an id & a data field => write */
+ int sector = (int) to7qdd->data[ i + 1 ] * 256 + (int) to7qdd->data[ i + 2 ];
+
+ LOG(( "%f $%04x to7_qdd_write_byte: goto data field for sector=%i\n",
+ machine.time().as_double(), cpu_get_previouspc(machine.device("maincpu")), sector ));
+
+ floppy_drive_write_sector_data( to7_qdd_image(machine), 0, sector, to7qdd->data + to7qdd->start_idx + 1, 128, 0 );
+ thom_floppy_active( machine, 1 );
+ }
+
+ to7qdd->start_idx = to7qdd->data_idx;
+ }
+
+ else to7qdd->data_crc += data;
+ }
+}
+
+
+
+static READ8_HANDLER ( to7_qdd_r )
+{
+ switch ( offset )
+ {
+
+ case 0: /* MC6852 status */
+ to7_qdd_stat_update(space->machine());
+ VLOG(( "%f $%04x to7_qdd_r: STAT=$%02X irq=%i pe=%i ovr=%i und=%i tr=%i rd=%i ncts=%i\n",
+ space->machine().time().as_double(), cpu_get_previouspc(space->machine().device("maincpu")), to7qdd->status,
+ to7qdd->status & QDD_S_IRQ ? 1 : 0,
+ to7qdd->status & QDD_S_PE ? 1 : 0,
+ to7qdd->status & QDD_S_OVR ? 1 : 0,
+ to7qdd->status & QDD_S_TUF ? 1 : 0,
+ to7qdd->status & QDD_S_TDRA ? 1 : 0,
+ to7qdd->status & QDD_S_RDA ? 1 : 0,
+ to7qdd->status & QDD_S_NCTS ? 1 : 0 ));
+ return to7qdd->status;
+
+ case 1: /* MC6852 data input => read byte from disk */
+ to7qdd->status &= ~(QDD_S_RDA | QDD_S_PE | QDD_S_OVR);
+ to7_qdd_stat_update(space->machine());
+ return to7_qdd_read_byte(space->machine());
+
+ case 8: /* floppy status */
+ {
+ UINT8 data = 0;
+ device_image_interface* img = dynamic_cast<device_image_interface *>(to7_qdd_image(space->machine()));
+ if ( ! img->exists() )
+ data |= 0x40; /* disk present */
+ if ( to7qdd->index_pulse )
+ data |= 0x80; /* disk start */
+ VLOG(( "%f $%04x to7_qdd_r: STATUS8 $%02X\n", space->machine().time().as_double(), cpu_get_previouspc(space->machine().device("maincpu")), data ));
+ return data;
+ }
+
+ default:
+ logerror ( "%f $%04x to7_qdd_r: invalid read offset %i\n", space->machine().time().as_double(), cpu_get_previouspc(space->machine().device("maincpu")), offset );
+ return 0;
+ }
+}
+
+
+
+static WRITE8_HANDLER( to7_qdd_w )
+{
+ switch ( offset )
+ {
+
+ case 0: /* MC6852 control 1 */
+ /* reset */
+ if ( data & QDD_C1_RRESET )
+ to7qdd->status &= ~(QDD_S_PE | QDD_S_RDA | QDD_S_OVR);
+ if ( data & QDD_C1_TRESET )
+ to7qdd->status &= ~(QDD_S_TDRA | QDD_S_TUF);
+
+ to7qdd->ctrl1 = ( data & ~(QDD_C1_RRESET | QDD_C1_TRESET) ) |( data & (QDD_C1_RRESET | QDD_C1_TRESET) & to7qdd->ctrl1 );
+ to7_qdd_stat_update(space->machine());
+ VLOG(( "%f $%04x to7_qdd_w: CTRL1=$%02X reset=%c%c %s%sirq=%c%c\n",
+ space->machine().time().as_double(), cpu_get_previouspc(space->machine().device("maincpu")), data,
+ data & QDD_C1_RRESET ? 'r' : '-', data & QDD_C1_TRESET ? 't' : '-',
+ data & QDD_C1_STRIPSYNC ? "strip-sync " : "",
+ data & QDD_C1_CLRSYNC ? "clear-sync " : "",
+ data & QDD_C1_RIE ? 'r' : '-',
+ data & QDD_C1_TIE ? 't' : '-' ));
+ break;
+
+ case 1:
+ switch ( to7qdd->ctrl1 >> 6 )
+ {
+
+ case 0: /* MC6852 control 2 */
+ {
+#if 0
+ /* most of these are unused now */
+ static const int bit[8] = { 6, 6, 7, 8, 7, 7, 8, 8 };
+ static const int par[8] = { 2, 1, 0, 0, 2, 1, 2, 1 };
+ static const char *const parname[3] = { "none", "odd", "even" };
+ int bits, parity;
+ bits = bit[ (data >> 3) & 7 ];
+ parity = par[ (data >> 3) & 7 ];
+ to7_qdd_stat_update(space->machine());
+ VLOG(( "%f $%04x to7_qdd_w: CTRL2=$%02X bits=%i par=%s blen=%i under=%s%s\n",
+ space->machine().time().as_double(), cpu_get_previouspc(space->machine().device("maincpu")), data,
+ bits, parname[ parity ], data & QDD_C2_BLEN ? 1 : 2,
+ data & QDD_C2_TSYNC ? "sync" : "ff",
+ data & QDD_C2_EIE ? "irq-err" : "" ));
+#endif
+ to7qdd->ctrl2 = data;
+ break;
+ }
+
+ case 1: /* MC6852 control 3 */
+ to7qdd->ctrl3 = data;
+ /* reset just once each write, not sticky */
+ if ( data & QDD_C3_CLRTUF )
+ to7qdd->status &= ~QDD_S_TUF;
+ if ( data & QDD_C3_CLRCTS )
+ to7qdd->status &= ~QDD_S_NCTS;
+ to7_qdd_stat_update(space->machine());
+ VLOG(( "%f $%04x to7_qdd_w: CTRL3=$%02X %s%ssync-len=%i sync-mode=%s\n",
+ space->machine().time().as_double(), cpu_get_previouspc(space->machine().device("maincpu")), data,
+ data & QDD_C3_CLRTUF ? "clr-tuf " : "",
+ data & QDD_C3_CLRCTS ? "clr-cts " : "",
+ data & QDD_C3_SYNCLEN ? 1 : 2,
+ data & QDD_C3_SYNCMODE ? "ext" : "int" ));
+ break;
+
+ case 2: /* MC6852 sync code => write byte to disk */
+ to7_qdd_write_byte( space->machine(), data );
+ break;
+
+ case 3: /* MC6852 data out => does not seem to be used */
+ VLOG(( "%f $%04x to7_qdd_w: ignored WDATA=$%02X\n", space->machine().time().as_double(), cpu_get_previouspc(space->machine().device("maincpu")), data ));
+ break;
+
+ }
+ break;
+
+ case 8: /* set drive */
+ to7qdd->drive = data;
+ VLOG(( "%f $%04x to7_qdd_w: DRIVE=$%02X\n", space->machine().time().as_double(), cpu_get_previouspc(space->machine().device("maincpu")), data ));
+ break;
+
+ case 12: /* motor pulse ? */
+ thom_floppy_active( space->machine(), 0 );
+ VLOG(( "%f $%04x to7_qdd_w: MOTOR=$%02X\n", space->machine().time().as_double(), cpu_get_previouspc(space->machine().device("maincpu")), data ));
+ break;
+
+ default:
+ logerror ( "%f $%04x to7_qdd_w: invalid write offset %i (data=$%02X)\n", space->machine().time().as_double(), cpu_get_previouspc(space->machine().device("maincpu")), offset, data );
+ }
+}
+
+
+
+static void to7_qdd_reset( running_machine &machine )
+{
+ int i;
+ LOG(( "to7_qdd_reset: CQ 90-028 controller\n" ));
+
+ for ( i = 0; i < floppy_get_count( machine ); i++ )
+ {
+ device_t * img = floppy_get_device( machine, i );
+ if (img) {
+ floppy_drive_set_ready_state( img, FLOPPY_DRIVE_READY, 0 );
+
+ motor_on = CLEAR_LINE;
+ floppy_mon_w(img, motor_on);
+
+ /* pulse each time the whole-disk spiraling track ends */
+ /* at 90us per byte read, the disk can be read in 6s */
+ floppy_drive_set_rpm( img, 60. / 6. );
+ }
+ }
+
+ to7qdd->ctrl1 |= QDD_C1_TRESET | QDD_C1_RRESET; /* reset */
+ to7qdd->ctrl2 &= 0x7c; /* clear EIE, PC2-PC1 */
+ to7qdd->ctrl3 &= 0xfe; /* internal sync */
+ to7qdd->drive = 0;
+ to7_qdd_stat_update(machine);
+}
+
+
+
+static void to7_qdd_init( running_machine &machine )
+{
+ LOG(( "to7_qdd_init: CQ 90-028 controller\n" ));
+
+ to7qdd = auto_alloc(machine, struct _to7qdd);
+
+ state_save_register_global( machine, to7qdd->status );
+ state_save_register_global( machine, to7qdd->ctrl1 );
+ state_save_register_global( machine, to7qdd->ctrl2 );
+ state_save_register_global( machine, to7qdd->ctrl3 );
+ state_save_register_global( machine, to7qdd->drive );
+ state_save_register_global( machine, to7qdd->data_idx );
+ state_save_register_global( machine, to7qdd->start_idx );
+ state_save_register_global( machine, to7qdd->data_size );
+ state_save_register_global( machine, to7qdd->data_crc );
+ state_save_register_global( machine, to7qdd->index_pulse );
+ state_save_register_global_array( machine, to7qdd->data );
+}
+
+
+
+/********************** THMFC1 controller *************************/
+
+/* custom Thomson Gate-array for 3''1/2, 5''1/4 (double density only) & QDD
+ */
+
+
+
+/* types of high-level operations */
+#define THMFC1_OP_RESET 0
+#define THMFC1_OP_WRITE_SECT 1
+#define THMFC1_OP_READ_ADDR 2
+#define THMFC1_OP_READ_SECT 3
+
+
+/* STAT0 flags */
+#define THMFC1_STAT0_SYNCHRO 0x01 /* bit clock synchronized */
+#define THMFC1_STAT0_BYTE_READY_OP 0x02 /* byte ready (high-level operation) */
+#define THMFC1_STAT0_CRC_ERROR 0x04
+#define THMFC1_STAT0_FINISHED 0x08
+#define THMFC1_STAT0_FINISHING 0x10 /* (unemulated) */
+#define THMFC1_STAT0_BYTE_READY_POL 0x80 /* polling mode */
+
+
+/*#define THOM_MAXBUF (THOM_SIZE_ID+THOM_SIZE_DATA_HI+2*THOM_SIZE_SYNCHRO)*17*/
+#define THOM_MAXBUF ( THOM_QDD_SIZE_ID + THOM_QDD_SIZE_DATA ) * 512
+
+
+static struct _thmfc1
+{
+
+ UINT8 op;
+ UINT8 sector; /* target sector, in [1,16] */
+ UINT32 sector_id;
+ UINT8 track; /* current track, in [0,79] */
+ UINT8 side; /* current side, 0 or 1 */
+ UINT8 drive; /* 0 to 3 */
+ UINT16 sector_size; /* 128 or 256 (512, 1024 not supported) */
+ UINT8 formatting;
+ UINT8 ipl; /* index pulse / QDD start */
+ UINT8 wsync; /* synchronization word */
+
+ UINT8 data[THOM_MAXBUF]; /* enough for a whole track */
+ UINT32 data_idx; /* reading / writing / formatting pos */
+ UINT32 data_size; /* bytes to read / write */
+ UINT32 data_finish; /* when to raise the finished flag */
+ UINT32 data_raw_idx; /* byte index for raw track reading */
+ UINT32 data_raw_size; /* size of track already cached in data */
+ UINT8 data_crc; /* check-sum of written data */
+
+ UINT8 stat0; /* status register */
+
+} * thmfc1;
+
+
+static emu_timer* thmfc_floppy_cmd;
+
+
+
+static device_t * thmfc_floppy_image ( running_machine &machine )
+{
+ return floppy_get_device( machine, thmfc1->drive );
+}
+
+
+
+static int thmfc_floppy_is_qdd ( device_image_interface *image )
+{
+ if (image==NULL) return 0;
+ if (!image->exists()) return 0;
+ return image->length()==51200; // idf QDD
+}
+
+
+
+static void thmfc_floppy_index_pulse_cb ( device_t *controller,device_t *image, int state )
+{
+ if ( image != thmfc_floppy_image(image->machine()))
+ return;
+
+ if ( thmfc_floppy_is_qdd(dynamic_cast<device_image_interface *>(image)))
+ {
+ /* pulse each time the whole-disk spiraling track ends */
+ floppy_drive_set_rpm( image, 16.92f /* 423/25 */ );
+ thmfc1->ipl = state;
+ if ( state )
+ {
+ thmfc1->data_raw_size = 0;
+ thmfc1->data_raw_idx = 0;
+ thmfc1->data_idx = 0;
+ }
+ }
+ else
+ {
+ floppy_drive_set_rpm( image, 300. );
+ thmfc1->ipl = state;
+ if ( state )
+ thmfc1->data_raw_idx = 0;
+ }
+
+ VLOG(( "%f thmfc_floppy_index_pulse_cb: state=%i\n", image->machine().time().as_double(), state ));
+}
+
+
+
+static int thmfc_floppy_find_sector ( running_machine &machine, chrn_id* dst )
+{
+ device_t* img = thmfc_floppy_image(machine);
+ chrn_id id;
+ int r = 0;
+
+ /* scan track, try 4 revolutions */
+ while ( r < 4 )
+ {
+
+ if ( floppy_drive_get_next_id( img, thmfc1->side, &id ) )
+ {
+ if ( id.C == thmfc1->track &&
+ id.R == thmfc1->sector &&
+ (128 << id.N) == thmfc1->sector_size
+ /* check side ? id.H == thmfc1->side */ )
+ {
+ if ( dst )
+ memcpy( dst, &id, sizeof( chrn_id ) );
+ thmfc1->stat0 = THMFC1_STAT0_BYTE_READY_POL;
+ LOG (( "thmfc_floppy_find_sector: sector found C=%i H=%i R=%i N=%i\n", id.C, id.H, id.R, id.N ));
+ return 1;
+ }
+ }
+
+ if ( floppy_drive_get_flag_state( img, FLOPPY_DRIVE_INDEX ) )
+ r++;
+ }
+
+ thmfc1->stat0 = THMFC1_STAT0_CRC_ERROR | THMFC1_STAT0_FINISHED;
+ LOG (( "thmfc_floppy_find_sector: sector not found drive=%i track=%i sector=%i\n", floppy_get_drive( img ), thmfc1->track, thmfc1->sector ));
+ return 0;
+}
+
+
+
+/* complete command (by read, write, or timeout) */
+static void thmfc_floppy_cmd_complete( running_machine &machine )
+{
+ LOG (( "%f thmfc_floppy_cmd_complete_cb: cmd=%i off=%i/%i/%i\n",
+ machine.time().as_double(), thmfc1->op, thmfc1->data_idx,
+ thmfc1->data_finish - 1, thmfc1->data_size - 1 ));
+
+ if ( thmfc1->op == THMFC1_OP_WRITE_SECT )
+ {
+ device_t * img = thmfc_floppy_image(machine);
+ floppy_drive_write_sector_data( img, thmfc1->side, thmfc1->sector_id, thmfc1->data + 3, thmfc1->data_size - 3, 0 );
+ thom_floppy_active( machine, 1 );
+ }
+ thmfc1->op = THMFC1_OP_RESET;
+ thmfc1->stat0 |= THMFC1_STAT0_FINISHED;
+ thmfc1->data_idx = 0;
+ thmfc1->data_size = 0;
+ thmfc_floppy_cmd->adjust(attotime::never);
+}
+
+
+
+static TIMER_CALLBACK( thmfc_floppy_cmd_complete_cb )
+{
+ thmfc_floppy_cmd_complete( machine );
+}
+
+
+
+/* intelligent read: show just one field, skip header */
+static UINT8 thmfc_floppy_read_byte ( running_machine &machine )
+{
+ UINT8 data = thmfc1->data[ thmfc1->data_idx ];
+
+ VLOG(( "%f $%04x thmfc_floppy_read_byte: off=%i/%i/%i data=$%02X\n",
+ machine.time().as_double(), cpu_get_previouspc(machine.device("maincpu")),
+ thmfc1->data_idx, thmfc1->data_finish - 1, thmfc1->data_size - 1,
+ data ));
+
+ if ( thmfc1->data_idx >= thmfc1->data_size - 1 )
+ thmfc_floppy_cmd_complete( machine );
+ else
+ thmfc1->data_idx++;
+
+ if ( thmfc1->data_idx >= thmfc1->data_finish )
+ thmfc1->stat0 |= THMFC1_STAT0_FINISHED;
+
+ return data;
+}
+
+
+
+/* dumb read: show whole track with field headers and gaps */
+static UINT8 thmfc_floppy_raw_read_byte ( running_machine &machine )
+{
+ UINT8 data;
+
+ /* rebuild track if needed */
+ if ( ! thmfc1->data_raw_size )
+ {
+ if ( thmfc_floppy_is_qdd(dynamic_cast<device_image_interface *>(thmfc_floppy_image(machine))))
+ /* QDD: track = whole disk */
+ thmfc1->data_raw_size = thom_qdd_make_disk ( thmfc_floppy_image(machine), thmfc1->data );
+ else
+ {
+ thmfc1->data_raw_idx = 0;
+ thmfc1->data_raw_size = thom_floppy_make_track( thmfc_floppy_image(machine), thmfc1->data,
+ thmfc1->sector_size, thmfc1->side );
+ }
+ assert( thmfc1->data_raw_size < sizeof( thmfc1->data ) );
+ }
+
+ if ( thmfc1->data_raw_idx >= thmfc1->data_raw_size )
+ data = 0;
+ else
+ data = thmfc1->data[ thmfc1->data_raw_idx ];
+
+ VLOG(( "%f $%04x thmfc_floppy_raw_read_byte: off=%i/%i data=$%02X\n",
+ machine.time().as_double(), cpu_get_previouspc(machine.device("maincpu")),
+ thmfc1->data_raw_idx, thmfc1->data_raw_size, data ));
+
+ thmfc1->data_raw_idx++;
+
+ return data;
+}
+
+
+
+/* QDD writing / formating */
+static void thmfc_floppy_qdd_write_byte ( running_machine &machine, UINT8 data )
+{
+ int i;
+
+ if ( thmfc1->formatting &&
+ ( thmfc1->data_idx || data==0xA5 || data==0x5A ) &&
+ thmfc1->data_raw_idx < THOM_MAXBUF )
+ {
+
+ if ( ! thmfc1->data_raw_size )
+ {
+ thmfc1->data_raw_size = thom_qdd_make_disk ( thmfc_floppy_image(machine), thmfc1->data );
+ assert( thmfc1->data_raw_size < sizeof( thmfc1->data ) );
+ }
+
+ /* accumulate bytes to form a field */
+ thmfc1->data[ thmfc1->data_raw_idx ] = data;
+ thmfc1->data_raw_idx++;
+
+ if ( ! thmfc1->data_idx )
+ {
+ /* start */
+ thmfc1->data_crc = 0;
+ thmfc1->data_idx = thmfc1->data_raw_idx;
+ }
+
+ VLOG (( "%f $%04x thmfc_floppy_qdd_write_byte: $%02X offs=%i-%i\n",
+ machine.time().as_double(), cpu_get_previouspc(machine.device("maincpu")), data,
+ thmfc1->data_idx,thmfc1->data_raw_idx ));
+
+ if ( thmfc1->data_raw_idx == thmfc1->data_idx + 3 &&
+ thmfc1->data[ thmfc1->data_idx - 1 ] == 0xA5 &&
+ thmfc1->data[ thmfc1->data_idx + 2 ] == thmfc1->data_crc )
+ {
+
+ /* got an id field => format */
+ int sector = (int) thmfc1->data[ thmfc1->data_idx ] * 256 + (int) thmfc1->data[ thmfc1->data_idx + 1 ];
+ UINT8 filler = 0xff;
+
+ LOG(( "%f $%04x thmfc_floppy_qdd_write_byte: id field, sector=%i\n", machine.time().as_double(), cpu_get_previouspc(machine.device("maincpu")), sector ));
+
+ floppy_drive_format_sector( thmfc_floppy_image(machine), 0, sector, 0, 0, sector, 128, filler );
+ thom_floppy_active( machine, 1 );
+ thmfc1->data_idx = 0;
+ }
+
+ else if ( thmfc1->data_raw_idx == thmfc1->data_idx + 129 &&
+ thmfc1->data[ thmfc1->data_idx - 1 ] == 0x5A &&
+ thmfc1->data[ thmfc1->data_idx + 128 ] == thmfc1->data_crc )
+ {
+
+ /* look backwards for previous id field */
+ for ( i = thmfc1->data_idx - 4; i >= 0; i-- )
+ {
+ if ( thmfc1->data[ i ] == 0xA5 &&
+ ( ( thmfc1->data[ i ] + thmfc1->data[ i + 1 ] +
+ thmfc1->data[ i + 2 ] ) & 0xff
+ ) == thmfc1->data[ i + 3 ] )
+ break;
+ }
+
+ if ( i >= 0 )
+ {
+ /* got an id & a data field => write */
+ device_t * img = thmfc_floppy_image(machine);
+ int sector = (int) thmfc1->data[ i + 1 ] * 256 +
+ (int) thmfc1->data[ i + 2 ];
+
+ LOG(( "%f $%04x thmfc_floppy_qdd_write_byte: data field, sector=%i\n",
+ machine.time().as_double(), cpu_get_previouspc(machine.device("maincpu")), sector ));
+
+ floppy_drive_write_sector_data( img, 0, sector, thmfc1->data + thmfc1->data_idx, 128, 0 );
+ thom_floppy_active( machine, 1 );
+ }
+
+ thmfc1->data_idx = 0;
+
+ }
+ else
+ thmfc1->data_crc += data;
+ }
+ else
+ {
+ thmfc1->data_raw_idx++;
+ VLOG (( "%f $%04x thmfc_floppy_qdd_write_byte: ignored $%02X\n", machine.time().as_double(), cpu_get_previouspc(machine.device("maincpu")), data ));
+ }
+
+}
+
+
+
+/* intelligent writing */
+static void thmfc_floppy_write_byte ( running_machine &machine, UINT8 data )
+{
+ VLOG (( "%f $%04x thmfc_floppy_write_byte: off=%i/%i data=$%02X\n",
+ machine.time().as_double(), cpu_get_previouspc(machine.device("maincpu")),
+ thmfc1->data_idx, thmfc1->data_size - 1, data ));
+
+ thmfc1->data_raw_size = 0;
+ thmfc1->data[ thmfc1->data_idx ] = data;
+ if ( thmfc1->data_idx >= thmfc1->data_size - 1 )
+ thmfc_floppy_cmd_complete( machine );
+ else
+ thmfc1->data_idx++;
+}
+
+/* intelligent formatting */
+static void thmfc_floppy_format_byte ( running_machine &machine, UINT8 data )
+{
+ VLOG (( "%f $%04x thmfc_floppy_format_byte: $%02X\n", machine.time().as_double(), cpu_get_previouspc(machine.device("maincpu")), data ));
+
+ thmfc1->data_raw_size = 0;
+
+ /* accumulate bytes to form an id field */
+ if ( thmfc1->data_idx || data==0xA1 )
+ {
+ static const UINT8 header[] = { 0xa1, 0xa1, 0xa1, 0xfe };
+ thmfc1->data[ thmfc1->data_idx ] = data;
+ thmfc1->data_idx++;
+ if ( thmfc1->data_idx > 11 )
+ {
+
+ if ( !memcmp ( thmfc1->data, header, sizeof( header ) ) )
+ {
+ /* got id field => format */
+ device_t * img = thmfc_floppy_image(machine);
+ UINT8 track = thmfc1->data[4];
+ UINT8 side = thmfc1->data[5];
+ UINT8 sector = thmfc1->data[6];
+ UINT8 length = thmfc1->data[7]; /* actually, log length */
+ UINT8 filler = 0xe5; /* standard Thomson filler */
+ chrn_id id;
+ if ( thmfc_floppy_find_sector( machine, &id ) )
+ {
+ floppy_drive_format_sector( img, side, thmfc1->sector_id, track, thmfc1->side, sector, length, filler );
+ thom_floppy_active( machine, 1 );
+ }
+ }
+
+ thmfc1->data_idx = 0;
+ }
+
+ }
+}
+
+
+
+READ8_HANDLER ( thmfc_floppy_r )
+{
+ switch ( offset )
+ {
+
+ case 0: /* STAT0 */
+ thmfc1->stat0 ^= THMFC1_STAT0_SYNCHRO | THMFC1_STAT0_BYTE_READY_POL;
+ VLOG(( "%f $%04x thmfc_floppy_r: STAT0=$%02X\n", space->machine().time().as_double(), cpu_get_previouspc(space->machine().device("maincpu")), thmfc1->stat0 ));
+ return thmfc1->stat0;
+
+ case 1: /* STAT1 */
+ {
+ UINT8 data = 0;
+ device_image_interface * img = dynamic_cast<device_image_interface *>(thmfc_floppy_image(space->machine()));
+ int flags = floppy_drive_get_flag_state( &img->device(), -1 );
+ if ( thmfc_floppy_is_qdd(img) )
+ {
+ if ( ! img->exists() )
+ data |= 0x40; /* disk present */
+ if ( ! thmfc1->ipl )
+ data |= 0x02; /* disk start */
+ data |= 0x08; /* connected */
+ }
+ else
+ {
+ if ( thmfc1->ipl )
+ data |= 0x40;
+ if ( img->exists() )
+ data |= 0x20; /* disk change (?) */
+
+ data |= !floppy_tk00_r(&img->device()) << 3;
+
+ if ( flags & FLOPPY_DRIVE_READY )
+ data |= 0x02;
+ }
+ if (!motor_on)
+ data |= 0x10;
+ if (!floppy_wpt_r(&img->device()))
+ data |= 0x04;
+ VLOG(( "%f $%04x thmfc_floppy_r: STAT1=$%02X\n", space->machine().time().as_double(), cpu_get_previouspc(space->machine().device("maincpu")), data ));
+ return data;
+ }
+
+ case 3: /* RDATA */
+
+ if ( thmfc1->op == THMFC1_OP_READ_SECT || thmfc1->op == THMFC1_OP_READ_ADDR )
+ return thmfc_floppy_read_byte(space->machine());
+ else
+ return thmfc_floppy_raw_read_byte(space->machine());
+
+ case 6:
+ return 0;
+
+ case 8:
+ {
+ /* undocumented => emulate TO7 QDD controller ? */
+ UINT8 data = thmfc1->ipl << 7;
+ VLOG(( "%f $%04x thmfc_floppy_r: STAT8=$%02X\n", space->machine().time().as_double(), cpu_get_previouspc(space->machine().device("maincpu")), data ));
+ return data;
+ }
+
+ default:
+ logerror ( "%f $%04x thmfc_floppy_r: invalid read offset %i\n", space->machine().time().as_double(), cpu_get_previouspc(space->machine().device("maincpu")), offset );
+ return 0;
+ }
+}
+
+
+
+WRITE8_HANDLER ( thmfc_floppy_w )
+{
+ switch ( offset ) {
+
+ case 0: /* CMD0 */
+ {
+ int wsync = (data >> 4) & 1;
+ int qdd = thmfc_floppy_is_qdd(dynamic_cast<device_image_interface *>(thmfc_floppy_image(space->machine())));
+ chrn_id id;
+ thmfc1->formatting = (data >> 2) & 1;
+ LOG (( "%f $%04x thmfc_floppy_w: CMD0=$%02X dens=%s wsync=%i dsync=%i fmt=%i op=%i\n",
+ space->machine().time().as_double(), cpu_get_previouspc(space->machine().device("maincpu")), data,
+ (BIT(data, 5) ? "FM" : "MFM"),
+ wsync, (data >> 3) & 1,
+ thmfc1->formatting, data & 3 ));
+
+ /* abort previous command, if any */
+ thmfc1->op = THMFC1_OP_RESET;
+ thmfc_floppy_cmd->adjust(attotime::never);
+
+ switch ( data & 3 )
+ {
+
+ case THMFC1_OP_RESET:
+ thmfc1->stat0 = THMFC1_STAT0_FINISHED;
+ break;
+
+ case THMFC1_OP_WRITE_SECT:
+ if ( qdd )
+ logerror( "thmfc_floppy_w: smart operation 1 not supported for QDD\n" );
+ else if ( thmfc_floppy_find_sector( space->machine(), &id ) )
+ {
+ thmfc1->sector_id = id.data_id;
+ thmfc1->data_idx = 0;
+ thmfc1->data_size = thmfc1->sector_size + 3; /* A1 A1 FB <data> */
+ thmfc1->data_finish = thmfc1->sector_size + 3;
+ thmfc1->stat0 |= THMFC1_STAT0_BYTE_READY_OP;
+ thmfc1->op = THMFC1_OP_WRITE_SECT;
+ thmfc_floppy_cmd->adjust(attotime::from_msec( 10 ));
+ }
+ break;
+
+ case THMFC1_OP_READ_ADDR:
+ if ( qdd )
+ logerror( "thmfc_floppy_w: smart operation 2 not supported for QDD\n" );
+ else if ( thmfc_floppy_find_sector( space->machine(), &id ) )
+ {
+ thmfc1->data_size =
+ thom_floppy_make_addr( id, thmfc1->data, thmfc1->sector_size );
+ assert( thmfc1->data_size < sizeof( thmfc1->data ) );
+ thmfc1->data_finish = 10;
+ thmfc1->data_idx = 1;
+ thmfc1->stat0 |= THMFC1_STAT0_BYTE_READY_OP;
+ thmfc1->op = THMFC1_OP_READ_ADDR;
+ thmfc_floppy_cmd->adjust(attotime::from_msec( 1 ));
+ }
+ break;
+
+ case THMFC1_OP_READ_SECT:
+ if ( qdd )
+ logerror( "thmfc_floppy_w: smart operation 3 not supported for QDD\n" );
+ else if ( thmfc_floppy_find_sector( space->machine(), &id ) )
+ {
+ thmfc1->data_size = thom_floppy_make_sector
+ ( thmfc_floppy_image(space->machine()), id, thmfc1->data, thmfc1->sector_size );
+ assert( thmfc1->data_size < sizeof( thmfc1->data ) );
+ thmfc1->data_finish = thmfc1->sector_size + 4;
+ thmfc1->data_idx = 1;
+ thmfc1->stat0 |= THMFC1_STAT0_BYTE_READY_OP;
+ thmfc1->op = THMFC1_OP_READ_SECT;
+ thmfc_floppy_cmd->adjust(attotime::from_msec( 10 ));
+ }
+ break;
+ }
+
+ /* synchronize to word, if needed (QDD only) */
+ if ( wsync && qdd ) {
+ if ( ! thmfc1->data_raw_size )
+ thmfc1->data_raw_size = thom_qdd_make_disk ( thmfc_floppy_image(space->machine()), thmfc1->data );
+ while ( thmfc1->data_raw_idx < thmfc1->data_raw_size &&
+ thmfc1->data[ thmfc1->data_raw_idx ] != thmfc1->wsync )
+ {
+ thmfc1->data_raw_idx++;
+ }
+ }
+ }
+
+ break;
+
+
+ case 1: /* CMD1 */
+ thmfc1->data_raw_size = 0;
+ thmfc1->sector_size = 128 << ( (data >> 5) & 3);
+ thmfc1->side = (data >> 4) & 1;
+ if ( thmfc1->sector_size > 256 )
+ {
+ logerror( "$%04x thmfc_floppy_w: sector size %i > 256 not handled\n",
+ cpu_get_previouspc(space->machine().device("maincpu")), thmfc1->sector_size );
+ thmfc1->sector_size = 256;
+ }
+
+ LOG (( "%f $%04x thmfc_floppy_w: CMD1=$%02X sect-size=%i comp=%i head=%i\n",
+ space->machine().time().as_double(), cpu_get_previouspc(space->machine().device("maincpu")), data,
+ thmfc1->sector_size, (data >> 1) & 7, thmfc1->side ));
+ break;
+
+
+ case 2: /* CMD2 */
+ {
+ device_t * img;
+ int seek = 0, motor;
+ thmfc1->drive = data & 2;
+
+ img = thmfc_floppy_image(space->machine());
+ if ( thmfc_floppy_is_qdd(dynamic_cast<device_image_interface *>(img)))
+ {
+ motor = !(data & 0x40);
+ /* no side select & no seek for QDD */
+ }
+ else
+ {
+ if ( data & 0x10 )
+ seek = (data & 0x20) ? 1 : -1;
+ motor = (data >> 2) & 1;
+ thmfc1->drive |= 1 ^ ((data >> 6) & 1);
+ img = thmfc_floppy_image(space->machine());
+ }
+
+ thom_floppy_active( space->machine(), 0 );
+
+ LOG (( "%f $%04x thmfc_floppy_w: CMD2=$%02X drv=%i step=%i motor=%i\n",
+ space->machine().time().as_double(), cpu_get_previouspc(space->machine().device("maincpu")), data,
+ thmfc1->drive, seek, motor ));
+
+ if ( seek )
+ {
+ thmfc1->data_raw_size = 0;
+ floppy_drive_seek( img, seek );
+ }
+
+ /* in real life, to keep the motor running, it is sufficient to
+ set motor to 1 every few seconds.
+ instead of counting, we assume the motor is always running...
+ */
+ motor_on = CLEAR_LINE /* motor */;
+ floppy_mon_w(img, motor_on);
+ }
+ break;
+
+
+ case 3: /* WDATA */
+ thmfc1->wsync = data;
+ if ( thmfc_floppy_is_qdd(dynamic_cast<device_image_interface *>(thmfc_floppy_image(space->machine()))))
+ thmfc_floppy_qdd_write_byte( space->machine(), data );
+ else if ( thmfc1->op==THMFC1_OP_WRITE_SECT )
+ thmfc_floppy_write_byte( space->machine(), data );
+ else if ( thmfc1->formatting )
+ thmfc_floppy_format_byte( space->machine(), data );
+ else
+ {
+ /* TODO: implement other forms of raw track writing */
+ LOG (( "%f $%04x thmfc_floppy_w: ignored raw WDATA $%02X\n",
+ space->machine().time().as_double(), cpu_get_previouspc(space->machine().device("maincpu")), data ));
+ }
+ break;
+
+
+ case 4: /* WCLK (unemulated) */
+ /* clock configuration: FF for data, 0A for synchro */
+ LOG (( "%f $%04x thmfc_floppy_w: WCLK=$%02X (%s)\n",
+ space->machine().time().as_double(), cpu_get_previouspc(space->machine().device("maincpu")), data,
+ (data == 0xff) ? "data" : (data == 0x0A) ? "synchro" : "?" ));
+ break;
+
+ case 5: /* WSECT */
+ thmfc1->sector = data;
+ LOG (( "%f $%04x thmfc_floppy_w: WSECT=%i\n",
+ space->machine().time().as_double(), cpu_get_previouspc(space->machine().device("maincpu")), data ));
+ break;
+
+ case 6: /* WTRCK */
+ thmfc1->track = data;
+ LOG (( "%f $%04x thmfc_floppy_w: WTRCK=%i (real=%i)\n",
+ space->machine().time().as_double(), cpu_get_previouspc(space->machine().device("maincpu")), data,
+ floppy_drive_get_current_track( thmfc_floppy_image(space->machine()) ) ));
+ break;
+
+ case 7: /* WCELL */
+ /* precompensation (unemulated) */
+ LOG (( "%f $%04x thmfc_floppy_w: WCELL=$%02X\n",
+ space->machine().time().as_double(), cpu_get_previouspc(space->machine().device("maincpu")), data ));
+ break;
+
+ default:
+ logerror ( "%f $%04x thmfc_floppy_w: invalid write offset %i (data=$%02X)\n",
+ space->machine().time().as_double(), cpu_get_previouspc(space->machine().device("maincpu")), offset, data );
+ }
+}
+
+
+
+void thmfc_floppy_reset( running_machine &machine )
+{
+ int i;
+ LOG(( "thmfc_floppy_reset: THMFC1 controller\n" ));
+
+ for ( i = 0; i < floppy_get_count( machine ); i++ )
+ {
+ device_t * img = floppy_get_device( machine, i );
+ if (img) {
+ floppy_drive_set_ready_state( img, FLOPPY_DRIVE_READY, 0 );
+ floppy_drive_seek( img, - floppy_drive_get_current_track( img ) );
+ }
+ }
+
+ thmfc1->op = THMFC1_OP_RESET;
+ thmfc1->track = 0;
+ thmfc1->sector = 0;
+ thmfc1->side = 0;
+ thmfc1->drive = 0;
+ thmfc1->sector_size = 256;
+ thmfc1->formatting = 0;
+ thmfc1->stat0 = 0;
+ thmfc1->data_idx = 0;
+ thmfc1->data_size = 0;
+ thmfc1->data_raw_idx = 0;
+ thmfc1->data_raw_size = 0;
+ thmfc1->data_crc = 0;
+ thmfc1->wsync = 0;
+ thmfc_floppy_cmd->adjust(attotime::never);
+}
+
+
+
+void thmfc_floppy_init( running_machine &machine )
+{
+ LOG(( "thmfc_floppy_init: THMFC1 controller\n" ));
+
+ thmfc1 = auto_alloc(machine, struct _thmfc1);
+
+ thmfc_floppy_cmd = machine.scheduler().timer_alloc(FUNC(thmfc_floppy_cmd_complete_cb));
+
+ state_save_register_global( machine, thmfc1->op );
+ state_save_register_global( machine, thmfc1->sector );
+ state_save_register_global( machine, thmfc1->sector_id );
+ state_save_register_global( machine, thmfc1->track );
+ state_save_register_global( machine, thmfc1->side );
+ state_save_register_global( machine, thmfc1->drive );
+ state_save_register_global( machine, thmfc1->sector_size );
+ state_save_register_global( machine, thmfc1->formatting );
+ state_save_register_global( machine, thmfc1->ipl );
+ state_save_register_global( machine, thmfc1->data_idx );
+ state_save_register_global( machine, thmfc1->data_size );
+ state_save_register_global( machine, thmfc1->data_finish );
+ state_save_register_global( machine, thmfc1->stat0 );
+ state_save_register_global( machine, thmfc1->data_raw_idx );
+ state_save_register_global( machine, thmfc1->data_raw_size );
+ state_save_register_global( machine, thmfc1->data_crc );
+ state_save_register_global( machine, thmfc1->wsync );
+ state_save_register_global_array( machine, thmfc1->data );
+}
+
+
+
+/*********************** Network ************************/
+
+/* The network extension is built as an external floppy controller.
+ It uses the same ROM and I/O space, and so, it is natural to have the
+ toplevel network emulation here!
+*/
+
+/* NOTE: This is work in progress!
+ For the moment, only hand-checks works: the TO7 can take the line, then
+ perform a DKBOOT request. We do not have the server emulated yet, so,
+ no way to answer the request.
+*/
+
+static TIMER_CALLBACK( ans4 )
+{
+ LOG(( "%f ans4\n", machine.time().as_double() ));
+ mc6854_set_cts( machine.device("mc6854"), 0 );
+}
+
+static TIMER_CALLBACK( ans3 )
+{
+ LOG(( "%f ans3\n", machine.time().as_double() ));
+ mc6854_set_cts( machine.device("mc6854"), 1 );
+ machine.scheduler().timer_set( attotime::from_usec( 100 ), FUNC(ans4));
+}
+
+static TIMER_CALLBACK( ans2 )
+{
+ LOG(( "%f ans2\n", machine.time().as_double() ));
+ mc6854_set_cts( machine.device("mc6854"), 0 );
+ machine.scheduler().timer_set( attotime::from_usec( 100 ), FUNC(ans3));
+}
+
+static TIMER_CALLBACK( ans )
+{
+ LOG(( "%f ans\n", machine.time().as_double() ));
+ mc6854_set_cts( machine.device("mc6854"), 1 );
+ machine.scheduler().timer_set( attotime::from_usec( 100 ), FUNC(ans2));
+}
+/* consigne DKBOOT
+
+ MO5 BASIC
+ $00 $00 $01 $00 $00 $00 $00 $00 $00 $00 $01 $00<$41 $00 $FF $20
+ $3D $4C $01 $60 $20 $3C $4F $01 $05 $20 $3F $9C $19 $25 $03 $11
+ $93 $15 $10 $25 $32 $8A $7E $FF $E1 $FD $E9 $41>$00 $00 $00 $00
+ $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00
+
+ TO7/70 BASIC
+ $00 $00 $01 $00 $00 $00 $00 $00 $00 $00 $02 $00<$20 $42 $41 $53
+ $49 $43 $20 $4D $49 $43 $52 $4F $53 $4F $46 $54 $20 $31 $2E $30
+ $04 $00 $00 $00 $00 $00 $60 $FF $37 $9B $37 $9C>$00 $00 $00 $00
+ $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00
+
+ TO7 BASIC
+ $00 $00 $01 $00 $00 $00 $00 $00 $00 $00 $00 $00<$20 $42 $41 $53
+ $49 $43 $20 $4D $49 $43 $52 $4F $53 $4F $46 $54 $20 $31 $2E $30
+ $04 $00 $00 $00 $00 $00 $60 $FF $37 $9B $37 $9C>$00 $00 $00 $00
+ $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00
+
+ TO7 LOGO
+ $00 $00 $01 $00 $00 $00 $00 $00 $00 $00 $00 $00<$00 $00 $00 $00
+ $00 $20 $4C $4F $47 $4F $04 $00 $00 $00 $00 $00 $00 $00 $00 $00
+ $00 $00 $00 $00 $00 $00 $AA $FF $01 $16 $00 $C8>$00 $00 $00 $00
+ $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00 $00
+
+
+*/
+
+static void to7_network_got_frame( device_t *device, UINT8* data, int length )
+{
+ int i;
+ LOG(( "%f to7_network_got_frame:", device->machine().time().as_double() ));
+ for ( i = 0; i < length; i++ )
+ LOG(( " $%02X", data[i] ));
+ LOG(( "\n" ));
+
+ if ( data[1] == 0xff )
+ {
+ LOG(( "to7_network_got_frame: %i phones %i\n", data[2], data[0] ));
+ device->machine().scheduler().timer_set( attotime::from_usec( 100 ), FUNC(ans));
+ mc6854_set_cts( device, 0 );
+ }
+ else if ( ! data[1] )
+ {
+ char name[33];
+ memcpy( name, data + 12, 32 );
+ name[32] = 0;
+ for (i=0;i<32;i++)
+ {
+ if ( name[i]<32 || name[i]>=127 )
+ name[i]=' ';
+ }
+ LOG(( "to7_network_got_frame: DKBOOT system=%s appli=\"%s\"\n",
+ (data[10] == 0) ? "TO7" : (data[10] == 1) ? "MO5" :
+ (data[10] == 2) ? "TO7/70" : "?", name ));
+ }
+
+}
+
+
+
+const mc6854_interface to7_network_iface = { DEVCB_NULL, DEVCB_NULL, DEVCB_NULL, to7_network_got_frame, DEVCB_NULL, DEVCB_NULL };
+
+
+
+static void to7_network_init( running_machine &machine )
+{
+ LOG(( "to7_network_init: NR 07-005 network extension\n" ));
+ logerror( "to7_network_init: network not handled!\n" );
+}
+
+
+
+static void to7_network_reset( running_machine &machine )
+{
+ LOG(( "to7_network_reset: NR 07-005 network extension\n" ));
+ mc6854_set_cts( machine.device("mc6854"), 0 );
+ mc6854_set_cts( machine.device("mc6854"), 1 );
+}
+
+
+
+static READ8_HANDLER ( to7_network_r )
+{
+ if ( offset < 4 )
+ return mc6854_r( space->machine().device("mc6854"), offset );
+
+ if ( offset == 8 )
+ {
+ /* network ID of the computer */
+ UINT8 id = space->machine().root_device().ioport("fconfig")->read() >> 3;
+ VLOG(( "%f $%04x to7_network_r: read id $%02X\n", space->machine().time().as_double(), cpu_get_previouspc(space->machine().device("maincpu")), id ));
+ return id;
+ }
+
+ logerror( "%f $%04x to7_network_r: invalid read offset %i\n", space->machine().time().as_double(), cpu_get_previouspc(space->machine().device("maincpu")), offset );
+ return 0;
+}
+
+
+
+static WRITE8_HANDLER ( to7_network_w )
+{
+ if ( offset < 4 )
+ mc6854_w( space->machine().device("mc6854"), offset, data );
+ else
+ {
+ logerror( "%f $%04x to7_network_w: invalid write offset %i (data=$%02X)\n",
+ space->machine().time().as_double(), cpu_get_previouspc(space->machine().device("maincpu")), offset, data );
+ }
+}
+
+
+
+/*********************** TO7 dispatch ************************/
+
+/* The TO7, TO7/70, MO5 and MO6 can use a variety of floppy controllers.
+ We use a PORT_CONFSETTING to chose the current controller, and dispatch
+ here.
+
+ NOTE: you need to reset the computer after changing the floppy controller!
+
+ The CD 90-351 controller seems similar to the THMFC1 gate-array
+ => we reuse the THMFC code!
+*/
+
+
+
+UINT8 to7_controller_type;
+UINT8 to7_floppy_bank;
+
+
+void to7_floppy_init ( running_machine &machine, void* base )
+{
+ machine.root_device().membank( THOM_FLOP_BANK )->configure_entries( 0, TO7_NB_FLOP_BANK, base, 0x800 );
+ state_save_register_global( machine, to7_controller_type );
+ state_save_register_global( machine, to7_floppy_bank );
+ to7_5p14sd_init(machine);
+ to7_5p14_init(machine);
+ to7_qdd_init(machine);
+ thmfc_floppy_init(machine);
+ to7_network_init(machine);
+}
+
+
+
+void to7_floppy_reset ( running_machine &machine )
+{
+ to7_controller_type = (machine.root_device().ioport("fconfig")->read() ) & 7;
+
+ switch ( to7_controller_type )
+ {
+
+ case 1:
+ to7_floppy_bank = 1;
+ to7_5p14sd_reset(machine);
+ break;
+
+ case 2:
+ to7_floppy_bank = 2;
+ to7_5p14_reset(machine);
+ break;
+
+ case 3:
+ to7_floppy_bank = 3;
+ thmfc_floppy_reset(machine);
+ break;
+
+ case 4:
+ to7_floppy_bank = 7;
+ to7_qdd_reset(machine);
+ break;
+
+ case 5:
+ to7_floppy_bank = 8;
+ to7_network_reset(machine);
+ break;
+
+ default:
+ to7_floppy_bank = 0;
+ break;
+ }
+
+ machine.root_device().membank( THOM_FLOP_BANK )->set_entry( to7_floppy_bank );
+}
+
+
+
+READ8_HANDLER ( to7_floppy_r )
+{
+ switch ( to7_controller_type )
+ {
+
+ case 1:
+ return to7_5p14sd_r( space, offset );
+
+ case 2:
+ return to7_5p14_r( space, offset );
+
+ case 3:
+ return thmfc_floppy_r( space, offset );
+
+ case 4:
+ return to7_qdd_r( space, offset );
+
+ case 5:
+ return to7_network_r( space, offset );
+ }
+
+ return 0;
+}
+
+
+
+WRITE8_HANDLER ( to7_floppy_w )
+{
+ switch ( to7_controller_type )
+ {
+
+ case 1:
+ to7_5p14sd_w( space, offset, data );
+ return;
+
+ case 2:
+ to7_5p14_w( space, offset, data );
+ break;
+
+ case 3:
+ if ( offset == 8 )
+ {
+ to7_floppy_bank = 3 + (data & 3);
+ space->machine().root_device().membank( THOM_FLOP_BANK )->set_entry( to7_floppy_bank );
+ VLOG (( "to7_floppy_w: set CD 90-351 ROM bank to %i\n", data & 3 ));
+ }
+ else
+ thmfc_floppy_w( space, offset, data );
+ break;
+
+ case 4:
+ to7_qdd_w( space, offset, data );
+ break;
+
+ case 5:
+ to7_network_w( space, offset, data );
+ break;
+ }
+}
+
+
+
+/*********************** TO9 ************************/
+
+/* the internal controller is WD2793-based (so, similar to to7_5p14)
+ we also emulate external controllers
+*/
+
+
+
+void to9_floppy_init( running_machine &machine, void* int_base, void* ext_base )
+{
+ to7_floppy_init( machine, ext_base );
+ machine.root_device().membank( THOM_FLOP_BANK )->configure_entry( TO7_NB_FLOP_BANK, int_base);
+}
+
+
+
+void to9_floppy_reset( running_machine &machine )
+{
+ to7_floppy_reset(machine);
+ if ( THOM_FLOPPY_EXT )
+ {
+ LOG(( "to9_floppy_reset: external controller\n" ));
+ }
+ else
+ {
+ LOG(( "to9_floppy_reset: internal controller\n" ));
+ to7_5p14_reset(machine);
+ machine.root_device().membank( THOM_FLOP_BANK )->set_entry( TO7_NB_FLOP_BANK );
+ }
+}
+
+
+
+READ8_HANDLER ( to9_floppy_r )
+{
+ if ( THOM_FLOPPY_EXT )
+ return to7_floppy_r( space, offset );
+ else
+ return to7_5p14_r( space, offset );
+}
+
+WRITE8_HANDLER ( to9_floppy_w )
+{
+ if ( THOM_FLOPPY_EXT )
+ to7_floppy_w( space, offset, data );
+ else
+ to7_5p14_w( space, offset, data );
+}
+
+WRITE_LINE_DEVICE_HANDLER(thomson_index_callback)
+{
+ switch ( to7_controller_type )
+ {
+ case 1:
+ to7_5p14_index_pulse_callback(NULL, device, state);
+ break;
+
+ case 2:
+ wd17xx_index_pulse_callback(device->machine().device("wd2793"), device, state);
+ break;
+
+ case 3:
+ thmfc_floppy_index_pulse_cb(NULL, device, state);
+ break;
+
+ case 4:
+ to7_qdd_index_pulse_cb(NULL, device, state);
+ break;
+
+ default:
+ break;
+ }
+}
diff --git a/src/mess/machine/thomflop.h b/src/mess/machine/thomflop.h
new file mode 100644
index 00000000000..b1f21b87453
--- /dev/null
+++ b/src/mess/machine/thomflop.h
@@ -0,0 +1,53 @@
+/**********************************************************************
+
+ Copyright (C) Antoine Mine' 2006
+
+ Thomson 8-bit computers
+
+**********************************************************************/
+
+#ifndef THOMFLOP_H_
+#define THOMFLOP_H_
+
+#include "image.h"
+#include "imagedev/flopdrv.h"
+#include "machine/mc6843.h"
+#include "machine/mc6854.h"
+
+extern const mc6843_interface to7_6843_itf;
+extern const mc6854_interface to7_network_iface;
+
+extern UINT8 to7_controller_type; /* set during init */
+extern UINT8 to7_floppy_bank;
+
+/* number of external floppy controller ROM banks */
+#define TO7_NB_FLOP_BANK 9
+
+/* external floppy / network controller active */
+#define THOM_FLOPPY_EXT (to7_controller_type >= 1)
+
+/* internal floppy controller active (no or network extension) */
+#define THOM_FLOPPY_INT (to7_controller_type == 0 || to7_controller_type > 4)
+
+
+/* external controllers */
+extern void to7_floppy_init ( running_machine &machine, void* base );
+extern void to7_floppy_reset ( running_machine &machine );
+extern READ8_HANDLER ( to7_floppy_r );
+extern WRITE8_HANDLER ( to7_floppy_w );
+
+/* TO9 internal (WD2793) & external controllers */
+extern void to9_floppy_init ( running_machine &machine, void* int_base, void* ext_base );
+extern void to9_floppy_reset ( running_machine &machine );
+extern READ8_HANDLER ( to9_floppy_r );
+extern WRITE8_HANDLER ( to9_floppy_w );
+
+/* TO8 internal (THMFC1) controller */
+extern void thmfc_floppy_init ( running_machine &machine );
+extern void thmfc_floppy_reset ( running_machine &machine );
+extern READ8_HANDLER ( thmfc_floppy_r );
+extern WRITE8_HANDLER ( thmfc_floppy_w );
+
+extern WRITE_LINE_DEVICE_HANDLER(thomson_index_callback);
+
+#endif /* THOMFLOP_H_ */
diff --git a/src/mess/machine/thomson.c b/src/mess/machine/thomson.c
new file mode 100644
index 00000000000..10ac5d13c67
--- /dev/null
+++ b/src/mess/machine/thomson.c
@@ -0,0 +1,5466 @@
+/**********************************************************************
+
+ Copyright (C) Antoine Mine' 2006
+
+ Thomson 8-bit computers
+
+**********************************************************************/
+
+#include "emu.h"
+#include "machine/thomflop.h"
+#include "formats/thom_dsk.h"
+#include "includes/thomson.h"
+#include "machine/6821pia.h"
+#include "machine/ctronics.h"
+#include "machine/ram.h"
+
+#define VERBOSE 0
+#define VERBOSE_IRQ 0
+#define VERBOSE_KBD 0 /* TO8 / TO9 / TO9+ keyboard */
+#define VERBOSE_BANK 0
+#define VERBOSE_VIDEO 0 /* video & lightpen */
+#define VERBOSE_IO 1 /* serial & parallel I/O */
+#define VERBOSE_MIDI 0
+
+#define PRINT(x) mame_printf_info x
+
+#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
+#define VLOG(x) do { if (VERBOSE > 1) logerror x; } while (0)
+#define LOG_IRQ(x) do { if (VERBOSE_IRQ) logerror x; } while (0)
+#define LOG_KBD(x) do { if (VERBOSE_KBD) logerror x; } while (0)
+#define LOG_BANK(x) do { if (VERBOSE_BANK) logerror x; } while (0)
+#define LOG_VIDEO(x) do { if (VERBOSE_VIDEO) logerror x; } while (0)
+#define LOG_IO(x) do { if (VERBOSE_IO) logerror x; } while (0)
+#define LOG_MIDI(x) do { if (VERBOSE_MIDI) logerror x; } while (0)
+
+/* This set to 1 handle the .k7 files without passing through .wav */
+/* It must be set accordingly in formats/thom_cas.c */
+#define K7_SPEED_HACK 0
+
+/* bank logging and optimisations */
+static int old_cart_bank;
+static int old_cart_bank_was_read_only;
+static int old_ram_bank;
+static int old_floppy_bank;
+
+
+
+/********************* common cassette code ***************************/
+
+INLINE cassette_image_device* thom_cassette_img( running_machine &machine )
+{ return machine.device<cassette_image_device>(CASSETTE_TAG); }
+
+/*-------------- TO7 ------------*/
+
+
+/* On the TO7 & compatible (TO7/70,TO8,TO9, but not MO5,MO6), bits are coded
+ in FM format with a 1.1 ms period (900 bauds):
+ - 0 is 5 periods at 4.5 kHz
+ - 1 is 7 periods at 6.3 kHz
+
+ Moreover, a byte is represented using 11 bits:
+ - one 0 start bit
+ - eight data bits (low bit first)
+ - two 1 stop bits
+
+ There are also long (1 s) sequences of 1 bits to re-synchronize the
+ cassette at places the motor can be cut off and back on (e.g., between
+ files).
+
+ The computer outputs a modulated wave that is directly put on the cassette.
+ However, the input is demodulated by the cassette-reader before being
+ sent to the computer: we got 0 when the signal is around 4.5 kHz and
+ 1 when the signal is around 6.3 kHz.
+*/
+
+#define TO7_BIT_LENGTH 0.001114
+
+/* buffer storing demodulated bits, only for k7 and with speed hack */
+static UINT32 to7_k7_bitsize;
+static UINT8* to7_k7_bits;
+
+
+/* 1-bit cassette input to the computer
+ inside the controller, two frequency filters (adjusted to 6.3 and 4.5 kHz)
+ and a comparator demodulate the raw signal into 0s and 1s.
+*/
+static int to7_get_cassette ( running_machine &machine )
+{
+ cassette_image_device* img = thom_cassette_img(machine);
+ if ( img->exists() )
+ {
+ cassette_image* cass = img->get_image();
+ cassette_state state = img->get_state();
+ double pos = img->get_position();
+ int bitpos = pos / TO7_BIT_LENGTH;
+
+ if ( (state & CASSETTE_MASK_MOTOR) == CASSETTE_MOTOR_DISABLED )
+ return 1;
+
+ if ( K7_SPEED_HACK && to7_k7_bits )
+ {
+ /* hack, feed existing bits */
+ if ( bitpos >= to7_k7_bitsize )
+ bitpos = to7_k7_bitsize -1;
+ VLOG (( "$%04x %f to7_get_cassette: state=$%X pos=%f samppos=%i bit=%i\n",
+ cpu_get_previouspc(machine.device("maincpu")), machine.time().as_double(), state, pos, bitpos,
+ to7_k7_bits[ bitpos ] ));
+ return to7_k7_bits[ bitpos ];
+ }
+ else
+ {
+ /* demodulate wave signal on-the-fly */
+ /* we simply count sign changes... */
+ int k, chg;
+ INT8 data[40];
+ cassette_get_samples( cass, 0, pos, TO7_BIT_LENGTH * 15. / 14., 40, 1, data, 0 );
+
+ for ( k = 1, chg = 0; k < 40; k++ )
+ {
+ if ( data[ k - 1 ] >= 0 && data[ k ] < 0 )
+ chg++;
+ if ( data[ k - 1 ] <= 0 && data[ k ] > 0 )
+ chg++;
+ }
+ k = ( chg >= 13 ) ? 1 : 0;
+ VLOG (( "$%04x %f to7_get_cassette: state=$%X pos=%f samppos=%i bit=%i (%i)\n",
+ cpu_get_previouspc(machine.device("maincpu")), machine.time().as_double(), state, pos, bitpos,
+ k, chg ));
+ return k;
+ }
+
+ }
+ else
+ return 0;
+}
+
+
+
+/* 1-bit cassette output */
+static void to7_set_cassette ( running_machine &machine, int data )
+{
+ cassette_image_device* img = thom_cassette_img(machine);
+ img->output(data ? 1. : -1. );
+}
+
+
+
+static WRITE8_DEVICE_HANDLER ( to7_set_cassette_motor )
+{
+ cassette_image_device* img = thom_cassette_img(device->machine());
+ cassette_state state = img->get_state();
+ double pos = img->get_position();
+
+ LOG (( "$%04x %f to7_set_cassette_motor: cassette motor %s bitpos=%i\n",
+ cpu_get_previouspc(device->machine().device("maincpu")), img->machine().time().as_double(), data ? "off" : "on",
+ (int) (pos / TO7_BIT_LENGTH) ));
+
+ if ( (state & CASSETTE_MASK_MOTOR) == CASSETTE_MOTOR_DISABLED && !data && pos > 0.3 )
+ {
+ /* rewind a little before starting the motor */
+ img->seek(-0.3, SEEK_CUR );
+ }
+
+ img->change_state(data ? CASSETTE_MOTOR_DISABLED : CASSETTE_MOTOR_ENABLED,CASSETTE_MASK_MOTOR );
+}
+
+
+
+/*-------------- MO5 ------------*/
+
+
+/* Each byte is represented as 8 bits without start or stop bit (unlike TO7).
+ Bits are coded in MFM, and the MFM signal is directly fed to the
+ computer which has to decode it in software (unlike TO7).
+ A 1 bit is one period at 1200 Hz; a 0 bit is one half-period at 600 Hz.
+ Bit-order is most significant bit first (unlike TO7).
+
+ Double-density MO6 cassettes follow the exact same mechanism, but with
+ at double frequency (perdiods at 2400 Hz, and half-perdios at 1200 Hz).
+*/
+
+
+#define MO5_BIT_LENGTH 0.000833
+#define MO5_HBIT_LENGTH (MO5_BIT_LENGTH / 2.)
+
+
+static int mo5_get_cassette ( running_machine &machine )
+{
+ cassette_image_device* img = thom_cassette_img(machine);
+ device_image_interface *image = dynamic_cast<device_image_interface *>(img);
+
+ if ( image->exists() )
+ {
+ cassette_image* cass = img->get_image();
+ cassette_state state = img->get_state();
+ double pos = img->get_position();
+ INT32 hbit;
+
+ if ( (state & CASSETTE_MASK_MOTOR) == CASSETTE_MOTOR_DISABLED )
+ return 1;
+
+ cassette_get_sample( cass, 0, pos, 0, &hbit );
+ hbit = hbit >= 0;
+
+ VLOG (( "$%04x %f mo5_get_cassette: state=$%X pos=%f hbitpos=%i hbit=%i\n",
+ cpu_get_previouspc(machine.device("maincpu")), machine.time().as_double(), state, pos,
+ (int) (pos / MO5_HBIT_LENGTH), hbit ));
+ return hbit;
+ }
+ else
+ return 0;
+}
+
+
+
+static void mo5_set_cassette ( running_machine &machine, int data )
+{
+ cassette_image_device* img = thom_cassette_img(machine);
+ img->output(data ? 1. : -1. );
+}
+
+
+
+static WRITE8_DEVICE_HANDLER ( mo5_set_cassette_motor )
+{
+ cassette_image_device* img = thom_cassette_img(device->machine());
+ cassette_state state = img->get_state();
+ double pos = img->get_position();
+
+ LOG (( "$%04x %f mo5_set_cassette_motor: cassette motor %s hbitpos=%i\n",
+ cpu_get_previouspc(device->machine().device("maincpu")), device->machine().time().as_double(), data ? "off" : "on",
+ (int) (pos / MO5_HBIT_LENGTH) ));
+
+ if ( (state & CASSETTE_MASK_MOTOR) == CASSETTE_MOTOR_DISABLED && !data && pos > 0.3 )
+ {
+ /* rewind a little before starting the motor */
+ img->seek(-0.3, SEEK_CUR );
+ }
+
+ img->change_state(data ? CASSETTE_MOTOR_DISABLED : CASSETTE_MOTOR_ENABLED,CASSETTE_MASK_MOTOR );
+}
+
+
+
+
+/*************************** utilities ********************************/
+
+
+
+/* ------------ IRQs ------------ */
+
+
+/* several devices on the same irqs */
+
+static UINT8 thom_irq;
+
+static UINT8 thom_firq;
+
+
+
+static void thom_set_irq ( running_machine &machine, int line, int state )
+{
+ int old = thom_irq;
+
+ if ( state )
+ thom_irq |= 1 << line;
+ else
+ thom_irq &= ~(1 << line);
+
+ if ( !old && thom_irq )
+ LOG_IRQ(( "%f thom_set_irq: irq line up %i\n", machine.time().as_double(), line ));
+ if ( old && !thom_irq )
+ LOG_IRQ(( "%f thom_set_irq: irq line down %i\n", machine.time().as_double(), line ));
+
+ cputag_set_input_line(machine, "maincpu", M6809_IRQ_LINE, thom_irq ? ASSERT_LINE : CLEAR_LINE);
+}
+
+
+
+static void thom_set_firq ( running_machine &machine, int line, int state )
+{
+ int old = thom_irq;
+
+ if ( state )
+ thom_firq |= 1 << line;
+ else
+ thom_firq &= ~(1 << line);
+
+ if ( !old && thom_firq )
+ LOG_IRQ(( "%f thom_set_firq: firq line up %i\n", machine.time().as_double(), line ));
+ if ( old && !thom_firq )
+ LOG_IRQ(( "%f thom_set_firq: firq line down %i\n", machine.time().as_double(), line ));
+
+ cputag_set_input_line(machine, "maincpu", M6809_FIRQ_LINE, thom_firq ? ASSERT_LINE : CLEAR_LINE);
+}
+
+
+
+static void thom_irq_reset ( running_machine &machine )
+{
+ thom_irq = 0;
+ thom_firq = 0;
+ cputag_set_input_line( machine, "maincpu", M6809_IRQ_LINE, CLEAR_LINE );
+ cputag_set_input_line( machine, "maincpu", M6809_FIRQ_LINE, CLEAR_LINE );
+}
+
+
+
+static void thom_irq_init ( running_machine &machine )
+{
+ state_save_register_global( machine, thom_irq );
+ state_save_register_global( machine, thom_firq );
+}
+
+
+
+static void thom_irq_0 ( running_machine &machine, int state )
+{
+ thom_set_irq ( machine, 0, state );
+}
+
+static void thom_dev_irq_0 ( device_t *device, int state )
+{
+ thom_irq_0( device->machine(), state );
+}
+
+
+
+static WRITE_LINE_DEVICE_HANDLER( thom_irq_1 )
+{
+ thom_set_irq ( device->machine(), 1, state );
+}
+
+static void thom_irq_3 ( running_machine &machine, int state )
+{
+ thom_set_irq ( machine, 3, state );
+}
+
+static WRITE_LINE_DEVICE_HANDLER( thom_firq_1 )
+{
+ thom_set_firq ( device->machine(), 1, state );
+}
+
+static void thom_firq_2 ( running_machine &machine, int state )
+{
+ thom_set_firq ( machine, 2, state );
+}
+
+#ifdef CHARDEV
+static void thom_irq_4 ( running_machine &machine, int state )
+{
+ thom_set_irq ( machine, 4, state );
+}
+#endif
+
+
+/*
+ current IRQ usage:
+
+ line 0 => 6846 interrupt
+ line 1 => 6821 interrupts (shared for all 6821)
+ line 2 => TO8 lightpen interrupt (from gate-array)
+ line 3 => TO9 keyboard interrupt (from 6850 ACIA)
+ line 4 => MIDI interrupt (from 6850 ACIA)
+*/
+
+
+
+/* ------------ LED ------------ */
+
+
+
+static void thom_set_caps_led ( running_machine &machine, int led )
+{
+ output_set_value( "led0", led );
+}
+
+/* ------------ 6850 defines ------------ */
+
+#define ACIA_6850_RDRF 0x01 /* Receive data register full */
+#define ACIA_6850_TDRE 0x02 /* Transmit data register empty */
+#define ACIA_6850_dcd 0x04 /* Data carrier detect, active low */
+#define ACIA_6850_cts 0x08 /* Clear to send, active low */
+#define ACIA_6850_FE 0x10 /* Framing error */
+#define ACIA_6850_OVRN 0x20 /* Receiver overrun */
+#define ACIA_6850_PE 0x40 /* Parity error */
+#define ACIA_6850_irq 0x80 /* Interrupt request, active low */
+
+
+
+/***************************** TO7 / T9000 *************************/
+
+
+
+/* ------------ cartridge ------------ */
+
+static UINT8 thom_cart_nb_banks; /* number of 16 KB banks (up to 4) */
+
+static UINT8 thom_cart_bank; /* current bank */
+
+
+DEVICE_IMAGE_LOAD( to7_cartridge )
+{
+ int i,j;
+ UINT8* pos = image.device().machine().root_device().memregion("maincpu" )->base() + 0x10000;
+ offs_t size = image.length();
+ char name[129];
+
+ /* get size & number of 16-KB banks */
+ if ( size <= 0x04000 )
+ thom_cart_nb_banks = 1;
+ else if ( size == 0x08000 )
+ thom_cart_nb_banks = 2;
+ else if ( size == 0x10000 )
+ thom_cart_nb_banks = 4;
+ else
+ {
+ logerror( "to7_cartridge_load: invalid cartridge size %i\n", size );
+ return IMAGE_INIT_FAIL;
+ }
+
+ if ( image.fread( pos, size ) != size )
+ {
+ logerror( "to7_cartridge_load: read error\n" );
+ return IMAGE_INIT_FAIL;
+ }
+
+ /* extract name */
+ for ( i = 0; i < size && pos[i] != ' '; i++ );
+ for ( i++, j = 0; i + j < size && j < 128 && pos[i+j] >= 0x20; j++)
+ name[j] = pos[i+j];
+ name[j] = 0;
+
+ /* sanitize name */
+ for ( i = 0; name[i]; i++)
+ {
+ if ( name[i] < ' ' || name[i] >= 127 )
+ name[i] = '?';
+ }
+
+ PRINT (( "to7_cartridge_load: cartridge \"%s\" banks=%i, size=%i\n", name, thom_cart_nb_banks, size ));
+
+ return IMAGE_INIT_PASS;
+}
+
+
+
+static void to7_update_cart_bank(running_machine &machine)
+{
+ address_space* space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ int bank = 0;
+ if ( thom_cart_nb_banks )
+ {
+ bank = thom_cart_bank % thom_cart_nb_banks;
+ if ( bank != old_cart_bank && old_cart_bank < 0 )
+ {
+ space->install_legacy_read_handler(0x0000, 0x0003, FUNC(to7_cartridge_r) );
+ }
+ }
+ if ( bank != old_cart_bank )
+ {
+ machine.root_device().membank( THOM_CART_BANK )->set_entry( bank );
+ old_cart_bank = bank;
+ LOG_BANK(( "to7_update_cart_bank: CART is cartridge bank %i\n", bank ));
+ }
+}
+
+
+
+static void to7_update_cart_bank_postload(running_machine *machine)
+{
+ to7_update_cart_bank(*machine);
+}
+
+
+
+/* write signal to 0000-1fff generates a bank switch */
+WRITE8_HANDLER ( to7_cartridge_w )
+{
+ if ( offset >= 0x2000 )
+ return;
+
+ thom_cart_bank = offset & 3;
+ to7_update_cart_bank(space->machine());
+}
+
+
+
+/* read signal to 0000-0003 generates a bank switch */
+READ8_HANDLER ( to7_cartridge_r )
+{
+ UINT8* pos = space->machine().root_device().memregion( "maincpu" )->base() + 0x10000;
+ UINT8 data = pos[offset + (thom_cart_bank % thom_cart_nb_banks) * 0x4000];
+ if ( !space->debugger_access() )
+ {
+ thom_cart_bank = offset & 3;
+ to7_update_cart_bank(space->machine());
+ }
+ return data;
+}
+
+
+
+/* ------------ 6846 (timer, I/O) ------------ */
+
+
+
+static WRITE8_DEVICE_HANDLER ( to7_timer_port_out )
+{
+ thom_set_mode_point( device->machine(), data & 1 ); /* bit 0: video bank switch */
+ thom_set_caps_led( device->machine(), (data & 8) ? 1 : 0 ) ; /* bit 3: keyboard led */
+ thom_set_border_color( device->machine(),
+ ((data & 0x10) ? 1 : 0) | /* bits 4-6: border color */
+ ((data & 0x20) ? 2 : 0) |
+ ((data & 0x40) ? 4 : 0) );
+}
+
+
+
+static WRITE8_DEVICE_HANDLER ( to7_timer_cp2_out )
+{
+ device->machine().device<dac_device>("buzzer")->write_unsigned8(data ? 0x80 : 0); /* 1-bit buzzer */
+}
+
+
+
+static READ8_DEVICE_HANDLER ( to7_timer_port_in )
+{
+ int lightpen = (device->machine().root_device().ioport("lightpen_button")->read() & 1) ? 2 : 0;
+ int cass = to7_get_cassette(device->machine()) ? 0x80 : 0;
+ return lightpen | cass;
+}
+
+
+
+static WRITE8_DEVICE_HANDLER ( to7_timer_tco_out )
+{
+ /* 1-bit cassette output */
+ to7_set_cassette( device->machine(), data );
+}
+
+
+
+const mc6846_interface to7_timer =
+{
+ to7_timer_port_out, NULL, to7_timer_cp2_out,
+ to7_timer_port_in, to7_timer_tco_out,
+ thom_dev_irq_0
+};
+
+
+
+/* ------------ lightpen automaton ------------ */
+
+
+
+static UINT8 to7_lightpen_step;
+
+static UINT8 to7_lightpen;
+
+
+
+static void to7_lightpen_cb ( running_machine &machine, int step )
+{
+ pia6821_device *sys_pia = machine.device<pia6821_device>(THOM_PIA_SYS );
+
+ if ( ! to7_lightpen )
+ return;
+
+ LOG_VIDEO(( "%f to7_lightpen_cb: step=%i\n", machine.time().as_double(), step ));
+ sys_pia->cb1_w( 1 );
+ sys_pia->cb1_w( 0 );
+ to7_lightpen_step = step;
+}
+
+
+
+/* ------------ video ------------ */
+
+
+
+static void to7_set_init ( running_machine &machine, int init )
+{
+ pia6821_device *sys_pia = machine.device<pia6821_device>(THOM_PIA_SYS );
+ /* INIT signal wired to system PIA 6821 */
+
+ LOG_VIDEO(( "%f to7_set_init: init=%i\n", machine.time().as_double(), init ));
+ sys_pia->ca1_w( init );
+}
+
+
+
+/* ------------ system PIA 6821 ------------ */
+
+
+
+static WRITE8_DEVICE_HANDLER ( to7_sys_cb2_out )
+{
+ to7_lightpen = !data;
+}
+
+
+
+static WRITE8_DEVICE_HANDLER ( to7_sys_portb_out )
+{
+ /* value fetched in to7_sys_porta_in */
+}
+
+
+
+#define TO7_LIGHTPEN_DECAL 17 /* horizontal lightpen shift, stored in $60D2 */
+
+
+
+static READ8_DEVICE_HANDLER ( to7_sys_porta_in )
+{
+ if ( to7_lightpen )
+ {
+ /* lightpen hi */
+ return to7_lightpen_gpl( device->machine(), TO7_LIGHTPEN_DECAL, to7_lightpen_step ) >> 8;
+ }
+ else
+ {
+ /* keyboard */
+ int keyline = downcast<pia6821_device *>(device)->b_output();
+ UINT8 val = 0xff;
+ int i;
+ static const char *const keynames[] = {
+ "keyboard_0", "keyboard_1", "keyboard_2", "keyboard_3",
+ "keyboard_4", "keyboard_5", "keyboard_6", "keyboard_7"
+ };
+
+ for ( i = 0; i < 8; i++ )
+ {
+ if ( ! (keyline & (1 << i)) )
+ val &= device->machine().root_device().ioport(keynames[i])->read();
+ }
+ return val;
+ }
+}
+
+
+
+static READ8_DEVICE_HANDLER ( to7_sys_portb_in )
+{
+ /* lightpen low */
+ return to7_lightpen_gpl( device->machine(), TO7_LIGHTPEN_DECAL, to7_lightpen_step ) & 0xff;
+}
+
+
+
+const pia6821_interface to7_pia6821_sys =
+{
+ DEVCB_HANDLER(to7_sys_porta_in),
+ DEVCB_HANDLER(to7_sys_portb_in),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(to7_sys_portb_out),
+ DEVCB_HANDLER(to7_set_cassette_motor),
+ DEVCB_HANDLER(to7_sys_cb2_out),
+ DEVCB_LINE(thom_firq_1),
+ DEVCB_LINE(thom_firq_1)
+};
+
+
+
+/* ------------ CC 90-232 I/O extension ------------ */
+
+/* Features:
+ - 6821 PIA
+ - serial RS232: bit-banging?
+ - parallel CENTRONICS: a printer (-prin) is emulated
+ - usable on TO7(/70), MO5(E) only; not on TO9 and higher
+
+ Note: it seems impossible to connect both a serial & a parallel device
+ because the Data Transmit Ready bit is shared in an incompatible way!
+*/
+
+
+
+typedef enum
+{
+ TO7_IO_NONE,
+ TO7_IO_CENTRONICS,
+ TO7_IO_RS232
+} to7_io_dev;
+
+/* test whether a parallel or a serial device is connected: both cannot
+ be exploited at the same time!
+*/
+static to7_io_dev to7_io_mode( running_machine &machine )
+{
+ centronics_device *centronics = machine.device<centronics_device>("centronics");
+ device_image_interface *serial = dynamic_cast<device_image_interface *>(machine.device("cc90232"));
+
+ if (centronics->pe_r() == TRUE)
+ return TO7_IO_CENTRONICS;
+ else if ( serial->exists())
+ return TO7_IO_RS232;
+ return TO7_IO_NONE;
+}
+
+
+
+static WRITE_LINE_DEVICE_HANDLER( to7_io_ack )
+{
+ pia6821_device *io_pia = device->machine().device<pia6821_device>(THOM_PIA_IO);
+
+ io_pia->cb1_w( state);
+ //LOG_IO (( "%f to7_io_ack: CENTRONICS new state $%02X (ack=%i)\n", machine.time().as_double(), data, ack ));
+}
+
+const device_type TO7_IO_LINE = &device_creator<to7_io_line_device>;
+
+//-------------------------------------------------
+// to7_io_line_device - constructor
+//-------------------------------------------------
+
+to7_io_line_device::to7_io_line_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, TO7_IO_LINE, "Serial source", tag, owner, clock),
+ device_serial_interface(mconfig, *this)
+{
+}
+
+void to7_io_line_device::device_start()
+{
+}
+
+WRITE8_MEMBER( to7_io_line_device::porta_out )
+{
+ int tx = data & 1;
+ int dtr = ( data & 2 ) ? 1 : 0;
+
+ LOG_IO(( "$%04x %f to7_io_porta_out: tx=%i, dtr=%i\n", cpu_get_previouspc(machine().device("maincpu")), machine().time().as_double(), tx, dtr ));
+ if ( dtr )
+ m_connection_state |= SERIAL_STATE_DTR;
+ else
+ m_connection_state &= ~SERIAL_STATE_DTR;
+
+ set_out_data_bit(tx);
+ serial_connection_out();
+}
+
+
+
+READ8_MEMBER( to7_io_line_device::porta_in )
+{
+ centronics_device *printer = machine().device<centronics_device>("centronics");
+ int cts = 1;
+ int dsr = ( m_input_state & SERIAL_STATE_DSR ) ? 0 : 1;
+ int rd = get_in_data_bit();
+
+ if ( to7_io_mode(machine()) == TO7_IO_RS232 )
+ cts = m_input_state & SERIAL_STATE_CTS ? 0 : 1;
+ else
+ cts = !printer->busy_r();
+
+ LOG_IO(( "$%04x %f to7_io_porta_in: mode=%i cts=%i, dsr=%i, rd=%i\n", cpu_get_previouspc(machine().device("maincpu")), machine().time().as_double(), to7_io_mode(machine()), cts, dsr, rd ));
+
+ return (dsr ? 0x20 : 0) | (cts ? 0x40 : 0) | (rd ? 0x80: 0);
+}
+
+
+
+static WRITE8_DEVICE_HANDLER( to7_io_portb_out )
+{
+ centronics_device *printer = device->machine().device<centronics_device>("centronics");
+
+ LOG_IO(( "$%04x %f to7_io_portb_out: CENTRONICS set data=$%02X\n", cpu_get_previouspc(device->machine().device("maincpu")), device->machine().time().as_double(), data ));
+
+ /* set 8-bit data */
+ printer->write( *device->machine().memory().first_space(), 0, data);
+}
+
+
+
+static WRITE8_DEVICE_HANDLER( to7_io_cb2_out )
+{
+ centronics_device *printer = device->machine().device<centronics_device>("centronics");
+
+ LOG_IO(( "$%04x %f to7_io_cb2_out: CENTRONICS set strobe=%i\n", cpu_get_previouspc(device->machine().device("maincpu")), device->machine().time().as_double(), data ));
+
+ /* send STROBE to printer */
+ printer->strobe_w(data);
+}
+
+
+void to7_io_line_device::input_callback(UINT8 state)
+{
+ m_input_state = state;
+
+ LOG_IO(( "%f to7_io_in_callback: cts=%i dsr=%i rd=%i\n", machine().time().as_double(), (state & SERIAL_STATE_CTS) ? 1 : 0, (state & SERIAL_STATE_DSR) ? 1 : 0, (int)get_in_data_bit() ));
+}
+
+
+
+const pia6821_interface to7_pia6821_io =
+{
+ DEVCB_DEVICE_MEMBER("to7_io", to7_io_line_device, porta_in),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER("to7_io", to7_io_line_device, porta_out),
+ DEVCB_HANDLER(to7_io_portb_out),
+ DEVCB_NULL,
+ DEVCB_HANDLER(to7_io_cb2_out),
+ DEVCB_LINE(thom_firq_1),
+ DEVCB_LINE(thom_firq_1)
+};
+
+
+const centronics_interface to7_centronics_config =
+{
+ DEVCB_LINE(to7_io_ack),
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+
+void to7_io_line_device::device_reset()
+{
+ pia6821_device *io_pia = machine().device<pia6821_device>(THOM_PIA_IO);
+
+ LOG (( "to7_io_reset called\n" ));
+
+ if (io_pia) io_pia->set_port_a_z_mask(0x03 );
+ m_input_state = SERIAL_STATE_CTS;
+ m_connection_state &= ~SERIAL_STATE_DTR;
+ m_connection_state |= SERIAL_STATE_RTS; /* always ready to send */
+ set_out_data_bit(1);
+ serial_connection_out();
+}
+
+/* ------------ RF 57-932 RS232 extension ------------ */
+
+/* Features:
+ - SY 6551 ACIA.
+ - higher transfer rates than the CC 90-232
+ - usable on all computer, including TO9 and higher
+ */
+
+
+
+/* ------------ MD 90-120 MODEM extension (not functional) ------------ */
+
+/* Features:
+ - 6850 ACIA
+ - 6821 PIA
+ - asymetric 1200/ 75 bauds (reversable)
+
+ TODO!
+ */
+
+
+
+static UINT8 to7_modem_rx;
+
+static UINT8 to7_modem_tx;
+
+
+
+static void to7_modem_cb( device_t *device, int state )
+{
+ LOG(( "to7_modem_cb: called %i\n", state ));
+}
+
+
+
+const pia6821_interface to7_pia6821_modem =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+static READ_LINE_DEVICE_HANDLER( to7_modem_rx_r )
+{
+ return to7_modem_rx;
+}
+
+static WRITE_LINE_DEVICE_HANDLER( to7_modem_tx_w )
+{
+ to7_modem_tx = state;
+}
+
+ACIA6850_INTERFACE( to7_modem )
+{
+ 1200,
+ 1200, /* 1200 bauds, might be divided by 16 */
+ DEVCB_LINE(to7_modem_rx_r), /*&to7_modem_rx,*/
+ DEVCB_LINE(to7_modem_tx_w), /*&to7_modem_tx,*/
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_LINE(to7_modem_cb)
+};
+
+
+
+static void to7_modem_reset( running_machine &machine )
+{
+ LOG (( "to7_modem_reset called\n" ));
+ to7_modem_rx = 0;
+ to7_modem_tx = 0;
+ /* pia_reset() is called in MACHINE_RESET */
+ /* acia_6850 has no reset (?) */
+}
+
+
+
+static void to7_modem_init( running_machine &machine )
+{
+ LOG (( "to7_modem_init: MODEM not implemented!\n" ));
+ state_save_register_global( machine, to7_modem_rx );
+ state_save_register_global( machine, to7_modem_tx );
+}
+
+
+
+/* ------------ dispatch MODEM / speech extension ------------ */
+
+
+const mea8000_interface to7_speech = { "speech", NULL };
+
+
+READ8_HANDLER ( to7_modem_mea8000_r )
+{
+ if ( space->debugger_access() )
+ {
+ return 0;
+ }
+
+ if ( space->machine().root_device().ioport("mconfig")->read() & 1 )
+ {
+ device_t* device = space->machine().device("mea8000" );
+ return mea8000_r( device, offset );
+ }
+ else
+ {
+ acia6850_device* acia = space->machine().device<acia6850_device>("acia6850" );
+ switch (offset) {
+ case 0: return acia->status_read(*space, offset );
+ case 1: return acia->data_read(*space, offset );
+ default: return 0;
+ }
+ }
+}
+
+
+
+WRITE8_HANDLER ( to7_modem_mea8000_w )
+{
+ if ( space->machine().root_device().ioport("mconfig")->read() & 1 )
+ {
+ device_t* device = space->machine().device("mea8000" );
+ mea8000_w( device, offset, data );
+ }
+ else
+ {
+ acia6850_device* acia = space->machine().device<acia6850_device>("acia6850" );
+ switch (offset) {
+ case 0: acia->control_write( *space, offset, data );
+ case 1: acia->data_write( *space, offset, data );
+ }
+ }
+}
+
+
+
+/* ------------ SX 90-018 (model 2) music & game extension ------------ */
+
+/* features:
+ - 6821 PIA
+ - two 8-position, 2-button game pads
+ - 2-button mouse (exclusive with pads)
+ do not confuse with the TO9-specific mouse
+ - 6-bit DAC sound
+
+ extends the CM 90-112 (model 1) with one extra button per pad and a mouse
+*/
+
+
+
+#define TO7_GAME_POLL_PERIOD attotime::from_usec( 500 )
+
+
+
+/* calls to7_game_update_cb periodically */
+static emu_timer* to7_game_timer;
+
+static UINT8 to7_game_sound;
+static UINT8 to7_game_mute;
+
+
+/* The mouse is a very simple phase quadrature one.
+ Each axis provides two 1-bit signals, A and B, that are toggled by the
+ axis rotation. The two signals are not in phase, so that whether A is
+ toggled before B or B before A gives the direction of rotation.
+ This is similar Atari & Amiga mouses.
+ Returns: 0 0 0 0 0 0 YB XB YA XA
+ */
+static UINT8 to7_get_mouse_signal( running_machine &machine )
+{
+ UINT8 xa, xb, ya, yb;
+ UINT16 dx = machine.root_device().ioport("mouse_x")->read(); /* x axis */
+ UINT16 dy = machine.root_device().ioport("mouse_y")->read(); /* y axis */
+ xa = ((dx + 1) & 3) <= 1;
+ xb = (dx & 3) <= 1;
+ ya = ((dy + 1) & 3) <= 1;
+ yb = (dy & 3) <= 1;
+ return xa | (ya << 1) | (xb << 2) | (yb << 3);
+}
+
+
+
+static void to7_game_sound_update ( running_machine &machine )
+{
+ machine.device<dac_device>("dac")->write_unsigned8(to7_game_mute ? 0 : (to7_game_sound << 2) );
+}
+
+
+
+static READ8_DEVICE_HANDLER ( to7_game_porta_in )
+{
+ UINT8 data;
+ if ( device->machine().root_device().ioport("config")->read() & 1 )
+ {
+ /* mouse */
+ data = to7_get_mouse_signal(device->machine()) & 0x0c; /* XB, YB */
+ data |= device->machine().root_device().ioport("mouse_button")->read() & 3; /* buttons */
+ }
+ else
+ {
+ /* joystick */
+ data = device->machine().root_device().ioport("game_port_directions")->read();
+ /* bit 0=0 => P1 up bit 4=0 => P2 up
+ bit 1=0 => P1 down bit 5=0 => P2 down
+ bit 2=0 => P1 left bit 6=0 => P2 left
+ bit 3=0 => P1 right bit 7=0 => P2 right
+ */
+ /* remove impossible combinations: up+down, left+right */
+ if ( ! ( data & 0x03 ) )
+ data |= 0x03;
+ if ( ! ( data & 0x0c ) )
+ data |= 0x0c;
+ if ( ! ( data & 0x30 ) )
+ data |= 0x30;
+ if ( ! ( data & 0xc0 ) )
+ data |= 0xc0;
+ if ( ! ( data & 0x03 ) )
+ data |= 0x03;
+ if ( ! ( data & 0x0c ) )
+ data |= 0x0c;
+ if ( ! ( data & 0x30 ) )
+ data |= 0x30;
+ if ( ! ( data & 0xc0 ) )
+ data |= 0xc0;
+ }
+ return data;
+}
+
+
+
+static READ8_DEVICE_HANDLER ( to7_game_portb_in )
+{
+ UINT8 data;
+ if ( device->machine().root_device().ioport("config")->read() & 1 )
+ {
+ /* mouse */
+ UINT8 mouse = to7_get_mouse_signal(device->machine());
+ data = 0;
+ if ( mouse & 1 )
+ data |= 0x04; /* XA */
+ if ( mouse & 2 )
+ data |= 0x40; /* YA */
+ }
+ else
+ {
+ /* joystick */
+ /* bits 6-7: action buttons A (0=pressed) */
+ /* bits 2-3: action buttons B (0=pressed) */
+ /* bits 4-5: unused (ouput) */
+ /* bits 0-1: unknown! */
+ data = device->machine().root_device().ioport("game_port_buttons")->read();
+ }
+ return data;
+}
+
+
+
+static WRITE8_DEVICE_HANDLER ( to7_game_portb_out )
+{
+ /* 6-bit DAC sound */
+ to7_game_sound = data & 0x3f;
+ to7_game_sound_update(device->machine());
+}
+
+
+
+static WRITE8_DEVICE_HANDLER ( to7_game_cb2_out )
+{
+ /* undocumented */
+ /* some TO8 games (e.g.: F15) seem to write here a lot */
+}
+
+
+
+const pia6821_interface to7_pia6821_game =
+{
+ DEVCB_HANDLER(to7_game_porta_in),
+ DEVCB_HANDLER(to7_game_portb_in),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(to7_game_portb_out),
+ DEVCB_NULL,
+ DEVCB_HANDLER(to7_game_cb2_out),
+ DEVCB_LINE(thom_irq_1),
+ DEVCB_LINE(thom_irq_1)
+};
+
+
+
+/* this should be called periodically */
+static TIMER_CALLBACK(to7_game_update_cb)
+{
+ pia6821_device *game_pia = machine.device<pia6821_device>(THOM_PIA_GAME);
+
+ if ( machine.root_device().ioport("config")->read() & 1 )
+ {
+ /* mouse */
+ UINT8 mouse = to7_get_mouse_signal(machine);
+ game_pia->ca1_w( (mouse & 1) ? 1 : 0 ); /* XA */
+ game_pia->ca2_w( (mouse & 2) ? 1 : 0 ); /* YA */
+ }
+ else
+ {
+ /* joystick */
+ UINT8 in = machine.root_device().ioport("game_port_buttons")->read();
+ game_pia->cb2_w( (in & 0x80) ? 1 : 0 ); /* P2 action A */
+ game_pia->ca2_w( (in & 0x40) ? 1 : 0 ); /* P1 action A */
+ game_pia->cb1_w( (in & 0x08) ? 1 : 0 ); /* P2 action B */
+ game_pia->ca1_w( (in & 0x04) ? 1 : 0 ); /* P1 action B */
+ /* TODO:
+ it seems that CM 90-112 behaves differently
+ - ca1 is P1 action A, i.e., in & 0x40
+ - ca2 is P2 action A, i.e., in & 0x80
+ - cb1, cb2 are not connected (should not be a problem)
+ */
+ /* Note: the MO6 & MO5NR have slightly different connections
+ (see mo6_game_update_cb)
+ */
+ }
+}
+
+
+
+static void to7_game_init ( running_machine &machine )
+{
+ LOG (( "to7_game_init called\n" ));
+ to7_game_timer = machine.scheduler().timer_alloc(FUNC(to7_game_update_cb));
+ to7_game_timer->adjust(TO7_GAME_POLL_PERIOD, 0, TO7_GAME_POLL_PERIOD);
+ state_save_register_global( machine, to7_game_sound );
+ state_save_register_global( machine, to7_game_mute );
+}
+
+
+
+static void to7_game_reset ( running_machine &machine )
+{
+ pia6821_device *game_pia = machine.device<pia6821_device>(THOM_PIA_GAME);
+
+ LOG (( "to7_game_reset called\n" ));
+ game_pia->ca1_w( 0 );
+ to7_game_sound = 0;
+ to7_game_mute = 0;
+ to7_game_sound_update( machine );
+}
+
+
+
+/* ------------ MIDI extension ------------ */
+
+/* IMPORTANT NOTE:
+ The following is experimental and not compiled in by default.
+ It relies on the existence of an hypothetical "character device" API able
+ to transmit bytes between the MESS driver and the outside world
+ (using, e.g., character device special files on some UNIX).
+*/
+
+#ifdef CHARDEV
+
+#include "devices/chardev.h"
+
+/* Features an EF 6850 ACIA
+
+ MIDI protocol is a serial asynchronous protocol
+ Each 8-bit byte is transmitted as:
+ - 1 start bit
+ - 8 data bits
+ - 1 stop bits
+ 320 us per transmitted byte => 31250 baud
+
+ Emulation is based on the Motorola 6850 documentation, not EF 6850.
+
+ We do not emulate the seral line but pass bytes directly between the
+ 6850 registers and the MIDI device.
+*/
+
+
+static UINT8 to7_midi_status; /* 6850 status word */
+static UINT8 to7_midi_overrun; /* pending overrun */
+static UINT8 to7_midi_intr; /* enabled interrupts */
+
+static chardev* to7_midi_chardev;
+
+
+
+static void to7_midi_update_irq ( running_machine &machine )
+{
+ if ( (to7_midi_intr & 4) && (to7_midi_status & ACIA_6850_RDRF) )
+ to7_midi_status |= ACIA_6850_irq; /* byte received interrupt */
+
+ if ( (to7_midi_intr & 4) && (to7_midi_status & ACIA_6850_OVRN) )
+ to7_midi_status |= ACIA_6850_irq; /* overrun interrupt */
+
+ if ( (to7_midi_intr & 3) == 1 && (to7_midi_status & ACIA_6850_TDRE) )
+ to7_midi_status |= ACIA_6850_irq; /* ready to transmit interrupt */
+
+ thom_irq_4( machine, to7_midi_status & ACIA_6850_irq );
+}
+
+
+
+static void to7_midi_byte_received_cb( running_machine &machine, chardev_err s )
+{
+ to7_midi_status |= ACIA_6850_RDRF;
+ if ( s == CHARDEV_OVERFLOW )
+ to7_midi_overrun = 1;
+ to7_midi_update_irq( machine );
+}
+
+
+
+static void to7_midi_ready_to_send_cb( running_machine &machine )
+{
+ to7_midi_status |= ACIA_6850_TDRE;
+ to7_midi_update_irq( machine );
+}
+
+
+
+READ8_HANDLER ( to7_midi_r )
+{
+ /* ACIA 6850 registers */
+
+ switch ( offset )
+ {
+
+ case 0: /* get status */
+ /* bit 0: data received */
+ /* bit 1: ready to transmit data */
+ /* bit 2: data carrier detect (ignored) */
+ /* bit 3: clear to send (ignored) */
+ /* bit 4: framing error (ignored) */
+ /* bit 5: overrun */
+ /* bit 6: parity error (ignored) */
+ /* bit 7: interrupt */
+ LOG_MIDI(( "$%04x %f to7_midi_r: status $%02X (rdrf=%i, tdre=%i, ovrn=%i, irq=%i)\n",
+ cpu_get_previouspc(space->machine().device("maincpu")), space->machine().time().as_double(), to7_midi_status,
+ (to7_midi_status & ACIA_6850_RDRF) ? 1 : 0,
+ (to7_midi_status & ACIA_6850_TDRE) ? 1 : 0,
+ (to7_midi_status & ACIA_6850_OVRN) ? 1 : 0,
+ (to7_midi_status & ACIA_6850_irq) ? 1 : 0 ));
+ return to7_midi_status;
+
+
+ case 1: /* get input data */
+ {
+ UINT8 data = chardev_in( to7_midi_chardev );
+ if ( !space->debugger_access() )
+ {
+ to7_midi_status &= ~(ACIA_6850_irq | ACIA_6850_RDRF);
+ if ( to7_midi_overrun )
+ to7_midi_status |= ACIA_6850_OVRN;
+ else
+ to7_midi_status &= ~ACIA_6850_OVRN;
+ to7_midi_overrun = 0;
+ LOG_MIDI(( "$%04x %f to7_midi_r: read data $%02X\n",
+ cpu_get_previouspc(space->machine().device("maincpu")), space->machine().time().as_double(), data ));
+ to7_midi_update_irq( space->machine() );
+ }
+ return data;
+ }
+
+
+ default:
+ logerror( "$%04x to7_midi_r: invalid offset %i\n",
+ cpu_get_previouspc(space->machine().device("maincpu")), offset );
+ return 0;
+ }
+}
+
+
+
+WRITE8_HANDLER ( to7_midi_w )
+{
+ /* ACIA 6850 registers */
+
+ switch ( offset )
+ {
+
+ case 0: /* set control */
+ /* bits 0-1: clock divide (ignored) or reset */
+ if ( (data & 3) == 3 )
+ {
+ /* reset */
+ LOG_MIDI(( "$%04x %f to7_midi_w: reset (data=$%02X)\n", cpu_get_previouspc(space->machine().device("maincpu")), space->machine().time().as_double(), data ));
+ to7_midi_overrun = 0;
+ to7_midi_status = 2;
+ to7_midi_intr = 0;
+ chardev_reset( to7_midi_chardev );
+ }
+ else
+ {
+ /* bits 2-4: parity */
+ /* bits 5-6: interrupt on transmit */
+ /* bit 7: interrupt on receive */
+ to7_midi_intr = data >> 5;
+ {
+ static const int bits[8] = { 7,7,7,7,8,8,8,8 };
+ static const int stop[8] = { 2,2,1,1,2,1,1,1 };
+ static const char parity[8] = { 'e','o','e','o','-','-','e','o' };
+ LOG_MIDI(( "$%04x %f to7_midi_w: set control to $%02X (bits=%i, stop=%i, parity=%c, intr in=%i out=%i)\n",
+ cpu_get_previouspc(space->machine().device("maincpu")), space->machine().time().as_double(),
+ data,
+ bits[ (data >> 2) & 7 ],
+ stop[ (data >> 2) & 7 ],
+ parity[ (data >> 2) & 7 ],
+ to7_midi_intr >> 2,
+ (to7_midi_intr & 3) ? 1 : 0));
+ }
+ }
+ to7_midi_update_irq( space->machine() );
+ break;
+
+
+ case 1: /* output data */
+ LOG_MIDI(( "$%04x %f to7_midi_w: write data $%02X\n", cpu_get_previouspc(space->machine().device("maincpu")), space->machine().time().as_double(), data ));
+ if ( data == 0x55 )
+ /* cable-detect: shortcut */
+ chardev_fake_in( to7_midi_chardev, 0x55 );
+ else
+ {
+ /* send to MIDI */
+ to7_midi_status &= ~(ACIA_6850_irq | ACIA_6850_TDRE);
+ chardev_out( to7_midi_chardev, data );
+ }
+ break;
+
+
+ default:
+ logerror( "$%04x to7_midi_w: invalid offset %i (data=$%02X) \n", cpu_get_previouspc(space->machine().device("maincpu")), offset, data );
+ }
+}
+
+
+
+static const chardev_interface to7_midi_interface =
+{
+ to7_midi_byte_received_cb,
+ to7_midi_ready_to_send_cb,
+};
+
+
+
+static void to7_midi_reset( running_machine &machine )
+{
+ LOG (( "to7_midi_reset called\n" ));
+ to7_midi_overrun = 0;
+ to7_midi_status = 0;
+ to7_midi_intr = 0;
+ chardev_reset( to7_midi_chardev );
+}
+
+
+
+static void to7_midi_init( running_machine &machine )
+{
+ LOG (( "to7_midi_init\n" ));
+ to7_midi_chardev = chardev_open( &machine, "/dev/snd/midiC0D0", "/dev/snd/midiC0D1", &to7_midi_interface );
+ state_save_register_global( machine, to7_midi_status );
+ state_save_register_global( machine, to7_midi_overrun );
+ state_save_register_global( machine, to7_midi_intr );
+}
+
+
+
+#else
+
+
+
+READ8_HANDLER ( to7_midi_r )
+{
+ logerror( "to7_midi_r: not implemented\n" );
+ return 0;
+}
+
+
+
+WRITE8_HANDLER ( to7_midi_w )
+{
+ logerror( "to7_midi_w: not implemented\n" );
+}
+
+
+
+static void to7_midi_reset( running_machine &machine )
+{
+ logerror( "to7_midi_reset: not implemented\n" );
+}
+
+
+
+static void to7_midi_init( running_machine &machine )
+{
+ logerror( "to7_midi_init: not implemented\n" );
+}
+
+
+
+#endif
+
+
+
+/* ------------ init / reset ------------ */
+
+
+
+MACHINE_RESET ( to7 )
+{
+ pia6821_device *sys_pia = machine.device<pia6821_device>(THOM_PIA_SYS );
+
+ LOG (( "to7: machine reset called\n" ));
+
+ /* subsystems */
+ thom_irq_reset(machine);
+ to7_game_reset(machine);
+ to7_floppy_reset(machine);
+ to7_modem_reset(machine);
+ to7_midi_reset(machine);
+
+ /* video */
+ thom_set_video_mode( machine, THOM_VMODE_TO770 );
+ thom_set_init_callback( machine, to7_set_init );
+ thom_set_lightpen_callback( machine, 3, to7_lightpen_cb );
+ thom_set_mode_point( machine, 0 );
+ thom_set_border_color( machine, 0 );
+ sys_pia->cb1_w( 0 );
+
+ /* memory */
+ old_cart_bank = -1;
+ to7_update_cart_bank(machine);
+ /* thom_cart_bank not reset */
+
+ /* lightpen */
+ to7_lightpen = 0;
+}
+
+
+
+MACHINE_START ( to7 )
+{
+ address_space* space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ UINT8* mem = machine.root_device().memregion("maincpu")->base();
+ UINT8* ram = machine.device<ram_device>(RAM_TAG)->pointer();
+
+ LOG (( "to7: machine start called\n" ));
+
+ /* subsystems */
+ thom_irq_init(machine);
+ to7_game_init(machine);
+ to7_floppy_init(machine, mem + 0x20000);
+ to7_modem_init(machine);
+ to7_midi_init(machine);
+
+ /* memory */
+ thom_cart_bank = 0;
+ thom_vram = ram;
+ machine.root_device().membank( THOM_BASE_BANK )->configure_entry( 0, ram + 0x4000);
+ machine.root_device().membank( THOM_VRAM_BANK )->configure_entries( 0, 2, thom_vram, 0x2000 );
+ machine.root_device().membank( THOM_CART_BANK )->configure_entries( 0, 4, mem + 0x10000, 0x4000 );
+ machine.root_device().membank( THOM_BASE_BANK )->set_entry( 0 );
+ machine.root_device().membank( THOM_VRAM_BANK )->set_entry( 0 );
+ machine.root_device().membank( THOM_CART_BANK )->set_entry( 0 );
+
+ if ( machine.device<ram_device>(RAM_TAG)->size() > 24*1024 )
+ {
+ /* install 16 KB or 16 KB + 8 KB memory extensions */
+ /* BASIC instruction to see free memory: ?FRE(0) */
+ int extram = machine.device<ram_device>(RAM_TAG)->size() - 24*1024;
+ space->install_write_bank(0x8000, 0x8000 + extram - 1, THOM_RAM_BANK);
+ space->install_read_bank(0x8000, 0x8000 + extram - 1, THOM_RAM_BANK );
+ machine.root_device().membank( THOM_RAM_BANK )->configure_entry( 0, ram + 0x6000);
+ machine.root_device().membank( THOM_RAM_BANK )->set_entry( 0 );
+ }
+
+ /* force 2 topmost color bits to 1 */
+ memset( thom_vram + 0x2000, 0xc0, 0x2000 );
+
+ /* save-state */
+ state_save_register_global( machine, thom_cart_nb_banks );
+ state_save_register_global( machine, thom_cart_bank );
+ state_save_register_global( machine, to7_lightpen );
+ state_save_register_global( machine, to7_lightpen_step );
+ state_save_register_global_pointer( machine, (mem + 0x10000), 0x10000 );
+ machine.save().register_postload(save_prepost_delegate(FUNC(to7_update_cart_bank_postload), &machine));
+}
+
+
+
+/***************************** TO7/70 *************************/
+
+
+
+/* ------------ system PIA 6821 ------------ */
+
+
+
+static WRITE8_DEVICE_HANDLER ( to770_sys_cb2_out )
+{
+ /* video overlay: black pixels are transparent and show TV image underneath */
+ LOG(( "$%04x to770_sys_cb2_out: video overlay %i\n", cpu_get_previouspc(device->machine().device("maincpu")), data ));
+}
+
+
+
+static READ8_DEVICE_HANDLER ( to770_sys_porta_in )
+{
+ /* keyboard */
+ static const char *const keynames[] = {
+ "keyboard_0", "keyboard_1", "keyboard_2", "keyboard_3",
+ "keyboard_4", "keyboard_5", "keyboard_6", "keyboard_7"
+ };
+ int keyline = downcast<pia6821_device *>(device)->b_output() & 7;
+
+ return device->machine().root_device().ioport(keynames[7 - keyline])->read();
+}
+
+
+
+static void to770_update_ram_bank(running_machine &machine)
+{
+ pia6821_device *sys_pia = machine.device<pia6821_device>(THOM_PIA_SYS );
+ address_space* space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ UINT8 portb = sys_pia->port_b_z_mask();
+ int bank;
+
+ switch (portb & 0xf8)
+ {
+ /* 2 * 16 KB internal RAM */
+ case 0xf0: bank = 0; break;
+ case 0xe8: bank = 1; break;
+
+ /* 4 * 16 KB extended RAM */
+ case 0x18: bank = 2; break;
+ case 0x98: bank = 3; break;
+ case 0x58: bank = 4; break;
+ case 0xd8: bank = 5; break;
+
+ /* none selected */
+ case 0xf8: return;
+
+ default:
+ logerror( "to770_update_ram_bank unknown bank $%02X\n", portb & 0xf8 );
+ return;
+ }
+
+ if ( bank != old_ram_bank )
+ {
+ if ( machine.device<ram_device>(RAM_TAG)->size() == 128*1024 || bank < 2 )
+ {
+ machine.root_device().membank( THOM_RAM_BANK )->set_entry( bank );
+ }
+ else
+ {
+ /* RAM size is 48 KB only and unavailable bank
+ * requested */
+ space->nop_readwrite(0xa000, 0xdfff);
+ }
+ old_ram_bank = bank;
+ LOG_BANK(( "to770_update_ram_bank: RAM bank change %i\n", bank ));
+ }
+}
+
+
+
+static void to770_update_ram_bank_postload(running_machine *machine)
+{
+ to770_update_ram_bank(*machine);
+}
+
+
+
+static WRITE8_DEVICE_HANDLER ( to770_sys_portb_out )
+{
+ to770_update_ram_bank(device->machine());
+}
+
+
+
+const pia6821_interface to770_pia6821_sys =
+{
+ DEVCB_HANDLER(to770_sys_porta_in),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(to770_sys_portb_out),
+ DEVCB_HANDLER(to7_set_cassette_motor),
+ DEVCB_HANDLER(to770_sys_cb2_out),
+ DEVCB_LINE(thom_firq_1),
+ DEVCB_LINE(thom_firq_1)
+};
+
+
+
+/* ------------ 6846 (timer, I/O) ------------ */
+
+
+
+static WRITE8_DEVICE_HANDLER ( to770_timer_port_out )
+{
+ thom_set_mode_point( device->machine(), data & 1 ); /* bit 0: video bank switch */
+ thom_set_caps_led( device->machine(), (data & 8) ? 1 : 0 ) ; /* bit 3: keyboard led */
+ thom_set_border_color( device->machine(),
+ ((data & 0x10) ? 1 : 0) | /* 4-bit border color */
+ ((data & 0x20) ? 2 : 0) |
+ ((data & 0x40) ? 4 : 0) |
+ ((data & 0x04) ? 0 : 8) );
+}
+
+
+
+const mc6846_interface to770_timer =
+{
+ to770_timer_port_out, NULL, to7_timer_cp2_out,
+ to7_timer_port_in, to7_timer_tco_out,
+ thom_dev_irq_0
+};
+
+
+
+/* ------------ gate-array ------------ */
+
+
+
+READ8_HANDLER ( to770_gatearray_r )
+{
+ struct thom_vsignal v = thom_get_vsignal(space->machine());
+ struct thom_vsignal l = thom_get_lightpen_vsignal( space->machine(), TO7_LIGHTPEN_DECAL, to7_lightpen_step - 1, 0 );
+ int count, inil, init, lt3;
+ count = to7_lightpen ? l.count : v.count;
+ inil = to7_lightpen ? l.inil : v.inil;
+ init = to7_lightpen ? l.init : v.init;
+ lt3 = to7_lightpen ? l.lt3 : v.lt3;
+
+ switch ( offset )
+ {
+ case 0: return (count >> 8) & 0xff;
+ case 1: return count & 0xff;
+ case 2: return (lt3 << 7) | (inil << 6);
+ case 3: return (init << 7);
+ default:
+ logerror( "$%04x to770_gatearray_r: invalid offset %i\n", cpu_get_previouspc(space->machine().device("maincpu")), offset );
+ return 0;
+ }
+}
+
+
+
+WRITE8_HANDLER ( to770_gatearray_w )
+{
+ if ( ! offset )
+ to7_lightpen = data & 1;
+}
+
+
+
+/* ------------ init / reset ------------ */
+
+
+
+MACHINE_RESET( to770 )
+{
+ pia6821_device *sys_pia = machine.device<pia6821_device>(THOM_PIA_SYS );
+
+ LOG (( "to770: machine reset called\n" ));
+
+ /* subsystems */
+ thom_irq_reset(machine);
+ to7_game_reset(machine);
+ to7_floppy_reset(machine);
+ to7_modem_reset(machine);
+ to7_midi_reset(machine);
+
+ /* video */
+ thom_set_video_mode( machine, THOM_VMODE_TO770 );
+ thom_set_init_callback( machine, to7_set_init );
+ thom_set_lightpen_callback( machine, 3, to7_lightpen_cb );
+ thom_set_mode_point( machine, 0 );
+ thom_set_border_color( machine, 8 );
+ sys_pia->cb1_w( 0 );
+
+ /* memory */
+ old_ram_bank = -1;
+ old_cart_bank = -1;
+ to7_update_cart_bank(machine);
+ to770_update_ram_bank(machine);
+ /* thom_cart_bank not reset */
+
+ /* lightpen */
+ to7_lightpen = 0;
+}
+
+
+
+MACHINE_START ( to770 )
+{
+ UINT8* mem = machine.root_device().memregion("maincpu")->base();
+ UINT8* ram = machine.device<ram_device>(RAM_TAG)->pointer();
+
+ LOG (( "to770: machine start called\n" ));
+
+ /* subsystems */
+ thom_irq_init(machine);
+ to7_game_init(machine);
+ to7_floppy_init( machine, mem + 0x20000 );
+ to7_modem_init(machine);
+ to7_midi_init(machine);
+
+ /* memory */
+ thom_cart_bank = 0;
+ thom_vram = ram;
+ machine.root_device().membank( THOM_BASE_BANK )->configure_entry( 0, ram + 0x4000);
+ machine.root_device().membank( THOM_RAM_BANK )->configure_entries( 0, 6, ram + 0x8000, 0x4000 );
+ machine.root_device().membank( THOM_VRAM_BANK )->configure_entries( 0, 2, thom_vram, 0x2000 );
+ machine.root_device().membank( THOM_CART_BANK )->configure_entries( 0, 4, mem + 0x10000, 0x4000 );
+ machine.root_device().membank( THOM_BASE_BANK )->set_entry( 0 );
+ machine.root_device().membank( THOM_RAM_BANK )->set_entry( 0 );
+ machine.root_device().membank( THOM_VRAM_BANK )->set_entry( 0 );
+ machine.root_device().membank( THOM_CART_BANK )->set_entry( 0 );
+
+ /* save-state */
+ state_save_register_global( machine, thom_cart_nb_banks );
+ state_save_register_global( machine, thom_cart_bank );
+ state_save_register_global( machine, to7_lightpen );
+ state_save_register_global( machine, to7_lightpen_step );
+ state_save_register_global_pointer( machine, (mem + 0x10000), 0x10000 );
+ machine.save().register_postload(save_prepost_delegate(FUNC(to770_update_ram_bank_postload), &machine));
+ machine.save().register_postload(save_prepost_delegate(FUNC(to7_update_cart_bank_postload), &machine));
+}
+
+
+
+/***************************** MO5 *************************/
+
+
+
+/* ------------ lightpen automaton ------------ */
+
+
+
+static void mo5_lightpen_cb ( running_machine &machine, int step )
+{
+ pia6821_device *sys_pia = machine.device<pia6821_device>(THOM_PIA_SYS );
+
+ /* MO5 signals ca1 (TO7 signals cb1) */
+ if ( ! to7_lightpen )
+ return;
+
+ sys_pia->ca1_w( 1 );
+ sys_pia->ca1_w( 0 );
+ to7_lightpen_step = step;
+}
+
+
+/* ------------ periodic interrupt ------------ */
+
+/* the MO5 & MO6 do not have a MC 6846 timer,
+ they have a fixed 50 Hz timer instead
+*/
+
+
+
+static emu_timer* mo5_periodic_timer;
+
+
+
+static TIMER_CALLBACK(mo5_periodic_cb)
+{
+ pia6821_device *sys_pia = machine.device<pia6821_device>(THOM_PIA_SYS );
+
+ /* pulse */
+ sys_pia->cb1_w( 1 );
+ sys_pia->cb1_w( 0 );
+}
+
+
+
+static void mo5_init_timer(running_machine &machine)
+{
+ /* time is a little faster than 50 Hz to match video framerate */
+ mo5_periodic_timer->adjust(attotime::zero, 0, attotime::from_usec( 19968 ));
+}
+
+
+
+/* ------------ system PIA 6821 ------------ */
+
+
+
+static WRITE8_DEVICE_HANDLER ( mo5_sys_porta_out )
+{
+ thom_set_mode_point( device->machine(), data & 1 ); /* bit 0: video bank switch */
+ thom_set_border_color( device->machine(), (data >> 1) & 15 ); /* bit 1-4: border color */
+ mo5_set_cassette( device->machine(), (data & 0x40) ? 1 : 0 ); /* bit 6: cassette output */
+}
+
+
+
+static READ8_DEVICE_HANDLER ( mo5_sys_porta_in )
+{
+ return
+ (mo5_get_cassette(device->machine()) ? 0x80 : 0) | /* bit 7: cassette input */
+ ((device->machine().root_device().ioport("lightpen_button")->read() & 1) ? 0x20 : 0)
+ /* bit 5: lightpen button */;
+}
+
+
+
+static WRITE8_DEVICE_HANDLER ( mo5_sys_portb_out )
+{
+ device->machine().device<dac_device>("buzzer")->write_unsigned8((data & 1) ? 0x80 : 0); /* 1-bit buzzer */
+}
+
+
+
+static READ8_DEVICE_HANDLER ( mo5_sys_portb_in )
+{
+ UINT8 portb = downcast<pia6821_device *>(device)->b_output();
+ int col = (portb >> 1) & 7; /* key column */
+ int lin = 7 - ((portb >> 4) & 7); /* key line */
+ static const char *const keynames[] = {
+ "keyboard_0", "keyboard_1", "keyboard_2", "keyboard_3",
+ "keyboard_4", "keyboard_5", "keyboard_6", "keyboard_7"
+ };
+
+ return ( device->machine().root_device().ioport(keynames[lin])->read() & (1 << col) ) ? 0x80 : 0;
+}
+
+
+
+const pia6821_interface mo5_pia6821_sys =
+{
+ DEVCB_HANDLER(mo5_sys_porta_in),
+ DEVCB_HANDLER(mo5_sys_portb_in),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(mo5_sys_porta_out),
+ DEVCB_HANDLER(mo5_sys_portb_out),
+ DEVCB_HANDLER(mo5_set_cassette_motor),
+ DEVCB_NULL,
+ DEVCB_LINE(thom_firq_1),
+ DEVCB_LINE(thom_irq_1) /* WARNING: differs from TO7 ! */
+};
+
+
+
+/* ------------ gate-array ------------ */
+
+
+
+#define MO5_LIGHTPEN_DECAL 12
+
+
+
+READ8_HANDLER ( mo5_gatearray_r )
+{
+ struct thom_vsignal v = thom_get_vsignal(space->machine());
+ struct thom_vsignal l = thom_get_lightpen_vsignal( space->machine(), MO5_LIGHTPEN_DECAL, to7_lightpen_step - 1, 0 );
+ int count, inil, init, lt3;
+ count = to7_lightpen ? l.count : v.count;
+ inil = to7_lightpen ? l.inil : v.inil;
+ init = to7_lightpen ? l.init : v.init;
+ lt3 = to7_lightpen ? l.lt3 : v.lt3;
+
+ switch ( offset ) {
+ case 0: return (count >> 8) & 0xff;
+ case 1: return count & 0xff;
+ case 2: return (lt3 << 7) | (inil << 6);
+ case 3: return (init << 7);
+ default:
+ logerror( "$%04x mo5_gatearray_r: invalid offset %i\n", cpu_get_previouspc(space->machine().device("maincpu")), offset );
+ return 0;
+ }
+}
+
+
+
+WRITE8_HANDLER ( mo5_gatearray_w )
+{
+ if ( ! offset )
+ to7_lightpen = data & 1;
+}
+
+
+
+/* ------------ cartridge / extended RAM ------------ */
+
+
+
+static UINT8 mo5_reg_cart; /* 0xa7cb bank switch */
+
+
+
+DEVICE_IMAGE_LOAD( mo5_cartridge )
+{
+ UINT8* pos = image.device().machine().root_device().memregion("maincpu")->base() + 0x10000;
+ UINT64 size = image.length();
+ int i,j;
+ char name[129];
+
+ /* get size & number of 16-KB banks */
+ if ( size > 32 && size <= 0x04000 )
+ thom_cart_nb_banks = 1;
+ else if ( size == 0x08000 )
+ thom_cart_nb_banks = 2;
+ else if ( size == 0x10000 )
+ thom_cart_nb_banks = 4;
+ else
+ {
+ logerror( "mo5_cartridge_load: invalid cartridge size %u\n", (unsigned) size );
+ return IMAGE_INIT_FAIL;
+ }
+
+ if ( image.fread(pos, size ) != size )
+ {
+ logerror( "mo5_cartridge_load: read error\n" );
+ return IMAGE_INIT_FAIL;
+ }
+
+ /* extract name */
+ i = size - 32;
+ while ( i < size && !pos[i] ) i++;
+ for ( j = 0; i < size && pos[i] >= 0x20; j++, i++)
+ name[j] = pos[i];
+ name[j] = 0;
+
+ /* sanitize name */
+ for ( i = 0; name[i]; i++)
+ {
+ if ( name[i] < ' ' || name[i] >= 127 ) name[i] = '?';
+ }
+
+ PRINT (( "mo5_cartridge_load: cartridge \"%s\" banks=%i, size=%u\n", name, thom_cart_nb_banks, (unsigned) size ));
+
+ return IMAGE_INIT_PASS;
+}
+
+
+
+static void mo5_update_cart_bank(running_machine &machine)
+{
+ address_space* space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ int rom_is_ram = mo5_reg_cart & 4;
+ int bank = 0;
+ int bank_is_read_only = 0;
+
+
+ if ( rom_is_ram && thom_cart_nb_banks == 4 )
+ {
+ /* 64 KB ROM from "JANE" cartridge */
+ bank = mo5_reg_cart & 3;
+ if ( bank != old_cart_bank )
+ {
+ if ( old_cart_bank < 0 || old_cart_bank > 3 )
+ {
+ space->install_read_bank( 0xb000, 0xefff, THOM_CART_BANK);
+ space->nop_write( 0xb000, 0xefff);
+ }
+ LOG_BANK(( "mo5_update_cart_bank: CART is cartridge bank %i (A7CB style)\n", bank ));
+ }
+ }
+ else if ( rom_is_ram )
+ {
+ /* 64 KB RAM from network extension */
+ bank = 4 + ( mo5_reg_cart & 3 );
+ bank_is_read_only = (( mo5_reg_cart & 8 ) == 0);
+
+ if ( bank != old_cart_bank || bank_is_read_only != old_cart_bank_was_read_only)
+ {
+ if ( bank_is_read_only )
+ {
+ space->install_read_bank( 0xb000, 0xefff, THOM_CART_BANK);
+ space->nop_write( 0xb000, 0xefff );
+ }
+ else
+ {
+ space->install_readwrite_bank( 0xb000, 0xefff, THOM_CART_BANK);
+ }
+ LOG_BANK(( "mo5_update_cart_bank: CART is nanonetwork RAM bank %i (%s)\n",
+ mo5_reg_cart & 3,
+ bank_is_read_only ? "read-only":"read-write"));
+ old_cart_bank_was_read_only = bank_is_read_only;
+ }
+ }
+ else
+ {
+ /* regular cartridge bank switch */
+ if ( thom_cart_nb_banks )
+ {
+ bank = thom_cart_bank % thom_cart_nb_banks;
+ if ( bank != old_cart_bank )
+ {
+ if ( old_cart_bank < 0 )
+ {
+ space->install_read_bank( 0xb000, 0xefff, THOM_CART_BANK);
+ space->install_legacy_write_handler( 0xb000, 0xefff, FUNC(mo5_cartridge_w) );
+ space->install_legacy_read_handler( 0xbffc, 0xbfff, FUNC(mo5_cartridge_r) );
+ }
+ LOG_BANK(( "mo5_update_cart_bank: CART is cartridge bank %i\n", bank ));
+ }
+ } else
+ /* internal ROM */
+ if ( old_cart_bank != 0 )
+ {
+ space->install_read_bank( 0xb000, 0xefff, THOM_CART_BANK);
+ space->install_legacy_write_handler( 0xb000, 0xefff, FUNC(mo5_cartridge_w) );
+ LOG_BANK(( "mo5_update_cart_bank: CART is internal\n"));
+ }
+ }
+ if ( bank != old_cart_bank )
+ {
+ machine.root_device().membank( THOM_CART_BANK )->set_entry( bank );
+ old_cart_bank = bank;
+ }
+}
+
+
+
+static void mo5_update_cart_bank_postload(running_machine *machine)
+{
+ mo5_update_cart_bank(*machine);
+}
+
+
+
+/* write signal to b000-cfff generates a bank switch */
+WRITE8_HANDLER ( mo5_cartridge_w )
+{
+ if ( offset >= 0x2000 )
+ return;
+
+ thom_cart_bank = offset & 3;
+ mo5_update_cart_bank(space->machine());
+}
+
+
+
+/* read signal to bffc-bfff generates a bank switch */
+READ8_HANDLER ( mo5_cartridge_r )
+{
+ UINT8* pos = space->machine().root_device().memregion( "maincpu" )->base() + 0x10000;
+ UINT8 data = pos[offset + 0xbffc + (thom_cart_bank % thom_cart_nb_banks) * 0x4000];
+ if ( !space->debugger_access() )
+ {
+ thom_cart_bank = offset & 3;
+ mo5_update_cart_bank(space->machine());
+ }
+ return data;
+}
+
+
+
+/* 0xa7cb bank-switch register */
+WRITE8_HANDLER ( mo5_ext_w )
+{
+ mo5_reg_cart = data;
+ mo5_update_cart_bank(space->machine());
+}
+
+
+
+/* ------------ init / reset ------------ */
+
+
+
+MACHINE_RESET( mo5 )
+{
+ pia6821_device *sys_pia = machine.device<pia6821_device>(THOM_PIA_SYS );
+
+ LOG (( "mo5: machine reset called\n" ));
+
+ /* subsystems */
+ thom_irq_reset(machine);
+ sys_pia->set_port_a_z_mask(0x5f );
+ to7_game_reset(machine);
+ to7_floppy_reset(machine);
+ to7_modem_reset(machine);
+ to7_midi_reset(machine);
+ mo5_init_timer(machine);
+
+ /* video */
+ thom_set_video_mode( machine, THOM_VMODE_MO5 );
+ thom_set_lightpen_callback( machine, 3, mo5_lightpen_cb );
+ thom_set_mode_point( machine, 0 );
+ thom_set_border_color( machine, 0 );
+ sys_pia->ca1_w( 0 );
+
+ /* memory */
+ old_cart_bank = -1;
+ mo5_update_cart_bank(machine);
+ /* mo5_reg_cart not reset */
+ /* thom_cart_bank not reset */
+
+ /* lightpen */
+ to7_lightpen = 0;
+}
+
+
+
+MACHINE_START ( mo5 )
+{
+ UINT8* mem = machine.root_device().memregion("maincpu")->base();
+ UINT8* ram = machine.device<ram_device>(RAM_TAG)->pointer();
+
+ LOG (( "mo5: machine start called\n" ));
+
+ /* subsystems */
+ thom_irq_init(machine);
+ to7_game_init(machine);
+ to7_floppy_init( machine, mem + 0x20000 );
+ to7_modem_init(machine);
+ to7_midi_init(machine);
+ mo5_periodic_timer = machine.scheduler().timer_alloc(FUNC(mo5_periodic_cb));
+
+ /* memory */
+ thom_cart_bank = 0;
+ mo5_reg_cart = 0;
+ thom_vram = ram;
+ machine.root_device().membank( THOM_BASE_BANK )->configure_entry( 0, ram + 0x4000);
+ machine.root_device().membank( THOM_CART_BANK )->configure_entries( 0, 4, mem + 0x10000, 0x4000 );
+ machine.root_device().membank( THOM_CART_BANK )->configure_entries( 4, 4, ram + 0xc000, 0x4000 );
+ machine.root_device().membank( THOM_VRAM_BANK )->configure_entries( 0, 2, thom_vram, 0x2000 );
+ machine.root_device().membank( THOM_BASE_BANK )->set_entry( 0 );
+ machine.root_device().membank( THOM_CART_BANK )->set_entry( 0 );
+ machine.root_device().membank( THOM_VRAM_BANK )->set_entry( 0 );
+
+ /* save-state */
+ state_save_register_global( machine, thom_cart_nb_banks );
+ state_save_register_global( machine, thom_cart_bank );
+ state_save_register_global( machine, to7_lightpen );
+ state_save_register_global( machine, to7_lightpen_step );
+ state_save_register_global( machine, mo5_reg_cart );
+ state_save_register_global_pointer( machine, (mem + 0x10000), 0x10000 );
+ machine.save().register_postload(save_prepost_delegate(FUNC(mo5_update_cart_bank_postload), &machine));
+}
+
+
+
+/***************************** TO9 *************************/
+
+
+
+/* ------------ IEEE extension ------------ */
+
+
+
+/* TODO: figure out what this extension is... IEEE-488 ??? */
+
+
+
+WRITE8_HANDLER ( to9_ieee_w )
+{
+ logerror( "$%04x %f to9_ieee_w: unhandled write $%02X to register %i\n", cpu_get_previouspc(space->machine().device("maincpu")), space->machine().time().as_double(), data, offset );
+}
+
+
+
+READ8_HANDLER ( to9_ieee_r )
+{
+ logerror( "$%04x %f to9_ieee_r: unhandled read from register %i\n", cpu_get_previouspc(space->machine().device("maincpu")), space->machine().time().as_double(), offset );
+ return 0;
+}
+
+
+
+/* ------------ system gate-array ------------ */
+
+
+
+#define TO9_LIGHTPEN_DECAL 8
+
+
+
+READ8_HANDLER ( to9_gatearray_r )
+{
+ struct thom_vsignal v = thom_get_vsignal(space->machine());
+ struct thom_vsignal l = thom_get_lightpen_vsignal( space->machine(), TO9_LIGHTPEN_DECAL, to7_lightpen_step - 1, 0 );
+ int count, inil, init, lt3;
+ count = to7_lightpen ? l.count : v.count;
+ inil = to7_lightpen ? l.inil : v.inil;
+ init = to7_lightpen ? l.init : v.init;
+ lt3 = to7_lightpen ? l.lt3 : v.lt3;
+
+ switch ( offset )
+ {
+ case 0: return (count >> 8) & 0xff;
+ case 1: return count & 0xff;
+ case 2: return (lt3 << 7) | (inil << 6);
+ case 3: return (v.init << 7) | (init << 6); /* != TO7/70 */
+ default:
+ logerror( "$%04x to9_gatearray_r: invalid offset %i\n", cpu_get_previouspc(space->machine().device("maincpu")), offset );
+ return 0;
+ }
+}
+
+
+
+WRITE8_HANDLER ( to9_gatearray_w )
+{
+ if ( ! offset )
+ to7_lightpen = data & 1;
+}
+
+
+
+/* ------------ video gate-array ------------ */
+
+
+
+static UINT8 to9_palette_data[32];
+
+static UINT8 to9_palette_idx;
+
+
+/* style: 0 => TO9, 1 => TO8/TO9, 2 => MO6 */
+static void to9_set_video_mode( running_machine &machine, UINT8 data, int style )
+{
+ switch ( data & 0x7f )
+ {
+ case 0x00:
+ if ( style == 2 )
+ thom_set_video_mode( machine, THOM_VMODE_MO5 );
+ else if ( style == 1 )
+ thom_set_video_mode( machine, THOM_VMODE_TO770 );
+ else
+ thom_set_video_mode( machine, THOM_VMODE_TO9 );
+ break;
+
+ case 0x21: thom_set_video_mode( machine, THOM_VMODE_BITMAP4 ); break;
+
+ case 0x41: thom_set_video_mode( machine, THOM_VMODE_BITMAP4_ALT ); break;
+
+ case 0x2a:
+ if ( style==0 )
+ thom_set_video_mode( machine, THOM_VMODE_80_TO9 );
+ else
+ thom_set_video_mode( machine, THOM_VMODE_80 );
+ break;
+
+ case 0x7b: thom_set_video_mode( machine, THOM_VMODE_BITMAP16 ); break;
+
+ case 0x24: thom_set_video_mode( machine, THOM_VMODE_PAGE1 ); break;
+
+ case 0x25: thom_set_video_mode( machine, THOM_VMODE_PAGE2 ); break;
+
+ case 0x26: thom_set_video_mode( machine, THOM_VMODE_OVERLAY ); break;
+
+ case 0x3f: thom_set_video_mode( machine, THOM_VMODE_OVERLAY3 ); break;
+
+ default:
+ logerror( "to9_set_video_mode: unknown mode $%02X tr=%i phi=%i mod=%i\n", data, (data >> 5) & 3, (data >> 3) & 2, data & 7 );
+ }
+}
+
+
+
+READ8_HANDLER ( to9_vreg_r )
+{
+ switch ( offset )
+ {
+
+ case 0: /* palette data */
+ {
+ UINT8 c = to9_palette_data[ to9_palette_idx ];
+ if ( !space->debugger_access() )
+ {
+ to9_palette_idx = ( to9_palette_idx + 1 ) & 31;
+ }
+ return c;
+ }
+
+ case 1: /* palette address */
+ return to9_palette_idx;
+
+ case 2:
+ case 3:
+ return 0;
+
+ default:
+ logerror( "to9_vreg_r: invalid read offset %i\n", offset );
+ return 0;
+ }
+}
+
+
+
+WRITE8_HANDLER ( to9_vreg_w )
+{
+ LOG_VIDEO(( "$%04x %f to9_vreg_w: off=%i ($%04X) data=$%02X\n", cpu_get_previouspc(space->machine().device("maincpu")), space->machine().time().as_double(), offset, 0xe7da + offset, data ));
+
+ switch ( offset )
+ {
+
+ case 0: /* palette data */
+ {
+ UINT16 color, idx;
+ to9_palette_data[ to9_palette_idx ] = data;
+ idx = to9_palette_idx / 2;
+ color = to9_palette_data[ 2 * idx + 1 ];
+ color = to9_palette_data[ 2 * idx ] | (color << 8);
+ thom_set_palette( space->machine(), idx ^ 8, color & 0x1fff );
+
+ to9_palette_idx = ( to9_palette_idx + 1 ) & 31;
+ }
+ break;
+
+ case 1: /* palette address */
+ to9_palette_idx = data & 31;
+ break;
+
+ case 2: /* video mode */
+ to9_set_video_mode( space->machine(), data, 0 );
+ break;
+
+ case 3: /* border color */
+ thom_set_border_color( space->machine(), data & 15 );
+ break;
+
+ default:
+ logerror( "to9_vreg_w: invalid write offset %i data=$%02X\n", offset, data );
+ }
+}
+
+
+
+static void to9_palette_init ( running_machine &machine )
+{
+ to9_palette_idx = 0;
+ memset( to9_palette_data, 0, sizeof( to9_palette_data ) );
+ state_save_register_global( machine, to9_palette_idx );
+ state_save_register_global_array( machine, to9_palette_data );
+}
+
+
+
+/* ------------ RAM / ROM banking ------------ */
+
+
+static UINT8 to9_soft_bank;
+
+
+static void to9_update_cart_bank(running_machine &machine)
+{
+ address_space* space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ int bank = 0;
+ int slot = ( mc6846_get_output_port(machine.device("mc6846")) >> 4 ) & 3; /* bits 4-5: ROM bank */
+
+ switch ( slot )
+ {
+ case 0:
+ /* BASIC (64 KB) */
+ bank = 4 + to9_soft_bank;
+ if ( bank != old_cart_bank )
+ {
+ if ( old_cart_bank < 4)
+ {
+ space->install_read_bank( 0x0000, 0x3fff, THOM_CART_BANK );
+ }
+ LOG_BANK(( "to9_update_cart_bank: CART is BASIC bank %i\n", to9_soft_bank ));
+ }
+ break;
+ case 1:
+ /* software 1 (32 KB) */
+ bank = 8 + (to9_soft_bank & 1);
+ if ( bank != old_cart_bank )
+ {
+ if ( old_cart_bank < 4)
+ {
+ space->install_read_bank( 0x0000, 0x3fff, THOM_CART_BANK );
+ }
+ LOG_BANK(( "to9_update_cart_bank: CART is software 1 bank %i\n", to9_soft_bank ));
+ }
+ break;
+ case 2:
+ /* software 2 (32 KB) */
+ bank = 10 + (to9_soft_bank & 1);
+ if ( bank != old_cart_bank )
+ {
+ if ( old_cart_bank < 4)
+ {
+ space->install_read_bank( 0x0000, 0x3fff, THOM_CART_BANK );
+ }
+ LOG_BANK(( "to9_update_cart_bank: CART is software 2 bank %i\n", to9_soft_bank ));
+ }
+ break;
+ case 3:
+ /* external cartridge */
+ if ( thom_cart_nb_banks )
+ {
+ bank = thom_cart_bank % thom_cart_nb_banks;
+ if ( bank != old_cart_bank )
+ {
+ if ( old_cart_bank < 0 || old_cart_bank > 3 )
+ {
+ space->install_read_bank( 0x0000, 0x3fff, THOM_CART_BANK );
+ space->install_legacy_write_handler( 0x0000, 0x3fff, FUNC(to9_cartridge_w) );
+ space->install_legacy_read_handler( 0x0000, 0x0003, FUNC(to9_cartridge_r) );
+ }
+ LOG_BANK(( "to9_update_cart_bank: CART is cartridge bank %i\n", thom_cart_bank ));
+ }
+ } else
+ if ( old_cart_bank != 0 )
+ {
+ space->nop_read( 0x0000, 0x3fff);
+ LOG_BANK(( "to9_update_cart_bank: CART is unmapped\n"));
+ }
+ break;
+ }
+ if ( bank != old_cart_bank )
+ {
+ machine.root_device().membank( THOM_CART_BANK )->set_entry( bank );
+ old_cart_bank = bank;
+ }
+}
+
+
+
+static void to9_update_cart_bank_postload(running_machine *machine)
+{
+ to9_update_cart_bank(*machine);
+}
+
+
+
+/* write signal to 0000-1fff generates a bank switch */
+WRITE8_HANDLER ( to9_cartridge_w )
+{
+ int slot = ( mc6846_get_output_port(space->machine().device("mc6846")) >> 4 ) & 3; /* bits 4-5: ROM bank */
+
+ if ( offset >= 0x2000 )
+ return;
+
+ if ( slot == 3 )
+ thom_cart_bank = offset & 3;
+ else
+ to9_soft_bank = offset & 3;
+ to9_update_cart_bank(space->machine());
+}
+
+
+
+/* read signal to 0000-0003 generates a bank switch */
+READ8_HANDLER ( to9_cartridge_r )
+{
+ UINT8* pos = space->machine().root_device().memregion( "maincpu" )->base() + 0x10000;
+ UINT8 data = pos[offset + (thom_cart_bank % thom_cart_nb_banks) * 0x4000];
+ if ( !space->debugger_access() )
+ {
+ thom_cart_bank = offset & 3;
+ to9_update_cart_bank(space->machine());
+ }
+ return data;
+}
+
+
+
+static void to9_update_ram_bank (running_machine &machine)
+{
+ pia6821_device *sys_pia = machine.device<pia6821_device>(THOM_PIA_SYS );
+ address_space* space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ UINT8 port = mc6846_get_output_port(machine.device("mc6846"));
+ UINT8 portb = sys_pia->port_b_z_mask();
+ UINT8 disk = ((port >> 2) & 1) | ((port >> 5) & 2); /* bits 6,2: RAM bank */
+ int bank;
+
+ switch ( portb & 0xf8 )
+ {
+ /* TO7/70 compatible */
+ case 0xf0: bank = 0; break;
+ case 0xe8: bank = 1; break;
+ case 0x18: bank = 2; break;
+ case 0x98: bank = 3; break;
+ case 0x58: bank = 4; break;
+ case 0xd8: bank = 5; break;
+
+ /* 64 KB of virtual disk */
+ case 0xf8: bank = 6 + disk ; break;
+
+ /* none selected */
+ case 0: return;
+
+ default:
+ logerror( "to9_update_ram_bank: unknown RAM bank pia=$%02X disk=%i\n", portb & 0xf8, disk );
+ return;
+ }
+
+ if ( old_ram_bank != bank )
+ {
+ if ( machine.device<ram_device>(RAM_TAG)->size() == 192*1024 || bank < 6 )
+ {
+ machine.root_device().membank( THOM_RAM_BANK )->set_entry( bank );
+ }
+ else
+ {
+ space->nop_readwrite( 0xa000, 0xdfff);
+ }
+ old_ram_bank = bank;
+ LOG_BANK(( "to9_update_ram_bank: bank %i selected (pia=$%02X disk=%i)\n", bank, portb & 0xf8, disk ));
+ }
+}
+
+
+
+static void to9_update_ram_bank_postload(running_machine *machine)
+{
+ to9_update_ram_bank(*machine);
+}
+
+
+
+/* ------------ keyboard (6850 ACIA + 6805 CPU) ------------ */
+
+/* The 6805 chip scans the keyboard and sends ASCII codes to the 6909.
+ Data between the 6809 and 6805 is serialized at 9600 bauds.
+ On the 6809 side, a 6850 ACIA is used.
+ We do not emulate the seral line but pass bytes directly between the
+ keyboard and the 6850 registers.
+ Note that the keyboard protocol uses the parity bit as an extra data bit.
+*/
+
+
+
+/* normal mode: polling interval */
+#define TO9_KBD_POLL_PERIOD attotime::from_msec( 10 )
+
+/* peripherial mode: time between two bytes, and after last byte */
+#define TO9_KBD_BYTE_SPACE attotime::from_usec( 300 )
+#define TO9_KBD_END_SPACE attotime::from_usec( 9100 )
+
+/* first and subsequent repeat periods, in TO9_KBD_POLL_PERIOD units */
+#define TO9_KBD_REPEAT_DELAY 80 /* 800 ms */
+#define TO9_KBD_REPEAT_PERIOD 7 /* 70 ms */
+
+
+
+static UINT8 to9_kbd_parity; /* 0=even, 1=odd, 2=no parity */
+static UINT8 to9_kbd_intr; /* interrupt mode */
+static UINT8 to9_kbd_in; /* data from keyboard */
+static UINT8 to9_kbd_status; /* status */
+static UINT8 to9_kbd_overrun; /* character lost */
+
+static UINT8 to9_kbd_periph; /* peripherial mode */
+static UINT8 to9_kbd_byte_count; /* byte-count in peripherial mode */
+static UINT16 to9_mouse_x, to9_mouse_y;
+
+static UINT8 to9_kbd_last_key; /* for key repetition */
+static UINT16 to9_kbd_key_count;
+
+static UINT8 to9_kbd_caps; /* caps-lock */
+static UINT8 to9_kbd_pad; /* keypad outputs special codes */
+
+static emu_timer* to9_kbd_timer;
+
+
+
+/* quick keyboard scan */
+static int to9_kbd_ktest ( running_machine &machine )
+{
+ int line, bit;
+ UINT8 port;
+ static const char *const keynames[] = {
+ "keyboard_0", "keyboard_1", "keyboard_2", "keyboard_3", "keyboard_4",
+ "keyboard_5", "keyboard_6", "keyboard_7", "keyboard_8", "keyboard_9"
+ };
+
+ for ( line = 0; line < 10; line++ )
+ {
+ port = machine.root_device().ioport(keynames[line])->read();
+
+ if ( line == 7 || line == 9 )
+ port |= 1; /* shift & control */
+
+ for ( bit = 0; bit < 8; bit++ )
+ {
+ if ( ! (port & (1 << bit)) )
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+
+static void to9_kbd_update_irq ( running_machine &machine )
+{
+ if ( (to9_kbd_intr & 4) && (to9_kbd_status & ACIA_6850_RDRF) )
+ to9_kbd_status |= ACIA_6850_irq; /* byte received interrupt */
+
+ if ( (to9_kbd_intr & 4) && (to9_kbd_status & ACIA_6850_OVRN) )
+ to9_kbd_status |= ACIA_6850_irq; /* overrun interrupt */
+
+ if ( (to9_kbd_intr & 3) == 1 && (to9_kbd_status & ACIA_6850_TDRE) )
+ to9_kbd_status |= ACIA_6850_irq; /* ready to transmit interrupt */
+
+ thom_irq_3( machine, to9_kbd_status & ACIA_6850_irq );
+}
+
+
+
+READ8_HANDLER ( to9_kbd_r )
+{
+ /* ACIA 6850 registers */
+
+ switch ( offset )
+ {
+
+ case 0: /* get status */
+ /* bit 0: data received */
+ /* bit 1: ready to transmit data (always 1) */
+ /* bit 2: data carrier detect (ignored) */
+ /* bit 3: clear to send (ignored) */
+ /* bit 4: framing error (ignored) */
+ /* bit 5: overrun */
+ /* bit 6: parity error */
+ /* bit 7: interrupt */
+
+ LOG_KBD(( "$%04x %f to9_kbd_r: status $%02X (rdrf=%i, tdre=%i, ovrn=%i, pe=%i, irq=%i)\n",
+ cpu_get_previouspc(space->machine().device("maincpu")), space->machine().time().as_double(), to9_kbd_status,
+ (to9_kbd_status & ACIA_6850_RDRF) ? 1 : 0,
+ (to9_kbd_status & ACIA_6850_TDRE) ? 1 : 0,
+ (to9_kbd_status & ACIA_6850_OVRN) ? 1 : 0,
+ (to9_kbd_status & ACIA_6850_PE) ? 1 : 0,
+ (to9_kbd_status & ACIA_6850_irq) ? 1 : 0 ));
+ return to9_kbd_status;
+
+ case 1: /* get input data */
+ if ( !space->debugger_access() )
+ {
+ to9_kbd_status &= ~(ACIA_6850_irq | ACIA_6850_PE);
+ if ( to9_kbd_overrun )
+ to9_kbd_status |= ACIA_6850_OVRN;
+ else
+ to9_kbd_status &= ~(ACIA_6850_OVRN | ACIA_6850_RDRF);
+ to9_kbd_overrun = 0;
+ LOG_KBD(( "$%04x %f to9_kbd_r: read data $%02X\n", cpu_get_previouspc(space->machine().device("maincpu")), space->machine().time().as_double(), to9_kbd_in ));
+ to9_kbd_update_irq(space->machine());
+ }
+ return to9_kbd_in;
+
+ default:
+ logerror( "$%04x to9_kbd_r: invalid offset %i\n", cpu_get_previouspc(space->machine().device("maincpu")), offset );
+ return 0;
+ }
+}
+
+
+
+WRITE8_HANDLER ( to9_kbd_w )
+{
+ /* ACIA 6850 registers */
+
+ switch ( offset )
+ {
+
+ case 0: /* set control */
+ /* bits 0-1: clock divide (ignored) or reset */
+ if ( (data & 3) == 3 )
+ {
+ /* reset */
+ to9_kbd_overrun = 0;
+ to9_kbd_status = ACIA_6850_TDRE;
+ to9_kbd_intr = 0;
+ LOG_KBD(( "$%04x %f to9_kbd_w: reset (data=$%02X)\n", cpu_get_previouspc(space->machine().device("maincpu")), space->machine().time().as_double(), data ));
+ }
+ else
+ {
+ /* bits 2-4: parity */
+ if ( (data & 0x18) == 0x10 )
+ to9_kbd_parity = 2;
+ else
+ to9_kbd_parity = (data >> 2) & 1;
+ /* bits 5-6: interrupt on transmit */
+ /* bit 7: interrupt on receive */
+ to9_kbd_intr = data >> 5;
+
+ LOG_KBD(( "$%04x %f to9_kbd_w: set control to $%02X (parity=%i, intr in=%i out=%i)\n",
+ cpu_get_previouspc(space->machine().device("maincpu")), space->machine().time().as_double(),
+ data, to9_kbd_parity, to9_kbd_intr >> 2,
+ (to9_kbd_intr & 3) ? 1 : 0 ));
+ }
+ to9_kbd_update_irq(space->machine());
+ break;
+
+ case 1: /* output data */
+ to9_kbd_status &= ~(ACIA_6850_irq | ACIA_6850_TDRE);
+ to9_kbd_update_irq(space->machine());
+ /* TODO: 1 ms delay here ? */
+ to9_kbd_status |= ACIA_6850_TDRE; /* data transmit ready again */
+ to9_kbd_update_irq(space->machine());
+
+ switch ( data )
+ {
+ case 0xF8:
+ /* reset */
+ to9_kbd_caps = 1;
+ to9_kbd_periph = 0;
+ to9_kbd_pad = 0;
+ break;
+
+ case 0xF9: to9_kbd_caps = 1; break;
+ case 0xFA: to9_kbd_caps = 0; break;
+ case 0xFB: to9_kbd_pad = 1; break;
+ case 0xFC: to9_kbd_pad = 0; break;
+ case 0xFD: to9_kbd_periph = 1; break;
+ case 0xFE: to9_kbd_periph = 0; break;
+
+ default:
+ logerror( "$%04x %f to9_kbd_w: unknown kbd command %02X\n", cpu_get_previouspc(space->machine().device("maincpu")), space->machine().time().as_double(), data );
+ }
+
+ thom_set_caps_led( space->machine(), !to9_kbd_caps );
+
+ LOG(( "$%04x %f to9_kbd_w: kbd command %02X (caps=%i, pad=%i, periph=%i)\n",
+ cpu_get_previouspc(space->machine().device("maincpu")), space->machine().time().as_double(), data,
+ to9_kbd_caps, to9_kbd_pad, to9_kbd_periph ));
+
+ break;
+
+ default:
+ logerror( "$%04x to9_kbd_w: invalid offset %i (data=$%02X) \n", cpu_get_previouspc(space->machine().device("maincpu")), offset, data );
+ }
+}
+
+
+
+/* send a key to the CPU, 8-bit + parity bit (0=even, 1=odd)
+ note: parity is not used as a checksum but to actually transmit a 9-th bit
+ of information!
+*/
+static void to9_kbd_send ( running_machine &machine, UINT8 data, int parity )
+{
+ if ( to9_kbd_status & ACIA_6850_RDRF )
+ {
+ /* overrun will be set when the current valid byte is read */
+ to9_kbd_overrun = 1;
+ LOG_KBD(( "%f to9_kbd_send: overrun => drop data=$%02X, parity=%i\n", machine.time().as_double(), data, parity ));
+ }
+ else
+ {
+ /* valid byte */
+ to9_kbd_in = data;
+ to9_kbd_status |= ACIA_6850_RDRF; /* raise data received flag */
+ if ( to9_kbd_parity == 2 || to9_kbd_parity == parity )
+ to9_kbd_status &= ~ACIA_6850_PE; /* parity OK */
+ else
+ to9_kbd_status |= ACIA_6850_PE; /* parity error */
+ LOG_KBD(( "%f to9_kbd_send: data=$%02X, parity=%i, status=$%02X\n", machine.time().as_double(), data, parity, to9_kbd_status ));
+ }
+ to9_kbd_update_irq(machine);
+}
+
+
+
+/* keycode => TO9 code (extended ASCII), shifted and un-shifted */
+static const int to9_kbd_code[80][2] =
+{
+ { 145, 150 }, { '_', '6' }, { 'Y', 'Y' }, { 'H', 'H' },
+ { 11, 11 }, { 9, 9 }, { 30, 12 }, { 'N', 'N' },
+
+ { 146, 151 }, { '(', '5' }, { 'T', 'T' }, { 'G', 'G' },
+ { '=', '+' }, { 8, 8 }, { 28, 28 }, { 'B', 'B' },
+
+ { 147, 152 }, { '\'', '4' }, { 'R', 'R' }, { 'F', 'F' },
+ { 22, 22 }, { 155, 155 }, { 29, 127 }, { 'V', 'V' },
+
+ { 148, 153 }, { '"', '3' }, { 'E', 'E' }, { 'D', 'D' },
+ { 161, 161 }, { 158, 158 },
+ { 154, 154 }, { 'C', 'C' },
+
+ { 144, 149 }, { 128, '2' }, { 'Z', 'Z' }, { 'S', 'S' },
+ { 162, 162 }, { 156, 156 },
+ { 164, 164 }, { 'X', 'X' },
+
+ { '#', '@' }, { '*', '1' }, { 'A', 'A' }, { 'Q', 'Q' },
+ { '[', '{' }, { 159, 159 }, { 160, 160 }, { 'W', 'W' },
+
+ { 2, 2 }, { 129, '7' }, { 'U', 'U' }, { 'J', 'J' },
+ { ' ', ' ' }, { 163, 163 }, { 165, 165 },
+ { ',', '?' },
+
+ { 0, 0 }, { '!', '8' }, { 'I', 'I' }, { 'K', 'K' },
+ { '$', '&' }, { 10, 10 }, { ']', '}' }, { ';', '.' },
+
+ { 0, 0 }, { 130, '9' }, { 'O', 'O' }, { 'L', 'L' },
+ { '-', '\\' }, { 132, '%' }, { 13, 13 }, { ':', '/' },
+
+ { 0, 0 }, { 131, '0' }, { 'P', 'P' }, { 'M', 'M' },
+ { ')', 134 }, { '^', 133 }, { 157, 157 }, { '>', '<' }
+};
+
+
+
+/* returns the ASCII code for the key, or 0 for no key */
+static int to9_kbd_get_key( running_machine &machine )
+{
+ int control = ! (machine.root_device().ioport("keyboard_7")->read() & 1);
+ int shift = ! (machine.root_device().ioport("keyboard_9")->read() & 1);
+ int key = -1, line, bit;
+ UINT8 port;
+ static const char *const keynames[] = {
+ "keyboard_0", "keyboard_1", "keyboard_2", "keyboard_3", "keyboard_4",
+ "keyboard_5", "keyboard_6", "keyboard_7", "keyboard_8", "keyboard_9"
+ };
+
+ for ( line = 0; line < 10; line++ )
+ {
+ port = machine.root_device().ioport(keynames[line])->read();
+
+ if ( line == 7 || line == 9 )
+ port |= 1; /* shift & control */
+
+ /* TODO: correct handling of simultaneous keystokes:
+ return the new key preferably & disable repeat
+ */
+ for ( bit = 0; bit < 8; bit++ )
+ {
+ if ( ! (port & (1 << bit)) )
+ key = line * 8 + bit;
+ }
+ }
+
+ if ( key == -1 )
+ {
+ to9_kbd_last_key = 0xff;
+ to9_kbd_key_count = 0;
+ return 0;
+ }
+ else if ( key == 64 )
+ {
+ /* caps lock */
+ if ( to9_kbd_last_key == key )
+ return 0; /* no repeat */
+
+ to9_kbd_last_key = key;
+ to9_kbd_caps = !to9_kbd_caps;
+ thom_set_caps_led( machine, !to9_kbd_caps );
+ return 0;
+ }
+ else
+ {
+ int asc;
+ asc = to9_kbd_code[key][shift];
+ if ( ! asc ) return 0;
+
+ /* keypad */
+ if ( ! to9_kbd_pad ) {
+ if ( asc >= 154 && asc <= 163 )
+ asc += '0' - 154;
+ else if ( asc == 164 )
+ asc = '.';
+ else if ( asc == 165 )
+ asc = 13;
+ }
+
+ /* shifted letter */
+ if ( asc >= 'A' && asc <= 'Z' && ( ! to9_kbd_caps ) && ( ! shift ) )
+ asc += 'a' - 'A';
+
+ /* control */
+ if ( control )
+ asc &= ~0x40;
+
+ if ( key == to9_kbd_last_key )
+ {
+ /* repeat */
+ to9_kbd_key_count++;
+ if ( to9_kbd_key_count < TO9_KBD_REPEAT_DELAY || (to9_kbd_key_count - TO9_KBD_REPEAT_DELAY) % TO9_KBD_REPEAT_PERIOD )
+ return 0;
+ LOG_KBD(( "to9_kbd_get_key: repeat key $%02X '%c'\n", asc, asc ));
+ return asc;
+ }
+ else {
+ to9_kbd_last_key = key;
+ to9_kbd_key_count = 0;
+ LOG_KBD(( "to9_kbd_get_key: key down $%02X '%c'\n", asc, asc ));
+ return asc;
+ }
+ }
+}
+
+
+
+static TIMER_CALLBACK(to9_kbd_timer_cb)
+{
+ if ( to9_kbd_periph )
+ {
+ /* peripherial mode: every 10 ms we send 4 bytes */
+
+ switch ( to9_kbd_byte_count )
+ {
+
+ case 0: /* key */
+ to9_kbd_send( machine, to9_kbd_get_key(machine), 0 );
+ break;
+
+ case 1: /* x axis */
+ {
+ int newx = machine.root_device().ioport("mouse_x")->read();
+ UINT8 data = ( (newx - to9_mouse_x) & 0xf ) - 8;
+ to9_kbd_send( machine, data, 1 );
+ to9_mouse_x = newx;
+ break;
+ }
+
+ case 2: /* y axis */
+ {
+ int newy = machine.root_device().ioport("mouse_y")->read();
+ UINT8 data = ( (newy - to9_mouse_y) & 0xf ) - 8;
+ to9_kbd_send( machine, data, 1 );
+ to9_mouse_y = newy;
+ break;
+ }
+
+ case 3: /* axis overflow & buttons */
+ {
+ int b = machine.root_device().ioport("mouse_button")->read();
+ UINT8 data = 0;
+ if ( b & 1 ) data |= 1;
+ if ( b & 2 ) data |= 4;
+ to9_kbd_send( machine, data, 1 );
+ break;
+ }
+
+ }
+
+ to9_kbd_byte_count = ( to9_kbd_byte_count + 1 ) & 3;
+ to9_kbd_timer->adjust(to9_kbd_byte_count ? TO9_KBD_BYTE_SPACE : TO9_KBD_END_SPACE);
+ }
+ else
+ {
+ int key = to9_kbd_get_key(machine);
+ /* keyboard mode: send a byte only if a key is down */
+ if ( key )
+ to9_kbd_send( machine, key, 0 );
+ to9_kbd_timer->adjust(TO9_KBD_POLL_PERIOD);
+ }
+}
+
+
+
+static void to9_kbd_reset ( running_machine &machine )
+{
+ LOG(( "to9_kbd_reset called\n" ));
+ to9_kbd_overrun = 0; /* no byte lost */
+ to9_kbd_status = ACIA_6850_TDRE; /* clear to transmit */
+ to9_kbd_intr = 0; /* interrupt disabled */
+ to9_kbd_caps = 1;
+ to9_kbd_periph = 0;
+ to9_kbd_pad = 0;
+ to9_kbd_byte_count = 0;
+ thom_set_caps_led( machine, !to9_kbd_caps );
+ to9_kbd_key_count = 0;
+ to9_kbd_last_key = 0xff;
+ to9_kbd_update_irq(machine);
+ to9_kbd_timer->adjust(TO9_KBD_POLL_PERIOD);
+}
+
+
+
+static void to9_kbd_init ( running_machine &machine )
+{
+ LOG(( "to9_kbd_init called\n" ));
+ to9_kbd_timer = machine.scheduler().timer_alloc(FUNC(to9_kbd_timer_cb));
+ state_save_register_global( machine, to9_kbd_parity );
+ state_save_register_global( machine, to9_kbd_intr );
+ state_save_register_global( machine, to9_kbd_in );
+ state_save_register_global( machine, to9_kbd_status );
+ state_save_register_global( machine, to9_kbd_overrun );
+ state_save_register_global( machine, to9_kbd_last_key );
+ state_save_register_global( machine, to9_kbd_key_count );
+ state_save_register_global( machine, to9_kbd_caps );
+ state_save_register_global( machine, to9_kbd_periph );
+ state_save_register_global( machine, to9_kbd_pad );
+ state_save_register_global( machine, to9_kbd_byte_count );
+ state_save_register_global( machine, to9_mouse_x );
+ state_save_register_global( machine, to9_mouse_y );
+}
+
+
+/* ------------ system PIA 6821 ------------ */
+
+/* afaik, P2-P7 are not connected, so, the warning about undefined 0xf0 can be safely ignored */
+
+
+static READ8_DEVICE_HANDLER ( to9_sys_porta_in )
+{
+ UINT8 ktest = to9_kbd_ktest(device->machine());
+
+ LOG_KBD(( "to9_sys_porta_in: ktest=%i\n", ktest ));
+
+ return ktest;
+}
+
+
+
+static WRITE8_DEVICE_HANDLER ( to9_sys_porta_out )
+{
+ centronics_device *printer = device->machine().device<centronics_device>("centronics");
+ printer->write(*device->machine().memory().first_space(), 0, data & 0xfe);
+}
+
+
+
+static WRITE8_DEVICE_HANDLER ( to9_sys_portb_out )
+{
+ centronics_device *printer = device->machine().device<centronics_device>("centronics");
+
+ printer->d0_w(BIT(data, 0));
+ printer->strobe_w(BIT(data, 1));
+
+ to9_update_ram_bank(device->machine());
+
+ if ( data & 4 ) /* bit 2: video overlay (TODO) */
+ LOG(( "to9_sys_portb_out: video overlay not handled\n" ));
+}
+
+
+
+const pia6821_interface to9_pia6821_sys =
+{
+ DEVCB_HANDLER(to9_sys_porta_in),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(to9_sys_porta_out),
+ DEVCB_HANDLER(to9_sys_portb_out),
+ DEVCB_HANDLER(to7_set_cassette_motor),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_LINE(thom_firq_1)
+};
+
+
+
+
+
+/* ------------ 6846 (timer, I/O) ------------ */
+
+
+
+static WRITE8_DEVICE_HANDLER ( to9_timer_port_out )
+{
+ thom_set_mode_point( device->machine(), data & 1 ); /* bit 0: video bank */
+ to9_update_ram_bank(device->machine());
+ to9_update_cart_bank(device->machine());
+}
+
+
+
+const mc6846_interface to9_timer =
+{
+ to9_timer_port_out, NULL, to7_timer_cp2_out,
+ to7_timer_port_in, to7_timer_tco_out,
+ thom_dev_irq_0
+};
+
+
+
+/* ------------ init / reset ------------ */
+
+
+
+MACHINE_RESET ( to9 )
+{
+ pia6821_device *sys_pia = machine.device<pia6821_device>(THOM_PIA_SYS );
+
+ LOG (( "to9: machine reset called\n" ));
+
+ /* subsystems */
+ thom_irq_reset(machine);
+ sys_pia->set_port_a_z_mask( 0xfe );
+ to7_game_reset(machine);
+ to9_floppy_reset(machine);
+ to9_kbd_reset(machine);
+ to7_modem_reset(machine);
+ to7_midi_reset(machine);
+
+ /* video */
+ thom_set_video_mode( machine, THOM_VMODE_TO9 );
+ thom_set_lightpen_callback( machine, 3, to7_lightpen_cb );
+ thom_set_border_color( machine, 8 );
+ thom_set_mode_point( machine, 0 );
+ sys_pia->cb1_w( 0 );
+
+ /* memory */
+ old_ram_bank = -1;
+ old_cart_bank = -1;
+ to9_soft_bank = 0;
+ to9_update_cart_bank(machine);
+ to9_update_ram_bank(machine);
+ /* thom_cart_bank not reset */
+
+ /* lightpen */
+ to7_lightpen = 0;
+}
+
+
+
+MACHINE_START ( to9 )
+{
+ UINT8* mem = machine.root_device().memregion("maincpu")->base();
+ UINT8* ram = machine.device<ram_device>(RAM_TAG)->pointer();
+
+ LOG (( "to9: machine start called\n" ));
+
+ /* subsystems */
+ thom_irq_init(machine);
+ to7_game_init(machine);
+ to9_floppy_init( machine, mem + 0xe000, mem + 0x40000 );
+ to9_kbd_init(machine);
+ to9_palette_init(machine);
+ to7_modem_init(machine);
+ to7_midi_init(machine);
+
+ /* memory */
+ thom_vram = ram;
+ thom_cart_bank = 0;
+ machine.root_device().membank( THOM_VRAM_BANK )->configure_entries( 0, 2, thom_vram, 0x2000 );
+ machine.root_device().membank( THOM_CART_BANK )->configure_entries( 0, 12, mem + 0x10000, 0x4000 );
+ machine.root_device().membank( THOM_BASE_BANK )->configure_entry( 0, ram + 0x4000);
+ machine.root_device().membank( THOM_RAM_BANK )->configure_entries( 0, 10, ram + 0x8000, 0x4000 );
+ machine.root_device().membank( THOM_VRAM_BANK )->set_entry( 0 );
+ machine.root_device().membank( THOM_CART_BANK )->set_entry( 0 );
+ machine.root_device().membank( THOM_BASE_BANK )->set_entry( 0 );
+ machine.root_device().membank( THOM_RAM_BANK )->set_entry( 0 );
+
+ /* save-state */
+ state_save_register_global( machine, thom_cart_nb_banks );
+ state_save_register_global( machine, thom_cart_bank );
+ state_save_register_global( machine, to7_lightpen );
+ state_save_register_global( machine, to7_lightpen_step );
+ state_save_register_global( machine, to9_soft_bank );
+ state_save_register_global_pointer( machine, (mem + 0x10000), 0x10000 );
+ machine.save().register_postload(save_prepost_delegate(FUNC(to9_update_ram_bank_postload), &machine));
+ machine.save().register_postload(save_prepost_delegate(FUNC(to9_update_cart_bank_postload), &machine));
+}
+
+
+
+/***************************** TO8 *************************/
+
+
+
+UINT8 to8_data_vpage;
+UINT8 to8_cart_vpage;
+
+
+
+/* ------------ keyboard (6804) ------------ */
+
+/* The 6804 chip scans the keyboard and sends keycodes to the 6809.
+ Data is serialized using variable pulse length encoding.
+ Unlike the TO9, there is no decoding chip on the 6809 side, only
+ 1-bit PIA ports (6821 & 6846). The 6809 does the decoding.
+
+ We do not emulate the 6804 but pass serialized data directly through the
+ PIA ports.
+
+ Note: if we conform to the (scarce) documentation the CPU tend to lock
+ waitting for keyboard input.
+ The protocol documentation is pretty scarce and does not account for these
+ behaviors!
+ The emulation code contains many hacks (delays, timeouts, spurious
+ pulses) to improve the stability.
+ This works well, but is not very accurate.
+*/
+
+
+
+/* polling interval */
+#define TO8_KBD_POLL_PERIOD attotime::from_msec( 1 )
+
+/* first and subsequent repeat periods, in TO8_KBD_POLL_PERIOD units */
+#define TO8_KBD_REPEAT_DELAY 800 /* 800 ms */
+#define TO8_KBD_REPEAT_PERIOD 70 /* 70 ms */
+
+/* timeout waiting for CPU */
+#define TO8_KBD_TIMEOUT attotime::from_msec( 100 )
+
+
+
+/* state */
+static UINT8 to8_kbd_ack; /* 1 = cpu inits / accepts transfers */
+static UINT16 to8_kbd_data; /* data to transmit */
+static UINT16 to8_kbd_step; /* transmission automaton state */
+static UINT8 to8_kbd_last_key; /* last key (for repetition) */
+static UINT32 to8_kbd_key_count; /* keypress time (for repetition) */
+static UINT8 to8_kbd_caps; /* caps lock */
+
+static emu_timer* to8_kbd_timer; /* bit-send */
+static emu_timer* to8_kbd_signal; /* signal from CPU */
+
+
+
+/* quick keyboard scan */
+static int to8_kbd_ktest ( running_machine &machine )
+{
+ int line, bit;
+ UINT8 port;
+ static const char *const keynames[] = {
+ "keyboard_0", "keyboard_1", "keyboard_2", "keyboard_3", "keyboard_4",
+ "keyboard_5", "keyboard_6", "keyboard_7", "keyboard_8", "keyboard_9"
+ };
+
+ if ( machine.root_device().ioport("config")->read() & 2 )
+ return 0; /* disabled */
+
+ for ( line = 0; line < 10; line++ )
+ {
+ port = machine.root_device().ioport(keynames[line])->read();
+
+ if ( line == 7 || line == 9 )
+ port |= 1; /* shift & control */
+
+ for ( bit = 0; bit < 8; bit++ )
+ {
+ if ( ! (port & (1 << bit)) )
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+
+/* keyboard scan & return keycode (or -1) */
+static int to8_kbd_get_key( running_machine &machine )
+{
+ int control = (machine.root_device().ioport("keyboard_7")->read() & 1) ? 0 : 0x100;
+ int shift = (machine.root_device().ioport("keyboard_9")->read() & 1) ? 0 : 0x080;
+ int key = -1, line, bit;
+ UINT8 port;
+ static const char *const keynames[] = {
+ "keyboard_0", "keyboard_1", "keyboard_2", "keyboard_3", "keyboard_4",
+ "keyboard_5", "keyboard_6", "keyboard_7", "keyboard_8", "keyboard_9"
+ };
+
+ if ( machine.root_device().ioport("config")->read() & 2 )
+ return -1; /* disabled */
+
+ for ( line = 0; line < 10; line++ )
+ {
+ port = machine.root_device().ioport(keynames[line])->read();
+
+ if ( line == 7 || line == 9 )
+ port |= 1; /* shift & control */
+
+ /* TODO: correct handling of simultaneous keystokes:
+ return the new key preferably & disable repeat
+ */
+ for ( bit = 0; bit < 8; bit++ )
+ {
+ if ( ! (port & (1 << bit)) )
+ key = line * 8 + bit;
+ }
+ }
+
+ if ( key == -1 )
+ {
+ to8_kbd_last_key = 0xff;
+ to8_kbd_key_count = 0;
+ return -1;
+ }
+ else if ( key == 64 )
+ {
+ /* caps lock */
+ if ( to8_kbd_last_key == key )
+ return -1; /* no repeat */
+ to8_kbd_last_key = key;
+ to8_kbd_caps = !to8_kbd_caps;
+ if ( to8_kbd_caps )
+ key |= 0x080; /* auto-shift */
+ thom_set_caps_led( machine, !to8_kbd_caps );
+ return key;
+ }
+ else if ( key == to8_kbd_last_key )
+ {
+ /* repeat */
+ to8_kbd_key_count++;
+ if ( to8_kbd_key_count < TO8_KBD_REPEAT_DELAY || (to8_kbd_key_count - TO8_KBD_REPEAT_DELAY) % TO8_KBD_REPEAT_PERIOD )
+ return -1;
+ return key | shift | control;
+ }
+ else
+ {
+ to8_kbd_last_key = key;
+ to8_kbd_key_count = 0;
+ return key | shift | control;
+ }
+}
+
+
+/* steps:
+ 0 = idle, key polling
+ 1 = wait for ack to go down (key to send)
+ 99-117 = key data transmit
+ 91-117 = signal
+ 255 = timeout
+*/
+
+/* keyboard automaton */
+static void to8_kbd_timer_func(running_machine &machine)
+{
+ attotime d;
+
+ LOG_KBD(( "%f to8_kbd_timer_cb: step=%i ack=%i data=$%03X\n", machine.time().as_double(), to8_kbd_step, to8_kbd_ack, to8_kbd_data ));
+
+ if( ! to8_kbd_step )
+ {
+ /* key polling */
+ int k = to8_kbd_get_key(machine);
+ /* if not in transfer, send pulse from time to time
+ (helps avoiding CPU lock)
+ */
+ if ( ! to8_kbd_ack )
+ mc6846_set_input_cp1( machine.device("mc6846"), 0 );
+ mc6846_set_input_cp1( machine.device("mc6846"), 1 );
+
+ if ( k == -1 )
+ d = TO8_KBD_POLL_PERIOD;
+ else
+ {
+ /* got key! */
+ LOG_KBD(( "to8_kbd_timer_cb: got key $%03X\n", k ));
+ to8_kbd_data = k;
+ to8_kbd_step = 1;
+ d = attotime::from_usec( 100 );
+ }
+ }
+ else if ( to8_kbd_step == 255 )
+ {
+ /* timeout */
+ to8_kbd_last_key = 0xff;
+ to8_kbd_key_count = 0;
+ to8_kbd_step = 0;
+ mc6846_set_input_cp1( machine.device("mc6846"), 1 );
+ d = TO8_KBD_POLL_PERIOD;
+ }
+ else if ( to8_kbd_step == 1 )
+ {
+ /* schedule timeout waiting for ack to go down */
+ mc6846_set_input_cp1( machine.device("mc6846"), 0 );
+ to8_kbd_step = 255;
+ d = TO8_KBD_TIMEOUT;
+ }
+ else if ( to8_kbd_step == 117 )
+ {
+ /* schedule timeout waiting for ack to go up */
+ mc6846_set_input_cp1( machine.device("mc6846"), 0 );
+ to8_kbd_step = 255;
+ d = TO8_KBD_TIMEOUT;
+ }
+ else if ( to8_kbd_step & 1 )
+ {
+ /* send silence between bits */
+ mc6846_set_input_cp1( machine.device("mc6846"), 0 );
+ d = attotime::from_usec( 100 );
+ to8_kbd_step++;
+ }
+ else
+ {
+ /* send bit */
+ int bpos = 8 - ( (to8_kbd_step - 100) / 2);
+ int bit = (to8_kbd_data >> bpos) & 1;
+ mc6846_set_input_cp1( machine.device("mc6846"), 1 );
+ d = attotime::from_usec( bit ? 56 : 38 );
+ to8_kbd_step++;
+ }
+ to8_kbd_timer->adjust(d);
+}
+
+
+
+static TIMER_CALLBACK(to8_kbd_timer_cb)
+{
+ to8_kbd_timer_func(machine);
+}
+
+
+
+/* cpu <-> keyboard hand-check */
+static void to8_kbd_set_ack ( running_machine &machine, int data )
+{
+ if ( data == to8_kbd_ack )
+ return;
+ to8_kbd_ack = data;
+
+ if ( data )
+ {
+ double len = to8_kbd_signal->elapsed( ).as_double() * 1000. - 2.;
+ LOG_KBD(( "%f to8_kbd_set_ack: CPU end ack, len=%f\n", machine.time().as_double(), len ));
+ if ( to8_kbd_data == 0xfff )
+ {
+ /* end signal from CPU */
+ if ( len >= 0.6 && len <= 0.8 )
+ {
+ LOG (( "%f to8_kbd_set_ack: INIT signal\n", machine.time().as_double() ));
+ to8_kbd_last_key = 0xff;
+ to8_kbd_key_count = 0;
+ to8_kbd_caps = 1;
+ /* send back signal: TODO returned codes ? */
+ to8_kbd_data = 0;
+ to8_kbd_step = 0;
+ to8_kbd_timer->adjust(attotime::from_msec( 1 ));
+ }
+ else
+ {
+ to8_kbd_step = 0;
+ to8_kbd_timer->adjust(TO8_KBD_POLL_PERIOD);
+ if ( len >= 1.2 && len <= 1.4 )
+ {
+ LOG (( "%f to8_kbd_set_ack: CAPS on signal\n", machine.time().as_double() ));
+ to8_kbd_caps = 1;
+ }
+ else if ( len >= 1.8 && len <= 2.0 )
+ {
+ LOG (( "%f to8_kbd_set_ack: CAPS off signal\n", machine.time().as_double() ));
+ to8_kbd_caps = 0;
+ }
+ }
+ thom_set_caps_led( machine, !to8_kbd_caps );
+ }
+ else
+ {
+ /* end key transmission */
+ to8_kbd_step = 0;
+ to8_kbd_timer->adjust(TO8_KBD_POLL_PERIOD);
+ }
+ }
+
+ else
+ {
+ if ( to8_kbd_step == 255 )
+ {
+ /* CPU accepts key */
+ to8_kbd_step = 99;
+ to8_kbd_timer->adjust(attotime::from_usec( 400 ));
+ }
+ else
+ {
+ /* start signal from CPU */
+ to8_kbd_data = 0xfff;
+ to8_kbd_step = 91;
+ to8_kbd_timer->adjust(attotime::from_usec( 400 ));
+ to8_kbd_signal->adjust(attotime::never);
+ }
+ LOG_KBD(( "%f to8_kbd_set_ack: CPU ack, data=$%03X\n", machine.time().as_double(), to8_kbd_data ));
+ }
+}
+
+
+
+static void to8_kbd_reset ( running_machine &machine )
+{
+ to8_kbd_last_key = 0xff;
+ to8_kbd_key_count = 0;
+ to8_kbd_step = 0;
+ to8_kbd_data = 0;
+ to8_kbd_ack = 1;
+ to8_kbd_caps = 1;
+ thom_set_caps_led( machine, !to8_kbd_caps );
+ to8_kbd_timer_func(machine);
+}
+
+
+
+static void to8_kbd_init ( running_machine &machine )
+{
+ to8_kbd_timer = machine.scheduler().timer_alloc(FUNC(to8_kbd_timer_cb));
+ to8_kbd_signal = machine.scheduler().timer_alloc(FUNC_NULL);
+ state_save_register_global( machine, to8_kbd_ack );
+ state_save_register_global( machine, to8_kbd_data );
+ state_save_register_global( machine, to8_kbd_step );
+ state_save_register_global( machine, to8_kbd_last_key );
+ state_save_register_global( machine, to8_kbd_key_count );
+ state_save_register_global( machine, to8_kbd_caps );
+}
+
+
+
+/* ------------ RAM / ROM banking ------------ */
+
+static UINT8 to8_reg_ram;
+static UINT8 to8_reg_cart;
+static UINT8 to8_reg_sys1;
+static UINT8 to8_reg_sys2;
+static UINT8 to8_lightpen_intr;
+static UINT8 to8_soft_select;
+static UINT8 to8_soft_bank;
+static UINT8 to8_bios_bank;
+
+
+
+static void to8_update_floppy_bank( running_machine &machine )
+{
+ int bank = (to8_reg_sys1 & 0x80) ? to7_floppy_bank : (to8_bios_bank + TO7_NB_FLOP_BANK);
+
+ if ( bank != old_floppy_bank )
+ {
+ LOG_BANK(( "to8_update_floppy_bank: floppy ROM is %s bank %i\n",
+ (to8_reg_sys1 & 0x80) ? "external" : "internal",
+ bank % TO7_NB_FLOP_BANK ));
+ machine.root_device().membank( THOM_FLOP_BANK )->set_entry( bank );
+ old_floppy_bank = bank;
+ }
+}
+
+
+
+static void to8_update_floppy_bank_postload(running_machine *machine)
+{
+ to8_update_floppy_bank(*machine);
+}
+
+
+
+static void to8_update_ram_bank (running_machine &machine)
+{
+ pia6821_device *sys_pia = machine.device<pia6821_device>(THOM_PIA_SYS );
+ address_space* space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ UINT8 bank = 0;
+
+ if ( to8_reg_sys1 & 0x10 )
+ {
+ bank = to8_reg_ram & 31;
+ }
+ else
+ {
+ UINT8 portb = sys_pia->port_b_z_mask();
+
+ switch ( portb & 0xf8 )
+ {
+ /* in compatibility mode, banks 5 and 6 are reversed wrt TO7/70 */
+ case 0xf0: bank = 2; break;
+ case 0xe8: bank = 3; break;
+ case 0x18: bank = 4; break;
+ case 0x58: bank = 5; break;
+ case 0x98: bank = 6; break;
+ case 0xd8: bank = 7; break;
+ case 0xf8: return;
+ default:
+ logerror( "to8_update_ram_bank: unknown RAM bank=$%02X\n", portb & 0xf8 );
+ return;
+ }
+ }
+
+ /* due to addressing distortion, the 16 KB banked memory space is
+ split into two 8 KB spaces:
+ - 0xa000-0xbfff maps to 0x2000-0x3fff in 16 KB bank
+ - 0xc000-0xdfff maps to 0x0000-0x1fff in 16 KB bank
+ this is important if we map a bank that is also reachable by another,
+ undistorted space, such as cartridge, page 0 (video), or page 1
+ */
+ if ( bank != old_ram_bank)
+ {
+ if (machine.device<ram_device>(RAM_TAG)->size() == 512*1024 || to8_data_vpage < 16)
+ {
+ machine.root_device().membank( TO8_DATA_LO )->set_entry( bank );
+ machine.root_device().membank( TO8_DATA_HI )->set_entry( bank );
+ } else
+ {
+ /* RAM size is 256 KB only and unavailable
+ * bank requested */
+ space->nop_readwrite( 0xa000, 0xbfff);
+ space->nop_readwrite( 0xc000, 0xdfff);
+ }
+ to8_data_vpage = bank;
+ old_ram_bank = bank;
+ LOG_BANK(( "to8_update_ram_bank: select bank %i (%s style)\n", bank, (to8_reg_sys1 & 0x10) ? "new" : "old"));
+ }
+}
+
+
+
+static void to8_update_ram_bank_postload(running_machine *machine)
+{
+ to8_update_ram_bank(*machine);
+}
+
+
+
+static void to8_update_cart_bank (running_machine &machine)
+{
+ address_space* space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ int bank = 0;
+ int bank_is_read_only = 0;
+
+ if ( to8_reg_cart & 0x20 )
+ {
+ /* RAM space */
+ to8_cart_vpage = to8_reg_cart & 31;
+ bank = 8 + to8_cart_vpage;
+ bank_is_read_only = (( to8_reg_cart & 0x40 ) == 0);
+ if ( bank != old_cart_bank )
+ {
+ /* mapping to VRAM */
+ if (machine.device<ram_device>(RAM_TAG)->size() == 512*1024 || to8_cart_vpage < 16)
+ {
+ if (to8_cart_vpage < 4)
+ {
+ if (old_cart_bank < 8 || old_cart_bank > 11)
+ {
+ space->install_read_bank( 0x0000, 0x3fff, THOM_CART_BANK );
+ if ( bank_is_read_only )
+ {
+ space->nop_write( 0x0000, 0x3fff);
+ }
+ else
+ {
+ space->install_legacy_write_handler( 0x0000, 0x3fff, FUNC(to8_vcart_w));
+ }
+ }
+ }
+ else
+ {
+ if (old_cart_bank < 12)
+ {
+ if ( bank_is_read_only )
+ {
+ space->install_read_bank( 0x0000, 0x3fff, THOM_CART_BANK );
+ space->nop_write( 0x0000, 0x3fff);
+ }
+ else
+ {
+ space->install_readwrite_bank( 0x0000, 0x3fff,THOM_CART_BANK);
+ }
+ }
+ }
+ }
+ else
+ {
+ /* RAM size is 256 KB only and unavailable
+ * bank requested */
+ space->nop_readwrite( 0x0000, 0x3fff);
+ }
+ LOG_BANK(( "to8_update_cart_bank: CART is RAM bank %i (%s)\n",
+ to8_cart_vpage,
+ bank_is_read_only ? "read-only":"read-write"));
+ }
+ else
+ {
+ if ( bank_is_read_only != old_cart_bank_was_read_only )
+ {
+ if ( bank_is_read_only )
+ {
+ space->nop_write( 0x0000, 0x3fff);
+ }
+ else
+ {
+ if (to8_cart_vpage < 4)
+ {
+ space->install_legacy_write_handler( 0x0000, 0x3fff, FUNC(to8_vcart_w));
+ }
+ else
+ {
+ space->install_readwrite_bank( 0x0000, 0x3fff, THOM_CART_BANK );
+ }
+ }
+ LOG_BANK(( "to8_update_cart_bank: update CART bank %i write status to %s\n",
+ to8_cart_vpage,
+ bank_is_read_only ? "read-only":"read-write"));
+ }
+ }
+ old_cart_bank_was_read_only = bank_is_read_only;
+ }
+ else
+ {
+ if ( to8_soft_select )
+ {
+ /* internal software ROM space */
+ bank = 4 + to8_soft_bank;
+ if ( bank != old_cart_bank )
+ {
+ if ( old_cart_bank < 4 || old_cart_bank > 7 )
+ {
+ space->install_read_bank( 0x0000, 0x3fff, THOM_CART_BANK );
+ space->install_legacy_write_handler( 0x0000, 0x3fff, FUNC(to8_cartridge_w) );
+ }
+ LOG_BANK(( "to8_update_cart_bank: CART is internal bank %i\n", to8_soft_bank ));
+ }
+ }
+ else
+ {
+ /* external cartridge ROM space */
+ if ( thom_cart_nb_banks )
+ {
+ bank = thom_cart_bank % thom_cart_nb_banks;
+ if ( bank != old_cart_bank )
+ {
+ if ( old_cart_bank < 0 || old_cart_bank > 3 )
+ {
+ space->install_read_bank( 0x0000, 0x3fff, THOM_CART_BANK );
+ space->install_legacy_write_handler( 0x0000, 0x3fff, FUNC(to8_cartridge_w) );
+ space->install_legacy_read_handler( 0x0000, 0x0003, FUNC(to8_cartridge_r) );
+ }
+ LOG_BANK(( "to8_update_cart_bank: CART is external cartridge bank %i\n", bank ));
+ }
+ }
+ else
+ {
+ if ( old_cart_bank != 0 )
+ {
+ space->nop_read( 0x0000, 0x3fff);
+ LOG_BANK(( "to8_update_cart_bank: CART is unmapped\n"));
+ }
+ }
+ }
+ }
+ if ( bank != old_cart_bank )
+ {
+ machine.root_device().membank( THOM_CART_BANK )->set_entry( bank );
+ old_cart_bank = bank;
+ }
+}
+
+
+
+static void to8_update_cart_bank_postload(running_machine *machine)
+{
+ to8_update_cart_bank(*machine);
+}
+
+
+
+/* ROM bank switch */
+WRITE8_HANDLER ( to8_cartridge_w )
+{
+ if ( offset >= 0x2000 )
+ return;
+
+ if ( to8_soft_select )
+ to8_soft_bank = offset & 3;
+ else
+ thom_cart_bank = offset & 3;
+
+ to8_update_cart_bank(space->machine());
+}
+
+
+
+/* read signal to 0000-0003 generates a bank switch */
+READ8_HANDLER ( to8_cartridge_r )
+{
+ UINT8* pos = space->machine().root_device().memregion( "maincpu" )->base() + 0x10000;
+ UINT8 data = pos[offset + (thom_cart_bank % thom_cart_nb_banks) * 0x4000];
+ if ( !space->debugger_access() )
+ {
+ thom_cart_bank = offset & 3;
+ to8_update_cart_bank(space->machine());
+ }
+ return data;
+}
+
+
+/* ------------ floppy / network controller dispatch ------------ */
+
+
+
+static void to8_floppy_init( running_machine &machine )
+{
+ UINT8* mem = machine.root_device().memregion("maincpu")->base();
+ to7_floppy_init( machine, mem + 0x34000 );
+}
+
+
+
+static void to8_floppy_reset( running_machine &machine )
+{
+ UINT8* mem = machine.root_device().memregion("maincpu")->base();
+ to7_floppy_reset(machine);
+ if ( THOM_FLOPPY_INT )
+ thmfc_floppy_reset(machine);
+ machine.root_device().membank( THOM_FLOP_BANK )->configure_entries( TO7_NB_FLOP_BANK, 2, mem + 0x30000, 0x2000 );
+}
+
+
+
+READ8_HANDLER ( to8_floppy_r )
+{
+ if ( space->debugger_access() )
+ return 0;
+
+ if ( (to8_reg_sys1 & 0x80) && THOM_FLOPPY_EXT )
+ /* external controller */
+ return to7_floppy_r( space, offset );
+ else if ( ! (to8_reg_sys1 & 0x80) && THOM_FLOPPY_INT )
+ /* internal controller */
+ return thmfc_floppy_r( space, offset );
+ else
+ /* no controller */
+ return 0;
+}
+
+
+
+WRITE8_HANDLER ( to8_floppy_w )
+{
+ if ( (to8_reg_sys1 & 0x80) && THOM_FLOPPY_EXT )
+ /* external controller */
+ to7_floppy_w( space, offset, data );
+ else if ( ! (to8_reg_sys1 & 0x80) && THOM_FLOPPY_INT )
+ /* internal controller */
+ thmfc_floppy_w( space, offset, data );
+}
+
+
+
+/* ------------ system gate-array ------------ */
+
+
+
+#define TO8_LIGHTPEN_DECAL 16
+
+
+
+READ8_HANDLER ( to8_gatearray_r )
+{
+ struct thom_vsignal v = thom_get_vsignal(space->machine());
+ struct thom_vsignal l = thom_get_lightpen_vsignal( space->machine(), TO8_LIGHTPEN_DECAL, to7_lightpen_step - 1, 6 );
+ int count, inil, init, lt3;
+ UINT8 res;
+ count = to7_lightpen ? l.count : v.count;
+ inil = to7_lightpen ? l.inil : v.inil;
+ init = to7_lightpen ? l.init : v.init;
+ lt3 = to7_lightpen ? l.lt3 : v.lt3;
+
+ switch ( offset )
+ {
+
+ case 0: /* system 2 / lightpen register 1 */
+ if ( to7_lightpen )
+ res = (count >> 8) & 0xff;
+ else
+ res = to8_reg_sys2 & 0xf0;
+ break;
+
+ case 1: /* ram register / lightpen register 2 */
+ if ( to7_lightpen )
+ {
+ if ( !space->debugger_access() )
+ {
+ thom_firq_2( space->machine(), 0 );
+ to8_lightpen_intr = 0;
+ }
+ res = count & 0xff;
+ }
+ else
+ res = to8_reg_ram & 0x1f;
+ break;
+
+ case 2: /* cartrige register / lightpen register 3 */
+ if ( to7_lightpen )
+ res = (lt3 << 7) | (inil << 6);
+ else
+ res = to8_reg_cart;
+ break;
+
+ case 3: /* lightpen register 4 */
+ res = (v.init << 7) | (init << 6) | (v.inil << 5) | (to8_lightpen_intr << 1) | to7_lightpen;
+ break;
+
+ default:
+ logerror( "$%04x to8_gatearray_r: invalid offset %i\n", cpu_get_previouspc(space->machine().device("maincpu")), offset );
+ res = 0;
+ }
+
+ LOG_VIDEO(( "$%04x %f to8_gatearray_r: off=%i ($%04X) res=$%02X lightpen=%i\n",
+ cpu_get_previouspc(space->machine().device("maincpu")), space->machine().time().as_double(),
+ offset, 0xe7e4 + offset, res, to7_lightpen ));
+
+ return res;
+}
+
+
+
+WRITE8_HANDLER ( to8_gatearray_w )
+{
+ LOG_VIDEO(( "$%04x %f to8_gatearray_w: off=%i ($%04X) data=$%02X\n",
+ cpu_get_previouspc(space->machine().device("maincpu")), space->machine().time().as_double(),
+ offset, 0xe7e4 + offset, data ));
+
+ switch ( offset )
+ {
+
+ case 0: /* switch */
+ to7_lightpen = data & 1;
+ break;
+
+ case 1: /* ram register */
+ if ( to8_reg_sys1 & 0x10 )
+ {
+ to8_reg_ram = data;
+ to8_update_ram_bank(space->machine());
+ }
+ break;
+
+ case 2: /* cartridge register */
+ to8_reg_cart = data;
+ to8_update_cart_bank(space->machine());
+ break;
+
+ case 3: /* system register 1 */
+ to8_reg_sys1 = data;
+ to8_update_floppy_bank(space->machine());
+ to8_update_ram_bank(space->machine());
+ to8_update_cart_bank(space->machine());
+ break;
+
+ default:
+ logerror( "$%04x to8_gatearray_w: invalid offset %i (data=$%02X)\n",
+ cpu_get_previouspc(space->machine().device("maincpu")), offset, data );
+ }
+}
+
+
+
+/* ------------ video gate-array ------------ */
+
+
+
+READ8_HANDLER ( to8_vreg_r )
+{
+ /* 0xe7dc from external floppy drive aliases the video gate-array */
+ if ( ( offset == 3 ) && ( to8_reg_ram & 0x80 ) && ( to8_reg_sys1 & 0x80 ) )
+ {
+ if ( space->debugger_access() )
+ return 0;
+
+ if ( THOM_FLOPPY_EXT )
+ return to7_floppy_r( space, 0xc );
+ else
+ return 0;
+ }
+
+ switch ( offset )
+ {
+
+ case 0: /* palette data */
+ {
+ UINT8 c = to9_palette_data[ to9_palette_idx ];
+ if ( !space->debugger_access() )
+ {
+ to9_palette_idx = ( to9_palette_idx + 1 ) & 31;
+ }
+ return c;
+ }
+
+ case 1: /* palette address */
+ return to9_palette_idx;
+
+ case 2:
+ case 3:
+ return 0;
+
+ default:
+ logerror( "to8_vreg_r: invalid read offset %i\n", offset );
+ return 0;
+ }
+}
+
+
+
+WRITE8_HANDLER ( to8_vreg_w )
+{
+ LOG_VIDEO(( "$%04x %f to8_vreg_w: off=%i ($%04X) data=$%02X\n",
+ cpu_get_previouspc(space->machine().device("maincpu")), space->machine().time().as_double(),
+ offset, 0xe7da + offset, data ));
+
+ switch ( offset )
+ {
+
+ case 0: /* palette data */
+ {
+ UINT16 color, idx;
+ to9_palette_data[ to9_palette_idx ] = data;
+ idx = to9_palette_idx / 2;
+ color = to9_palette_data[ 2 * idx + 1 ];
+ color = to9_palette_data[ 2 * idx ] | (color << 8);
+ thom_set_palette( space->machine(), idx, color & 0x1fff );
+ to9_palette_idx = ( to9_palette_idx + 1 ) & 31;
+ }
+ break;
+
+ case 1: /* palette address */
+ to9_palette_idx = data & 31;
+ break;
+
+ case 2: /* display register */
+ to9_set_video_mode( space->machine(), data, 1 );
+ break;
+
+ case 3: /* system register 2 */
+ /* 0xe7dc from external floppy drive aliases the video gate-array */
+ if ( ( offset == 3 ) && ( to8_reg_ram & 0x80 ) && ( to8_reg_sys1 & 0x80 ) )
+ {
+ if ( THOM_FLOPPY_EXT )
+ to7_floppy_w( space, 0xc, data );
+ }
+ else
+ {
+ to8_reg_sys2 = data;
+ thom_set_video_page( space->machine(), data >> 6 );
+ thom_set_border_color( space->machine(), data & 15 );
+ }
+ break;
+
+ default:
+ logerror( "to8_vreg_w: invalid write offset %i data=$%02X\n", offset, data );
+ }
+}
+
+
+
+/* ------------ system PIA 6821 ------------ */
+
+
+
+static READ8_DEVICE_HANDLER ( to8_sys_porta_in )
+{
+ int ktest = to8_kbd_ktest (device->machine());
+
+ LOG_KBD(( "$%04x %f: to8_sys_porta_in ktest=%i\n", cpu_get_previouspc(device->machine().device("maincpu")), device->machine().time().as_double(), ktest ));
+
+ return ktest;
+}
+
+
+
+static WRITE8_DEVICE_HANDLER ( to8_sys_portb_out )
+{
+ centronics_device *printer = device->machine().device<centronics_device>("centronics");
+
+ printer->d0_w(BIT(data, 0));
+ printer->strobe_w(BIT(data, 1));
+
+ to8_update_ram_bank(device->machine());
+
+ if ( data & 4 ) /* bit 2: video overlay (TODO) */
+ LOG(( "to8_sys_portb_out: video overlay not handled\n" ));
+}
+
+
+
+const pia6821_interface to8_pia6821_sys =
+{
+ DEVCB_HANDLER(to8_sys_porta_in),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(to9_sys_porta_out),
+ DEVCB_HANDLER(to8_sys_portb_out),
+ DEVCB_HANDLER(to7_set_cassette_motor),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_LINE(thom_firq_1)
+};
+
+
+
+/* ------------ 6846 (timer, I/O) ------------ */
+
+
+
+static READ8_DEVICE_HANDLER ( to8_timer_port_in )
+{
+ centronics_device *printer = device->machine().device<centronics_device>("centronics");
+ int lightpen = (device->machine().root_device().ioport("lightpen_button")->read() & 1) ? 2 : 0;
+ int cass = to7_get_cassette(device->machine()) ? 0x80 : 0;
+ int dtr = printer->busy_r() << 6;
+ int lock = to8_kbd_caps ? 0 : 8; /* undocumented! */
+ return lightpen | cass | dtr | lock;
+}
+
+
+
+static WRITE8_DEVICE_HANDLER ( to8_timer_port_out )
+{
+ int ack = (data & 0x20) ? 1 : 0; /* bit 5: keyboard ACK */
+ to8_bios_bank = (data & 0x10) ? 1 : 0; /* bit 4: BIOS bank*/
+ thom_set_mode_point( device->machine(), data & 1 ); /* bit 0: video bank switch */
+ device->machine().root_device().membank( TO8_BIOS_BANK )->set_entry( to8_bios_bank );
+ to8_soft_select = (data & 0x04) ? 1 : 0; /* bit 2: internal ROM select */
+ to8_update_floppy_bank(device->machine());
+ to8_update_cart_bank(device->machine());
+ to8_kbd_set_ack(device->machine(), ack);
+}
+
+
+
+static WRITE8_DEVICE_HANDLER ( to8_timer_cp2_out )
+{
+ /* mute */
+ to7_game_mute = data;
+ to7_game_sound_update(device->machine());
+}
+
+
+
+const mc6846_interface to8_timer =
+{
+ to8_timer_port_out, NULL, to8_timer_cp2_out,
+ to8_timer_port_in, to7_timer_tco_out,
+ thom_dev_irq_0
+};
+
+
+
+/* ------------ lightpen ------------ */
+
+
+
+/* direct connection to interrupt line instead of through a PIA */
+static void to8_lightpen_cb ( running_machine &machine, int step )
+{
+ if ( ! to7_lightpen )
+ return;
+
+ thom_firq_2( machine, 1 );
+ to7_lightpen_step = step;
+ to8_lightpen_intr = 1;
+}
+
+
+
+/* ------------ init / reset ------------ */
+
+
+
+MACHINE_RESET ( to8 )
+{
+ pia6821_device *sys_pia = machine.device<pia6821_device>(THOM_PIA_SYS );
+ LOG (( "to8: machine reset called\n" ));
+
+ /* subsystems */
+ thom_irq_reset(machine);
+ sys_pia->set_port_a_z_mask( 0xfe );
+ to7_game_reset(machine);
+ to8_floppy_reset(machine);
+ to8_kbd_reset(machine);
+ to7_modem_reset(machine);
+ to7_midi_reset(machine);
+
+ /* gate-array */
+ to7_lightpen = 0;
+ to8_reg_ram = 0;
+ to8_reg_cart = 0;
+ to8_reg_sys1 = 0;
+ to8_reg_sys2 = 0;
+ to8_lightpen_intr = 0;
+ to8_soft_select = 0;
+
+ /* video */
+ thom_set_video_mode( machine, THOM_VMODE_TO770 );
+ thom_set_lightpen_callback( machine, 4, to8_lightpen_cb );
+ thom_set_border_color( machine, 0 );
+ thom_set_mode_point( machine, 0 );
+ sys_pia->cb1_w( 0 );
+
+ /* memory */
+ old_ram_bank = -1;
+ old_cart_bank = -1;
+ old_cart_bank_was_read_only = 0;
+ old_floppy_bank = -1;
+ to8_cart_vpage = 0;
+ to8_data_vpage = 0;
+ to8_soft_bank = 0;
+ to8_bios_bank = 0;
+ to8_update_ram_bank(machine);
+ to8_update_cart_bank(machine);
+ to8_update_floppy_bank(machine);
+ machine.root_device().membank( TO8_BIOS_BANK )->set_entry( 0 );
+ /* thom_cart_bank not reset */
+}
+
+
+
+MACHINE_START ( to8 )
+{
+ UINT8* mem = machine.root_device().memregion("maincpu")->base();
+ UINT8* ram = machine.device<ram_device>(RAM_TAG)->pointer();
+
+ LOG (( "to8: machine start called\n" ));
+
+ /* subsystems */
+ thom_irq_init(machine);
+ to7_game_init(machine);
+ to8_floppy_init(machine);
+ to8_kbd_init(machine);
+ to9_palette_init(machine);
+ to7_modem_init(machine);
+ to7_midi_init(machine);
+
+ /* memory */
+ thom_cart_bank = 0;
+ thom_vram = ram;
+ machine.root_device().membank( THOM_CART_BANK )->configure_entries( 0, 8, mem + 0x10000, 0x4000 );
+ machine.root_device().membank( THOM_CART_BANK )->configure_entries( 8, 32, ram, 0x4000 );
+ machine.root_device().membank( THOM_VRAM_BANK )->configure_entries( 0, 2, ram, 0x2000 );
+ machine.root_device().membank( TO8_SYS_LO )->configure_entry( 0, ram + 0x6000);
+ machine.root_device().membank( TO8_SYS_HI )->configure_entry( 0, ram + 0x4000);
+ machine.root_device().membank( TO8_DATA_LO )->configure_entries( 0, 32, ram + 0x2000, 0x4000 );
+ machine.root_device().membank( TO8_DATA_HI )->configure_entries( 0, 32, ram + 0x0000, 0x4000 );
+ machine.root_device().membank( TO8_BIOS_BANK )->configure_entries( 0, 2, mem + 0x30800, 0x2000 );
+ machine.root_device().membank( THOM_CART_BANK )->set_entry( 0 );
+ machine.root_device().membank( THOM_VRAM_BANK )->set_entry( 0 );
+ machine.root_device().membank( TO8_SYS_LO )->set_entry( 0 );
+ machine.root_device().membank( TO8_SYS_HI )->set_entry( 0 );
+ machine.root_device().membank( TO8_DATA_LO )->set_entry( 0 );
+ machine.root_device().membank( TO8_DATA_HI )->set_entry( 0 );
+ machine.root_device().membank( TO8_BIOS_BANK )->set_entry( 0 );
+
+ /* save-state */
+ state_save_register_global( machine, thom_cart_nb_banks );
+ state_save_register_global( machine, thom_cart_bank );
+ state_save_register_global( machine, to7_lightpen );
+ state_save_register_global( machine, to7_lightpen_step );
+ state_save_register_global( machine, to8_reg_ram );
+ state_save_register_global( machine, to8_reg_cart );
+ state_save_register_global( machine, to8_reg_sys1 );
+ state_save_register_global( machine, to8_reg_sys2 );
+ state_save_register_global( machine, to8_soft_select );
+ state_save_register_global( machine, to8_soft_bank );
+ state_save_register_global( machine, to8_bios_bank );
+ state_save_register_global( machine, to8_lightpen_intr );
+ state_save_register_global( machine, to8_data_vpage );
+ state_save_register_global( machine, to8_cart_vpage );
+ state_save_register_global_pointer( machine, (mem + 0x10000), 0x10000 );
+ machine.save().register_postload(save_prepost_delegate(FUNC(to8_update_ram_bank_postload), &machine));
+ machine.save().register_postload(save_prepost_delegate(FUNC(to8_update_cart_bank_postload), &machine));
+ machine.save().register_postload(save_prepost_delegate(FUNC(to8_update_floppy_bank_postload), &machine));
+}
+
+
+
+/***************************** TO9+ *************************/
+
+
+
+/* ------------ system PIA 6821 ------------ */
+
+
+
+const pia6821_interface to9p_pia6821_sys =
+{
+ DEVCB_HANDLER(to9_sys_porta_in),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(to9_sys_porta_out),
+ DEVCB_HANDLER(to8_sys_portb_out),
+ DEVCB_HANDLER(to7_set_cassette_motor),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_LINE(thom_firq_1)
+};
+
+
+
+/* ------------ 6846 (timer, I/O) ------------ */
+
+
+
+static READ8_DEVICE_HANDLER ( to9p_timer_port_in )
+{
+ centronics_device *printer = device->machine().device<centronics_device>("centronics");
+ int lightpen = (device->machine().root_device().ioport("lightpen_button")->read() & 1) ? 2 : 0;
+ int cass = to7_get_cassette(device->machine()) ? 0x80 : 0;
+ int dtr = printer->busy_r() << 6;
+ return lightpen | cass | dtr;
+}
+
+
+
+static WRITE8_DEVICE_HANDLER ( to9p_timer_port_out )
+{
+ int bios_bank = (data & 0x10) ? 1 : 0; /* bit 4: BIOS bank */
+ thom_set_mode_point( device->machine(), data & 1 ); /* bit 0: video bank switch */
+ device->machine().root_device().membank( TO8_BIOS_BANK )->set_entry( bios_bank );
+ to8_soft_select = (data & 0x04) ? 1 : 0; /* bit 2: internal ROM select */
+ to8_update_floppy_bank(device->machine());
+ to8_update_cart_bank(device->machine());
+}
+
+
+
+const mc6846_interface to9p_timer =
+{
+ to9p_timer_port_out, NULL, to8_timer_cp2_out,
+ to9p_timer_port_in, to7_timer_tco_out,
+ thom_dev_irq_0
+};
+
+
+
+/* ------------ init / reset ------------ */
+
+
+
+MACHINE_RESET ( to9p )
+{
+ pia6821_device *sys_pia = machine.device<pia6821_device>(THOM_PIA_SYS );
+ LOG (( "to9p: machine reset called\n" ));
+
+ /* subsystems */
+ thom_irq_reset(machine);
+ sys_pia->set_port_a_z_mask( 0xfe );
+ to7_game_reset(machine);
+ to8_floppy_reset(machine);
+ to9_kbd_reset(machine);
+ to7_modem_reset(machine);
+ to7_midi_reset(machine);
+
+ /* gate-array */
+ to7_lightpen = 0;
+ to8_reg_ram = 0;
+ to8_reg_cart = 0;
+ to8_reg_sys1 = 0;
+ to8_reg_sys2 = 0;
+ to8_lightpen_intr = 0;
+ to8_soft_select = 0;
+
+ /* video */
+ thom_set_video_mode( machine, THOM_VMODE_TO770 );
+ thom_set_lightpen_callback( machine, 4, to8_lightpen_cb );
+ thom_set_border_color( machine, 0 );
+ thom_set_mode_point( machine, 0 );
+ sys_pia->cb1_w( 0 );
+
+ /* memory */
+ old_ram_bank = -1;
+ old_cart_bank = -1;
+ old_floppy_bank = -1;
+ to8_cart_vpage = 0;
+ to8_data_vpage = 0;
+ to8_soft_bank = 0;
+ to8_bios_bank = 0;
+ to8_update_ram_bank(machine);
+ to8_update_cart_bank(machine);
+ to8_update_floppy_bank(machine);
+ machine.root_device().membank( TO8_BIOS_BANK )->set_entry( 0 );
+ /* thom_cart_bank not reset */
+}
+
+
+
+MACHINE_START ( to9p )
+{
+ UINT8* mem = machine.root_device().memregion("maincpu")->base();
+ UINT8* ram = machine.device<ram_device>(RAM_TAG)->pointer();
+
+ LOG (( "to9p: machine start called\n" ));
+
+ /* subsystems */
+ thom_irq_init(machine);
+ to7_game_init(machine);
+ to8_floppy_init( machine );
+ to9_kbd_init(machine);
+ to9_palette_init(machine);
+ to7_modem_init(machine);
+ to7_midi_init(machine);
+
+ /* memory */
+ thom_cart_bank = 0;
+ thom_vram = ram;
+ machine.root_device().membank( THOM_CART_BANK )->configure_entries( 0, 8, mem + 0x10000, 0x4000 );
+ machine.root_device().membank( THOM_CART_BANK )->configure_entries( 8, 32, ram, 0x4000 );
+ machine.root_device().membank( THOM_VRAM_BANK )->configure_entries( 0, 2, ram, 0x2000 );
+ machine.root_device().membank( TO8_SYS_LO )->configure_entry( 0, ram + 0x6000);
+ machine.root_device().membank( TO8_SYS_HI )->configure_entry( 0, ram + 0x4000);
+ machine.root_device().membank( TO8_DATA_LO )->configure_entries( 0, 32, ram + 0x2000, 0x4000 );
+ machine.root_device().membank( TO8_DATA_HI )->configure_entries( 0, 32, ram + 0x0000, 0x4000 );
+ machine.root_device().membank( TO8_BIOS_BANK )->configure_entries( 0, 2, mem + 0x30800, 0x2000 );
+ machine.root_device().membank( THOM_CART_BANK )->set_entry( 0 );
+ machine.root_device().membank( THOM_VRAM_BANK )->set_entry( 0 );
+ machine.root_device().membank( TO8_SYS_LO )->set_entry( 0 );
+ machine.root_device().membank( TO8_SYS_HI )->set_entry( 0 );
+ machine.root_device().membank( TO8_DATA_LO )->set_entry( 0 );
+ machine.root_device().membank( TO8_DATA_HI )->set_entry( 0 );
+ machine.root_device().membank( TO8_BIOS_BANK )->set_entry( 0 );
+
+ /* save-state */
+ state_save_register_global( machine, thom_cart_nb_banks );
+ state_save_register_global( machine, thom_cart_bank );
+ state_save_register_global( machine, to7_lightpen );
+ state_save_register_global( machine, to7_lightpen_step );
+ state_save_register_global( machine, to8_reg_ram );
+ state_save_register_global( machine, to8_reg_cart );
+ state_save_register_global( machine, to8_reg_sys1 );
+ state_save_register_global( machine, to8_reg_sys2 );
+ state_save_register_global( machine, to8_soft_select );
+ state_save_register_global( machine, to8_soft_bank );
+ state_save_register_global( machine, to8_bios_bank );
+ state_save_register_global( machine, to8_lightpen_intr );
+ state_save_register_global( machine, to8_data_vpage );
+ state_save_register_global( machine, to8_cart_vpage );
+ state_save_register_global_pointer( machine, (mem + 0x10000), 0x10000 );
+ machine.save().register_postload(save_prepost_delegate(FUNC(to8_update_ram_bank_postload), &machine));
+ machine.save().register_postload(save_prepost_delegate(FUNC(to8_update_cart_bank_postload), &machine));
+ machine.save().register_postload(save_prepost_delegate(FUNC(to8_update_floppy_bank_postload), &machine));
+}
+
+
+
+/****************** MO6 / Olivetti Prodest PC 128 *******************/
+
+
+
+/* ------------ RAM / ROM banking ------------ */
+
+
+
+static void mo6_update_ram_bank ( running_machine &machine )
+{
+ UINT8 bank = 0;
+
+ if ( to8_reg_sys1 & 0x10 )
+ {
+ bank = to8_reg_ram & 7; /* 128 KB RAM only = 8 pages */
+ }
+ if ( bank != to8_data_vpage ) {
+ machine.root_device().membank( TO8_DATA_LO )->set_entry( bank );
+ machine.root_device().membank( TO8_DATA_HI )->set_entry( bank );
+ to8_data_vpage = bank;
+ old_ram_bank = bank;
+ LOG_BANK(( "mo6_update_ram_bank: select bank %i (new style)\n", bank ));
+ }
+}
+
+
+
+static void mo6_update_ram_bank_postload(running_machine *machine)
+{
+ mo6_update_ram_bank(*machine);
+}
+
+
+
+static void mo6_update_cart_bank (running_machine &machine)
+{
+ pia6821_device *sys_pia = machine.device<pia6821_device>(THOM_PIA_SYS );
+ address_space* space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ int b = (sys_pia->a_output() >> 5) & 1;
+ int bank = 0;
+ int bank_is_read_only = 0;
+
+ // space->install_read_bank( 0xb000, 0xefff, THOM_CART_BANK );
+
+ if ( ( ( to8_reg_sys1 & 0x40 ) && ( to8_reg_cart & 0x20 ) ) || ( ! ( to8_reg_sys1 & 0x40 ) && ( mo5_reg_cart & 4 ) ) )
+ {
+ /* RAM space */
+ if ( to8_reg_sys1 & 0x40 )
+ {
+ /* use a7e6 */
+ to8_cart_vpage = to8_reg_cart & 7; /* 128 KB RAM only = 8 pages */
+ bank = 8 + to8_cart_vpage;
+ bank_is_read_only = (( to8_reg_cart & 0x40 ) == 0);
+ if ( bank != old_cart_bank )
+ {
+ if (to8_cart_vpage < 4)
+ {
+ if (old_cart_bank < 8 || old_cart_bank > 11)
+ {
+ space->install_read_bank( 0xb000, 0xefff, THOM_CART_BANK );
+ if ( bank_is_read_only )
+ {
+ space->nop_write( 0xb000, 0xefff);
+ }
+ else
+ {
+ space->install_legacy_write_handler( 0xb000, 0xefff, FUNC(to8_vcart_w));
+ }
+ }
+ }
+ else
+ {
+
+ if (old_cart_bank < 12)
+ {
+ if ( bank_is_read_only )
+ {
+ space->install_read_bank( 0xb000, 0xefff, THOM_CART_BANK );
+ space->nop_write( 0xb000, 0xefff);
+ }
+ else
+ {
+ space->install_readwrite_bank( 0xb000, 0xefff,THOM_CART_BANK);
+ }
+ }
+ }
+ LOG_BANK(( "mo6_update_cart_bank: CART is RAM bank %i (%s)\n",
+ to8_cart_vpage,
+ bank_is_read_only ? "read-only":"read-write"));
+ }
+ else if ( bank_is_read_only != old_cart_bank_was_read_only )
+ {
+ if ( bank_is_read_only )
+ {
+ space->nop_write( 0xb000, 0xefff);
+ }
+ else
+ {
+ if (to8_cart_vpage < 4)
+ {
+ space->install_legacy_write_handler( 0xb000, 0xefff, FUNC(to8_vcart_w));
+ }
+ else
+ {
+ space->install_readwrite_bank( 0xb000, 0xefff, THOM_CART_BANK );
+ }
+ }
+ LOG_BANK(( "mo6_update_cart_bank: update CART bank %i write status to %s\n",
+ to8_cart_vpage,
+ bank_is_read_only ? "read-only":"read-write"));
+ }
+ old_cart_bank_was_read_only = bank_is_read_only;
+ }
+ else if ( thom_cart_nb_banks == 4 )
+ {
+ /* "JANE"-style cartridge bank switching */
+ bank = mo5_reg_cart & 3;
+ if ( bank != old_cart_bank )
+ {
+ if ( old_cart_bank < 0 || old_cart_bank > 3 )
+ {
+ space->install_read_bank( 0xb000, 0xefff, THOM_CART_BANK );
+ space->nop_write( 0xb000, 0xefff);
+ }
+ LOG_BANK(( "mo6_update_cart_bank: CART is external cartridge bank %i (A7CB style)\n", bank ));
+ }
+ }
+ else
+ {
+ /* RAM from MO5 network extension */
+ int bank_is_read_only = (( mo5_reg_cart & 8 ) == 0);
+ to8_cart_vpage = (mo5_reg_cart & 3) | 4;
+ bank = 8 + to8_cart_vpage;
+ if ( bank != old_cart_bank )
+ {
+ if ( old_cart_bank < 12 )
+ {
+ if ( bank_is_read_only )
+ {
+ space->install_read_bank( 0xb000, 0xefff, THOM_CART_BANK);
+ space->nop_write( 0xb000, 0xefff);
+ } else
+ {
+ space->install_readwrite_bank( 0xb000, 0xefff, THOM_CART_BANK);
+ }
+ }
+ LOG_BANK(( "mo6_update_cart_bank: CART is RAM bank %i (MO5 compat.) (%s)\n",
+ to8_cart_vpage,
+ bank_is_read_only ? "read-only":"read-write"));
+ }
+ else if ( bank_is_read_only != old_cart_bank_was_read_only )
+ {
+ if ( bank_is_read_only )
+ {
+ space->install_read_bank( 0xb000, 0xefff, THOM_CART_BANK);
+ space->nop_write( 0xb000, 0xefff);
+ }
+ else
+ {
+ space->install_readwrite_bank( 0xb000, 0xefff, THOM_CART_BANK);
+ }
+ LOG_BANK(( "mo5_update_cart_bank: update CART bank %i write status to %s\n",
+ to8_cart_vpage,
+ bank_is_read_only ? "read-only":"read-write"));
+ }
+ old_cart_bank_was_read_only = bank_is_read_only;
+ }
+ }
+ else
+ {
+ /* ROM space */
+ if ( to8_reg_sys2 & 0x20 )
+ {
+ /* internal ROM */
+ if ( to8_reg_sys2 & 0x10)
+ {
+ bank = b + 6; /* BASIC 128 */
+ }
+ else
+ {
+ bank = b + 4; /* BASIC 1 */
+ }
+ if ( bank != old_cart_bank )
+ {
+ if ( old_cart_bank < 4 || old_cart_bank > 7 )
+ {
+ space->install_read_bank( 0xb000, 0xefff, THOM_CART_BANK);
+ space->install_legacy_write_handler( 0xb000, 0xefff, FUNC(mo6_cartridge_w) );
+ }
+ LOG_BANK(( "mo6_update_cart_bank: CART is internal ROM bank %i\n", b ));
+ }
+ }
+ else
+ {
+ /* cartridge */
+ if ( thom_cart_nb_banks )
+ {
+ bank = thom_cart_bank % thom_cart_nb_banks;
+ if ( bank != old_cart_bank )
+ {
+ if ( old_cart_bank < 0 || old_cart_bank > 3 )
+ {
+ space->install_read_bank( 0xb000, 0xefff, THOM_CART_BANK );
+ space->install_legacy_write_handler( 0xb000, 0xefff, FUNC(mo6_cartridge_w) );
+ space->install_legacy_read_handler( 0xbffc, 0xbfff, FUNC(mo6_cartridge_r) );
+ }
+ LOG_BANK(( "mo6_update_cart_bank: CART is external cartridge bank %i\n", bank ));
+ }
+ }
+ else
+ {
+ if ( old_cart_bank != 0 )
+ {
+ space->nop_read( 0xb000, 0xefff );
+ LOG_BANK(( "mo6_update_cart_bank: CART is unmapped\n"));
+ }
+ }
+ }
+ }
+ if ( bank != old_cart_bank )
+ {
+ machine.root_device().membank( THOM_CART_BANK )->set_entry( bank );
+ machine.root_device().membank( TO8_BIOS_BANK )->set_entry( b );
+ old_cart_bank = bank;
+ }
+}
+
+
+
+static void mo6_update_cart_bank_postload(running_machine *machine)
+{
+ mo6_update_cart_bank(*machine);
+}
+
+
+
+/* write signal generates a bank switch */
+WRITE8_HANDLER ( mo6_cartridge_w )
+{
+ if ( offset >= 0x2000 )
+ return;
+
+ thom_cart_bank = offset & 3;
+ mo6_update_cart_bank(space->machine());
+}
+
+
+
+/* read signal generates a bank switch */
+READ8_HANDLER ( mo6_cartridge_r )
+{
+ UINT8* pos = space->machine().root_device().memregion( "maincpu" )->base() + 0x10000;
+ UINT8 data = pos[offset + 0xbffc + (thom_cart_bank % thom_cart_nb_banks) * 0x4000];
+ if ( !space->debugger_access() )
+ {
+ thom_cart_bank = offset & 3;
+ mo6_update_cart_bank(space->machine());
+ }
+ return data;
+}
+
+
+
+WRITE8_HANDLER ( mo6_ext_w )
+{
+ /* MO5 network extension compatible */
+ mo5_reg_cart = data;
+ mo6_update_cart_bank(space->machine());
+}
+
+
+
+/* ------------ game 6821 PIA ------------ */
+
+/* similar to SX 90-018, but with a few differences: mute, printer */
+
+
+static WRITE_LINE_DEVICE_HANDLER( mo6_centronics_busy )
+{
+ pia6821_device *game_pia = device->machine().device<pia6821_device>( THOM_PIA_GAME );
+ game_pia->cb1_w(state);
+}
+
+
+const centronics_interface mo6_centronics_config =
+{
+ DEVCB_NULL,
+ DEVCB_LINE(mo6_centronics_busy),
+ DEVCB_NULL
+};
+
+
+static WRITE8_DEVICE_HANDLER ( mo6_game_porta_out )
+{
+ centronics_device *printer = device->machine().device<centronics_device>("centronics");
+
+ LOG (( "$%04x %f mo6_game_porta_out: CENTRONICS set data=$%02X\n", cpu_get_previouspc(device->machine().device("maincpu")), device->machine().time().as_double(), data ));
+
+ /* centronics data */
+ printer->write( *device->machine().memory().first_space(), 0, data);
+}
+
+
+
+static WRITE8_DEVICE_HANDLER ( mo6_game_cb2_out )
+{
+ centronics_device *printer = device->machine().device<centronics_device>("centronics");
+
+ LOG (( "$%04x %f mo6_game_cb2_out: CENTRONICS set strobe=%i\n", cpu_get_previouspc(device->machine().device("maincpu")), device->machine().time().as_double(), data ));
+
+ /* centronics strobe */
+ printer->strobe_w(data);
+}
+
+
+
+const pia6821_interface mo6_pia6821_game =
+{
+ DEVCB_HANDLER(to7_game_porta_in),
+ DEVCB_HANDLER(to7_game_portb_in),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(mo6_game_porta_out),
+ DEVCB_HANDLER(to7_game_portb_out),
+ DEVCB_NULL,
+ DEVCB_HANDLER(mo6_game_cb2_out),
+ DEVCB_LINE(thom_irq_1),
+ DEVCB_LINE(thom_irq_1)
+};
+
+
+
+static TIMER_CALLBACK(mo6_game_update_cb)
+{
+ pia6821_device *game_pia = machine.device<pia6821_device>(THOM_PIA_GAME);
+
+ /* unlike the TO8, CB1 & CB2 are not connected to buttons */
+ if ( machine.root_device().ioport("config")->read() & 1 )
+ {
+ UINT8 mouse = to7_get_mouse_signal(machine);
+ game_pia->ca1_w( BIT(mouse, 0) ); /* XA */
+ game_pia->ca2_w( BIT(mouse, 1) ); /* YA */
+ }
+ else
+ {
+ /* joystick */
+ UINT8 in = machine.root_device().ioport("game_port_buttons")->read();
+ game_pia->ca1_w( BIT(in, 2) ); /* P1 action B */
+ game_pia->ca2_w( BIT(in, 6) ); /* P1 action A */
+ }
+}
+
+
+
+static void mo6_game_init ( running_machine &machine )
+{
+ LOG (( "mo6_game_init called\n" ));
+ to7_game_timer = machine.scheduler().timer_alloc(FUNC(mo6_game_update_cb));
+ to7_game_timer->adjust(TO7_GAME_POLL_PERIOD, 0, TO7_GAME_POLL_PERIOD);
+ state_save_register_global( machine, to7_game_sound );
+ state_save_register_global( machine, to7_game_mute );
+}
+
+
+
+static void mo6_game_reset ( running_machine &machine )
+{
+ pia6821_device *game_pia = machine.device<pia6821_device>(THOM_PIA_GAME);
+ LOG (( "mo6_game_reset called\n" ));
+ game_pia->ca1_w( 0 );
+ to7_game_sound = 0;
+ to7_game_mute = 0;
+ to7_game_sound_update(machine);
+}
+
+
+
+/* ------------ system PIA 6821 ------------ */
+
+
+
+static READ8_DEVICE_HANDLER ( mo6_sys_porta_in )
+{
+ return
+ (mo5_get_cassette(device->machine()) ? 0x80 : 0) | /* bit 7: cassette input */
+ 8 | /* bit 3: kbd-line float up to 1 */
+ ((device->machine().root_device().ioport("lightpen_button")->read() & 1) ? 2 : 0);
+ /* bit 1: lightpen button */;
+}
+
+
+
+static READ8_DEVICE_HANDLER ( mo6_sys_portb_in )
+{
+ /* keyboard: 9 lines of 8 keys */
+ UINT8 porta = downcast<pia6821_device *>(device)->a_output();
+ UINT8 portb =downcast<pia6821_device *>(device)->b_output();
+ int col = (portb >> 4) & 7; /* B bits 4-6: kbd column */
+ int lin = (portb >> 1) & 7; /* B bits 1-3: kbd line */
+ static const char *const keynames[] = {
+ "keyboard_0", "keyboard_1", "keyboard_2", "keyboard_3", "keyboard_4",
+ "keyboard_5", "keyboard_6", "keyboard_7", "keyboard_8", "keyboard_9"
+ };
+
+ if ( ! (porta & 8) )
+ lin = 8; /* A bit 3: 9-th kbd line select */
+
+ return
+ ( device->machine().root_device().ioport(keynames[lin])->read() & (1 << col) ) ? 0x80 : 0;
+ /* bit 7: key up */
+}
+
+
+
+static WRITE8_DEVICE_HANDLER ( mo6_sys_porta_out )
+{
+ thom_set_mode_point( device->machine(),data & 1 ); /* bit 0: video bank switch */
+ to7_game_mute = data & 4; /* bit 2: sound mute */
+ thom_set_caps_led( device->machine(),(data & 16) ? 0 : 1 ) ; /* bit 4: keyboard led */
+ mo5_set_cassette( device->machine(), (data & 0x40) ? 1 : 0 ); /* bit 6: cassette output */
+ mo6_update_cart_bank(device->machine()); /* bit 5: rom bank */
+ to7_game_sound_update(device->machine());
+}
+
+
+
+static WRITE8_DEVICE_HANDLER ( mo6_sys_portb_out )
+{
+ device->machine().device<dac_device>("buzzer")->write_unsigned8((data & 1) ? 0x80 : 0); /* bit 0: buzzer */
+}
+
+
+
+static WRITE8_DEVICE_HANDLER ( mo6_sys_cb2_out )
+{
+ /* SCART pin 8 = slow switch (?) */
+ LOG(( "mo6_sys_cb2_out: SCART slow switch set to %i\n", data ));
+}
+
+
+
+const pia6821_interface mo6_pia6821_sys =
+{
+ DEVCB_HANDLER(mo6_sys_porta_in),
+ DEVCB_HANDLER(mo6_sys_portb_in),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(mo6_sys_porta_out),
+ DEVCB_HANDLER(mo6_sys_portb_out),
+ DEVCB_HANDLER(mo5_set_cassette_motor),
+ DEVCB_HANDLER(mo6_sys_cb2_out),
+ DEVCB_LINE(thom_firq_1),
+ DEVCB_LINE(thom_irq_1) /* differs from TO */
+};
+
+
+
+/* ------------ system gate-array ------------ */
+
+#define MO6_LIGHTPEN_DECAL 12
+
+
+
+READ8_HANDLER ( mo6_gatearray_r )
+{
+ struct thom_vsignal v = thom_get_vsignal(space->machine());
+ struct thom_vsignal l = thom_get_lightpen_vsignal( space->machine(), MO6_LIGHTPEN_DECAL, to7_lightpen_step - 1, 6 );
+ int count, inil, init, lt3;
+ UINT8 res;
+ count = to7_lightpen ? l.count : v.count;
+ inil = to7_lightpen ? l.inil : v.inil;
+ init = to7_lightpen ? l.init : v.init;
+ lt3 = to7_lightpen ? l.lt3 : v.lt3;
+
+ switch ( offset )
+ {
+
+ case 0: /* system 2 / lightpen register 1 */
+ if ( to7_lightpen )
+ res = (count >> 8) & 0xff;
+ else
+ res = to8_reg_sys2 & 0xf0;
+ break;
+
+ case 1: /* ram register / lightpen register 2 */
+ if ( to7_lightpen )
+ {
+ if ( !space->debugger_access() )
+ {
+ thom_firq_2( space->machine(), 0 );
+ to8_lightpen_intr = 0;
+ }
+ res = count & 0xff;
+ }
+ else
+ res = to8_reg_ram & 0x1f;
+ break;
+
+ case 2: /* cartrige register / lightpen register 3 */
+ if ( to7_lightpen )
+ res = (lt3 << 7) | (inil << 6);
+ else
+ res = 0;
+ break;
+
+ case 3: /* lightpen register 4 */
+ res = (v.init << 7) | (init << 6) | (v.inil << 5) | (to8_lightpen_intr << 1) | to7_lightpen;
+ break;
+
+ default:
+ logerror( "$%04x mo6_gatearray_r: invalid offset %i\n", cpu_get_previouspc(space->machine().device("maincpu")), offset );
+ res = 0;
+ }
+
+ LOG_VIDEO(( "$%04x %f mo6_gatearray_r: off=%i ($%04X) res=$%02X lightpen=%i\n",
+ cpu_get_previouspc(space->machine().device("maincpu")), space->machine().time().as_double(),
+ offset, 0xa7e4 + offset, res, to7_lightpen ));
+
+ return res;
+}
+
+
+
+WRITE8_HANDLER ( mo6_gatearray_w )
+{
+ LOG_VIDEO(( "$%04x %f mo6_gatearray_w: off=%i ($%04X) data=$%02X\n",
+ cpu_get_previouspc(space->machine().device("maincpu")), space->machine().time().as_double(),
+ offset, 0xa7e4 + offset, data ));
+
+ switch ( offset )
+ {
+
+ case 0: /* switch */
+ to7_lightpen = data & 1;
+ break;
+
+ case 1: /* ram register */
+ if ( to8_reg_sys1 & 0x10 )
+ {
+ to8_reg_ram = data;
+ mo6_update_ram_bank(space->machine());
+ }
+ break;
+
+ case 2: /* cartridge register */
+ to8_reg_cart = data;
+ mo6_update_cart_bank(space->machine());
+ break;
+
+ case 3: /* system register 1 */
+ to8_reg_sys1 = data;
+ mo6_update_ram_bank(space->machine());
+ mo6_update_cart_bank(space->machine());
+ break;
+
+ default:
+ logerror( "$%04x mo6_gatearray_w: invalid offset %i (data=$%02X)\n", cpu_get_previouspc(space->machine().device("maincpu")), offset, data );
+ }
+}
+
+
+/* ------------ video gate-array ------------ */
+
+
+
+READ8_HANDLER ( mo6_vreg_r )
+{
+ /* 0xa7dc from external floppy drive aliases the video gate-array */
+ if ( ( offset == 3 ) && ( to8_reg_ram & 0x80 ) )
+ {
+ if ( !space->debugger_access() )
+ return to7_floppy_r( space, 0xc );
+ }
+
+ switch ( offset )
+ {
+
+ case 0: /* palette data */
+ case 1: /* palette address */
+ return to8_vreg_r( space, offset );
+
+ case 2:
+ case 3:
+ return 0;
+
+ default:
+ logerror( "mo6_vreg_r: invalid read offset %i\n", offset );
+ return 0;
+ }
+}
+
+
+
+WRITE8_HANDLER ( mo6_vreg_w )
+{
+ LOG_VIDEO(( "$%04x %f mo6_vreg_w: off=%i ($%04X) data=$%02X\n",
+ cpu_get_previouspc(space->machine().device("maincpu")), space->machine().time().as_double(),
+ offset, 0xa7da + offset, data ));
+
+ switch ( offset )
+ {
+
+ case 0: /* palette data */
+ case 1: /* palette address */
+ to8_vreg_w( space, offset, data );
+ return;
+
+ case 2: /* display / external floppy register */
+ if ( ( to8_reg_sys1 & 0x80 ) && ( to8_reg_ram & 0x80 ) )
+ to7_floppy_w( space, 0xc, data );
+ else
+ to9_set_video_mode( space->machine(), data, 2 );
+ break;
+
+ case 3: /* system register 2 */
+ /* 0xa7dc from external floppy drive aliases the video gate-array */
+ if ( ( offset == 3 ) && ( to8_reg_ram & 0x80 ) )
+ to7_floppy_w( space, 0xc, data );
+ else
+ {
+ to8_reg_sys2 = data;
+ thom_set_video_page( space->machine(), data >> 6 );
+ thom_set_border_color( space->machine(), data & 15 );
+ mo6_update_cart_bank(space->machine());
+ }
+ break;
+
+ default:
+ logerror( "mo6_vreg_w: invalid write offset %i data=$%02X\n", offset, data );
+ }
+}
+
+
+
+/* ------------ init / reset ------------ */
+
+
+
+MACHINE_RESET ( mo6 )
+{
+ pia6821_device *sys_pia = machine.device<pia6821_device>(THOM_PIA_SYS );
+ LOG (( "mo6: machine reset called\n" ));
+
+ /* subsystems */
+ thom_irq_reset(machine);
+ sys_pia->set_port_a_z_mask( 0x75 );
+ mo6_game_reset(machine);
+ to7_floppy_reset(machine);
+ to7_modem_reset(machine);
+ to7_midi_reset(machine);
+ mo5_init_timer(machine);
+
+ /* gate-array */
+ to7_lightpen = 0;
+ to8_reg_ram = 0;
+ to8_reg_cart = 0;
+ to8_reg_sys1 = 0;
+ to8_reg_sys2 = 0;
+ to8_lightpen_intr = 0;
+
+ /* video */
+ thom_set_video_mode( machine, THOM_VMODE_MO5 );
+ thom_set_lightpen_callback( machine, 3, to8_lightpen_cb );
+ thom_set_border_color( machine, 0 );
+ thom_set_mode_point( machine, 0 );
+ sys_pia->ca1_w( 0 );
+
+ /* memory */
+ old_ram_bank = -1;
+ old_cart_bank = -1;
+ to8_cart_vpage = 0;
+ to8_data_vpage = 0;
+ mo6_update_ram_bank(machine);
+ mo6_update_cart_bank(machine);
+ /* mo5_reg_cart not reset */
+ /* thom_cart_bank not reset */
+}
+
+
+
+MACHINE_START ( mo6 )
+{
+ UINT8* mem = machine.root_device().memregion("maincpu")->base();
+ UINT8* ram = machine.device<ram_device>(RAM_TAG)->pointer();
+
+ LOG (( "mo6: machine start called\n" ));
+
+ /* subsystems */
+ thom_irq_init(machine);
+ mo6_game_init(machine);
+ to7_floppy_init( machine, mem + 0x30000 );
+ to9_palette_init(machine);
+ to7_modem_init(machine);
+ to7_midi_init(machine);
+ mo5_periodic_timer = machine.scheduler().timer_alloc(FUNC(mo5_periodic_cb));
+
+ /* memory */
+ thom_cart_bank = 0;
+ mo5_reg_cart = 0;
+ thom_vram = ram;
+ machine.root_device().membank( THOM_CART_BANK )->configure_entries( 0, 4, mem + 0x10000, 0x4000 );
+ machine.root_device().membank( THOM_CART_BANK )->configure_entries( 4, 2, mem + 0x1f000, 0x4000 );
+ machine.root_device().membank( THOM_CART_BANK )->configure_entries( 6, 2, mem + 0x28000, 0x4000 );
+ machine.root_device().membank( THOM_CART_BANK )->configure_entries( 8, 8, ram, 0x4000 );
+ machine.root_device().membank( THOM_VRAM_BANK )->configure_entries( 0, 2, ram, 0x2000 );
+ machine.root_device().membank( TO8_SYS_LO )->configure_entry( 0, ram + 0x6000);
+ machine.root_device().membank( TO8_SYS_HI )->configure_entry( 0, ram + 0x4000);
+ machine.root_device().membank( TO8_DATA_LO )->configure_entries( 0, 8, ram + 0x2000, 0x4000 );
+ machine.root_device().membank( TO8_DATA_HI )->configure_entries( 0, 8, ram + 0x0000, 0x4000 );
+ machine.root_device().membank( TO8_BIOS_BANK )->configure_entries( 0, 2, mem + 0x23000, 0x4000 );
+ machine.root_device().membank( THOM_CART_BANK )->set_entry( 0 );
+ machine.root_device().membank( THOM_VRAM_BANK )->set_entry( 0 );
+ machine.root_device().membank( TO8_SYS_LO )->set_entry( 0 );
+ machine.root_device().membank( TO8_SYS_HI )->set_entry( 0 );
+ machine.root_device().membank( TO8_DATA_LO )->set_entry( 0 );
+ machine.root_device().membank( TO8_DATA_HI )->set_entry( 0 );
+ machine.root_device().membank( TO8_BIOS_BANK )->set_entry( 0 );
+
+ /* save-state */
+ state_save_register_global( machine, thom_cart_nb_banks );
+ state_save_register_global( machine, thom_cart_bank );
+ state_save_register_global( machine, to7_lightpen );
+ state_save_register_global( machine, to7_lightpen_step );
+ state_save_register_global( machine, to8_reg_ram );
+ state_save_register_global( machine, to8_reg_cart );
+ state_save_register_global( machine, to8_reg_sys1 );
+ state_save_register_global( machine, to8_reg_sys2 );
+ state_save_register_global( machine, to8_lightpen_intr );
+ state_save_register_global( machine, to8_data_vpage );
+ state_save_register_global( machine, to8_cart_vpage );
+ state_save_register_global( machine, mo5_reg_cart );
+ state_save_register_global_pointer( machine, (mem + 0x10000), 0x10000 );
+ machine.save().register_postload(save_prepost_delegate(FUNC(mo6_update_ram_bank_postload), &machine));
+ machine.save().register_postload(save_prepost_delegate(FUNC(mo6_update_cart_bank_postload), &machine));
+}
+
+
+
+/***************************** MO5 NR *************************/
+
+
+
+/* ------------ network ( & external floppy) ------------ */
+
+
+
+READ8_HANDLER ( mo5nr_net_r )
+{
+ if ( space->debugger_access() )
+ return 0;
+
+ if ( to7_controller_type )
+ return to7_floppy_r ( space, offset );
+
+ logerror( "$%04x %f mo5nr_net_r: read from reg %i\n", cpu_get_previouspc(space->machine().device("maincpu")), space->machine().time().as_double(), offset );
+
+ return 0;
+}
+
+
+
+WRITE8_HANDLER ( mo5nr_net_w )
+{
+ if ( to7_controller_type )
+ to7_floppy_w ( space, offset, data );
+ else
+ logerror( "$%04x %f mo5nr_net_w: write $%02X to reg %i\n",
+ cpu_get_previouspc(space->machine().device("maincpu")), space->machine().time().as_double(), data, offset );
+}
+
+
+/* ------------ printer ------------ */
+
+/* Unlike the TO8, TO9, TO9+, MO6, the printer has its own ports and does not
+ go through the 6821 PIA.
+*/
+
+
+READ8_HANDLER( mo5nr_prn_r )
+{
+ centronics_device *printer = space->machine().device<centronics_device>("centronics");
+ UINT8 result = 0;
+
+ result |= !printer->busy_r() << 7;
+
+ return result;
+}
+
+
+WRITE8_HANDLER( mo5nr_prn_w )
+{
+ centronics_device *printer = space->machine().device<centronics_device>("centronics");
+
+ /* TODO: understand other bits */
+ printer->strobe_w(BIT(data, 3));
+}
+
+
+
+/* ------------ system PIA 6821 ------------ */
+
+
+
+static READ8_DEVICE_HANDLER ( mo5nr_sys_portb_in )
+{
+ /* keyboard: only 8 lines of 8 keys (MO6 has 9 lines) */
+ UINT8 portb = downcast<pia6821_device *>(device)->b_output();
+ int col = (portb >> 4) & 7; /* B bits 4-6: kbd column */
+ int lin = (portb >> 1) & 7; /* B bits 1-3: kbd line */
+ static const char *const keynames[] = {
+ "keyboard_0", "keyboard_1", "keyboard_2", "keyboard_3",
+ "keyboard_4", "keyboard_5", "keyboard_6", "keyboard_7"
+ };
+
+ return ( device->machine().root_device().ioport(keynames[lin])->read() & (1 << col) ) ? 0x80 : 0;
+ /* bit 7: key up */
+}
+
+
+
+static WRITE8_DEVICE_HANDLER ( mo5nr_sys_porta_out )
+{
+ /* no keyboard LED */
+ thom_set_mode_point( device->machine(), data & 1 ); /* bit 0: video bank switch */
+ to7_game_mute = data & 4; /* bit 2: sound mute */
+ mo5_set_cassette( device->machine(), (data & 0x40) ? 1 : 0 ); /* bit 6: cassette output */
+ mo6_update_cart_bank(device->machine()); /* bit 5: rom bank */
+ to7_game_sound_update(device->machine());
+}
+
+
+
+const pia6821_interface mo5nr_pia6821_sys =
+{
+ DEVCB_HANDLER(mo6_sys_porta_in),
+ DEVCB_HANDLER(mo5nr_sys_portb_in),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(mo5nr_sys_porta_out),
+ DEVCB_HANDLER(mo6_sys_portb_out),
+ DEVCB_HANDLER(mo5_set_cassette_motor),
+ DEVCB_HANDLER(mo6_sys_cb2_out),
+ DEVCB_LINE(thom_firq_1),
+ DEVCB_LINE(thom_irq_1) /* differs from TO */
+};
+
+
+
+
+/* ------------ game 6821 PIA ------------ */
+
+/* similar to the MO6, without the printer */
+
+
+
+const pia6821_interface mo5nr_pia6821_game =
+{
+ DEVCB_HANDLER(to7_game_porta_in),
+ DEVCB_HANDLER(to7_game_portb_in),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_HANDLER(mo6_game_porta_out),
+ DEVCB_HANDLER(to7_game_portb_out),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_LINE(thom_irq_1),
+ DEVCB_LINE(thom_irq_1)
+};
+
+
+
+static void mo5nr_game_init ( running_machine &machine )
+{
+ LOG (( "mo5nr_game_init called\n" ));
+ to7_game_timer = machine.scheduler().timer_alloc(FUNC(mo6_game_update_cb));
+ to7_game_timer->adjust( TO7_GAME_POLL_PERIOD, 0, TO7_GAME_POLL_PERIOD );
+ state_save_register_global( machine, to7_game_sound );
+ state_save_register_global( machine, to7_game_mute );
+}
+
+
+
+static void mo5nr_game_reset ( running_machine &machine )
+{
+ pia6821_device *game_pia = machine.device<pia6821_device>(THOM_PIA_GAME);
+ LOG (( "mo5nr_game_reset called\n" ));
+ game_pia->ca1_w( 0 );
+ to7_game_sound = 0;
+ to7_game_mute = 0;
+ to7_game_sound_update(machine);
+}
+
+
+
+/* ------------ init / reset ------------ */
+
+
+
+MACHINE_RESET ( mo5nr )
+{
+ pia6821_device *sys_pia = machine.device<pia6821_device>(THOM_PIA_SYS );
+ LOG (( "mo5nr: machine reset called\n" ));
+
+ /* subsystems */
+ thom_irq_reset(machine);
+ sys_pia->set_port_a_z_mask( 0x65 );
+ mo5nr_game_reset(machine);
+ to7_floppy_reset(machine);
+ to7_modem_reset(machine);
+ to7_midi_reset(machine);
+ mo5_init_timer(machine);
+
+ /* gate-array */
+ to7_lightpen = 0;
+ to8_reg_ram = 0;
+ to8_reg_cart = 0;
+ to8_reg_sys1 = 0;
+ to8_reg_sys2 = 0;
+ to8_lightpen_intr = 0;
+
+ /* video */
+ thom_set_video_mode( machine, THOM_VMODE_MO5 );
+ thom_set_lightpen_callback( machine, 3, to8_lightpen_cb );
+ thom_set_border_color( machine, 0 );
+ thom_set_mode_point( machine, 0 );
+ sys_pia->ca1_w( 0 );
+
+ /* memory */
+ old_ram_bank = -1;
+ old_cart_bank = -1;
+ to8_cart_vpage = 0;
+ to8_data_vpage = 0;
+ mo6_update_ram_bank(machine);
+ mo6_update_cart_bank(machine);
+ /* mo5_reg_cart not reset */
+ /* thom_cart_bank not reset */
+}
+
+
+
+MACHINE_START ( mo5nr )
+{
+ UINT8* mem = machine.root_device().memregion("maincpu")->base();
+ UINT8* ram = machine.device<ram_device>(RAM_TAG)->pointer();
+
+ LOG (( "mo5nr: machine start called\n" ));
+
+ /* subsystems */
+ thom_irq_init(machine);
+ mo5nr_game_init(machine);
+ to7_floppy_init( machine, mem + 0x30000 );
+ to9_palette_init(machine);
+ to7_modem_init(machine);
+ to7_midi_init(machine);
+ mo5_periodic_timer = machine.scheduler().timer_alloc(FUNC(mo5_periodic_cb));
+
+ /* memory */
+ thom_cart_bank = 0;
+ mo5_reg_cart = 0;
+ thom_vram = ram;
+ machine.root_device().membank( THOM_CART_BANK )->configure_entries( 0, 4, mem + 0x10000, 0x4000 );
+ machine.root_device().membank( THOM_CART_BANK )->configure_entries( 4, 2, mem + 0x1f000, 0x4000 );
+ machine.root_device().membank( THOM_CART_BANK )->configure_entries( 6, 2, mem + 0x28000, 0x4000 );
+ machine.root_device().membank( THOM_CART_BANK )->configure_entries( 8, 8, ram, 0x4000 );
+ machine.root_device().membank( THOM_VRAM_BANK )->configure_entries( 0, 2, ram, 0x2000 );
+ machine.root_device().membank( TO8_SYS_LO )->configure_entry( 0, ram + 0x6000);
+ machine.root_device().membank( TO8_SYS_HI )->configure_entry( 0, ram + 0x4000);
+ machine.root_device().membank( TO8_DATA_LO )->configure_entries( 0, 8, ram + 0x2000, 0x4000 );
+ machine.root_device().membank( TO8_DATA_HI )->configure_entries( 0, 8, ram + 0x0000, 0x4000 );
+ machine.root_device().membank( TO8_BIOS_BANK )->configure_entries( 0, 2, mem + 0x23000, 0x4000 );
+ machine.root_device().membank( THOM_CART_BANK )->set_entry( 0 );
+ machine.root_device().membank( THOM_VRAM_BANK )->set_entry( 0 );
+ machine.root_device().membank( TO8_SYS_LO )->set_entry( 0 );
+ machine.root_device().membank( TO8_SYS_HI )->set_entry( 0 );
+ machine.root_device().membank( TO8_DATA_LO )->set_entry( 0 );
+ machine.root_device().membank( TO8_DATA_HI )->set_entry( 0 );
+ machine.root_device().membank( TO8_BIOS_BANK )->set_entry( 0 );
+
+ /* save-state */
+ state_save_register_global( machine, thom_cart_nb_banks );
+ state_save_register_global( machine, thom_cart_bank );
+ state_save_register_global( machine, to7_lightpen );
+ state_save_register_global( machine, to7_lightpen_step );
+ state_save_register_global( machine, to8_reg_ram );
+ state_save_register_global( machine, to8_reg_cart );
+ state_save_register_global( machine, to8_reg_sys1 );
+ state_save_register_global( machine, to8_reg_sys2 );
+ state_save_register_global( machine, to8_lightpen_intr );
+ state_save_register_global( machine, to8_data_vpage );
+ state_save_register_global( machine, to8_cart_vpage );
+ state_save_register_global( machine, mo5_reg_cart );
+ state_save_register_global_pointer( machine, (mem + 0x10000), 0x10000 );
+ machine.save().register_postload(save_prepost_delegate(FUNC(mo6_update_ram_bank_postload), &machine));
+ machine.save().register_postload(save_prepost_delegate(FUNC(mo6_update_cart_bank_postload), &machine));
+}
diff --git a/src/mess/machine/ti85.c b/src/mess/machine/ti85.c
new file mode 100644
index 00000000000..77290e41816
--- /dev/null
+++ b/src/mess/machine/ti85.c
@@ -0,0 +1,725 @@
+/***************************************************************************
+ TI-85 driver by Krzysztof Strzecha
+
+ Functions to emulate general aspects of the machine (RAM, ROM, interrupts,
+ I/O ports)
+
+***************************************************************************/
+
+#include <stdarg.h>
+#include "emu.h"
+#include "cpu/z80/z80.h"
+#include "includes/ti85.h"
+
+#define TI85_SNAPSHOT_SIZE 32976
+#define TI86_SNAPSHOT_SIZE 131284
+
+
+static TIMER_CALLBACK(ti85_timer_callback)
+{
+ ti85_state *state = machine.driver_data<ti85_state>();
+ if (machine.root_device().ioport("ON")->read() & 0x01)
+ {
+ if (state->m_ON_interrupt_mask && !state->m_ON_pressed)
+ {
+ device_set_input_line(state->m_maincpu, 0, HOLD_LINE);
+ state->m_ON_interrupt_status = 1;
+ if (!state->m_timer_interrupt_mask) state->m_timer_interrupt_mask = 1;
+ }
+ state->m_ON_pressed = 1;
+ return;
+ }
+ else
+ state->m_ON_pressed = 0;
+ if (state->m_timer_interrupt_mask)
+ {
+ device_set_input_line(state->m_maincpu, 0, HOLD_LINE);
+ state->m_timer_interrupt_status = 1;
+ }
+}
+
+inline void ti8x_update_bank(address_space *space, UINT8 bank, UINT8 *base, UINT8 page, bool is_ram)
+{
+ ti85_state *state = space->machine().driver_data<ti85_state>();
+ static const char *const tag[] = {"bank1", "bank2", "bank3", "bank4"};
+
+ state->membank(tag[bank&3])->set_base(base + (0x4000 * page));
+
+ if (is_ram)
+ space->install_write_bank(bank * 0x4000, bank * 0x4000 + 0x3fff, tag[bank&3]);
+ else
+ space->nop_write(bank * 0x4000, bank * 0x4000 + 0x3fff);
+}
+
+static void update_ti85_memory (running_machine &machine)
+{
+ ti85_state *state = machine.driver_data<ti85_state>();
+ state->membank("bank2")->set_base(state->m_bios + 0x004000*state->m_ti8x_memory_page_1);
+}
+
+static void update_ti83p_memory (running_machine &machine)
+{
+ ti85_state *state = machine.driver_data<ti85_state>();
+ address_space *space = state->m_maincpu->memory().space(AS_PROGRAM);
+
+ if (state->m_ti8x_memory_page_1 & 0x40)
+ {
+ ti8x_update_bank(space, (state->m_ti83p_port4 & 1) ? 2 : 1, state->m_ti8x_ram, state->m_ti8x_memory_page_1 & 0x01, true);
+ }
+ else
+ {
+ ti8x_update_bank(space, (state->m_ti83p_port4 & 1) ? 2 : 1, state->m_bios, state->m_ti8x_memory_page_1 & 0x1f, false);
+ }
+
+ if (state->m_ti8x_memory_page_2 & 0x40)
+ {
+ ti8x_update_bank(space, (state->m_ti83p_port4 & 1) ? 3 : 2, state->m_ti8x_ram, state->m_ti8x_memory_page_2 & 0x01, true);
+ }
+ else
+ {
+ ti8x_update_bank(space, (state->m_ti83p_port4 & 1) ? 3 : 2, state->m_bios, state->m_ti8x_memory_page_2 & 0x1f, false);
+ }
+}
+
+static void update_ti86_memory (running_machine &machine)
+{
+ ti85_state *state = machine.driver_data<ti85_state>();
+ address_space *space = state->m_maincpu->memory().space(AS_PROGRAM);
+
+ if (state->m_ti8x_memory_page_1 & 0x40)
+ {
+ ti8x_update_bank(space, 1, state->m_ti8x_ram, state->m_ti8x_memory_page_1 & 0x07, true);
+ }
+ else
+ {
+ ti8x_update_bank(space, 1, state->m_bios, state->m_ti8x_memory_page_1 & 0x0f, false);
+ }
+
+ if (state->m_ti8x_memory_page_2 & 0x40)
+ {
+ ti8x_update_bank(space, 2, state->m_ti8x_ram, state->m_ti8x_memory_page_2 & 0x07, true);
+ }
+ else
+ {
+ ti8x_update_bank(space, 2, state->m_bios, state->m_ti8x_memory_page_2 & 0x0f, false);
+ }
+
+}
+
+/***************************************************************************
+ Machine Initialization
+***************************************************************************/
+
+MACHINE_START( ti81 )
+{
+ ti85_state *state = machine.driver_data<ti85_state>();
+ address_space *space = state->m_maincpu->memory().space(AS_PROGRAM);
+ state->m_bios = state->memregion("bios")->base();
+
+ state->m_timer_interrupt_mask = 0;
+ state->m_timer_interrupt_status = 0;
+ state->m_ON_interrupt_mask = 0;
+ state->m_ON_interrupt_status = 0;
+ state->m_ON_pressed = 0;
+ state->m_power_mode = 0;
+ state->m_keypad_mask = 0;
+ state->m_ti8x_memory_page_1 = 0;
+ state->m_LCD_memory_base = 0;
+ state->m_LCD_status = 0;
+ state->m_LCD_mask = 0;
+ state->m_video_buffer_width = 0;
+ state->m_interrupt_speed = 0;
+ state->m_port4_bit0 = 0;
+ state->m_ti81_port_7_data = 0;
+
+ machine.scheduler().timer_pulse(attotime::from_hz(200), FUNC(ti85_timer_callback));
+
+ space->unmap_write(0x0000, 0x3fff);
+ space->unmap_write(0x4000, 0x7fff);
+ state->membank("bank1")->set_base(state->m_bios);
+ state->membank("bank2")->set_base(state->m_bios + 0x04000);
+}
+
+MACHINE_RESET( ti85 )
+{
+ ti85_state *state = machine.driver_data<ti85_state>();
+ state->m_red_out = 0x00;
+ state->m_white_out = 0x00;
+ state->m_PCR = 0xc0;
+}
+
+
+MACHINE_START( ti83p )
+{
+ ti85_state *state = machine.driver_data<ti85_state>();
+ address_space *space = state->m_maincpu->memory().space(AS_PROGRAM);
+ state->m_bios = state->memregion("bios")->base();
+
+ state->m_timer_interrupt_mask = 0;
+ state->m_timer_interrupt_status = 0;
+ state->m_ON_interrupt_mask = 0;
+ state->m_ON_interrupt_status = 0;
+ state->m_ON_pressed = 0;
+ state->m_ti8x_memory_page_1 = 0;
+ state->m_ti8x_memory_page_2 = 0;
+ state->m_LCD_memory_base = 0;
+ state->m_LCD_status = 0;
+ state->m_LCD_mask = 0;
+ state->m_power_mode = 0;
+ state->m_keypad_mask = 0;
+ state->m_video_buffer_width = 0;
+ state->m_interrupt_speed = 0;
+ state->m_port4_bit0 = 0;
+
+ state->m_ti8x_ram = auto_alloc_array(machine, UINT8, 32*1024);
+ memset(state->m_ti8x_ram, 0, sizeof(UINT8)*32*1024);
+
+ space->unmap_write(0x0000, 0x3fff);
+ space->unmap_write(0x4000, 0x7fff);
+ space->unmap_write(0x8000, 0xbfff);
+
+ state->membank("bank1")->set_base(state->m_bios);
+ state->membank("bank2")->set_base(state->m_bios);
+ state->membank("bank3")->set_base(state->m_bios);
+ state->membank("bank4")->set_base(state->m_ti8x_ram);
+
+ machine.scheduler().timer_pulse(attotime::from_hz(200), FUNC(ti85_timer_callback));
+
+}
+
+
+MACHINE_START( ti86 )
+{
+ ti85_state *state = machine.driver_data<ti85_state>();
+ address_space *space = state->m_maincpu->memory().space(AS_PROGRAM);
+ state->m_bios = state->memregion("bios")->base();
+
+ state->m_timer_interrupt_mask = 0;
+ state->m_timer_interrupt_status = 0;
+ state->m_ON_interrupt_mask = 0;
+ state->m_ON_interrupt_status = 0;
+ state->m_ON_pressed = 0;
+ state->m_ti8x_memory_page_1 = 0;
+ state->m_ti8x_memory_page_2 = 0;
+ state->m_LCD_memory_base = 0;
+ state->m_LCD_status = 0;
+ state->m_LCD_mask = 0;
+ state->m_power_mode = 0;
+ state->m_keypad_mask = 0;
+ state->m_video_buffer_width = 0;
+ state->m_interrupt_speed = 0;
+ state->m_port4_bit0 = 0;
+
+ state->m_ti8x_ram = auto_alloc_array(machine, UINT8, 128*1024);
+ memset(state->m_ti8x_ram, 0, sizeof(UINT8)*128*1024);
+
+ space->unmap_write(0x0000, 0x3fff);
+
+ state->membank("bank1")->set_base(state->m_bios);
+ state->membank("bank2")->set_base(state->m_bios + 0x04000);
+
+ state->membank("bank4")->set_base(state->m_ti8x_ram);
+
+ machine.scheduler().timer_pulse(attotime::from_hz(200), FUNC(ti85_timer_callback));
+}
+
+
+/* I/O ports handlers */
+
+READ8_MEMBER(ti85_state::ti85_port_0000_r)
+{
+ return 0xff;
+}
+
+READ8_MEMBER(ti85_state::ti8x_keypad_r)
+{
+ int data = 0xff;
+ int port;
+ int bit;
+ static const char *const bitnames[] = { "BIT0", "BIT1", "BIT2", "BIT3", "BIT4", "BIT5", "BIT6", "BIT7" };
+
+ if (m_keypad_mask == 0x7f) return data;
+
+ for (bit = 0; bit < 7; bit++)
+ {
+ if (~m_keypad_mask&(0x01<<bit))
+ {
+ for (port = 0; port < 8; port++)
+ {
+ data ^= ioport(bitnames[port])->read() & (0x01<<bit) ? 0x01<<port : 0x00;
+ }
+ }
+ }
+ return data;
+}
+
+ READ8_MEMBER(ti85_state::ti85_port_0002_r )
+{
+ return 0xff;
+}
+
+ READ8_MEMBER(ti85_state::ti85_port_0003_r )
+{
+ int data = 0;
+
+ if (m_LCD_status)
+ data |= m_LCD_mask;
+ if (m_ON_interrupt_status)
+ data |= 0x01;
+ if (m_timer_interrupt_status)
+ data |= 0x04;
+ if (!m_ON_pressed)
+ data |= 0x08;
+ m_ON_interrupt_status = 0;
+ m_timer_interrupt_status = 0;
+ return data;
+}
+
+ READ8_MEMBER(ti85_state::ti85_port_0004_r )
+{
+ return 0xff;
+}
+
+ READ8_MEMBER(ti85_state::ti85_port_0005_r )
+{
+ return m_ti8x_memory_page_1;
+}
+
+READ8_MEMBER(ti85_state::ti85_port_0006_r)
+{
+ return m_power_mode;
+}
+
+READ8_MEMBER(ti85_state::ti8x_serial_r)
+{
+
+ //ti85_update_serial(m_serial);
+ return (m_white_out<<3)
+ | (m_red_out<<2)
+ //| ((ti85serial_white_in(m_serial,0)&(1-m_white_out))<<1)
+ //| (ti85serial_red_in(m_serial,0)&(1-m_red_out))
+ | 0x03 // no link cable
+ | m_PCR;
+}
+
+READ8_MEMBER(ti85_state::ti82_port_0002_r )
+{
+ return m_ti8x_port2;
+}
+
+READ8_MEMBER(ti85_state::ti86_port_0005_r)
+{
+ return m_ti8x_memory_page_1;
+}
+
+READ8_MEMBER(ti85_state::ti86_port_0006_r )
+{
+ return m_ti8x_memory_page_2;
+}
+
+READ8_MEMBER(ti85_state::ti83_port_0000_r)
+{
+ return ((m_ti8x_memory_page_1 & 0x08) << 1) | 0x0C;
+}
+
+READ8_MEMBER(ti85_state::ti83_port_0002_r )
+{
+ return m_ti8x_port2;
+}
+
+READ8_MEMBER(ti85_state::ti83_port_0003_r )
+{
+ int data = 0;
+
+ data |= m_LCD_mask;
+
+ if (m_ON_interrupt_status)
+ data |= 0x01;
+ if (!m_ON_pressed)
+ data |= 0x08;
+ m_ON_interrupt_status = 0;
+ m_timer_interrupt_status = 0;
+ return data;
+}
+
+READ8_MEMBER(ti85_state::ti8x_plus_serial_r)
+{
+
+ //ti85_update_serial(m_serial);
+ return (m_white_out<<3)
+ | (m_red_out<<2)
+ //| ((ti85serial_white_in(m_serial,0)&(1-m_white_out))<<1)
+ //| (ti85serial_red_in(m_serial,0)&(1-m_red_out))
+ | 0x03 // no link cable
+ | m_PCR;
+}
+
+READ8_MEMBER(ti85_state::ti83p_port_0002_r )
+{
+ return m_ti8x_port2|3;
+}
+
+WRITE8_MEMBER(ti85_state::ti81_port_0007_w)
+{
+ m_ti81_port_7_data = data;
+}
+
+WRITE8_MEMBER(ti85_state::ti85_port_0000_w)
+{
+ m_LCD_memory_base = data;
+}
+
+WRITE8_MEMBER(ti85_state::ti8x_keypad_w)
+{
+ m_keypad_mask = data&0x7f;
+}
+
+WRITE8_MEMBER(ti85_state::ti85_port_0002_w)
+{
+ m_LCD_contrast = data&0x1f;
+}
+
+WRITE8_MEMBER(ti85_state::ti85_port_0003_w)
+{
+ if (m_LCD_status && !(data&0x08)) m_timer_interrupt_mask = 0;
+ m_ON_interrupt_mask = data&0x01;
+// m_timer_interrupt_mask = data&0x04;
+ m_LCD_mask = data&0x02;
+ m_LCD_status = data&0x08;
+}
+
+WRITE8_MEMBER(ti85_state::ti85_port_0004_w)
+{
+ m_video_buffer_width = (data>>3)&0x03;
+ m_interrupt_speed = (data>>1)&0x03;
+ m_port4_bit0 = data&0x01;
+}
+
+WRITE8_MEMBER(ti85_state::ti85_port_0005_w)
+{
+ m_ti8x_memory_page_1 = data;
+ update_ti85_memory(machine());
+}
+
+WRITE8_MEMBER(ti85_state::ti85_port_0006_w)
+{
+ m_power_mode = data;
+}
+
+WRITE8_MEMBER(ti85_state::ti8x_serial_w)
+{
+
+ speaker_level_w(m_speaker, ( (data>>2)|(data>>3) ) & 0x01);
+ m_red_out=(data>>2)&0x01;
+ m_white_out=(data>>3)&0x01;
+ //ti85serial_red_out( m_serial, 0, m_red_out );
+ //ti85serial_white_out( m_serial, 0, m_white_out );
+ //ti85_update_serial(m_serial);
+ m_PCR = data&0xf0;
+}
+
+WRITE8_MEMBER(ti85_state::ti86_port_0005_w)
+{
+ m_ti8x_memory_page_1 = data&((data&0x40)?0x47:0x4f);
+ update_ti86_memory(machine());
+}
+
+WRITE8_MEMBER(ti85_state::ti86_port_0006_w)
+{
+ m_ti8x_memory_page_2 = data&((data&0x40)?0x47:0x4f);
+ update_ti86_memory(machine());
+}
+
+WRITE8_MEMBER(ti85_state::ti82_port_0002_w)
+{
+ m_ti8x_memory_page_1 = (data & 0x07);
+ update_ti85_memory(machine());
+ m_ti8x_port2 = data;
+}
+
+WRITE8_MEMBER(ti85_state::ti83_port_0000_w)
+{
+ m_ti8x_memory_page_1 = (m_ti8x_memory_page_1 & 7) | ((data & 16) >> 1);
+ update_ti85_memory(machine());
+}
+
+WRITE8_MEMBER(ti85_state::ti83_port_0002_w)
+{
+ m_ti8x_memory_page_1 = (m_ti8x_memory_page_1 & 8) | (data & 7);
+ update_ti85_memory(machine());
+ m_ti8x_port2 = data;
+}
+
+WRITE8_MEMBER(ti85_state::ti83_port_0003_w)
+{
+ if (m_LCD_status && !(data&0x08)) m_timer_interrupt_mask = 0;
+ m_ON_interrupt_mask = data&0x01;
+ //m_timer_interrupt_mask = data&0x04;
+ m_LCD_mask = data&0x02;
+ m_LCD_status = data&0x08;
+}
+
+WRITE8_MEMBER(ti85_state::ti8x_plus_serial_w)
+{
+
+ speaker_level_w(m_speaker,( (data>>0)|(data>>1) )&0x01 );
+ m_red_out=(data>>0)&0x01;
+ m_white_out=(data>>1)&0x01;
+ //ti85serial_red_out( m_serial, 0, m_red_out );
+ //ti85serial_white_out( m_serial, 0, m_white_out );
+ //ti85_update_serial(m_serial);
+ m_PCR = data&0xf0;
+}
+
+WRITE8_MEMBER(ti85_state::ti83p_port_0002_w)
+{
+ m_ti8x_port2 = data;
+}
+
+WRITE8_MEMBER(ti85_state::ti83p_port_0003_w)
+{
+ m_LCD_mask = (data&0x08) >> 2;
+ m_ON_interrupt_mask = data & 0x01;
+}
+
+WRITE8_MEMBER(ti85_state::ti83p_port_0004_w)
+{
+ if ((data & 1) && !(m_ti83p_port4 & 1))
+ {
+ m_ti8x_memory_page_1 = 0x1f;
+ m_ti8x_memory_page_2 = 0x1f;
+ }
+ else if (!(data & 1) && (m_ti83p_port4 & 1))
+ {
+ m_ti8x_memory_page_1 = 0x1f;
+ m_ti8x_memory_page_2 = 0x40;
+ }
+ update_ti83p_memory(machine());
+ m_ti83p_port4 = data;
+}
+
+WRITE8_MEMBER(ti85_state::ti83p_port_0006_w)
+{
+ m_ti8x_memory_page_1 = data & ((data&0x40) ? 0x41 : 0x5f);
+ update_ti83p_memory(machine());
+}
+
+WRITE8_MEMBER(ti85_state::ti83p_port_0007_w)
+{
+ m_ti8x_memory_page_2 = data & ((data&0x40) ? 0x41 : 0x5f);
+ update_ti83p_memory(machine());
+}
+
+/* NVRAM functions */
+NVRAM_HANDLER( ti83p )
+{
+ ti85_state *state = machine.driver_data<ti85_state>();
+ if (read_or_write)
+ {
+ file->write(state->m_ti8x_ram, sizeof(unsigned char)*32*1024);
+ }
+ else
+ {
+ if (file)
+ {
+ file->read(state->m_ti8x_ram, sizeof(unsigned char)*32*1024);
+ cpu_set_reg(state->m_maincpu, Z80_PC,0x0c59);
+ }
+ else
+ memset(state->m_ti8x_ram, 0, sizeof(unsigned char)*32*1024);
+ }
+}
+
+NVRAM_HANDLER( ti86 )
+{
+ ti85_state *state = machine.driver_data<ti85_state>();
+ if (read_or_write)
+ {
+ file->write(state->m_ti8x_ram, sizeof(unsigned char)*128*1024);
+ }
+ else
+ {
+ if (file)
+ {
+ file->read(state->m_ti8x_ram, sizeof(unsigned char)*128*1024);
+ cpu_set_reg(state->m_maincpu, Z80_PC,0x0c59);
+ }
+ else
+ memset(state->m_ti8x_ram, 0, sizeof(unsigned char)*128*1024);
+ }
+}
+
+/***************************************************************************
+ TI calculators snapshot files (SAV)
+***************************************************************************/
+
+static void ti8x_snapshot_setup_registers (running_machine &machine, UINT8 * data)
+{
+ ti85_state *state = machine.driver_data<ti85_state>();
+ unsigned char lo,hi;
+ unsigned char * reg = data + 0x40;
+
+ /* Set registers */
+ lo = reg[0x00] & 0x0ff;
+ hi = reg[0x01] & 0x0ff;
+ cpu_set_reg(state->m_maincpu, Z80_AF, (hi << 8) | lo);
+ lo = reg[0x04] & 0x0ff;
+ hi = reg[0x05] & 0x0ff;
+ cpu_set_reg(state->m_maincpu, Z80_BC, (hi << 8) | lo);
+ lo = reg[0x08] & 0x0ff;
+ hi = reg[0x09] & 0x0ff;
+ cpu_set_reg(state->m_maincpu, Z80_DE, (hi << 8) | lo);
+ lo = reg[0x0c] & 0x0ff;
+ hi = reg[0x0d] & 0x0ff;
+ cpu_set_reg(state->m_maincpu, Z80_HL, (hi << 8) | lo);
+ lo = reg[0x10] & 0x0ff;
+ hi = reg[0x11] & 0x0ff;
+ cpu_set_reg(state->m_maincpu, Z80_IX, (hi << 8) | lo);
+ lo = reg[0x14] & 0x0ff;
+ hi = reg[0x15] & 0x0ff;
+ cpu_set_reg(state->m_maincpu, Z80_IY, (hi << 8) | lo);
+ lo = reg[0x18] & 0x0ff;
+ hi = reg[0x19] & 0x0ff;
+ cpu_set_reg(state->m_maincpu, Z80_PC, (hi << 8) | lo);
+ lo = reg[0x1c] & 0x0ff;
+ hi = reg[0x1d] & 0x0ff;
+ cpu_set_reg(state->m_maincpu, Z80_SP, (hi << 8) | lo);
+ lo = reg[0x20] & 0x0ff;
+ hi = reg[0x21] & 0x0ff;
+ cpu_set_reg(state->m_maincpu, Z80_AF2, (hi << 8) | lo);
+ lo = reg[0x24] & 0x0ff;
+ hi = reg[0x25] & 0x0ff;
+ cpu_set_reg(state->m_maincpu, Z80_BC2, (hi << 8) | lo);
+ lo = reg[0x28] & 0x0ff;
+ hi = reg[0x29] & 0x0ff;
+ cpu_set_reg(state->m_maincpu, Z80_DE2, (hi << 8) | lo);
+ lo = reg[0x2c] & 0x0ff;
+ hi = reg[0x2d] & 0x0ff;
+ cpu_set_reg(state->m_maincpu, Z80_HL2, (hi << 8) | lo);
+ cpu_set_reg(state->m_maincpu, Z80_IFF1, reg[0x30]&0x0ff);
+ cpu_set_reg(state->m_maincpu, Z80_IFF2, reg[0x34]&0x0ff);
+ cpu_set_reg(state->m_maincpu, Z80_HALT, reg[0x38]&0x0ff);
+ cpu_set_reg(state->m_maincpu, Z80_IM, reg[0x3c]&0x0ff);
+ cpu_set_reg(state->m_maincpu, Z80_I, reg[0x40]&0x0ff);
+
+ cpu_set_reg(state->m_maincpu, Z80_R, (reg[0x44]&0x7f) | (reg[0x48]&0x80));
+
+ device_set_input_line(state->m_maincpu, 0, 0);
+ device_set_input_line(state->m_maincpu, INPUT_LINE_NMI, 0);
+ device_set_input_line(state->m_maincpu, INPUT_LINE_HALT, 0);
+}
+
+static void ti85_setup_snapshot (running_machine &machine, UINT8 * data)
+{
+ ti85_state *state = machine.driver_data<ti85_state>();
+ address_space *space = state->m_maincpu->memory().space(AS_PROGRAM);
+ int i;
+ unsigned char lo,hi;
+ unsigned char * hdw = data + 0x8000 + 0x94;
+
+ ti8x_snapshot_setup_registers (machine, data);
+
+ /* Memory dump */
+ for (i = 0; i < 0x8000; i++)
+ space->write_byte(i + 0x8000, data[i+0x94]);
+
+ state->m_keypad_mask = hdw[0x00]&0x7f;
+
+ state->m_ti8x_memory_page_1 = hdw[0x08]&0xff;
+ update_ti85_memory(machine);
+
+ state->m_power_mode = hdw[0x14]&0xff;
+
+ lo = hdw[0x28] & 0x0ff;
+ hi = hdw[0x29] & 0x0ff;
+ state->m_LCD_memory_base = (((hi << 8) | lo)-0xc000)>>8;
+
+ state->m_LCD_status = hdw[0x2c]&0xff ? 0 : 0x08;
+ if (state->m_LCD_status) state->m_LCD_mask = 0x02;
+
+ state->m_LCD_contrast = hdw[0x30]&0xff;
+
+ state->m_timer_interrupt_mask = !hdw[0x38];
+ state->m_timer_interrupt_status = 0;
+
+ state->m_ON_interrupt_mask = !state->m_LCD_status && state->m_timer_interrupt_status;
+ state->m_ON_interrupt_status = 0;
+ state->m_ON_pressed = 0;
+
+ state->m_video_buffer_width = 0x02;
+ state->m_interrupt_speed = 0x03;
+}
+
+static void ti86_setup_snapshot (running_machine &machine, UINT8 * data)
+{
+ ti85_state *state = machine.driver_data<ti85_state>();
+ unsigned char lo,hi;
+ unsigned char * hdw = data + 0x20000 + 0x94;
+
+ ti8x_snapshot_setup_registers (machine, data);
+
+ /* Memory dump */
+ memcpy(state->m_ti8x_ram, data+0x94, 0x20000);
+
+ state->m_keypad_mask = hdw[0x00]&0x7f;
+
+ state->m_ti8x_memory_page_1 = hdw[0x04]&0xff ? 0x40 : 0x00;
+ state->m_ti8x_memory_page_1 |= hdw[0x08]&0x0f;
+
+ state->m_ti8x_memory_page_2 = hdw[0x0c]&0xff ? 0x40 : 0x00;
+ state->m_ti8x_memory_page_2 |= hdw[0x10]&0x0f;
+
+ update_ti86_memory(machine);
+
+ lo = hdw[0x2c] & 0x0ff;
+ hi = hdw[0x2d] & 0x0ff;
+ state->m_LCD_memory_base = (((hi << 8) | lo)-0xc000)>>8;
+
+ state->m_LCD_status = hdw[0x30]&0xff ? 0 : 0x08;
+ if (state->m_LCD_status) state->m_LCD_mask = 0x02;
+
+ state->m_LCD_contrast = hdw[0x34]&0xff;
+
+ state->m_timer_interrupt_mask = !hdw[0x3c];
+ state->m_timer_interrupt_status = 0;
+
+ state->m_ON_interrupt_mask = !state->m_LCD_status && state->m_timer_interrupt_status;
+ state->m_ON_interrupt_status = 0;
+ state->m_ON_pressed = 0;
+
+ state->m_video_buffer_width = 0x02;
+ state->m_interrupt_speed = 0x03;
+}
+
+SNAPSHOT_LOAD( ti8x )
+{
+ int expected_snapshot_size = 0;
+ UINT8 *ti8x_snapshot_data;
+
+ if (!strncmp(image.device().machine().system().name, "ti85", 4))
+ expected_snapshot_size = TI85_SNAPSHOT_SIZE;
+ else if (!strncmp(image.device().machine().system().name, "ti86", 4))
+ expected_snapshot_size = TI86_SNAPSHOT_SIZE;
+
+ logerror("Snapshot loading\n");
+
+ if (snapshot_size != expected_snapshot_size)
+ {
+ logerror ("Incomplete snapshot file\n");
+ return IMAGE_INIT_FAIL;
+ }
+
+ if (!(ti8x_snapshot_data = (UINT8*)malloc(snapshot_size)))
+ return IMAGE_INIT_FAIL;
+
+ image.fread( ti8x_snapshot_data, snapshot_size);
+
+ if (!strncmp(image.device().machine().system().name, "ti85", 4))
+ ti85_setup_snapshot(image.device().machine(), ti8x_snapshot_data);
+ else if (!strncmp(image.device().machine().system().name, "ti86", 4))
+ ti86_setup_snapshot(image.device().machine(), ti8x_snapshot_data);
+
+ free(ti8x_snapshot_data);
+ return IMAGE_INIT_PASS;
+}
+
diff --git a/src/mess/machine/ti85_ser.c b/src/mess/machine/ti85_ser.c
new file mode 100644
index 00000000000..6c7de85fc3f
--- /dev/null
+++ b/src/mess/machine/ti85_ser.c
@@ -0,0 +1,1544 @@
+
+#include "emu.h"
+#include "emuopts.h"
+#include "ti85_ser.h"
+
+enum
+{
+ TI85_SEND_STOP,
+ TI85_SEND_HEADER,
+ TI85_RECEIVE_OK_1,
+ TI85_RECEIVE_ANSWER_1,
+ TI85_RECEIVE_ANSWER_2,
+ TI85_RECEIVE_ANSWER_3,
+ TI85_SEND_OK,
+ TI85_SEND_DATA,
+ TI85_RECEIVE_OK_2,
+ TI85_SEND_END,
+ TI85_RECEIVE_OK_3,
+ TI85_RECEIVE_HEADER_1,
+ TI85_PREPARE_VARIABLE_DATA,
+ TI85_RECEIVE_HEADER_2,
+ TI85_SEND_OK_1,
+ TI85_SEND_CONTINUE,
+ TI85_RECEIVE_OK,
+ TI85_RECEIVE_DATA,
+ TI85_SEND_OK_2,
+ TI85_RECEIVE_END_OR_HEADER_1,
+ TI85_SEND_OK_3,
+ TI85_PREPARE_SCREEN_REQUEST,
+ TI85_SEND_SCREEN_REQUEST
+};
+
+//supported image formats
+enum
+{
+ TI_FILE_UNK,
+ TI_FILE_V1, //used for TI-85 and TI-86 image
+ TI_FILE_V2, //used for TI-82, TI-83 and TI-73 image
+ TI_FILE_V3 //used for TI-83+ and TI-84+ image
+};
+
+#define TI85_HEADER_SIZE 0x37
+
+#define TI85_SEND_VARIABLES 1
+#define TI85_SEND_BACKUP 2
+#define TI85_RECEIVE_BACKUP 3
+#define TI85_RECEIVE_VARIABLES 4
+#define TI85_RECEIVE_SCREEN 5
+
+#define TI85_PC_OK_PACKET_SIZE 4
+#define TI85_PC_END_PACKET_SIZE 4
+
+#define TI82_BACKUP_ID 0x0f //used by the TI-82
+#define TI85_BACKUP_ID 0x1d //used by the TI-85 and TI-86
+#define TI83_BACKUP_ID 0x13 //used by the TI-73, TI-83 and TI-83+
+
+//known tranfer ID
+#define TI_TRANFER_ID_TI73 0x07
+#define TI_TRANFER_ID_TI82 0x02
+#define TI_TRANFER_ID_TI83 0x03
+#define TI_TRANFER_ID_TI83P 0x23
+#define TI_TRANFER_ID_TI85 0x05
+#define TI_TRANFER_ID_TI86 0x06
+
+//packet type
+#define TI_OK_PACKET 0x56
+#define TI_CONTINUE_PACKET 0x09
+#define TI_SCREEN_REQUEST_PACKET 0x6d
+#define TI_END_PACKET 0x92
+
+static const UINT8 ti73_file_signature[] = {0x2a, 0x2a, 0x54, 0x49, 0x37, 0x33, 0x2a, 0x2a, 0x1a, 0x0a, 0x00};
+static const UINT8 ti85_file_signature[] = {0x2a, 0x2a, 0x54, 0x49, 0x38, 0x35, 0x2a, 0x2a, 0x1a, 0x0c, 0x00};
+static const UINT8 ti82_file_signature[] = {0x2a, 0x2a, 0x54, 0x49, 0x38, 0x32, 0x2a, 0x2a, 0x1a, 0x0a, 0x00};
+static const UINT8 ti83_file_signature[] = {0x2a, 0x2a, 0x54, 0x49, 0x38, 0x33, 0x2a, 0x2a, 0x1a, 0x0a, 0x00};
+static const UINT8 ti83p_file_signature[]= {0x2a, 0x2a, 0x54, 0x49, 0x38, 0x33, 0x46, 0x2a, 0x1a, 0x0a, 0x00};
+static const UINT8 ti86_file_signature[] = {0x2a, 0x2a, 0x54, 0x49, 0x38, 0x36, 0x2a, 0x2a, 0x1a, 0x0a, 0x00};
+
+typedef struct {
+ UINT16 head_size;
+ UINT16 data_size;
+ unsigned char type;
+ unsigned char name_size;
+ unsigned int offset;
+} ti85_entry;
+
+
+typedef struct {
+ UINT8* header;
+ UINT16 header_size;
+ UINT8* ok;
+ UINT16 ok_size;
+ UINT8* data;
+ UINT32 data_size;
+} ti85_serial_variable;
+
+
+typedef struct {
+ ti85_serial_variable * variables;
+ UINT8* end;
+ UINT16 end_size;
+ UINT16 number_of_variables;
+} ti85_serial_data;
+
+
+typedef struct
+{
+ UINT8 status;
+ int transfer_type;
+ UINT8 image_type;
+ UINT8 send_id; /* ID used for PC to TI transfer */
+ UINT8 receive_id; /* ID used for TI to PC transfer */
+ UINT8 red_out; /* signal line from machine */
+ UINT8 white_out; /* signal line from machine */
+ UINT8 red_in; /* signal line to machine */
+ UINT8 white_in; /* signal line to machine */
+ UINT8 *receive_buffer;
+ UINT8 *receive_data;
+ ti85_serial_data stream;
+ /* receive_data_counter and send_data_counter can be combined? */
+ UINT32 receive_data_counter; /* from ti85_receive_serial */
+ UINT32 send_data_counter; /* from ti85_send_serial */
+ /* variables_variable_number, send_backup_variable_number, and backup_variable_number can be combined? */
+ UINT16 variables_variable_number; /* from ti85_send_variables */
+ UINT16 send_backup_variable_number; /* from ti85_send_backup */
+ int variable_number; /* from ti85_receive_variables */
+ UINT8 *var_data; /* from ti85_receive_variables */
+ UINT32 var_file_number; /* from ti85_receive_variables */
+ UINT8 *var_file_data; /* from ti85_receive_variables */
+ int var_file_size; /* from ti85_receive_variables */
+ int backup_variable_number; /* from ti85_receive_backup */
+ int backup_data_size[3]; /* from ti85_receive_backup */
+ UINT8 *backup_file_data; /* from ti85_receive_backup */
+ UINT32 backup_file_number; /* from ti85_receive_backup */
+ UINT32 image_file_number; /* from ti85_receive_screen */
+} ti85serial_state;
+
+
+INLINE ti85serial_state *get_token(device_t *device)
+{
+ assert(device != NULL);
+ assert((device->type() == TI82SERIAL) ||
+ (device->type() == TI73SERIAL) ||
+ (device->type() == TI83PSERIAL) ||
+ (device->type() == TI85SERIAL) ||
+ (device->type() == TI86SERIAL));
+ return (ti85serial_state *) downcast<legacy_device_base *>(device)->token();
+}
+
+
+static UINT16 ti85_calculate_checksum(const UINT8* data, unsigned int size)
+{
+ UINT16 checksum = 0;
+ unsigned int i;
+
+ for (i = 0; i<size; i++)
+ checksum += data[i];
+ return checksum;
+}
+
+
+static UINT16 ti85_variables_count (const UINT8 * ti85_data, unsigned int ti85_data_size)
+{
+ unsigned int pos, head_size, var_size;
+ UINT16 number_of_entries = 0;
+ pos = TI85_HEADER_SIZE;
+ while (pos < ti85_data_size-2)
+ {
+ head_size = ti85_data[pos+0x00] + ti85_data[pos+0x01]*256;
+ var_size = ti85_data[pos+0x02] + ti85_data[pos+0x03]*256;
+ pos += head_size+var_size+4;
+ number_of_entries++;
+ }
+ return number_of_entries;
+}
+
+
+static void ti85_free_serial_data_memory (device_t *device)
+{
+ ti85serial_state *ti85serial = get_token( device );
+
+ if (ti85serial->receive_buffer)
+ {
+ free (ti85serial->receive_buffer);
+ ti85serial->receive_buffer = NULL;
+ }
+ if (ti85serial->receive_data)
+ {
+ free (ti85serial->receive_data);
+ ti85serial->receive_data = NULL;
+ }
+}
+
+
+static int ti85_alloc_serial_data_memory (device_t *device, UINT32 size)
+{
+ ti85serial_state *ti85serial = get_token( device );
+
+ if (!ti85serial->receive_buffer)
+ {
+ ti85serial->receive_buffer = (UINT8*) malloc (8*size*sizeof(UINT8));
+ if (!ti85serial->receive_buffer)
+ return 0;
+ }
+
+ if (!ti85serial->receive_data)
+ {
+ ti85serial->receive_data = (UINT8*) malloc (size * sizeof(UINT8));
+ if (!ti85serial->receive_data)
+ {
+ free (ti85serial->receive_buffer);
+ ti85serial->receive_buffer = NULL;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+
+static void ti85_backup_read (const UINT8 * ti85_data, unsigned int ti85_data_size, ti85_entry * ti85_entries)
+{
+ unsigned int pos = 0x42+2;
+
+ ti85_entries[0].head_size = 0x09;
+ ti85_entries[0].data_size = ti85_data[0x39] + ti85_data[0x3a]*256;
+ ti85_entries[0].offset = pos;
+ pos += ti85_entries[0].data_size + 2;
+ ti85_entries[1].head_size = 0;
+ ti85_entries[1].data_size = ti85_data[0x3c] + ti85_data[0x3d]*256;
+ ti85_entries[1].offset = pos;
+ pos += ti85_entries[1].data_size + 2;
+ ti85_entries[2].head_size = 0;
+ ti85_entries[2].data_size = ti85_data[0x3e] + ti85_data[0x3f]*256;
+ ti85_entries[2].offset = pos;
+}
+
+
+static void ti85_variables_read (device_t *device, const UINT8 * ti85_data, unsigned int ti85_data_size, ti85_entry * ti85_entries)
+{
+ ti85serial_state *ti85serial = get_token( device );
+ unsigned int pos, i=0;
+
+ pos = TI85_HEADER_SIZE;
+ while (pos < ti85_data_size-2)
+ {
+ ti85_entries[i].head_size = ti85_data[pos+0x00] + ti85_data[pos+0x01]*256;
+ ti85_entries[i].data_size = ti85_data[pos+0x02] + ti85_data[pos+0x03]*256;
+ ti85_entries[i].type = ti85_data[pos+0x04];
+ ti85_entries[i].name_size = (ti85serial->image_type != TI_FILE_V1) ? 8 : ti85_data[pos+0x05];
+ ti85_entries[i].offset = pos;
+ pos += ti85_entries[i].head_size+ti85_entries[i].data_size+4;
+ i++;
+ }
+}
+
+
+static int ti85_receive_serial (device_t *device, UINT8* received_data, UINT32 received_data_size)
+{
+ ti85serial_state *ti85serial = get_token( device );
+
+ if (ti85serial->receive_data_counter >= received_data_size)
+ {
+ if (!ti85serial->red_out && !ti85serial->white_out)
+ {
+ ti85serial->red_in = ti85serial->white_in = 1;
+ ti85serial->receive_data_counter = 0;
+ return 0;
+ }
+ return 1;
+ }
+
+ if (ti85serial->red_in && ti85serial->white_in && (ti85serial->red_out!=ti85serial->white_out))
+ {
+ ti85serial->white_in = ti85serial->white_out;
+ ti85serial->red_in = ti85serial->red_out;
+ received_data[ti85serial->receive_data_counter] = ti85serial->white_out;
+ return 1;
+ }
+
+ if (ti85serial->red_in!=ti85serial->white_in && !ti85serial->red_out && !ti85serial->white_out)
+ {
+ ti85serial->red_in = ti85serial->white_in = 1;
+ ti85serial->receive_data_counter ++;
+ return 1;
+ }
+ return 1;
+}
+
+
+static int ti85_send_serial(device_t *device, UINT8* serial_data, UINT32 serial_data_size)
+{
+ ti85serial_state *ti85serial = get_token( device );
+
+ if (ti85serial->send_data_counter>=serial_data_size)
+ {
+ if (!ti85serial->red_out && !ti85serial->white_out)
+ {
+ ti85serial->red_in = ti85serial->white_in = 1;
+ ti85serial->send_data_counter = 0;
+ return 0;
+ }
+ ti85serial->red_in = ti85serial->white_in = 1;
+ return 1;
+ }
+
+ if (ti85serial->red_in && ti85serial->white_in && !ti85serial->red_out && !ti85serial->white_out)
+ {
+ ti85serial->red_in = serial_data[ti85serial->send_data_counter] ? 1 : 0;
+ ti85serial->white_in = serial_data[ti85serial->send_data_counter] ? 0 : 1;
+ return 1;
+ }
+
+ if ((ti85serial->red_in == ti85serial->red_out) && (ti85serial->white_in == ti85serial->white_out))
+ {
+ ti85serial->red_in = ti85serial->white_in = 1;
+ ti85serial->send_data_counter++;
+ return 1;
+ }
+ return 1;
+}
+
+
+static void ti85_convert_data_to_stream (const UINT8* file_data, unsigned int size, UINT8* serial_data)
+{
+ unsigned int i, bits;
+
+ for (i=0; i<size; i++)
+ for (bits = 0; bits < 8; bits++)
+ serial_data[i*8+bits] = (file_data[i]>>bits) & 0x01;
+}
+
+
+static void ti85_append_head_to_stream (UINT8 transfer_id, UINT8 tranfer_type, UINT8* serial_data)
+{
+ UINT8 tmp_data[4];
+
+ tmp_data[0] = transfer_id;
+ tmp_data[1] = tranfer_type;
+ tmp_data[2] = 0;
+ tmp_data[3] = 0;
+
+ ti85_convert_data_to_stream(tmp_data, sizeof(tmp_data), serial_data);
+}
+
+
+static void ti85_convert_stream_to_data (const UINT8* serial_data, UINT32 size, UINT8* data)
+{
+ UINT32 i;
+ UINT8 bits;
+
+ size = size/8;
+
+ for (i=0; i<size; i++)
+ {
+ data[i] = 0;
+ for (bits = 0; bits < 8; bits++)
+ data[i] |= serial_data[i*8+bits]<<bits;
+ }
+}
+
+
+static int ti85_convert_file_data_to_serial_stream (device_t *device, const UINT8* file_data, unsigned int file_size, ti85_serial_data* serial_data)
+{
+ ti85serial_state *ti85serial = get_token( device );
+ UINT16 i;
+ UINT16 number_of_entries;
+ UINT8 backup_id = (ti85serial->image_type == TI_FILE_V1) ? TI85_BACKUP_ID : ((device->type() == TI82SERIAL) ? TI82_BACKUP_ID : TI83_BACKUP_ID);
+
+ ti85_entry* ti85_entries = NULL;
+
+ UINT8* temp_data_to_convert = NULL;
+ UINT16 checksum;
+
+ //verify that the provided file is compatible with the model
+ if (device->type() == TI73SERIAL)
+ if (strncmp((char *) file_data, (char *) ti73_file_signature, 11))
+ return 0;
+ if (device->type() == TI85SERIAL)
+ if (strncmp((char *) file_data, (char *) ti85_file_signature, 11))
+ return 0;
+ if (device->type() == TI82SERIAL)
+ if (strncmp((char *) file_data, (char *) ti82_file_signature, 11))
+ return 0;
+ if (device->type() == TI83PSERIAL) //TI-83+ is compatible with TI-83 and TI-82 file
+ if (strncmp((char *) file_data, (char *) ti83p_file_signature, 10) && strncmp((char *) file_data, (char *) ti83_file_signature, 11)
+ && strncmp((char *) file_data, (char *) ti82_file_signature, 11))
+ return 0;
+ if (device->type() == TI86SERIAL) //TI-86 is compatible with TI-85 file
+ if (strncmp((char *) file_data, (char *) ti86_file_signature, 11) && strncmp((char *) file_data, (char *) ti85_file_signature, 11))
+ return 0;
+
+ //identify the image
+ if (!strncmp((char *) file_data, (char *) ti73_file_signature, 11))
+ {
+ ti85serial->send_id = TI_TRANFER_ID_TI73;
+ ti85serial->image_type = TI_FILE_V2;
+ }
+ else if (!strncmp((char *) file_data, (char *) ti85_file_signature, 11))
+ {
+ ti85serial->send_id = TI_TRANFER_ID_TI85;
+ ti85serial->image_type = TI_FILE_V1;
+ }
+ else if (!strncmp((char *) file_data, (char *) ti82_file_signature, 11))
+ {
+ ti85serial->send_id = TI_TRANFER_ID_TI82;
+ ti85serial->image_type = TI_FILE_V2;
+ }
+ else if (!strncmp((char *) file_data, (char *) ti83_file_signature, 11))
+ {
+ ti85serial->send_id = TI_TRANFER_ID_TI83;
+ ti85serial->image_type = TI_FILE_V2;
+ }
+ else if (!strncmp((char *) file_data, (char *) ti83p_file_signature, 11))
+ {
+ ti85serial->send_id = TI_TRANFER_ID_TI83P;
+ ti85serial->image_type = TI_FILE_V3;
+ }
+ else if (!strncmp((char *) file_data, (char *) ti86_file_signature, 11))
+ {
+ ti85serial->send_id = TI_TRANFER_ID_TI86;
+ ti85serial->image_type = TI_FILE_V1;
+ }
+
+ logerror("Image ID: 0x%02x, version: 0x%02x\n", ti85serial->send_id, ti85serial->image_type);
+
+ /*Serial stream preparing*/
+ serial_data->end = NULL;
+
+ number_of_entries = (file_data[0x3b]==backup_id) ? 3 : ti85_variables_count(file_data, file_size);
+ if (!number_of_entries) return 0;
+
+ serial_data->variables = (ti85_serial_variable*)malloc(sizeof(ti85_serial_variable)*number_of_entries);
+ if (!serial_data->variables) return 0;
+
+ for (i=0; i<number_of_entries; i++)
+ {
+ serial_data->variables[i].header = NULL;
+ serial_data->variables[i].ok = NULL;
+ serial_data->variables[i].data = NULL;
+ }
+
+ serial_data->number_of_variables = number_of_entries;
+
+ ti85_entries = (ti85_entry*) malloc (sizeof(ti85_entry)*number_of_entries);
+ if (!ti85_entries) return 0;
+
+ if (file_data[0x3b]==backup_id)
+ {
+ ti85serial->transfer_type = TI85_SEND_BACKUP;
+ ti85_backup_read (file_data, file_size, ti85_entries);
+ }
+ else
+ {
+ ti85serial->transfer_type = TI85_SEND_VARIABLES;
+ ti85_variables_read (device, file_data, file_size, ti85_entries);
+ }
+ for (i=0; i<number_of_entries; i++)
+ {
+ /*Header packet*/
+ if (file_data[0x3b]==backup_id)
+ {
+ if (!i)
+ {
+ temp_data_to_convert = (UINT8*) malloc (0x0f);
+ if (!temp_data_to_convert)
+ {
+ free (ti85_entries);
+ return 0;
+ }
+ serial_data->variables[i].header = (UINT8*) malloc (0x0f*8);
+
+ if (!serial_data->variables[i].header)
+ {
+ free (ti85_entries);
+ free (temp_data_to_convert);
+ return 0;
+ }
+ serial_data->variables[i].header_size = 0x0f*8;
+ temp_data_to_convert[0] = ti85serial->send_id; //PC sends
+ temp_data_to_convert[1] = 0x06; //header
+ memcpy( temp_data_to_convert+0x02, file_data+0x37, 0x0b);
+ checksum = ti85_calculate_checksum(temp_data_to_convert+4, 0x09);
+ temp_data_to_convert[13] = checksum&0x00ff;
+ temp_data_to_convert[14] = (checksum&0xff00)>>8;
+ ti85_convert_data_to_stream(temp_data_to_convert, 0x0f, serial_data->variables[i].header);
+ free(temp_data_to_convert);
+ }
+ else
+ {
+ serial_data->variables[i].header = NULL;
+ serial_data->variables[i].header_size = 0;
+ }
+ }
+ else
+ {
+ temp_data_to_convert = (UINT8*) malloc (10+ti85_entries[i].name_size);
+ if (!temp_data_to_convert)
+ {
+ free (ti85_entries);
+ return 0;
+ }
+ serial_data->variables[i].header = (UINT8*) malloc ((10+ti85_entries[i].name_size)*8);
+ if (!serial_data->variables[i].header)
+ {
+ free (temp_data_to_convert);
+ free (ti85_entries);
+ return 0;
+ }
+
+ if (ti85serial->image_type == TI_FILE_V1)
+ {
+ serial_data->variables[i].header_size = (10+ti85_entries[i].name_size)*8;
+
+ temp_data_to_convert[0] = ti85serial->send_id;
+ temp_data_to_convert[1] = 0x06; //header
+ temp_data_to_convert[2] = (4+ti85_entries[i].name_size)&0x00ff;
+ temp_data_to_convert[3] = ((4+ti85_entries[i].name_size)&0xff00)>>8;
+ temp_data_to_convert[4] = (ti85_entries[i].data_size)&0x00ff;
+ temp_data_to_convert[5] = ((ti85_entries[i].data_size)&0xff00)>>8;
+ temp_data_to_convert[6] = ti85_entries[i].type;
+ temp_data_to_convert[7] = ti85_entries[i].name_size;
+ memcpy(temp_data_to_convert+8, file_data+ti85_entries[i].offset+0x06, ti85_entries[i].name_size);
+ checksum = ti85_calculate_checksum(temp_data_to_convert+4,ti85_entries[i].name_size+4);
+ temp_data_to_convert[10+ti85_entries[i].name_size-2] = checksum&0x00ff;
+ temp_data_to_convert[10+ti85_entries[i].name_size-1] = (checksum&0xff00)>>8;
+ ti85_convert_data_to_stream(temp_data_to_convert, 10+ti85_entries[i].name_size, serial_data->variables[i].header);
+ }
+
+ if (ti85serial->image_type == TI_FILE_V2 || ti85serial->image_type == TI_FILE_V3)
+ {
+ serial_data->variables[i].header_size = (9+ti85_entries[i].name_size)*8;
+
+ temp_data_to_convert[0] = ti85serial->send_id;
+ temp_data_to_convert[1] = 0x06; //header
+ temp_data_to_convert[2] = (3+ti85_entries[i].name_size)&0x00ff;
+ temp_data_to_convert[3] = ((3+ti85_entries[i].name_size)&0xff00)>>8;
+ temp_data_to_convert[4] = (ti85_entries[i].data_size)&0x00ff;
+ temp_data_to_convert[5] = ((ti85_entries[i].data_size)&0xff00)>>8;
+ temp_data_to_convert[6] = ti85_entries[i].type;
+ memcpy(temp_data_to_convert+7, file_data+ti85_entries[i].offset+0x05, ti85_entries[i].name_size);
+ checksum = ti85_calculate_checksum(temp_data_to_convert+4,ti85_entries[i].name_size+3);
+ temp_data_to_convert[9+ti85_entries[i].name_size-2] = checksum&0x00ff;
+ temp_data_to_convert[9+ti85_entries[i].name_size-1] = (checksum&0xff00)>>8;
+ ti85_convert_data_to_stream(temp_data_to_convert, 9+ti85_entries[i].name_size, serial_data->variables[i].header);
+ }
+
+ free(temp_data_to_convert);
+ }
+
+ /*OK packet*/
+ serial_data->variables[i].ok = (UINT8*) malloc (TI85_PC_OK_PACKET_SIZE*8);
+ if (!serial_data->variables[i].ok)
+ {
+ free (ti85_entries);
+ return 0;
+ }
+ ti85_append_head_to_stream(ti85serial->send_id, TI_OK_PACKET, serial_data->variables[i].ok);
+ serial_data->variables[i].ok_size = TI85_PC_OK_PACKET_SIZE*8;
+
+ /*Data packet*/
+ temp_data_to_convert = (UINT8*) malloc (6+ti85_entries[i].data_size);
+ if (!temp_data_to_convert)
+ {
+ free (ti85_entries);
+ return 0;
+ }
+ serial_data->variables[i].data = (UINT8*) malloc ((6+ti85_entries[i].data_size)*8);
+ if (!serial_data->variables[i].data)
+ {
+ free (temp_data_to_convert);
+ free (ti85_entries);
+ return 0;
+ }
+ serial_data->variables[i].data_size = (6+ti85_entries[i].data_size)*8;
+
+ temp_data_to_convert[0] = ti85serial->send_id;
+ temp_data_to_convert[1] = 0x15; //data
+ temp_data_to_convert[2] = (ti85_entries[i].data_size)&0x00ff;
+ temp_data_to_convert[3] = ((ti85_entries[i].data_size)&0xff00)>>8;
+
+ UINT8 name_start = (ti85serial->image_type != TI_FILE_V1) ? 5 : 6;
+
+ //TI-83+ files have two additional byte used for the file's version and flag
+ if (ti85serial->image_type == TI_FILE_V3)
+ name_start += 2;
+
+ if (file_data[0x3b]==backup_id)
+ memcpy(temp_data_to_convert+4, file_data+ti85_entries[i].offset, ti85_entries[i].data_size);
+ else
+ memcpy(temp_data_to_convert+4, file_data+ti85_entries[i].offset+name_start+ti85_entries[i].name_size+0x02, ti85_entries[i].data_size);
+
+ checksum = ti85_calculate_checksum(temp_data_to_convert+4,ti85_entries[i].data_size);
+ temp_data_to_convert[6+ti85_entries[i].data_size-2] = checksum&0x00ff;
+ temp_data_to_convert[6+ti85_entries[i].data_size-1] = (checksum&0xff00)>>8;
+ ti85_convert_data_to_stream(temp_data_to_convert, 6+ti85_entries[i].data_size, serial_data->variables[i].data);
+ free(temp_data_to_convert);
+ }
+
+
+ /*END packet*/
+ serial_data->end = (UINT8*) malloc (TI85_PC_END_PACKET_SIZE*8);
+ if (!serial_data->end)
+ {
+ free (ti85_entries);
+ return 0;
+ }
+ ti85_append_head_to_stream(ti85serial->send_id, TI_END_PACKET, serial_data->end);
+ serial_data->end_size = TI85_PC_END_PACKET_SIZE*8;
+
+ free (ti85_entries);
+
+ return 1;
+}
+
+
+static void ti85_free_serial_stream (ti85_serial_data* serial_data)
+{
+ UINT16 i;
+ if (serial_data->variables)
+ {
+ for (i=0; i<serial_data->number_of_variables; i++)
+ {
+ if (serial_data->variables[i].header) free (serial_data->variables[i].header);
+ if (serial_data->variables[i].ok) free (serial_data->variables[i].ok);
+ if (serial_data->variables[i].data) free (serial_data->variables[i].data);
+ }
+ free (serial_data->variables);
+ serial_data->variables = NULL;
+ }
+ serial_data->number_of_variables = 0;
+ if (serial_data->end)
+ {
+ free (serial_data->end);
+ serial_data->end = NULL;
+ }
+}
+
+
+static void ti85_send_variables (device_t *device)
+{
+ ti85serial_state *ti85serial = get_token( device );
+
+ if (!ti85_alloc_serial_data_memory(device, 7))
+ ti85serial->status = TI85_SEND_STOP;
+
+ switch (ti85serial->status)
+ {
+ case TI85_SEND_HEADER:
+ if(!ti85_send_serial(device, ti85serial->stream.variables[ti85serial->variables_variable_number].header,ti85serial->stream.variables[ti85serial->variables_variable_number].header_size))
+ {
+ ti85serial->status = TI85_RECEIVE_OK_1;
+ memset (ti85serial->receive_data, 0, 7);
+ logerror ("Header sent\n");
+ }
+ break;
+ case TI85_RECEIVE_OK_1:
+ if(!ti85_receive_serial (device, ti85serial->receive_buffer, 4*8))
+ {
+ ti85_convert_stream_to_data (ti85serial->receive_buffer, 4*8, ti85serial->receive_data);
+ ti85serial->status = TI85_RECEIVE_ANSWER_1;
+ logerror ("OK received\n");
+ }
+ break;
+ case TI85_RECEIVE_ANSWER_1:
+ if(!ti85_receive_serial (device, ti85serial->receive_buffer, 4*8))
+ {
+ ti85_convert_stream_to_data (ti85serial->receive_buffer, 4*8, ti85serial->receive_data);
+ switch (ti85serial->receive_data[1])
+ {
+ case 0x09: //continue
+ ti85serial->status = TI85_SEND_OK;
+ logerror ("Continue received\n");
+ break;
+ case 0x36: //out of memory, skip or exit
+ ti85serial->status = TI85_RECEIVE_ANSWER_2;
+ break;
+ }
+ }
+ break;
+ case TI85_RECEIVE_ANSWER_2:
+ if(!ti85_receive_serial (device, ti85serial->receive_buffer+4*8, 1*8))
+ {
+ ti85_convert_stream_to_data (ti85serial->receive_buffer, 5*8, ti85serial->receive_data);
+ switch (ti85serial->receive_data[4])
+ {
+ case 0x01: //exit
+ case 0x02: //skip
+ ti85serial->status = TI85_RECEIVE_ANSWER_3;
+ break;
+ case 0x03: //out of memory
+ ti85serial->variables_variable_number = 0;
+ ti85_free_serial_data_memory(device);
+ ti85serial->status = TI85_SEND_STOP;
+ break;
+ }
+ }
+ break;
+ case TI85_RECEIVE_ANSWER_3:
+ if(!ti85_receive_serial (device, ti85serial->receive_buffer+5*8, 2*8))
+ {
+ ti85_convert_stream_to_data (ti85serial->receive_buffer, 7*8, ti85serial->receive_data);
+ switch (ti85serial->receive_data[4])
+ {
+ case 0x01: //exit
+ ti85serial->variables_variable_number = 0;
+ ti85_free_serial_data_memory(device);
+ ti85serial->status = TI85_SEND_STOP;
+ break;
+ case 0x02: //skip
+ ti85serial->variables_variable_number++;
+ ti85serial->status = TI85_SEND_OK;
+ break;
+ }
+ }
+ break;
+ case TI85_SEND_OK:
+ if(!ti85_send_serial(device, ti85serial->stream.variables[ti85serial->variables_variable_number].ok,ti85serial->stream.variables[ti85serial->variables_variable_number].ok_size))
+ {
+ ti85serial->status = (ti85serial->receive_data[4]==0x02) ? ((ti85serial->variables_variable_number < ti85serial->stream.number_of_variables) ? TI85_SEND_HEADER : TI85_SEND_END) : TI85_SEND_DATA;
+ memset(ti85serial->receive_data, 0, 7);
+ }
+ break;
+ case TI85_SEND_DATA:
+ if(!ti85_send_serial(device, ti85serial->stream.variables[ti85serial->variables_variable_number].data,ti85serial->stream.variables[ti85serial->variables_variable_number].data_size))
+ ti85serial->status = TI85_RECEIVE_OK_2;
+ break;
+ case TI85_RECEIVE_OK_2:
+ if(!ti85_receive_serial (device, ti85serial->receive_buffer, 4*8))
+ {
+ ti85serial->variables_variable_number++;
+ ti85_convert_stream_to_data (ti85serial->receive_buffer, 4*8, ti85serial->receive_data);
+ ti85serial->status = (ti85serial->variables_variable_number < ti85serial->stream.number_of_variables) ? TI85_SEND_HEADER : TI85_SEND_END;
+ }
+ break;
+ case TI85_SEND_END:
+ if(!ti85_send_serial(device, ti85serial->stream.end,ti85serial->stream.end_size))
+ {
+ logerror ("End sent\n");
+ ti85serial->variables_variable_number = 0;
+ ti85serial->status = TI85_RECEIVE_OK_3;
+ }
+ break;
+ case TI85_RECEIVE_OK_3:
+ if(!ti85_receive_serial (device, ti85serial->receive_buffer, 4*8))
+ {
+ logerror ("OK received\n");
+ ti85_convert_stream_to_data (ti85serial->receive_buffer, 4*8, ti85serial->receive_data);
+ ti85_free_serial_data_memory(device);
+ ti85serial->status = TI85_SEND_STOP;
+ }
+ break;
+ }
+}
+
+
+static void ti85_send_backup (device_t *device)
+{
+ ti85serial_state *ti85serial = get_token( device );
+
+ if (!ti85_alloc_serial_data_memory(device, 7))
+ ti85serial->status = TI85_SEND_STOP;
+
+ switch (ti85serial->status)
+ {
+ case TI85_SEND_HEADER:
+ if(!ti85_send_serial(device, ti85serial->stream.variables[ti85serial->send_backup_variable_number].header,ti85serial->stream.variables[ti85serial->send_backup_variable_number].header_size))
+ ti85serial->status = TI85_RECEIVE_OK_1;
+ break;
+ case TI85_RECEIVE_OK_1:
+ if(!ti85_receive_serial (device, ti85serial->receive_buffer, 4*8))
+ {
+ ti85_convert_stream_to_data (ti85serial->receive_buffer, 4*8, ti85serial->receive_data);
+ ti85serial->status = TI85_RECEIVE_ANSWER_1;
+ }
+ break;
+ case TI85_RECEIVE_ANSWER_1:
+ if(!ti85_receive_serial (device, ti85serial->receive_buffer, 4*8))
+ {
+ ti85_convert_stream_to_data (ti85serial->receive_buffer, 4*8, ti85serial->receive_data);
+ switch (ti85serial->receive_data[1])
+ {
+ case 0x09: //continue
+ ti85serial->status = TI85_SEND_OK;
+ break;
+ case 0x36: //out of memory, skip or exit
+ ti85serial->status = TI85_RECEIVE_ANSWER_2;
+ break;
+ }
+ }
+ break;
+ case TI85_RECEIVE_ANSWER_2:
+ if(!ti85_receive_serial (device, ti85serial->receive_buffer+4*8, 3*8))
+ {
+ ti85_convert_stream_to_data (ti85serial->receive_buffer, 5*8, ti85serial->receive_data);
+ ti85serial->send_backup_variable_number = 0;
+ ti85_free_serial_data_memory(device);
+ ti85serial->status = TI85_SEND_STOP;
+ }
+ break;
+ case TI85_SEND_OK:
+ if(!ti85_send_serial(device, ti85serial->stream.variables[ti85serial->send_backup_variable_number].ok,ti85serial->stream.variables[ti85serial->send_backup_variable_number].ok_size))
+ ti85serial->status = TI85_SEND_DATA;
+ break;
+ case TI85_SEND_DATA:
+ if(!ti85_send_serial(device, ti85serial->stream.variables[ti85serial->send_backup_variable_number].data,ti85serial->stream.variables[ti85serial->send_backup_variable_number].data_size))
+ ti85serial->status = TI85_RECEIVE_OK_2;
+ break;
+ case TI85_RECEIVE_OK_2:
+ if(!ti85_receive_serial (device, ti85serial->receive_buffer, 4*8))
+ {
+ ti85serial->send_backup_variable_number++;
+ ti85_convert_stream_to_data (ti85serial->receive_buffer, 4*8, ti85serial->receive_data);
+ ti85serial->status = (ti85serial->send_backup_variable_number < ti85serial->stream.number_of_variables) ? TI85_SEND_DATA : TI85_SEND_END;
+ }
+ break;
+ case TI85_SEND_END:
+ if(!ti85_send_serial(device, ti85serial->stream.end,ti85serial->stream.end_size))
+ {
+ ti85serial->send_backup_variable_number = 0;
+ ti85_free_serial_data_memory(device);
+ ti85serial->status = TI85_SEND_STOP;
+ }
+ break;
+ }
+}
+
+
+static void ti85_receive_variables (device_t *device)
+{
+ ti85serial_state *ti85serial = get_token( device );
+ char var_file_name[16];
+ UINT8* temp;
+ file_error filerr;
+
+ switch (ti85serial->status)
+ {
+ case TI85_RECEIVE_HEADER_1:
+ if(!ti85_receive_serial(device, ti85serial->receive_buffer+4*8, 3*8))
+ {
+ ti85_convert_stream_to_data (ti85serial->receive_buffer+4*8, 3*8, ti85serial->receive_data+4);
+ ti85serial->status = TI85_PREPARE_VARIABLE_DATA;
+ }
+ break;
+ case TI85_PREPARE_VARIABLE_DATA:
+ ti85serial->var_data = (UINT8*) malloc (ti85serial->receive_data[2]+2+ti85serial->receive_data[4]+ti85serial->receive_data[5]*256+2);
+ if(!ti85serial->var_data)
+ ti85serial->status = TI85_SEND_STOP;
+ memcpy (ti85serial->var_data, ti85serial->receive_data+2, 5);
+ ti85_free_serial_data_memory(device);
+ if (!ti85_alloc_serial_data_memory(device, ti85serial->var_data[0]-1))
+ {
+ free(ti85serial->var_data); ti85serial->var_data = NULL;
+ free(ti85serial->var_file_data); ti85serial->var_file_data = NULL;
+ ti85serial->status = TI85_SEND_STOP;
+ return;
+ }
+ ti85serial->status = TI85_RECEIVE_HEADER_2;
+ case TI85_RECEIVE_HEADER_2:
+ if(!ti85_receive_serial(device, ti85serial->receive_buffer, (ti85serial->var_data[0]-1)*8))
+ {
+ ti85_convert_stream_to_data (ti85serial->receive_buffer, (ti85serial->var_data[0]-1)*8, ti85serial->receive_data);
+ memcpy (ti85serial->var_data+5, ti85serial->receive_data, ti85serial->var_data[0]-3);
+ ti85_free_serial_data_memory(device);
+ if(!ti85_alloc_serial_data_memory (device, 8))
+ {
+ free(ti85serial->var_data); ti85serial->var_data = NULL;
+ free(ti85serial->var_file_data); ti85serial->var_file_data = NULL;
+ ti85serial->status = TI85_SEND_STOP;
+ return;
+ }
+ ti85_append_head_to_stream(ti85serial->receive_id, TI_OK_PACKET, ti85serial->receive_buffer);
+ ti85_append_head_to_stream(ti85serial->receive_id, TI_CONTINUE_PACKET, ti85serial->receive_buffer+4*8);
+ ti85serial->status = TI85_SEND_OK_1;
+ }
+ break;
+ case TI85_SEND_OK_1:
+ if(!ti85_send_serial(device, ti85serial->receive_buffer, 4*8))
+ ti85serial->status = TI85_SEND_CONTINUE;
+ break;
+ case TI85_SEND_CONTINUE:
+ if(!ti85_send_serial(device, ti85serial->receive_buffer+4*8, 4*8))
+ {
+ ti85_free_serial_data_memory(device);
+ if(!ti85_alloc_serial_data_memory(device, 4))
+ {
+ free(ti85serial->var_data); ti85serial->var_data = NULL;
+ free(ti85serial->var_file_data); ti85serial->var_file_data = NULL;
+ ti85serial->status = TI85_SEND_STOP;
+ return;
+ }
+ ti85serial->status = TI85_RECEIVE_OK;
+ }
+ break;
+ case TI85_RECEIVE_OK:
+ if(!ti85_receive_serial (device, ti85serial->receive_buffer, 4*8))
+ {
+ ti85_convert_stream_to_data (ti85serial->receive_buffer, 4*8, ti85serial->receive_data);
+ ti85_free_serial_data_memory(device);
+ if(!ti85_alloc_serial_data_memory(device, ti85serial->var_data[2]+ti85serial->var_data[3]*256+6))
+ {
+ free(ti85serial->var_data); ti85serial->var_data = NULL;
+ free(ti85serial->var_file_data); ti85serial->var_file_data = NULL;
+ ti85serial->status = TI85_SEND_STOP;
+ return;
+ }
+ ti85serial->status = TI85_RECEIVE_DATA;
+ }
+ break;
+ case TI85_RECEIVE_DATA:
+ if(!ti85_receive_serial (device, ti85serial->receive_buffer, (ti85serial->var_data[2]+ti85serial->var_data[3]*256+6)*8))
+ {
+ ti85_convert_stream_to_data (ti85serial->receive_buffer, (ti85serial->var_data[2]+ti85serial->var_data[3]*256+6)*8, ti85serial->receive_data);
+ memcpy (ti85serial->var_data+ti85serial->var_data[0]+2, ti85serial->receive_data+2, ti85serial->var_data[2]+ti85serial->var_data[3]*256+2);
+ ti85_free_serial_data_memory(device);
+ if(!ti85_alloc_serial_data_memory (device, 4))
+ {
+ free(ti85serial->var_data); ti85serial->var_data = NULL;
+ free(ti85serial->var_file_data); ti85serial->var_file_data = NULL;
+ ti85serial->status = TI85_SEND_STOP;
+ return;
+ }
+ ti85_append_head_to_stream(ti85serial->receive_id, TI_OK_PACKET, ti85serial->receive_buffer);
+ ti85serial->status = TI85_SEND_OK_2;
+ }
+ break;
+ case TI85_SEND_OK_2:
+ if(!ti85_send_serial(device, ti85serial->receive_buffer, 4*8))
+ {
+ ti85_free_serial_data_memory(device);
+ if(!ti85_alloc_serial_data_memory(device, 7))
+ {
+ free(ti85serial->var_data); ti85serial->var_data = NULL;
+ free(ti85serial->var_file_data); ti85serial->var_file_data = NULL;
+ ti85serial->status = TI85_SEND_STOP;
+ return;
+ }
+ ti85serial->status = TI85_RECEIVE_END_OR_HEADER_1;
+ }
+ break;
+ case TI85_RECEIVE_END_OR_HEADER_1:
+ if(!ti85_receive_serial (device, ti85serial->receive_buffer, 4*8))
+ {
+ if (ti85serial->variable_number == 0)
+ {
+ ti85serial->var_file_data = (UINT8*) malloc (0x39);
+ if (!ti85serial->var_file_data)
+ {
+ free (ti85serial->var_data); ti85serial->var_data = NULL;
+ free (ti85serial->var_file_data); ti85serial->var_file_data = NULL;
+ ti85serial->status = TI85_SEND_STOP;
+ }
+ else
+ {
+ memcpy(ti85serial->var_file_data, ti85_file_signature, 0x0b);
+ memcpy(ti85serial->var_file_data+0x0b, "File created by MESS", 0x14);
+ memset(ti85serial->var_file_data+0x1f, 0, 0x1a);
+ ti85serial->var_file_size = 0x39;
+ }
+ }
+ temp = (UINT8*)malloc (ti85serial->var_file_size+ti85serial->var_data[0]+2+ti85serial->var_data[2]+ti85serial->var_data[3]*256+2);
+ if (temp)
+ {
+ memcpy (temp, ti85serial->var_file_data, ti85serial->var_file_size);
+ free (ti85serial->var_file_data);
+ ti85serial->var_file_data = temp;
+ memcpy (ti85serial->var_file_data + ti85serial->var_file_size -2, ti85serial->var_data, ti85serial->var_data[0]+2+ti85serial->var_data[2]+ti85serial->var_data[3]*256+2);
+ ti85serial->var_file_size += ti85serial->var_data[0]+2+ti85serial->var_data[2]+ti85serial->var_data[3]*256+2;
+ ti85serial->var_file_data[0x35] = (ti85serial->var_file_size-0x39)&0x00ff;
+ ti85serial->var_file_data[0x36] = ((ti85serial->var_file_size-0x39)&0xff00)>>8;
+ ti85serial->var_file_data[ti85serial->var_file_size-2] = ti85_calculate_checksum(ti85serial->var_file_data+0x37, ti85serial->var_file_size-0x39)&0x00ff;
+ ti85serial->var_file_data[ti85serial->var_file_size-1] = (ti85_calculate_checksum(ti85serial->var_file_data+0x37, ti85serial->var_file_size-0x39)&0xff00)>>8;
+ }
+ free (ti85serial->var_data);
+ ti85serial->var_data = NULL;
+ ti85serial->variable_number ++;
+
+ ti85_convert_stream_to_data (ti85serial->receive_buffer, 4*8, ti85serial->receive_data);
+ if (ti85serial->receive_data[1] == 0x06)
+ ti85serial->status = TI85_RECEIVE_HEADER_1;
+ else
+ {
+ ti85_free_serial_data_memory(device);
+ if(!ti85_alloc_serial_data_memory (device, 4))
+ {
+ free(ti85serial->var_data); ti85serial->var_data = NULL;
+ free(ti85serial->var_file_data); ti85serial->var_file_data = NULL;
+ ti85serial->status = TI85_SEND_STOP;
+ return;
+ }
+ ti85_append_head_to_stream(ti85serial->receive_id, TI_OK_PACKET, ti85serial->receive_buffer);
+ ti85serial->status = TI85_SEND_OK_3;
+ }
+ }
+ break;
+ case TI85_SEND_OK_3:
+ if(!ti85_send_serial(device, ti85serial->receive_buffer, 4*8))
+ {
+ ti85_free_serial_data_memory(device);
+ ti85serial->variable_number = 0;
+ ti85serial->status = TI85_SEND_STOP;
+ sprintf (var_file_name, "%08d.85g", ti85serial->var_file_number);
+ emu_file var_file(device->machine().options().memcard_directory(), OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
+ filerr = var_file.open(var_file_name);
+
+ if (filerr == FILERR_NONE)
+ {
+ var_file.write(ti85serial->var_file_data, ti85serial->var_file_size);
+ free (ti85serial->var_file_data);
+ ti85serial->var_file_data = NULL;
+ ti85serial->var_file_size = 0;
+ ti85serial->var_file_number++;
+ }
+ }
+ break;
+ }
+}
+
+
+static void ti85_receive_backup (device_t *device)
+{
+ ti85serial_state *ti85serial = get_token( device );
+
+ file_error filerr;
+ char backup_file_name[] = "00000000.85b";
+
+ switch (ti85serial->status)
+ {
+ case TI85_RECEIVE_HEADER_2:
+ if(!ti85_receive_serial(device, ti85serial->receive_buffer+7*8, 8*8))
+ {
+ ti85_convert_stream_to_data (ti85serial->receive_buffer+7*8, 8*8, ti85serial->receive_data+7);
+ ti85serial->backup_data_size[0] = ti85serial->receive_data[4] + ti85serial->receive_data[5]*256;
+ ti85serial->backup_data_size[1] = ti85serial->receive_data[7] + ti85serial->receive_data[8]*256;
+ ti85serial->backup_data_size[2] = ti85serial->receive_data[9] + ti85serial->receive_data[10]*256;
+ ti85serial->backup_file_data = (UINT8*)malloc (0x42+0x06+ti85serial->backup_data_size[0]+ti85serial->backup_data_size[1]+ti85serial->backup_data_size[2]+0x02);
+ if(!ti85serial->backup_file_data)
+ {
+ ti85serial->backup_variable_number = 0;
+ ti85serial->status = TI85_SEND_STOP;
+ return;
+ }
+ memcpy(ti85serial->backup_file_data, ti85_file_signature, 0x0b);
+ memcpy(ti85serial->backup_file_data+0x0b, "File created by MESS", 0x14);
+ memset(ti85serial->backup_file_data+0x1f, 0, 0x16);
+ ti85serial->backup_file_data[0x35] = (ti85serial->backup_data_size[0]+ti85serial->backup_data_size[1]+ti85serial->backup_data_size[2]+0x11)&0x00ff;
+ ti85serial->backup_file_data[0x36] = ((ti85serial->backup_data_size[0]+ti85serial->backup_data_size[1]+ti85serial->backup_data_size[2]+0x11)&0xff00)>>8;
+ memcpy(ti85serial->backup_file_data+0x37, ti85serial->receive_data+0x02, 0x0b);
+ ti85_free_serial_data_memory(device);
+ if(!ti85_alloc_serial_data_memory (device, 8))
+ {
+ free(ti85serial->backup_file_data); ti85serial->backup_file_data = NULL;
+ ti85serial->backup_variable_number = 0;
+ ti85serial->status = TI85_SEND_STOP;
+ return;
+ }
+ ti85_append_head_to_stream(ti85serial->receive_id, TI_OK_PACKET, ti85serial->receive_buffer);
+ ti85_append_head_to_stream(ti85serial->receive_id, TI_CONTINUE_PACKET, ti85serial->receive_buffer+4*8);
+ ti85serial->status = TI85_SEND_OK_1;
+ }
+ break;
+ case TI85_SEND_OK_1:
+ if(!ti85_send_serial(device, ti85serial->receive_buffer, 4*8))
+ ti85serial->status = TI85_SEND_CONTINUE;
+ break;
+ case TI85_SEND_CONTINUE:
+ if(!ti85_send_serial(device, ti85serial->receive_buffer+4*8, 4*8))
+ {
+ ti85_free_serial_data_memory(device);
+ if(!ti85_alloc_serial_data_memory(device, 4))
+ {
+ free(ti85serial->backup_file_data); ti85serial->backup_file_data = NULL;
+ ti85serial->backup_variable_number = 0;
+ ti85serial->status = TI85_SEND_STOP;
+ return;
+ }
+ ti85serial->status = TI85_RECEIVE_OK;
+ }
+ break;
+ case TI85_RECEIVE_OK:
+ if(!ti85_receive_serial (device, ti85serial->receive_buffer, 4*8))
+ {
+ ti85_convert_stream_to_data (ti85serial->receive_buffer, 4*8, ti85serial->receive_data);
+ ti85_free_serial_data_memory(device);
+ if(!ti85_alloc_serial_data_memory(device, ti85serial->backup_data_size[ti85serial->backup_variable_number]+6))
+ {
+ free(ti85serial->backup_file_data); ti85serial->backup_file_data = NULL;
+ ti85serial->backup_variable_number = 0;
+ ti85serial->status = TI85_SEND_STOP;
+ return;
+ }
+ ti85serial->status = TI85_RECEIVE_DATA;
+ }
+ break;
+ case TI85_RECEIVE_DATA:
+ if(!ti85_receive_serial (device, ti85serial->receive_buffer, (ti85serial->backup_data_size[ti85serial->backup_variable_number]+6)*8))
+ {
+ ti85_convert_stream_to_data (ti85serial->receive_buffer, (ti85serial->backup_data_size[ti85serial->backup_variable_number]+6)*8, ti85serial->receive_data);
+ switch (ti85serial->backup_variable_number)
+ {
+ case 0:
+ memcpy(ti85serial->backup_file_data+0x42, ti85serial->receive_data+0x02, ti85serial->backup_data_size[0]+0x02);
+ break;
+ case 1:
+ memcpy(ti85serial->backup_file_data+0x42+ti85serial->backup_data_size[0]+0x02, ti85serial->receive_data+0x02, ti85serial->backup_data_size[1]+0x02);
+ break;
+ case 2:
+ memcpy(ti85serial->backup_file_data+0x42+ti85serial->backup_data_size[0]+ti85serial->backup_data_size[1]+0x04, ti85serial->receive_data+0x02, ti85serial->backup_data_size[2]+0x02);
+ break;
+ }
+ ti85_free_serial_data_memory(device);
+ if(!ti85_alloc_serial_data_memory (device, 4))
+ {
+ free(ti85serial->backup_file_data); ti85serial->backup_file_data = NULL;
+ ti85serial->backup_variable_number = 0;
+ ti85serial->status = TI85_SEND_STOP;
+ return;
+ }
+ ti85_append_head_to_stream(ti85serial->receive_id, TI_OK_PACKET, ti85serial->receive_buffer);
+ ti85serial->status = TI85_SEND_OK_2;
+ }
+ break;
+ case TI85_SEND_OK_2:
+ if(!ti85_send_serial(device, ti85serial->receive_buffer, 4*8))
+ {
+ ti85_free_serial_data_memory(device);
+ ti85serial->backup_variable_number++;
+ if (ti85serial->backup_variable_number<3)
+ {
+ if(!ti85_alloc_serial_data_memory(device, ti85serial->backup_data_size[ti85serial->backup_variable_number]+6))
+ {
+ free(ti85serial->backup_file_data); ti85serial->backup_file_data = NULL;
+ ti85serial->backup_variable_number = 0;
+ ti85serial->status = TI85_SEND_STOP;
+ return;
+ }
+ ti85serial->status = TI85_RECEIVE_DATA;
+ }
+ else
+ {
+ ti85serial->backup_variable_number = 0;
+ ti85serial->backup_file_data[0x42+0x06+ti85serial->backup_data_size[0]+ti85serial->backup_data_size[1]+ti85serial->backup_data_size[2]] = ti85_calculate_checksum(ti85serial->backup_file_data+0x37, 0x42+ti85serial->backup_data_size[0]+ti85serial->backup_data_size[1]+ti85serial->backup_data_size[2]+0x06-0x37)&0x00ff;
+ ti85serial->backup_file_data[0x42+0x06+ti85serial->backup_data_size[0]+ti85serial->backup_data_size[1]+ti85serial->backup_data_size[2]+0x01] = (ti85_calculate_checksum(ti85serial->backup_file_data+0x37, 0x42+ti85serial->backup_data_size[0]+ti85serial->backup_data_size[1]+ti85serial->backup_data_size[2]+0x06-0x37)&0xff00)>>8;
+ sprintf (backup_file_name, "%08d.85b", ti85serial->backup_file_number);
+
+ emu_file backup_file(device->machine().options().memcard_directory(), OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
+ filerr = backup_file.open(backup_file_name);
+
+ if (filerr == FILERR_NONE)
+ {
+ backup_file.write(ti85serial->backup_file_data, 0x42+0x06+ti85serial->backup_data_size[0]+ti85serial->backup_data_size[1]+ti85serial->backup_data_size[2]+0x02);
+ ti85serial->backup_file_number++;
+ }
+ free(ti85serial->backup_file_data); ti85serial->backup_file_data = NULL;
+ ti85serial->status = TI85_SEND_STOP;
+ }
+ }
+ break;
+ }
+}
+
+static void ti85_receive_screen (device_t *device)
+{
+ ti85serial_state *ti85serial = get_token( device );
+ char image_file_name[] = "00000000.85i";
+ file_error filerr;
+ UINT8 * image_file_data;
+
+ switch (ti85serial->status)
+ {
+ case TI85_PREPARE_SCREEN_REQUEST:
+ if(!ti85_alloc_serial_data_memory (device, 4))
+ {
+ ti85serial->status = TI85_SEND_STOP;
+ return;
+ }
+ ti85_append_head_to_stream(ti85serial->receive_id, TI_SCREEN_REQUEST_PACKET, ti85serial->receive_buffer);
+ ti85serial->status = TI85_SEND_SCREEN_REQUEST;
+ break;
+ case TI85_SEND_SCREEN_REQUEST:
+ if(!ti85_send_serial(device, ti85serial->receive_buffer, 4*8))
+ {
+ ti85_free_serial_data_memory(device);
+ if(!ti85_alloc_serial_data_memory (device, 4))
+ {
+ ti85serial->status = TI85_SEND_STOP;
+ return;
+ }
+ ti85serial->status = TI85_RECEIVE_OK;
+ }
+ break;
+ case TI85_RECEIVE_OK:
+ if(!ti85_receive_serial (device, ti85serial->receive_buffer, 4*8))
+ {
+ ti85_convert_stream_to_data (ti85serial->receive_buffer, 4*8, ti85serial->receive_data);
+ ti85_free_serial_data_memory(device);
+ if(!ti85_alloc_serial_data_memory (device, 1030))
+ {
+ ti85serial->status = TI85_SEND_STOP;
+ return;
+ }
+ ti85serial->status = TI85_RECEIVE_DATA;
+ }
+ break;
+ case TI85_RECEIVE_DATA:
+ if(!ti85_receive_serial (device, ti85serial->receive_buffer, 1030*8))
+ {
+ ti85_convert_stream_to_data (ti85serial->receive_buffer, 1030*8, ti85serial->receive_data);
+ sprintf (image_file_name, "%08d.85i", ti85serial->image_file_number);
+
+ emu_file image_file(device->machine().options().memcard_directory(), OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
+ filerr = image_file.open(image_file_name);
+
+ if (filerr == FILERR_NONE)
+ {
+ image_file_data = (UINT8*)malloc (0x49+1008);
+ if(!image_file_data)
+ {
+ ti85_free_serial_data_memory(device);
+ ti85serial->status = TI85_SEND_OK;
+ return;
+ }
+ memcpy(image_file_data, ti85_file_signature, 0x0b);
+ memcpy(image_file_data+0x0b, "File created by MESS", 0x14);
+ memset(image_file_data+0x1f, 0, 0x16);
+ image_file_data[0x35] = 0x00;
+ image_file_data[0x36] = 0x04;
+ image_file_data[0x37] = 0x0a; //header size
+ image_file_data[0x38] = 0x00;
+ image_file_data[0x39] = 0xf2; //data size
+ image_file_data[0x3a] = 0x03;
+ image_file_data[0x3b] = 0x11; //data type
+ image_file_data[0x3c] = 0x06; //name size
+ memcpy(image_file_data+0x3d, "Screen", 0x06);
+ image_file_data[0x43] = 0xf2;
+ image_file_data[0x44] = 0x03;
+ image_file_data[0x45] = 0xf0;
+ image_file_data[0x46] = 0x03;
+ memcpy(image_file_data+0x47, ti85serial->receive_data+4, 1008);
+ image_file_data[1008+0x49-2] = ti85_calculate_checksum(image_file_data+0x37, 1008+0x10)&0x00ff;
+ image_file_data[1008+0x49-1] = (ti85_calculate_checksum(image_file_data+0x37, 1008+0x10)&0xff00)>>8;
+ image_file.write(image_file_data, 1008+0x49);
+ free(image_file_data);
+ ti85serial->image_file_number++;
+ }
+ ti85_free_serial_data_memory(device);
+ if(!ti85_alloc_serial_data_memory (device, 4))
+ {
+ ti85serial->status = TI85_SEND_STOP;
+ return;
+ }
+ ti85_append_head_to_stream(ti85serial->receive_id, TI_OK_PACKET, ti85serial->receive_buffer);
+ ti85serial->status = TI85_SEND_OK;
+ }
+ break;
+ case TI85_SEND_OK:
+ if(!ti85_send_serial(device, ti85serial->receive_buffer, 4*8))
+ {
+ ti85_free_serial_data_memory(device);
+ ti85serial->status = TI85_SEND_STOP;
+ }
+ break;
+ }
+}
+
+
+void ti85_update_serial (device_t *device)
+{
+ ti85serial_state *ti85serial = get_token( device );
+
+ if (ti85serial->status == TI85_SEND_STOP)
+ {
+ if (input_port_read(*device, "SERIAL") & 0x01)
+ {
+ if(!ti85_alloc_serial_data_memory(device, 15)) return;
+ if(!ti85_receive_serial (device, ti85serial->receive_buffer, 7*8))
+ {
+ ti85_convert_stream_to_data (ti85serial->receive_buffer, 7*8, ti85serial->receive_data);
+ if (ti85serial->receive_data[0]!=0x85 || ti85serial->receive_data[1]!=0x06)
+ {
+ ti85_receive_serial (device, NULL, 0);
+ return;
+ }
+ ti85serial->transfer_type = (ti85serial->receive_data[6]==0x1d) ? TI85_RECEIVE_BACKUP : TI85_RECEIVE_VARIABLES;
+ ti85serial->status = (ti85serial->receive_data[6]==0x1d) ? TI85_RECEIVE_HEADER_2 : TI85_PREPARE_VARIABLE_DATA;
+ }
+ }
+ else
+ {
+ ti85_receive_serial(device, NULL, 0);
+ ti85_free_serial_data_memory(device);
+ if (input_port_read(*device, "DUMP") & 0x01)
+ {
+ ti85serial->status = TI85_PREPARE_SCREEN_REQUEST;
+ ti85serial->transfer_type = TI85_RECEIVE_SCREEN;
+ }
+ return;
+ }
+ }
+
+ switch (ti85serial->transfer_type)
+ {
+ case TI85_SEND_VARIABLES:
+ ti85_send_variables(device);
+ break;
+ case TI85_SEND_BACKUP:
+ ti85_send_backup(device);
+ break;
+ case TI85_RECEIVE_BACKUP:
+ ti85_receive_backup(device);
+ break;
+ case TI85_RECEIVE_VARIABLES:
+ ti85_receive_variables(device);
+ break;
+ case TI85_RECEIVE_SCREEN:
+ ti85_receive_screen(device);
+ break;
+ }
+}
+
+
+WRITE8_DEVICE_HANDLER( ti85serial_red_out )
+{
+ ti85serial_state *ti85serial = get_token( device );
+
+ ti85serial->red_out = data;
+}
+
+
+WRITE8_DEVICE_HANDLER( ti85serial_white_out )
+{
+ ti85serial_state *ti85serial = get_token( device );
+
+ ti85serial->white_out = data;
+}
+
+
+READ8_DEVICE_HANDLER( ti85serial_red_in )
+{
+ ti85serial_state *ti85serial = get_token( device );
+
+ return ti85serial->red_in;
+}
+
+
+READ8_DEVICE_HANDLER( ti85serial_white_in )
+{
+ ti85serial_state *ti85serial = get_token( device );
+
+ return ti85serial->white_in;
+}
+
+
+static DEVICE_START( ti85serial )
+{
+ ti85serial_state *ti85serial = get_token( device );
+
+ ti85serial->transfer_type = TI85_SEND_VARIABLES;
+ ti85serial->receive_buffer = NULL;
+ ti85serial->receive_data = NULL;
+ ti85serial->var_file_number = 0;
+ ti85serial->backup_file_number = 0;
+ ti85serial->image_file_number = 0;
+}
+
+
+static DEVICE_STOP( ti85serial )
+{
+ ti85serial_state *ti85serial = get_token( device );
+
+ ti85_free_serial_data_memory(device);
+ if (ti85serial->var_data)
+ {
+ free(ti85serial->var_data); ti85serial->var_data = NULL;
+ }
+ if (ti85serial->var_file_data)
+ {
+ free(ti85serial->var_file_data); ti85serial->var_file_data = NULL;
+ }
+ if (ti85serial->backup_file_data)
+ {
+ free(ti85serial->backup_file_data); ti85serial->backup_file_data = NULL;
+ }
+}
+
+
+static DEVICE_RESET( ti85serial )
+{
+ ti85serial_state *ti85serial = get_token( device );
+
+ ti85serial->receive_data_counter = 0;
+ ti85serial->send_data_counter = 0;
+ ti85_free_serial_data_memory(device);
+ ti85serial->red_in = 0;
+ ti85serial->white_in = 0;
+ ti85serial->red_out = 1;
+ ti85serial->white_out = 1;
+ ti85serial->variables_variable_number = 0;
+ ti85serial->send_backup_variable_number = 0;
+ ti85serial->var_data = NULL;
+ ti85serial->var_file_data = NULL;
+ ti85serial->var_file_size = 0;
+ ti85serial->variable_number = 0;
+ ti85serial->backup_file_data = NULL;
+ ti85serial->backup_variable_number = 0;
+ ti85serial->status = TI85_SEND_STOP;
+
+ //initialize the receive_id used for TI to PC transfer
+ if (device->type() == TI73SERIAL)
+ ti85serial->receive_id = TI_TRANFER_ID_TI73;
+ else if (device->type() == TI85SERIAL)
+ ti85serial->receive_id = TI_TRANFER_ID_TI85;
+ else if (device->type() == TI82SERIAL)
+ ti85serial->receive_id = TI_TRANFER_ID_TI82;
+ else if (device->type() == TI83PSERIAL)
+ ti85serial->receive_id = TI_TRANFER_ID_TI83P;
+ else if (device->type() == TI86SERIAL)
+ ti85serial->receive_id = TI_TRANFER_ID_TI86;
+
+ ti85serial->send_id = ti85serial->receive_id;
+}
+
+
+static DEVICE_IMAGE_LOAD( ti85serial )
+{
+ ti85serial_state *ti85serial = get_token( image );
+ UINT8* file_data;
+ UINT16 file_size;
+
+ if (ti85serial->status != TI85_SEND_STOP) return IMAGE_INIT_FAIL;
+
+ file_size = image.length();
+
+ if (file_size != 0)
+ {
+ file_data = auto_alloc_array(image.device().machine(), UINT8, file_size);
+ image.fread( file_data, file_size);
+
+ if(!ti85_convert_file_data_to_serial_stream(image, file_data, file_size, &ti85serial->stream))
+ {
+ ti85_free_serial_stream (&ti85serial->stream);
+ return IMAGE_INIT_FAIL;
+ }
+
+ ti85serial->status = TI85_SEND_HEADER;
+ }
+ else
+ {
+ return IMAGE_INIT_FAIL;
+ }
+ return IMAGE_INIT_PASS;
+}
+
+
+static DEVICE_IMAGE_UNLOAD( ti85serial )
+{
+ ti85serial_state *ti85serial = get_token( image );
+
+ ti85_free_serial_data_memory(image);
+ ti85serial->status = TI85_SEND_STOP;
+ ti85_free_serial_stream (&ti85serial->stream);
+}
+
+
+static INPUT_PORTS_START ( ti85serial )
+ PORT_START("SERIAL") /* receive data from calculator */
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Receive data") PORT_CODE(KEYCODE_R)
+ PORT_START("DUMP") /* screen dump requesting */
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Screen dump request") PORT_CODE(KEYCODE_S)
+INPUT_PORTS_END
+
+
+DEVICE_GET_INFO( ti85serial )
+{
+ switch ( state )
+ {
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof( ti85serial_state ); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+ case DEVINFO_INT_IMAGE_TYPE: info->i = IO_SERIAL; break;
+ case DEVINFO_INT_IMAGE_READABLE: info->i = 1; break;
+ case DEVINFO_INT_IMAGE_WRITEABLE: info->i = 0; break;
+ case DEVINFO_INT_IMAGE_CREATABLE: info->i = 0; break;
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( ti85serial ); break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME( ti85serial ); break;
+ case DEVINFO_FCT_STOP: info->stop = DEVICE_STOP_NAME( ti85serial ); break;
+ case DEVINFO_FCT_IMAGE_LOAD: info->f = (genf *) DEVICE_IMAGE_LOAD_NAME( ti85serial ); break;
+ case DEVINFO_FCT_IMAGE_UNLOAD: info->f = (genf *) DEVICE_IMAGE_UNLOAD_NAME( ti85serial ); break;
+ case DEVINFO_PTR_INPUT_PORTS: info->ipt = INPUT_PORTS_NAME( ti85serial ); break;
+ case DEVINFO_STR_IMAGE_BRIEF_INSTANCE_NAME: strcpy(info->s, "ser"); break;
+ case DEVINFO_STR_IMAGE_INSTANCE_NAME: strcpy(info->s, "serial"); break;
+ case DEVINFO_STR_NAME: strcpy(info->s, "TI85 Serial"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "serial protocol"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_IMAGE_FILE_EXTENSIONS: strcpy(info->s, "85p,85s,85i,85n,85c,85l,85k,85m,85v,85d,85e,85r,85g,85b"); break;
+ }
+}
+
+DEVICE_GET_INFO( ti73serial )
+{
+ switch ( state )
+ {
+ case DEVINFO_STR_NAME: strcpy(info->s, "TI73 Serial"); break;
+ case DEVINFO_STR_IMAGE_FILE_EXTENSIONS: strcpy(info->s, "73p,73s,73i,73n,73c,73l,73k,73m,73v,73d,73e,73r,73g"); break;
+ default: DEVICE_GET_INFO_CALL( ti85serial );
+ }
+}
+
+DEVICE_GET_INFO( ti82serial )
+{
+ switch ( state )
+ {
+ case DEVINFO_STR_NAME: strcpy(info->s, "TI82 Serial"); break;
+ case DEVINFO_STR_IMAGE_FILE_EXTENSIONS: strcpy(info->s, "82p,82s,82i,82n,82c,82l,82k,82m,82v,82d,82e,82r,82g"); break;
+ default: DEVICE_GET_INFO_CALL( ti85serial );
+ }
+}
+
+
+DEVICE_GET_INFO( ti83pserial )
+{
+ switch ( state )
+ {
+ case DEVINFO_STR_NAME: strcpy(info->s, "TI83 Plus Serial"); break;
+ case DEVINFO_STR_IMAGE_FILE_EXTENSIONS: strcpy(info->s, "82p,82s,82i,82n,82c,82l,82k,82m,82v,82d,82e,82r,82g," //for TI-82 compatibility
+ "83p,83s,83i,83n,83c,83l,83k,83m,83v,83d,83e,83r,83g," //for TI-83 compatibility
+ "8xc,8xd,8xg,8xi,8xl,8xm,8xn,8xp,8xs,8xt,8xv,8xw,8xy,8xz"); break;
+ default: DEVICE_GET_INFO_CALL( ti85serial );
+ }
+}
+
+DEVICE_GET_INFO( ti86serial )
+{
+ switch ( state )
+ {
+ case DEVINFO_STR_NAME: strcpy(info->s, "TI86 Serial"); break;
+ case DEVINFO_STR_IMAGE_FILE_EXTENSIONS: strcpy(info->s, "85p,85s,85i,85n,85c,85l,85k,85m,85v,85d,85e,85r,85g,85b" //for TI-85 compatibility
+ "86p,86s,86i,86n,86c,86l,86k,86m,86v,86d,86e,86r,86g"); break;
+ default: DEVICE_GET_INFO_CALL( ti85serial );
+ }
+}
+
+DEFINE_LEGACY_IMAGE_DEVICE(TI85SERIAL, ti85serial);
+DEFINE_LEGACY_IMAGE_DEVICE(TI73SERIAL, ti73serial);
+DEFINE_LEGACY_IMAGE_DEVICE(TI82SERIAL, ti82serial);
+DEFINE_LEGACY_IMAGE_DEVICE(TI83PSERIAL, ti83pserial);
+DEFINE_LEGACY_IMAGE_DEVICE(TI86SERIAL, ti86serial);
diff --git a/src/mess/machine/ti85_ser.h b/src/mess/machine/ti85_ser.h
new file mode 100644
index 00000000000..b5e81cc5e12
--- /dev/null
+++ b/src/mess/machine/ti85_ser.h
@@ -0,0 +1,34 @@
+
+#ifndef __TI85SERIAL_H_
+#define __TI85SERIAL_H_
+
+
+DECLARE_LEGACY_IMAGE_DEVICE(TI85SERIAL, ti85serial);
+DECLARE_LEGACY_IMAGE_DEVICE(TI73SERIAL, ti73serial);
+DECLARE_LEGACY_IMAGE_DEVICE(TI82SERIAL, ti82serial);
+DECLARE_LEGACY_IMAGE_DEVICE(TI83PSERIAL, ti83pserial);
+DECLARE_LEGACY_IMAGE_DEVICE(TI86SERIAL, ti86serial);
+
+extern void ti85_update_serial(device_t *device);
+
+#define MCFG_TI85SERIAL_ADD( _tag ) \
+ MCFG_DEVICE_ADD( _tag, TI85SERIAL, 0 )
+
+#define MCFG_TI73SERIAL_ADD( _tag ) \
+ MCFG_DEVICE_ADD( _tag, TI73SERIAL, 0 )
+
+#define MCFG_TI82SERIAL_ADD( _tag ) \
+ MCFG_DEVICE_ADD( _tag, TI82SERIAL, 0 )
+
+#define MCFG_TI83PSERIAL_ADD( _tag ) \
+ MCFG_DEVICE_ADD( _tag, TI83PSERIAL, 0 )
+
+#define MCFG_TI86SERIAL_ADD( _tag ) \
+ MCFG_DEVICE_ADD( _tag, TI86SERIAL, 0 )
+
+WRITE8_DEVICE_HANDLER( ti85serial_red_out );
+WRITE8_DEVICE_HANDLER( ti85serial_white_out );
+READ8_DEVICE_HANDLER( ti85serial_red_in );
+READ8_DEVICE_HANDLER( ti85serial_white_in );
+
+#endif
diff --git a/src/mess/machine/ti99/bwg.c b/src/mess/machine/ti99/bwg.c
new file mode 100644
index 00000000000..81e283bee03
--- /dev/null
+++ b/src/mess/machine/ti99/bwg.c
@@ -0,0 +1,489 @@
+/*******************************************************************************
+ 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)
+ <http://home.t-online.de/home/harald.glaab/snug/bwg.pdf>
+
+ +------------------------+
+ | 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)
+*******************************************************************************/
+
+#include "emu.h"
+#include "peribox.h"
+#include "bwg.h"
+#include "machine/wd17xx.h"
+#include "formats/ti99_dsk.h"
+#include "imagedev/flopdrv.h"
+#include "machine/mm58274c.h"
+
+#define LOG logerror
+#define VERBOSE 1
+
+#define MOTOR_TIMER 1
+#define FDC_TAG "wd1773"
+#define CLOCK_TAG "mm58274c"
+
+#define BUFFER "ram"
+
+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)
+{
+ m_shortname = "ti99_bwg";
+}
+
+/*
+ Callback called at the end of DVENA pulse
+*/
+void snug_bwg_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ m_DVENA = CLEAR_LINE;
+ handle_hold();
+}
+
+/*
+ Call this when the state of DSKhold or DRQ/IRQ or DVENA change
+ Also see ti_fdc.
+
+ Emulation is faulty because the CPU is actually stopped in the midst of
+ instruction, at the end of the memory access
+
+ TODO: This has to be replaced by the proper READY handling that is already
+ prepared here. (Requires READY handling by the CPU.)
+*/
+void snug_bwg_device::handle_hold()
+{
+ line_state state;
+
+ if (m_hold && !m_DRQ && !m_IRQ && (m_DVENA==ASSERT_LINE))
+ state = ASSERT_LINE;
+ else
+ state = CLEAR_LINE;
+
+ m_slot->set_ready((state==CLEAR_LINE)? ASSERT_LINE : CLEAR_LINE);
+// cputag_set_input_line(machine(), "maincpu", INPUT_LINE_HALT, state);
+}
+
+/*
+ Callback, called from the controller chip whenever DRQ/IRQ state change
+*/
+WRITE_LINE_MEMBER( snug_bwg_device::intrq_w )
+{
+ if (VERBOSE>8) LOG("bwg: set irq = %02x\n", state);
+ m_IRQ = (state==ASSERT_LINE);
+
+ // Note that INTB is actually not used in the TI-99 family. But the
+ // controller asserts the line nevertheless, probably intended for
+ // use in another planned TI system
+ m_slot->set_intb(state);
+
+ handle_hold();
+}
+
+WRITE_LINE_MEMBER( snug_bwg_device::drq_w )
+{
+ if (VERBOSE>8) LOG("bwg: set drq = %02x\n", state);
+ m_DRQ = (state==ASSERT_LINE);
+ handle_hold();
+}
+
+/*
+ Read a byte
+ 4000 - 5bff: ROM (4 banks)
+
+ 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)
+*/
+READ8Z_MEMBER(snug_bwg_device::readz)
+{
+ if (m_selected)
+ {
+ if ((offset & m_select_mask)==m_select_value)
+ {
+ // 010x xxxx xxxx xxxx
+ if ((offset & 0x1c00)==0x1c00)
+ {
+ // ...1 11xx xxxx xxxx
+ if (m_rtc_enabled)
+ {
+ if ((offset & 0x03e1)==0x03e0)
+ {
+ // .... ..11 111x xxx0
+ *value = mm58274c_r(m_clock, (offset & 0x001e) >> 1);
+ }
+ else
+ {
+ *value = m_buffer_ram[(m_ram_page<<10) | (offset & 0x03ff)];
+ }
+ }
+ else
+ {
+ if ((offset & 0x03f9)==0x03f0)
+ {
+ // .... ..11 1111 0xx0
+ // Note that the value is inverted again on the board,
+ // so we can drop the inversion
+ *value = wd17xx_r(m_controller, (offset >> 1)&0x03);
+ }
+ else
+ {
+ *value = m_buffer_ram[(m_ram_page<<10) | (offset & 0x03ff)];
+ }
+ }
+ }
+ else
+ {
+ *value = m_dsrrom[(m_rom_page<<13) | (offset & 0x1fff)];
+ if (VERBOSE>7) LOG("bwg read dsr: %04x -> %02x\n", offset, *value);
+ }
+ }
+ }
+}
+
+/*
+ Resets the drive geometry. This is required because the heuristic of
+ the default implementation sets the drive geometry to the geometry
+ of the medium.
+*/
+void snug_bwg_device::set_geometry(device_t *drive, floppy_type_t type)
+{
+ // This assertion may fail when the names of the floppy devices change.
+ // Unfortunately, the wd17xx device assumes the floppy drives at root
+ // level, so we use an explicitly qualified tag. See peribox.h.
+ assert(drive != NULL);
+ floppy_drive_set_geometry(drive, type);
+}
+
+void snug_bwg_device::set_all_geometries(floppy_type_t type)
+{
+ set_geometry(machine().device(PFLOPPY_0), type);
+ set_geometry(machine().device(PFLOPPY_1), type);
+ set_geometry(machine().device(PFLOPPY_2), type);
+}
+
+/*
+ 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 (m_selected)
+ {
+ if ((offset & m_select_mask)==m_select_value)
+ {
+ // 010x xxxx xxxx xxxx
+ if ((offset & 0x1c00)==0x1c00)
+ {
+ // ...1 11xx xxxx xxxx
+ if (m_rtc_enabled)
+ {
+ if ((offset & 0x03e1)==0x03e0)
+ {
+ // .... ..11 111x xxx0
+ mm58274c_w(m_clock, (offset & 0x001e) >> 1, data);
+ }
+ else
+ {
+ m_buffer_ram[(m_ram_page<<10) | (offset & 0x03ff)] = data;
+ }
+ }
+ else
+ {
+ if ((offset & 0x03f9)==0x03f8)
+ {
+ // .... ..11 1111 1xx0
+ // Note that the value is inverted again on the board,
+ // so we can drop the inversion
+ wd17xx_w(m_controller, (offset >> 1)&0x03, data);
+ }
+ else
+ {
+ m_buffer_ram[(m_ram_page<<10) | (offset & 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
+*/
+void snug_bwg_device::crureadz(offs_t offset, UINT8 *value)
+{
+ UINT8 reply = 0;
+
+ if ((offset & 0xff00)==m_cru_base)
+ {
+ if ((offset & 0x00ff)==0)
+ {
+ // Assume that we have 4 drives connected
+ // If we want to do that properly, we need to check the actually
+ // available drives (not the images!). But why should we connect less?
+ reply = 0x00;
+
+ // DIP switches. Note that a closed switch means 0
+ // xx01 1111 11 = only dsk1; 10 = 1+2, 01=1/2/3, 00=1-4
+
+ if (m_dip1 != 0) reply |= 0x10;
+ if (m_dip2 != 0) reply |= 0x20;
+ reply |= (m_dip34 << 6);
+ *value = ~reply;
+ }
+ else
+ *value = 0;
+ }
+}
+
+void snug_bwg_device::cruwrite(offs_t offset, UINT8 data)
+{
+ 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 (VERBOSE>4) LOG("bwg: Map DSR = %d\n", m_selected);
+ break;
+
+ case 1:
+ /* Activate motor */
+ if (data && !m_strobe_motor)
+ { /* on rising edge, set motor_running for 4.23s */
+ m_DVENA = ASSERT_LINE;
+ handle_hold();
+ m_motor_on_timer->adjust(attotime::from_msec(4230));
+ }
+ m_strobe_motor = (data != 0);
+ 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
+ // This is not emulated and could cause the TI99 to lock up
+ m_hold = (data != 0);
+ handle_hold();
+ break;
+
+ case 4:
+ case 5:
+ case 6:
+ case 8:
+ /* Select drive 0-2 (DSK1-DSK3) (bits 4-6) */
+ /* Select drive 3 (DSK4) (bit 8) */
+ drive = (bit == 8) ? 3 : (bit - 4); /* drive # (0-3) */
+ drivebit = 1<<drive;
+
+ if (data != 0)
+ {
+ if ((m_DSEL & drivebit) == 0) /* select drive */
+ {
+ if (m_DSEL != 0)
+ logerror("bwg: Multiple drives selected, %02x\n", m_DSEL);
+ m_DSEL |= drivebit;
+ wd17xx_set_drive(m_controller, drive);
+ }
+ }
+ else
+ m_DSEL &= ~drivebit;
+ break;
+
+ case 7:
+ /* Select side of disk (bit 7) */
+ m_SIDE = data;
+ wd17xx_set_side(m_controller, m_SIDE);
+ break;
+
+ case 10:
+ /* double density enable (active low) */
+ wd17xx_dden_w(m_controller, (data != 0) ? ASSERT_LINE : CLEAR_LINE);
+ break;
+
+ case 11:
+ /* EPROM A13 */
+ if (data != 0)
+ m_rom_page |= 1;
+ else
+ m_rom_page &= 0xfe; // 11111110
+ break;
+
+ case 13:
+ /* RAM A10 */
+ m_ram_page = data;
+ break;
+
+ case 14:
+ /* Override FDC with RTC (active high) */
+ m_rtc_enabled = (data != 0);
+ break;
+
+ case 15:
+ /* EPROM A14 */
+ if (data != 0)
+ m_rom_page |= 2;
+ else
+ m_rom_page &= 0xfd; // 11111101
+ break;
+
+ case 3:
+ case 9:
+ case 12:
+ /* Unused (bit 3, 9 & 12) */
+ break;
+ }
+ }
+}
+
+void snug_bwg_device::device_start(void)
+{
+ if (VERBOSE>5) LOG("bwg: BWG start\n");
+ m_dsrrom = memregion(DSRROM)->base();
+ m_buffer_ram = memregion(BUFFER)->base();
+ m_motor_on_timer = timer_alloc(MOTOR_TIMER);
+ m_controller = subdevice(FDC_TAG);
+ m_clock = subdevice(CLOCK_TAG);
+ m_cru_base = 0x1100;
+}
+
+void snug_bwg_device::device_reset()
+{
+ if (VERBOSE>5) LOG("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_strobe_motor = false;
+ m_DVENA = CLEAR_LINE;
+ ti99_set_80_track_drives(FALSE);
+ floppy_type_t type = FLOPPY_STANDARD_5_25_DSDD_40;
+ set_all_geometries(type);
+ m_DRQ = false;
+ m_IRQ = false;
+ m_hold = false;
+ m_rtc_enabled = false;
+ m_selected = false;
+
+ m_dip1 = ioport("BWGDIP1")->read();
+ m_dip2 = ioport("BWGDIP2")->read();
+ m_dip34 = ioport("BWGDIP34")->read();
+
+ m_rom_page = 0;
+ m_ram_page = 0;
+}
+
+const wd17xx_interface bwg_wd17xx_interface =
+{
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, snug_bwg_device, intrq_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, snug_bwg_device, drq_w),
+ { PFLOPPY_0, PFLOPPY_1, PFLOPPY_2, PFLOPPY_3 }
+};
+
+static const mm58274c_interface floppy_mm58274c_interface =
+{
+ 1, /* mode 24*/
+ 0 /* first day of week */
+};
+
+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, 0x00, "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
+
+MACHINE_CONFIG_FRAGMENT( bwg_fdc )
+ MCFG_WD1773_ADD(FDC_TAG, bwg_wd17xx_interface )
+ MCFG_MM58274C_ADD(CLOCK_TAG, floppy_mm58274c_interface)
+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 );
+}
+
+const rom_entry *snug_bwg_device::device_rom_region() const
+{
+ return ROM_NAME( bwg_fdc );
+}
+
+ioport_constructor snug_bwg_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME(bwg_fdc);
+}
+
+const device_type TI99_BWG = &device_creator<snug_bwg_device>;
+
diff --git a/src/mess/machine/ti99/bwg.h b/src/mess/machine/ti99/bwg.h
new file mode 100644
index 00000000000..a99c3aa0d18
--- /dev/null
+++ b/src/mess/machine/ti99/bwg.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+
+ 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 "ti99defs.h"
+#include "imagedev/flopdrv.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_WRITE_LINE_MEMBER( intrq_w );
+ DECLARE_WRITE_LINE_MEMBER( drq_w );
+
+ void crureadz(offs_t offset, UINT8 *value);
+ void cruwrite(offs_t offset, UINT8 value);
+
+protected:
+ void device_start(void);
+ void device_reset(void);
+ const rom_entry *device_rom_region() const;
+ machine_config_constructor device_mconfig_additions() const;
+ ioport_constructor device_input_ports() const;
+
+private:
+ void handle_hold(void);
+ void set_all_geometries(floppy_type_t type);
+ void set_geometry(device_t *drive, floppy_type_t type);
+ void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+ // Holds the status of the DRQ and IRQ lines.
+ bool 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
+
+ // When TRUE the CPU is halted while DRQ/IRQ are true.
+ bool m_hold;
+
+ /* Indicates whether the clock is mapped into the address space. */
+ bool m_rtc_enabled;
+
+ /* When TRUE, keeps DVENA high. */
+ bool m_strobe_motor;
+
+ // Signal DVENA. When TRUE, makes some drive turning.
+ line_state m_DVENA;
+
+ /* 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. */
+ int m_SIDE;
+
+ // Link to the FDC1771 controller on the board.
+ device_t* m_controller;
+
+ // Link to the real-time clock on the board.
+ device_t* m_clock;
+
+ // 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;
+};
+
+#endif
diff --git a/src/mess/machine/ti99/datamux.c b/src/mess/machine/ti99/datamux.c
new file mode 100644
index 00000000000..f11fc709553
--- /dev/null
+++ b/src/mess/machine/ti99/datamux.c
@@ -0,0 +1,330 @@
+/***************************************************************************
+
+ 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 -------------------------+------+
+
+ 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)
+{
+}
+
+#define VERBOSE 0
+#define LOG logerror
+
+/***************************************************************************
+ DEVICE ACCESSOR FUNCTIONS
+***************************************************************************/
+
+/*
+ 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)
+
+ TODO: Check two-pass operation
+*/
+READ16_MEMBER( ti99_datamux_device::read )
+{
+ UINT8 hbyte = 0;
+ UINT16 addr = (offset << 1);
+
+ assert (mem_mask == 0xffff);
+
+ // 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_use32k)
+ {
+ UINT16 base = 0;
+ if ((addr & 0xe000)==0x2000) base = 0x1000;
+ if (((addr & 0xe000)==0xa000) || ((addr & 0xc000)==0xc000)) base = 0x4000;
+
+ if (base != 0)
+ {
+ UINT16 reply = m_ram16b[offset-base];
+ return reply;
+ }
+ }
+
+ attached_device *dev = m_devices.first();
+
+ // Reading the odd address first (addr+1)
+ while (dev != NULL)
+ {
+ if (((addr+1) & dev->m_config->address_mask)==dev->m_config->select)
+ {
+ // Cast to the bus8z_device (see ti99defs.h)
+ bus8z_device *devz = static_cast<bus8z_device *>(dev->m_device);
+ devz->readz(*m_space, addr+1, &m_latch);
+ }
+ // hope we don't have two devices answering...
+ // consider something like a logical OR and maybe some artificial smoke
+ dev = dev->m_next;
+ }
+
+ dev = m_devices.first();
+
+ // Reading the even address now (addr)
+ while (dev != NULL)
+ {
+ if (dev->m_config->write_select != 0xffff) // write-only
+ {
+ if ((addr & dev->m_config->address_mask)==dev->m_config->select)
+ {
+ bus8z_device *devz = static_cast<bus8z_device *>(dev->m_device);
+ devz->readz(*m_space, addr, &hbyte);
+ }
+ }
+ dev = dev->m_next;
+ }
+
+ // Insert four wait states and let CPU enter wait state
+ // The counter in the real console is implemented by a shift register
+ // that is triggered on a memory access
+ m_waitcount = 6;
+ m_ready(CLEAR_LINE);
+
+ // use the latch and the currently read byte and put it on the 16bit bus
+ return (hbyte<<8) | m_latch ;
+}
+
+/*
+ Write access.
+*/
+WRITE16_MEMBER( ti99_datamux_device::write )
+{
+ UINT16 addr = (offset << 1);
+
+ // Although MESS allows for using mem_mask to address parts of the
+ // data bus, this is not used in the TMS implementation. In fact, all
+ // accesses are true 16-bit accesses. We check for mem_mask always
+ // being ffff.
+
+// printf("write addr=%04x, value=%04x\n", addr, data);
+
+ assert (mem_mask == 0xffff);
+
+ // Handle the internal 32K expansion
+ if (m_use32k)
+ {
+ if (addr>=0x2000 && addr<0x4000)
+ {
+ m_ram16b[offset-0x1000] = data; // index 0000 - 0fff
+ return;
+ }
+ if (addr>=0xa000)
+ {
+ m_ram16b[offset-0x4000] = data; // index 1000 - 4fff
+ return;
+ }
+ }
+
+ attached_device *dev = m_devices.first();
+ while (dev != NULL)
+ {
+ if (((addr+1) & dev->m_config->address_mask)==(dev->m_config->select | dev->m_config->write_select))
+ {
+ bus8z_device *devz = static_cast<bus8z_device *>(dev->m_device);
+ devz->write(*m_space, addr+1, data & 0xff);
+ }
+ dev = dev->m_next;
+ }
+
+ dev = m_devices.first();
+
+ while (dev != NULL)
+ {
+ if ((addr & dev->m_config->address_mask)==(dev->m_config->select | dev->m_config->write_select))
+ {
+ // write the byte from the upper 8 lines
+ bus8z_device *devz = static_cast<bus8z_device *>(dev->m_device);
+ devz->write(*m_space, addr, (data>>8) & 0xff);
+ }
+ dev = dev->m_next;
+ }
+
+ // Insert four wait states and let CPU enter wait state
+ m_waitcount = 6;
+ m_ready(CLEAR_LINE);
+}
+
+/*
+ The datamux is connected to the clock line in order to operate
+ the wait state counter.
+*/
+void ti99_datamux_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
+***************************************************************************/
+
+void ti99_datamux_device::device_start(void)
+{
+ m_ram16b = NULL;
+}
+
+void ti99_datamux_device::device_stop(void)
+{
+ if (m_ram16b) free(m_ram16b);
+}
+
+void ti99_datamux_device::device_reset(void)
+{
+ const datamux_config *conf = reinterpret_cast<const datamux_config *>(static_config());
+
+ const dmux_device_list_entry *list = conf->devlist;
+ m_ready.resolve(conf->ready, *this);
+
+ 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 = (UINT16*)malloc(32768);
+
+ // 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 (VERBOSE>8) LOG("datamux: Device %s mounted at index %d.\n", list[i].name, i);
+ }
+ else
+ {
+ if (VERBOSE>8) LOG("datamux: Device %s not found.\n", list[i].name);
+ }
+ }
+ else
+ {
+ if (VERBOSE>8) LOG("datamux: Device %s not mounted due to configuration setting %s.\n", list[i].name, list[i].setting);
+ }
+ }
+ }
+ }
+ if (VERBOSE>8) LOG("datamux: Device count = %d\n", m_devices.count());
+ m_ready(ASSERT_LINE);
+}
+
+INPUT_PORTS_START( datamux )
+ PORT_START( "RAM" ) /* config */
+ PORT_CONFNAME( 0x01, 0x01, "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<ti99_datamux_device>;
diff --git a/src/mess/machine/ti99/datamux.h b/src/mess/machine/ti99/datamux.h
new file mode 100644
index 00000000000..9f5dd7711f6
--- /dev/null
+++ b/src/mess/machine/ti99/datamux.h
@@ -0,0 +1,115 @@
+/****************************************************************************
+
+ 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.
+*/
+typedef 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
+} dmux_device_list_entry;
+
+#define DMUX_CONFIG(name) \
+ const datamux_config(name) =
+
+typedef struct _datamux_config
+{
+ devcb_write_line ready;
+ const dmux_device_list_entry *devlist;
+} datamux_config;
+
+/*
+ Device list of this datamux.
+*/
+class attached_device
+{
+ friend class simple_list<attached_device>;
+ 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 );
+
+ void clock_in(int state);
+
+protected:
+ /* Constructor */
+ virtual void device_start(void);
+ virtual void device_stop(void);
+ virtual void device_reset(void);
+ ioport_constructor device_input_ports() const;
+
+private:
+ // Ready line to the CPU
+ devcb_resolved_write_line m_ready;
+
+ /* All devices that are attached to the 8-bit bus. */
+ simple_list<attached_device> 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;
+
+ /* Reference to the CPU; avoid lookups. */
+ device_t *m_cpu;
+
+ /* Reference to the address space, maybe unnecessary. */
+ address_space *m_space;
+};
+
+/******************************************************************************/
+
+#define MCFG_DMUX_ADD(_tag, _devices) \
+ MCFG_DEVICE_ADD(_tag, DATAMUX, 0) \
+ MCFG_DEVICE_CONFIG( _devices )
+#endif
+
diff --git a/src/mess/machine/ti99/evpc.c b/src/mess/machine/ti99/evpc.c
new file mode 100644
index 00000000000..65bf8955603
--- /dev/null
+++ b/src/mess/machine/ti99/evpc.c
@@ -0,0 +1,368 @@
+/****************************************************************************
+ 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),
+ device_nvram_interface(mconfig, *this)
+{
+ m_shortname = "ti99_evpc";
+}
+
+//-------------------------------------------------
+// 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
+*/
+void snug_enhanced_video_device::crureadz(offs_t offset, UINT8 *value)
+{
+ 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: -
+*/
+void snug_enhanced_video_device::cruwrite(offs_t offset, UINT8 data)
+{
+ 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 = (UINT8*)malloc(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;
+}
+
+void snug_enhanced_video_device::device_stop()
+{
+ free(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<snug_enhanced_video_device>;
+
diff --git a/src/mess/machine/ti99/evpc.h b/src/mess/machine/ti99/evpc.h
new file mode 100644
index 00000000000..0c78328cc33
--- /dev/null
+++ b/src/mess/machine/ti99/evpc.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+
+ 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 "ti99defs.h"
+#include "peribox.h"
+#include "dinvram.h"
+
+extern const device_type TI99_EVPC;
+
+typedef struct _evpc_palette
+{
+ UINT8 read_index, write_index, mask;
+ int read;
+ int state;
+ struct { UINT8 red, green, blue; } color[0x100];
+ //int dirty;
+} evpc_palette;
+
+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);
+
+ void crureadz(offs_t offset, UINT8 *value);
+ void cruwrite(offs_t offset, UINT8 data);
+
+protected:
+ void device_start(void);
+ void device_reset(void);
+ void device_stop(void);
+
+ const rom_entry *device_rom_region() const;
+ 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/mess/machine/ti99/genboard.c b/src/mess/machine/ti99/genboard.c
new file mode 100644
index 00000000000..208843635c3
--- /dev/null
+++ b/src/mess/machine/ti99/genboard.c
@@ -0,0 +1,1493 @@
+/***************************************************************************
+ 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.
+
+ For the page numbers we get:
+ Standard:
+ 00-3f are internal (DRAM)
+ 40-7f are internal expansion, never used
+ 80-bf are the P-Box address space (optional Memex and peripheral cards at that location)
+ c0-ff are internal (SRAM, EPROM)
+
+ Genmod:
+ 00-3f are the P-Box address space (expect Memex at that location)
+ 40-7f are the P-Box address space (expect Memex at that location)
+ 80-bf are the P-Box address space (expect Memex at that location)
+ c0-ef are the P-Box address space (expect Memex at that location)
+ f0-ff are internal (EPROM)
+
+ 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.
+
+ 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: 14 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.
+
+ There is also a flag for video wait states. Waiting for video at first
+ means an access to a memory-mapped device, giving 1 or 2 WS, and an
+ additional 14 WS after the access. As said, these waitstates will run
+ unnoticed when the code is located in the on-chip RAM. This makes emulation
+ a bit non-straightforward.
+
+ These 14 WS are simulated by a timer device which is started together with
+ the video access, and when some external access occurs later, the
+ remaining time will be used to produce wait states.
+
+ Michael Zapf, October 2011
+ February 2012: rewritten as class, restructured
+
+***************************************************************************/
+
+#include "genboard.h"
+#include "machine/mm58274c.h"
+
+#define VERBOSE 1
+#define LOG logerror
+
+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)
+{
+ m_eprom = NULL;
+}
+
+INPUT_CHANGED_MEMBER( geneve_mapper_device::gm_changed )
+{
+ int number = (int)((UINT64)param&0x03);
+ int value = newval;
+
+ if (number==1)
+ {
+ // Turbo switch. May be changed at any time.
+ if (VERBOSE>0) LOG("genboard: Setting turbo flag to %d\n", value);
+ m_turbo = (value!=0);
+ }
+ else
+ {
+ // TIMode switch. Causes reset when changed.
+ if (VERBOSE>0) LOG("genboard: Setting timode flag to %d\n", value);
+ m_timode = (value!=0);
+ machine().schedule_hard_reset();
+ }
+}
+
+/****************************************************************************
+ 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;
+ }
+}
+
+/*
+Geneve mode:
+f100 / fff5: v9938_r
+f110 / fff8: mapper_r
+f118 / ffff: key_r
+f130 / fff0: clock_r
+
+TI mode:
+8000 / fff8: mapper_r
+8008 / ffff: key_r
+8010 / fff0: clock_r
+8800 / fffd: v9938_r
+9000 / ffc0: speech_r
+9800 / ffc0: grom_r
+
+*/
+
+void geneve_mapper_device::do_wait(int min)
+{
+ min = min + 1;
+ // Extra waitstates?
+ if (m_extra_waitstates && min < 4) min = 3;
+ m_waitcount = min;
+ if (m_waitcount > 0)
+ {
+ if (VERBOSE>8) LOG("genboard: Pulling down READY line for %d cycles\n", m_waitcount);
+ m_ready(CLEAR_LINE);
+ }
+}
+
+/************************************************************************
+ Called by the address map
+************************************************************************/
+
+READ8_MEMBER( geneve_mapper_device::readm )
+{
+ UINT8 value = 0;
+ int page;
+ UINT32 physaddr;
+
+ // Premature access. The CPU reads the start vector before RESET.
+ if (m_eprom==NULL) return 0;
+
+ 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
+
+ // 1 WS is always added; any pending video wait states are canceled
+ m_video_waiting = false;
+ do_wait(1);
+
+ // Initialize wait state timer
+ // Create 16 wait states (2 more than expected, experimenting)
+ if (m_video_waitstates)
+ do_wait(16);
+
+ m_video->readz(space, offset, &value, mem_mask);
+ if (VERBOSE>7) LOG("genboard: Read video %04x -> %02x\n", offset, value);
+ return value;
+ }
+ if ((offset & 0xfff8)==0xf110)
+ {
+ // mapper
+ value = m_map[offset & 0x0007];
+
+ // Add appropriate number of waitstates
+ // 1 WS is added at least
+ do_wait(1);
+ if (VERBOSE>7) LOG("genboard: read mapper %04x -> %02x\n", offset, value);
+ return value;
+ }
+ if ((offset & 0xfff8) == 0xf118)
+ {
+ // key
+ value = m_keyboard->get_recent_key();
+ do_wait(1);
+ if (VERBOSE>7) LOG("genboard: Read keyboard -> %02x\n", value);
+ return value;
+ }
+ if ((offset & 0xfff0)==0xf130)
+ {
+ // clock
+ // tests on the real machine showed that
+ // upper nibble is 0xf (probably because of the location at 0xf130?)
+ value = mm58274c_r(m_clock, offset & 0x000f) | 0xf0;
+ do_wait(1);
+ if (VERBOSE>7) LOG("genboard: Read clock %04x -> %02x\n", offset, value);
+ return value;
+ }
+ }
+ else // TI mode
+ {
+ if ((offset & 0xfff8)==0x8000)
+ {
+ // mapper
+ value = m_map[offset & 0x0007];
+ do_wait(1);
+ if (VERBOSE>7) LOG("genboard: Read mapper %04x -> %02x\n", offset, value);
+ return value;
+ }
+ if ((offset & 0xfff8)== 0x8008)
+ {
+ // key
+ value = m_keyboard->get_recent_key();
+ do_wait(1);
+ if (VERBOSE>7) LOG("genboard: Read keyboard -> %02x\n", value);
+ return value;
+ }
+ if ((offset & 0xfff0)==0x8010)
+ {
+ // 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 = mm58274c_r(m_clock, offset & 0x000f);
+ value |= ((offset & 0x000f)==0x000f)? 0x20 : 0x10;
+
+ do_wait(1);
+ if (VERBOSE>7) LOG("genboard: Read clock %04x -> %02x\n", offset, value);
+ return value;
+ }
+ if ((offset & 0xfc01)==0x8800)
+ {
+ // video
+ // ++++ ++-- ---- ---+
+ // 1000 1000 0000 00x0
+
+ // 1 WS is always added; any pending video waitstates are canceled
+ m_video_waiting = false;
+ do_wait(1);
+
+ // Initialize waitstate timer
+ // Create 14 waitstates (+2, see above)
+ if (m_video_waitstates)
+ do_wait(16);
+
+ m_video->readz(space, offset, &value, mem_mask);
+ if (VERBOSE>7) LOG("genboard: Read video %04x -> %02x\n", offset, value);
+ return value;
+ }
+ if ((offset & 0xfc01)==0x9000)
+ {
+ // speech
+ // ++++ ++-- ---- ---+
+ // 1001 0000 0000 0000
+ // We need to add the address prefix bits
+ m_peribox->readz(space, offset | ((m_genmod)? 0x170000 : 0x070000), &value, mem_mask);
+
+ do_wait(1);
+ if (VERBOSE>7) LOG("genboard: Read speech -> %02x\n", value);
+ return value;
+ }
+ if ((offset & 0xfc01)==0x9800)
+ {
+ // grom simulation
+ // ++++ ++-- ---- ---+
+ // 1001 1000 0000 00x0
+ value = read_grom(space, offset, mem_mask);
+
+ do_wait(1);
+ if (VERBOSE>7) LOG("genboard: Read GROM %04x -> %02x\n", offset, value);
+ return value;
+ }
+ }
+
+ page = (offset & 0xe000) >> 13;
+
+ if (m_direct_mode)
+ {
+ physaddr = 0x1e0000; // points to boot eprom
+ }
+ else
+ {
+ if (!m_geneve_mode && page==3)
+ {
+ // Cartridge paging in TI mode
+ // See also cartridge type "paged" in gromport.h
+ // value 0x36 = 0 0110 110x xxxx xxxx xxxx (page 1)
+ // value 0x37 = 0 0110 111x xxxx xxxx xxxx (page 2)
+ // Only use this if there are 2*8 KiB cartridge ROM
+ if (VERBOSE>7) LOG("genboard: Cartridge area\n");
+ if (m_cartridge_size==0x4000 && m_cartridge_secondpage) physaddr = 0x06e000;
+ else physaddr = 0x06c000;
+ }
+ else
+ {
+ physaddr = (m_map[page] << 13);
+ }
+ }
+
+ physaddr |= (offset & 0x1fff);
+
+ if (!m_genmod)
+ {
+ // Standard Geneve
+ if ((physaddr & 0x180000)==0x000000)
+ {
+ // DRAM. One wait state.
+ do_wait(1);
+
+ value = m_dram[physaddr & 0x07ffff];
+// printf("dram read physaddr = %06x logaddr = %04x value = %02x\n", physaddr, offset, value);
+ if (VERBOSE>7) LOG("genboard: Read DRAM %04x (%06x) -> %02x\n", offset, physaddr, value);
+ return value;
+ }
+
+ if ((physaddr & 0x180000)==0x080000)
+ {
+ // On-board memory expansion for standard Geneve (never used)
+ do_wait(1);
+ if (VERBOSE>7) LOG("genboard: Read unmapped area %06x\n", physaddr);
+ return 0;
+ }
+
+ if ((physaddr & 0x1e0000)==0x1e0000)
+ {
+ // 1 111. ..xx xxxx xxxx xxxx on-board eprom (16K)
+ // mirrored for f0, f2, f4, ...; f1, f3, f5, ...
+ value = m_eprom[physaddr & 0x003fff];
+ do_wait(0);
+ if (VERBOSE>7) LOG("genboard: Read EPROM %04x (%06x) -> %02x\n", offset, physaddr, value);
+ return value;
+ }
+
+ if ((physaddr & 0x180000)==0x180000)
+ {
+ if ((physaddr & m_sram_mask)==m_sram_val)
+ {
+ value = m_sram[physaddr & ~m_sram_mask];
+ }
+ // Return in any case
+// printf("sram read physaddr = %06x logaddr = %04x value = %02x\n", physaddr, offset, value);
+ do_wait(0);
+ if (VERBOSE>7) LOG("genboard: Read SRAM %04x (%06x) -> %02x\n", offset, physaddr, value);
+ return value;
+ }
+
+ // 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
+ do_wait(1);
+
+ physaddr = (physaddr & 0x0007ffff); // 19 bit address (with AMA..AMC)
+ m_peribox->readz(space, physaddr, &value, mem_mask);
+ if (VERBOSE>7) LOG("genboard: Read P-Box %04x (%06x) -> %02x\n", offset, physaddr, value);
+ return value;
+ }
+ else
+ {
+ // GenMod mode
+ if ((m_timode) && ((physaddr & 0x180000)==0x000000))
+ {
+ // DRAM. One wait state.
+ value = m_dram[physaddr & 0x07ffff];
+ if (!m_turbo) do_wait(1);
+ return value;
+ }
+
+ if ((physaddr & 0x1e0000)==0x1e0000)
+ {
+ // 1 111. ..xx xxxx xxxx xxxx on-board eprom (16K)
+ // mirrored for f0, f2, f4, ...; f1, f3, f5, ...
+ value = m_eprom[physaddr & 0x003fff];
+ do_wait(0);
+ return value;
+ }
+ // Route everything else to the P-Box
+ physaddr = (physaddr & 0x001fffff); // 21 bit address for Genmod
+
+ if (!m_turbo) do_wait(1);
+ // Check: Are waitstates completely turned off for turbo mode, or
+ // merely the waitstates for DRAM memory access and box access?
+
+ m_peribox->readz(space, physaddr, &value, mem_mask);
+ return value;
+ }
+}
+
+
+/*
+Geneve mode:
+f100 / fff1: v9938_w
+f110 / fff8: mapper_w
+f120 / fff0: sound_w
+f130 / fff0: clock_w
+
+TI mode:
+8000 / fff8: mapper_w
+8010 / fff0: clock_w
+8400 / fc00: sound_w
+8c00 / fff9: v9938_w
+9400 / fc00: speech_w
+9c00 / fffd: grom_w
+
+*/
+
+WRITE8_MEMBER( geneve_mapper_device::writem )
+{
+ UINT32 physaddr;
+ int page;
+
+ if (m_peribox==NULL) return; // see above: prevent premature access
+
+ if (m_geneve_mode)
+ {
+ if ((offset & 0xfff1)==0xf100)
+ {
+ // video
+ // ++++ ++++ ++++ ---+
+ // 1111 0001 0000 .cc0
+ m_video->write(space, offset, data, mem_mask);
+
+ // 1 WS is always added; any pending video waitstates are canceled
+ m_video_waiting = false;
+ do_wait(1);
+
+ // Initialize waitstate timer
+ // Create 14 waitstates (+3, experimenting)
+ if (m_video_waitstates)
+ do_wait(17);
+
+ if (VERBOSE>7) LOG("genboard: Write video %04x <- %02x\n", offset, data);
+ return;
+ }
+ if ((offset & 0xfff8)==0xf110)
+ {
+ // mapper
+ m_map[offset & 0x0007] = data;
+ do_wait(1);
+ if (VERBOSE>7) LOG("genboard: Write mapper %04x <- %02x\n", offset, data);
+ return;
+ }
+ if ((offset & 0xfff1)==0xf120)
+ {
+ // sound
+ // ++++ ++++ ++++ ---+
+ m_sound->write(space, 0, data, mem_mask);
+
+ // Add 24 waitstates. This is an average value, as the
+ // waitstate generation seems to depend on an external timer of
+ // the sound chip
+ m_waitcount = 24;
+ m_ready(CLEAR_LINE);
+ if (VERBOSE>7) LOG("genboard: Write sound <- %02x\n", data);
+ return;
+ }
+ if ((offset & 0xfff0)==0xf130)
+ {
+ // clock
+ // ++++ ++++ ++++ ----
+ mm58274c_w(m_clock, offset & 0x00f, data);
+ do_wait(1);
+ if (VERBOSE>7) LOG("genboard: Write clock %04x <- %02x\n", offset, data);
+ return;
+ }
+ }
+ else
+ {
+ // TI mode
+ if ((offset & 0xfff8)==0x8000)
+ {
+ // mapper
+ m_map[offset & 0x0007] = data;
+ do_wait(1);
+ if (VERBOSE>7) LOG("genboard: Write mapper %04x <- %02x\n", offset, data);
+ return;
+ }
+ // No key write at 8008
+ if ((offset & 0xfff0)==0x8010)
+ {
+ // clock
+ mm58274c_w(m_clock, offset & 0x00f, data);
+ do_wait(1);
+ if (VERBOSE>7) LOG("genboard: Write clock %04x <- %02x\n", offset, data);
+ return;
+ }
+ if ((offset & 0xfc01)==0x8400)
+ {
+ // sound
+ // ++++ ++-- ---- ---+
+ // 1000 0100 0000 0000
+
+ m_sound->write(space, 0, data, mem_mask);
+ // Add 24 waitstates. This is an approximation, as the
+ // waitstate generation seems to depend on an external timer of
+ // the sound chip
+ m_waitcount = 24;
+ m_ready(CLEAR_LINE);
+ if (VERBOSE>7) LOG("genboard: Write sound <- %02x\n", data);
+ return;
+ }
+ if ((offset & 0xfc01)==0x8c00)
+ {
+ // video
+ // ++++ ++-- ---- ---+
+ // 1000 1100 0000 00c0
+ // Initialize waitstate timer
+ m_video->write(space, offset, data, mem_mask);
+
+ // 1 WS is always added; any pending video waitstates are canceled
+ m_video_waiting = false;
+ do_wait(1);
+
+ // Initialize waitstate timer
+ // Create 14 waitstates (+3)
+ if (m_video_waitstates)
+ do_wait(17);
+
+ if (VERBOSE>7) LOG("genboard: Write video %04x <- %02x\n", offset, data);
+ return;
+ }
+ if ((offset & 0xfc01)==0x9400)
+ {
+ // speech
+ // ++++ ++-- ---- ---+
+ // 1001 0100 0000 0000
+ // We need to add the address prefix bits
+ m_peribox->write(space, offset | ((m_genmod)? 0x170000 : 0x070000), data, mem_mask);
+ do_wait(1);
+ if (VERBOSE>7) LOG("genboard: Write speech <- %02x\n", data);
+ return;
+ }
+ if ((offset & 0xfc01)==0x9c00)
+ {
+ // grom simulation
+ // ++++ ++-- ---- ---+
+ // 1001 1100 0000 00c0
+ write_grom(space, offset, data, mem_mask);
+ do_wait(1);
+ if (VERBOSE>7) LOG("genboard: Write GROM %04x <- %02x\n", offset, data);
+ return;
+ }
+ }
+
+ page = (offset & 0xe000) >> 13;
+ if (m_direct_mode)
+ {
+ physaddr = 0x1e0000; // points to boot eprom
+ }
+ else
+ {
+ if (!m_geneve_mode && page==3)
+ {
+ if (m_cartridge_size==0x4000)
+ {
+ // Writing to 0x6000 selects page 1,
+ // writing to 0x6002 selects page 2
+ m_cartridge_secondpage = ((offset & 0x0002)!=0);
+ do_wait(1);
+ if (VERBOSE>7) LOG("genboard: Set cartridge page %02x\n", m_cartridge_secondpage);
+
+ return;
+ }
+ else
+ {
+ // writing into cartridge rom space (no bankswitching)
+ if ((((offset & 0x1000)==0x0000) && !m_cartridge6_writable)
+ || (((offset & 0x1000)==0x1000) && !m_cartridge7_writable))
+ {
+ if (VERBOSE>0) LOG("genboard: Writing to protected cartridge space %04x ignored\n", offset);
+ return;
+ }
+ else
+ // TODO: Check whether secondpage is really ignored
+ physaddr = 0x06c000;
+ }
+ }
+ else
+ physaddr = (m_map[page] << 13);
+ }
+
+ physaddr |= offset & 0x1fff;
+
+// printf("write physaddr = %06x logaddr = %04x value = %02x\n", physaddr, offset, data);
+
+ if (!m_genmod)
+ {
+ if ((physaddr & 0x180000)==0x000000)
+ {
+ // DRAM write. One wait state. (only for normal Geneve)
+ m_dram[physaddr & 0x07ffff] = data;
+ do_wait(1);
+ if (VERBOSE>7) LOG("genboard: Write DRAM %04x (%06x) <- %02x\n", offset, physaddr, data);
+ return;
+ }
+
+ if ((physaddr & 0x180000)==0x080000)
+ {
+ // On-board memory expansion for standard Geneve (never used)
+ do_wait(1);
+ if (VERBOSE>7) LOG("genboard: Write unmapped area %06x\n", physaddr);
+ return;
+ }
+
+ if ((physaddr & 0x1e0000)==0x1e0000)
+ {
+ // 1 111. ..xx xxxx xxxx xxxx on-board eprom (16K)
+ // mirrored for f0, f2, f4, ...; f1, f3, f5, ...
+ // Ignore EPROM write
+ do_wait(0);
+ if (VERBOSE>7) LOG("genboard: Write EPROM %04x (%06x) <- %02x, ignored\n", offset, physaddr, data);
+ return;
+ }
+
+ if ((physaddr & 0x180000)==0x180000)
+ {
+ if ((physaddr & m_sram_mask)==m_sram_val)
+ {
+ m_sram[physaddr & ~m_sram_mask] = data;
+ }
+ if (VERBOSE>7) LOG("genboard: Write SRAM %04x (%06x) <- %02x\n", offset, physaddr, data);
+ do_wait(0);
+ // Return in any case
+ return;
+ }
+ // Route everything else to the P-Box
+ // Add a wait state
+
+ // only AMA, AMB, AMC are used; AMD and AME are not used
+ physaddr = (physaddr & 0x0007ffff); // 19 bit address
+ if (VERBOSE>7) LOG("genboard: Write P-Box %04x (%06x) <- %02x\n", offset, physaddr, data);
+ m_peribox->write(space, physaddr, data, mem_mask);
+ do_wait(1);
+ }
+ else
+ {
+ // GenMod mode
+ if ((m_timode) && ((physaddr & 0x180000)==0x000000))
+ {
+ // DRAM. One wait state.
+ m_dram[physaddr & 0x07ffff] = data;
+ if (!m_turbo) do_wait(1);
+ return;
+ }
+
+ if ((physaddr & 0x1e0000)==0x1e0000)
+ {
+ // 1 111. ..xx xxxx xxxx xxxx on-board eprom (16K)
+ // mirrored for f0, f2, f4, ...; f1, f3, f5, ...
+ // Ignore EPROM write
+ if (!m_turbo) do_wait(1);
+ return;
+ }
+ // Route everything else to the P-Box
+ physaddr = (physaddr & 0x001fffff); // 21 bit address for Genmod
+ m_peribox->write(space, physaddr, data, mem_mask);
+ if (!m_turbo) do_wait(1);
+ }
+}
+
+/*
+ The mapper is connected to the clock line in order to operate
+ the wait state counter.
+*/
+void geneve_mapper_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 ***/
+
+void geneve_mapper_device::device_start()
+{
+ const geneve_mapper_config *conf = reinterpret_cast<const geneve_mapper_config *>(static_config());
+
+ if (VERBOSE>0) LOG("genboard: Starting Geneve mapper\n");
+ // Get pointers
+ m_peribox = machine().device<bus8z_device>(PERIBOX_TAG);
+ m_keyboard = machine().device<geneve_keyboard_device>(GKEYBOARD_TAG);
+ m_video = machine().device<bus8z_device>(VIDEO_SYSTEM_TAG);
+ m_sound = machine().device<bus8z_device>(TISOUND_TAG);
+ m_clock = machine().device(GCLOCK_TAG);
+
+ m_ready.resolve(conf->ready, *this);
+
+ // This is a preliminary setting; the initial context switch occurs before
+ // device_reset. Luckily, the reset vector at >0000/>0002 is the same for
+ // all variants of the boot eprom.
+// m_eprom = machine().root_device().memregion("maincpu")->base();
+
+ m_sram = machine().root_device().memregion(SRAM_TAG)->base();
+ m_dram = machine().root_device().memregion(DRAM_TAG)->base();
+
+ m_geneve_mode = false;
+ m_direct_mode = true;
+
+ m_waitcount = 0;
+}
+
+void geneve_mapper_device::device_reset()
+{
+ if (VERBOSE>1) LOG("genboard: Resetting mapper\n");
+
+ m_extra_waitstates = false;
+ m_video_waitstates = true;
+ m_video_waiting = false;
+
+ m_geneve_mode =false;
+ m_direct_mode = true;
+ m_cartridge_size = 0x4000;
+ m_cartridge_secondpage = false;
+ m_cartridge6_writable = false;
+ m_cartridge7_writable = false;
+
+ // Clear map
+ for (int i=0; i < 8; i++) m_map[i] = 0;
+
+ m_genmod = false;
+
+ if (machine().root_device().ioport("MODE")->read()==0)
+ {
+ switch (machine().root_device().ioport("BOOTROM")->read())
+ {
+ case GENEVE_098:
+ if (VERBOSE>0) LOG("genboard: Using 0.98 boot eprom\n");
+ m_eprom = machine().root_device().memregion("maincpu")->base() + 0x4000;
+ break;
+ case GENEVE_100:
+ if (VERBOSE>0) LOG("genboard: Using 1.00 boot eprom\n");
+ m_eprom = machine().root_device().memregion("maincpu")->base();
+ break;
+ }
+ }
+ else
+ {
+ if (VERBOSE>0) LOG("genboard: Using GenMod modification\n");
+ 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<geneve_mapper_device>;
+
+/****************************************************************************
+ 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)
+{
+}
+
+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 (VERBOSE>5) LOG("genboard: posting keycode %02x\n", 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 (VERBOSE>7) LOG("genboard: poll keyboard\n");
+ 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 (VERBOSE>6) LOG("genboard: signalling key available\n");
+ 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 (VERBOSE>5) LOG("genboard: keyboard clock_control state=%d\n", 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_config_complete()
+{
+ // Resolve the callback lines to the console
+ const geneve_keyboard_config *intf = reinterpret_cast<const geneve_keyboard_config *>(static_config());
+ m_interrupt.resolve(intf->interrupt, *this);
+}
+
+void geneve_keyboard_device::device_start()
+{
+ if (VERBOSE>2) LOG("genboard: Keyboard started\n");
+ m_timer = timer_alloc(0);
+}
+
+void geneve_keyboard_device::device_reset()
+{
+ reset_line(CLEAR_LINE);
+ m_key_queue_length = 0;
+ m_key_reset = true;
+ m_keyboard_clock = false;
+ m_key_in_buffer = 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<geneve_keyboard_device>;
+
+/****************************************************************************
+ 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)
+{
+}
+
+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<v9938_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<geneve_mouse_device>;
+
diff --git a/src/mess/machine/ti99/genboard.h b/src/mess/machine/ti99/genboard.h
new file mode 100644
index 00000000000..0a0afb754e3
--- /dev/null
+++ b/src/mess/machine/ti99/genboard.h
@@ -0,0 +1,200 @@
+/****************************************************************************
+
+ 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 "video/v9938.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:
+ void device_start();
+ void device_reset();
+ 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)
+
+/*****************************************************************************/
+
+typedef struct _geneve_keyboard_config
+{
+ devcb_write_line interrupt;
+} geneve_keyboard_config;
+
+#define GENEVE_KEYBOARD_CONFIG(name) \
+ const geneve_keyboard_config(name) =
+
+
+#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();
+
+protected:
+ void device_start();
+ void device_reset();
+ void device_config_complete();
+ ioport_constructor device_input_ports() const;
+ devcb_resolved_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_KEYBOARD_ADD(_tag, _intf ) \
+ MCFG_DEVICE_ADD(_tag, GENEVE_KEYBOARD, 0) \
+ MCFG_DEVICE_CONFIG(_intf)
+
+/*****************************************************************************/
+
+typedef struct _geneve_mapper_config
+{
+ devcb_write_line ready;
+} geneve_mapper_config;
+
+class geneve_mapper_device : public device_t
+{
+public:
+ geneve_mapper_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ inline void set_geneve_mode(bool geneve) { m_geneve_mode = geneve; }
+ inline void set_direct_mode(bool direct) { m_direct_mode = direct; }
+ inline void set_cartridge_size(int size) { m_cartridge_size = size; }
+ inline void set_cartridge_writable(int base, bool write)
+ {
+ if (base==0x6000) m_cartridge6_writable = write;
+ else m_cartridge7_writable = write;
+ }
+ inline void set_video_waitstates(bool wait) { m_video_waitstates = wait; }
+ inline void set_extra_waitstates(bool wait) { m_extra_waitstates = wait; }
+
+ void do_wait(int min);
+
+ DECLARE_READ8_MEMBER( readm );
+ DECLARE_WRITE8_MEMBER( writem );
+
+ DECLARE_INPUT_CHANGED_MEMBER( gm_changed );
+
+ void clock_in(int state);
+
+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
+ bool m_video_waiting;
+ bool m_video_waitstates;
+ bool m_extra_waitstates;
+
+ // Mapper function
+ 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];
+
+ // Genmod modifications
+ bool m_turbo;
+ bool m_genmod;
+ bool m_timode;
+
+ int m_sram_mask;
+ int m_sram_val;
+
+ // Ready line to the CPU
+ devcb_resolved_write_line m_ready;
+
+ // Counter for the wait states.
+ int m_waitcount;
+
+ // Devices
+ device_t* m_clock;
+ 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 GENEVE_MAPPER_CONFIG(name) \
+ const geneve_mapper_config(name) =
+
+#define MCFG_GENEVE_MAPPER_ADD(_tag, _conf ) \
+ MCFG_DEVICE_ADD(_tag, GENEVE_MAPPER, 0) \
+ MCFG_DEVICE_CONFIG( _conf )
+
+#endif
diff --git a/src/mess/machine/ti99/grom.c b/src/mess/machine/ti99/grom.c
new file mode 100644
index 00000000000..c3705fa73cd
--- /dev/null
+++ b/src/mess/machine/ti99/grom.c
@@ -0,0 +1,260 @@
+/***************************************************************************
+
+ 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 LOG logerror
+#define VERBOSE 1
+
+/*
+ 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)
+{
+}
+
+/*
+ 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 )
+{
+ 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.
+ *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.
+ m_address = (m_address + 1)&0xFFFF;
+
+ // 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 )
+{
+ 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;
+ }
+ 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 - 1) & 0xFFFF;
+
+ // 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 + 1) & 0xFFFF;
+}
+
+/*
+ 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<const ti99grom_config *>(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(conf->ready, *this);
+
+ 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<ti99_grom_device>;
diff --git a/src/mess/machine/ti99/grom.h b/src/mess/machine/ti99/grom.h
new file mode 100644
index 00000000000..3093e8bc45b
--- /dev/null
+++ b/src/mess/machine/ti99/grom.h
@@ -0,0 +1,102 @@
+/***************************************************************************
+
+ GROM emulation
+ See grom.c for documentation,
+
+ Michael Zapf
+
+ February 2012: Rewritten as class
+
+***************************************************************************/
+#ifndef __TI99GROM__
+#define __TI99GROM__
+
+#include "ti99defs.h"
+
+typedef struct _ti99grom_config
+{
+ bool writable;
+ int ident;
+ const char *regionname;
+ offs_t offset_reg;
+ int size;
+ devcb_write_line ready;
+ int clockrate;
+} ti99grom_config;
+
+#define GROM_CONFIG(name) \
+ const ti99grom_config(name) =
+
+
+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);
+ 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_resolved_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();
+
+ void device_start(void);
+ void device_reset(void);
+ 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/mess/machine/ti99/gromport.c b/src/mess/machine/ti99/gromport.c
new file mode 100644
index 00000000000..3f2b61a2bcc
--- /dev/null
+++ b/src/mess/machine/ti99/gromport.c
@@ -0,0 +1,2234 @@
+/***************************************************************************
+ 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 VERBOSE 1
+#define LOG logerror
+
+#define GROM_AREA 0x9800
+#define GROM_MASK 0xf800
+
+#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 CARTROM2_TAG "rom2_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),
+ device_slot_interface(mconfig, *this),
+ m_connector(NULL)
+{
+}
+
+/* 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);
+}
+
+void gromport_device::crureadz(offs_t offset, UINT8 *value)
+{
+ if (m_connector != NULL)
+ m_connector->crureadz(offset, value);
+}
+
+void gromport_device::cruwrite(offs_t offset, UINT8 data)
+{
+ if (m_connector != NULL)
+ m_connector->cruwrite(offset, data);
+}
+
+WRITE_LINE_MEMBER(gromport_device::ready_line)
+{
+ m_console_ready(state);
+}
+
+void gromport_device::device_start()
+{
+}
+
+void gromport_device::device_reset()
+{
+ m_reset_on_insert = (ioport("CARTRESET")->read()==0x01);
+}
+
+/*
+ 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()
+{
+ const gromport_config *intf = reinterpret_cast<const gromport_config *>(static_config());
+ m_console_ready.resolve(intf->ready, *this);
+ m_console_reset.resolve(intf->reset, *this);
+ m_connector = static_cast<ti99_cartridge_connector_device*>(first_subdevice());
+}
+
+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<gromport_device>;
+
+/***************************************************************************
+ 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<single_conn_device>;
+const device_type GROMPORT_MULTI = &device_creator<multi_conn_device>;
+const device_type GROMPORT_GK = &device_creator<gkracker_device>;
+
+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)
+: bus8z_device(mconfig, type, name, tag, owner, clock)
+{
+}
+
+void ti99_cartridge_connector_device::ready_line(int state)
+{
+ m_gromport->ready_line(state);
+}
+
+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)
+{
+ m_shortname = "single";
+}
+
+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);
+}
+
+void single_conn_device::crureadz(offs_t offset, UINT8 *value)
+{
+ // Pass through
+ m_cartridge->crureadz(offset, value);
+}
+
+void single_conn_device::cruwrite(offs_t offset, UINT8 data)
+{
+ // Pass through
+ m_cartridge->cruwrite(offset, data);
+}
+
+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 );
+}
+
+void single_conn_device::device_config_complete()
+{
+ m_cartridge = static_cast<ti99_cartridge_device*>(first_subdevice());
+ m_gromport = static_cast<gromport_device*>(owner());
+}
+
+/********************************************************/
+
+/*
+ The multi-cartridge extender
+
+ This is a somewhat mythical device which was never available for the normal
+ customer, but there are reports of the existance 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)
+{
+ m_shortname = "multi";
+}
+
+/*
+ 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 (VERBOSE>7)
+ if (m_active_slot != slotnumber) LOG("multi_conn_device: Setting cartslot to %d\n", 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_AREA)
+ {
+ set_slot((offset>>2) & 0x00ff);
+ }
+ }
+ slot = m_active_slot;
+ return slot;
+}
+
+void multi_conn_device::insert(int index, ti99_cartridge_device* cart)
+{
+ if (VERBOSE>3) LOG("multi_conn_device: insert slot %d\n", index);
+ m_cartridge[index] = cart;
+ m_gromport->cartridge_inserted();
+}
+
+void multi_conn_device::remove(int index)
+{
+ if (VERBOSE>3) LOG("multi_conn_device: remove slot %d\n", 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_AREA)
+ {
+ 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_AREA)
+ {
+ 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)
+ {
+ // LOG("try it on slot %d\n", slot);
+ m_cartridge[slot]->write(space, offset, data, mem_mask);
+ }
+ }
+}
+
+void multi_conn_device::crureadz(offs_t offset, UINT8 *value)
+{
+ 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(offset, value);
+ }
+}
+
+void multi_conn_device::cruwrite(offs_t offset, UINT8 data)
+{
+ 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(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;
+ }
+ m_gromport = static_cast<gromport_device*>(owner());
+}
+
+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),
+ device_nvram_interface(mconfig, *this)
+{
+ m_shortname = "ti99_gkracker";
+}
+
+READ8Z_MEMBER(gkracker_device::readz)
+{
+ if ((offset & GROM_MASK) == GROM_AREA)
+ {
+ // 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 (VERBOSE>8) LOG("gkracker_device: read %04x -> %02x\n", 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_AREA)
+ {
+ // 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 (VERBOSE>8) LOG("gkracker_device: set grom address %04x\n", 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 (VERBOSE>7) LOG("gkracker_device: gwrite %04x(%04x) <- %02x\n", 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 (VERBOSE>7) LOG("gkracker_device: write %04x <- %02x\n", 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;
+ }
+ }
+ }
+}
+
+void gkracker_device::crureadz(offs_t offset, UINT8 *value)
+{
+ if (m_cartridge != NULL) m_cartridge->crureadz(offset, value);
+}
+
+void gkracker_device::cruwrite(offs_t offset, UINT8 data)
+{
+ if (m_cartridge != NULL) m_cartridge->cruwrite(offset, data);
+}
+
+INPUT_CHANGED_MEMBER( gkracker_device::gk_changed )
+{
+ if (VERBOSE>7) LOG("gkracker_device: input changed %d - %d\n", (int)((UINT64)param & 0x07), newval);
+ m_gk_switch[(UINT64)param & 0x07] = newval;
+}
+
+void gkracker_device::insert(int index, ti99_cartridge_device* cart)
+{
+ if (VERBOSE>3) LOG("gkracker_device: insert cartridge\n");
+ 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 (VERBOSE>3) LOG("gkracker_device: remove cartridge\n");
+ 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 (VERBOSE>3) LOG("gkracker_device: Creating default NVRAM\n");
+ 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 (VERBOSE>3) LOG("gkracker_device: reading NVRAM\n");
+ // 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 (VERBOSE>3) LOG("gkracker_device: writing NVRAM\n");
+ 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;
+ m_grom_address = 0; // for the GROM emulation
+ for (int i=1; i < 6; i++) m_gk_switch[i] = 0;
+ m_gromport = static_cast<gromport_device*>(owner());
+}
+
+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();
+}
+
+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_PAGEDCRU
+};
+
+static const pcb_type pcbdefs[] =
+{
+ { PCB_STANDARD, "standard" },
+ { PCB_PAGED, "paged" },
+ { PCB_MINIMEM, "minimem" },
+ { PCB_SUPER, "super" },
+ { PCB_MBX, "mbx" },
+ { PCB_PAGED379I, "paged379i" },
+ { PCB_PAGEDCRU, "pagedcru" },
+ { 0, NULL}
+};
+
+// Softlists do not support the cartridges with RAM yet
+static const pcb_type sw_pcbdefs[] =
+{
+ { PCB_STANDARD, "standard" },
+ { PCB_PAGED, "paged" },
+ { 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),
+ device_image_interface(mconfig, *this),
+ m_pcb(NULL)
+{
+ m_shortname = "cartridge";
+}
+
+void ti99_cartridge_device::prepare_cartridge()
+{
+ int rom2_length;
+
+ UINT8* grom_ptr;
+
+ memory_region *regg;
+ memory_region *regr;
+ memory_region *regr2;
+
+ m_pcb->m_grom_size = m_softlist? get_software_region_length("grom_socket") : m_rpk->get_resource_length("grom_socket");
+ if (VERBOSE>6) LOG("gromport: grom_socket.size=0x%04x\n", m_pcb->m_grom_size);
+
+ if (m_pcb->m_grom_size > 0)
+ {
+ regg = memregion("grom_contents");
+ grom_ptr = m_softlist? get_software_region("grom_socket") : (UINT8*)m_rpk->get_contents_of_socket("grom_socket");
+ memcpy(regg->base(), grom_ptr, m_pcb->m_grom_size);
+
+ // 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 (VERBOSE>6) LOG("gromport: rom_socket.size=0x%04x\n", m_pcb->m_rom_size);
+ regr = memregion("rom_contents");
+ m_pcb->m_rom_ptr = m_softlist? get_software_region("rom_socket") : (UINT8*)m_rpk->get_contents_of_socket("rom_socket");
+ memcpy(regr->base(), m_pcb->m_rom_ptr, m_pcb->m_rom_size);
+ }
+
+ 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
+ regr2 = memregion("rom2_contents");
+ m_pcb->m_rom2_ptr = m_softlist? get_software_region("rom2_socket") : (UINT8*)m_rpk->get_contents_of_socket("rom2_socket");
+ memcpy(regr2->base(), m_pcb->m_rom2_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 = (UINT8*)m_rpk->get_contents_of_socket("ram_socket");
+ }
+ }
+}
+
+/*
+ Find the index of the cartridge name. We assume the format
+ <name><number>, 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;
+}
+
+bool ti99_cartridge_device::call_load()
+{
+ // File name is in m_basename
+ // return true = error
+ if (VERBOSE>8) LOG("cartridge_device: loading %s in slot %s\n", m_basename.cstr(), tag());
+
+ if (m_softlist)
+ {
+ if (VERBOSE>7) LOG("using softlists\n");
+ 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 (VERBOSE>5) LOG("gromport.cartridge_device: Cartridge type is %s (%d)\n", 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)
+ {
+ LOG("gromport.cartridge_device: Failed to load cartridge '%s': %s\n", basename(), err.to_string());
+ m_rpk = NULL;
+ m_err = IMAGE_ERROR_INVALIDIMAGE;
+ return true;
+ }
+ }
+
+ switch (m_pcbtype)
+ {
+ case PCB_STANDARD:
+ if (VERBOSE>6) LOG("gromport.cartridge_device: standard PCB\n");
+ m_pcb = new ti99_standard_cartridge();
+ break;
+ case PCB_PAGED:
+ if (VERBOSE>6) LOG("gromport.cartridge_device: paged PCB\n");
+ m_pcb = new ti99_paged_cartridge();
+ break;
+ case PCB_MINIMEM:
+ if (VERBOSE>6) LOG("gromport.cartridge_device: minimem PCB\n");
+ m_pcb = new ti99_minimem_cartridge();
+ break;
+ case PCB_SUPER:
+ if (VERBOSE>6) LOG("gromport.cartridge_device: superspace PCB\n");
+ m_pcb = new ti99_super_cartridge();
+ break;
+ case PCB_MBX:
+ if (VERBOSE>6) LOG("gromport.cartridge_device: MBX PCB\n");
+ m_pcb = new ti99_mbx_cartridge();
+ break;
+ case PCB_PAGED379I:
+ if (VERBOSE>6) LOG("gromport.cartridge_device: Paged379i PCB\n");
+ m_pcb = new ti99_paged379i_cartridge();
+ break;
+ case PCB_PAGEDCRU:
+ if (VERBOSE>6) LOG("gromport.cartridge_device: PagedCRU PCB\n");
+ m_pcb = new ti99_pagedcru_cartridge();
+ break;
+ }
+
+ prepare_cartridge();
+ m_slot = get_index_from_tagname();
+ m_connector->insert(m_slot, this);
+ return false;
+}
+
+void ti99_cartridge_device::call_unload()
+{
+ if (VERBOSE>7) LOG("ti99_cartridge_device: unload\n");
+ 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(char *swlist, char *swname, rom_entry *start_entry)
+{
+ if (VERBOSE>8) LOG("ti99_cartridge_device: swlist = %s, swname = %s\n", swlist, 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);
+}
+
+void ti99_cartridge_device::crureadz(offs_t offset, UINT8 *value)
+{
+ if (m_pcb != NULL) m_pcb->crureadz(offset, value);
+}
+
+void ti99_cartridge_device::cruwrite(offs_t offset, UINT8 data)
+{
+ if (m_pcb != NULL) m_pcb->cruwrite(offset, data);
+}
+
+void ti99_cartridge_device::ready_line(int state)
+{
+ m_connector->ready_line(state);
+}
+
+void ti99_cartridge_device::device_config_complete()
+{
+ update_names();
+ m_softlist = false;
+ m_connector = static_cast<ti99_cartridge_connector_device*>(owner());
+}
+
+static GROM_CONFIG(grom3_config)
+{
+ false, 3, CARTGROM_TAG, 0x0000, 0x1800, DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ti99_cartridge_device, ready_line), GROMFREQ
+};
+static GROM_CONFIG(grom4_config)
+{
+ false, 4, CARTGROM_TAG, 0x2000, 0x1800, DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ti99_cartridge_device, ready_line), GROMFREQ
+};
+static GROM_CONFIG(grom5_config)
+{
+ false, 5, CARTGROM_TAG, 0x4000, 0x1800, DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ti99_cartridge_device, ready_line), GROMFREQ
+};
+static GROM_CONFIG(grom6_config)
+{
+ false, 6, CARTGROM_TAG, 0x6000, 0x1800, DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ti99_cartridge_device, ready_line), GROMFREQ
+};
+static GROM_CONFIG(grom7_config)
+{
+ false, 7, CARTGROM_TAG, 0x8000, 0x1800, DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ti99_cartridge_device, ready_line), 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_ADD( GROM4_TAG, grom4_config )
+ MCFG_GROM_ADD( GROM5_TAG, grom5_config )
+ MCFG_GROM_ADD( GROM6_TAG, grom6_config )
+ MCFG_GROM_ADD( GROM7_TAG, grom7_config )
+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 "paged379i" type have up to 128 KiB
+ 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(0x20000, CARTROM_TAG, ROMREGION_ERASE00)
+ ROM_REGION(0x2000, CARTROM2_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<ti99_cartridge_device>;
+
+/***************************************************************************
+ 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()
+{
+}
+
+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_AREA)
+ 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];
+ // LOG("read cartridge rom space %04x = %02x\n", offset, *value);
+ }
+ }
+}
+
+WRITE8_MEMBER(ti99_cartridge_pcb::write)
+{
+ // LOG("write standard\n");
+ if ((offset & GROM_MASK)==GROM_AREA)
+ gromwrite(space, offset, data, mem_mask);
+ else
+ {
+ if (VERBOSE>5) LOG("cartridge_pcb_device: Cannot write to ROM space at %04x\n", offset);
+ }
+}
+
+void ti99_cartridge_pcb::crureadz(offs_t offset, UINT8 *value)
+{
+}
+
+void ti99_cartridge_pcb::cruwrite(offs_t offset, UINT8 data)
+{
+}
+
+inline void ti99_cartridge_pcb::set_grom_pointer(int number, device_t *dev)
+{
+ m_grom[number] = static_cast<ti99_grom_device*>(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_AREA)
+ gromreadz(space, offset, value, mem_mask);
+ else
+ {
+ if (m_rom_page==0)
+ {
+ *value = m_rom_ptr[offset & 0x1fff];
+ }
+ else
+ {
+ *value = m_rom2_ptr[offset & 0x1fff];
+ }
+ }
+}
+
+WRITE8_MEMBER(ti99_paged_cartridge::write)
+{
+ // LOG("write standard\n");
+ if ((offset & GROM_MASK)==GROM_AREA)
+ 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_AREA)
+ gromreadz(space, offset, value, mem_mask);
+
+ else
+ {
+ if ((offset & 0x1000)==0x0000)
+ {
+ *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)
+{
+ // LOG("write standard\n");
+ if ((offset & GROM_MASK)==GROM_AREA)
+ gromwrite(space, offset, data, mem_mask);
+
+ else
+ {
+ if ((offset & 0x1000)==0x0000)
+ {
+ if (VERBOSE>1) LOG("ti99: gromport: Write access to cartridge ROM at address %04x ignored", 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_AREA)
+ 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_AREA)
+ gromwrite(space, offset, data, mem_mask);
+ else
+ {
+ m_ram_ptr[(m_ram_page << 13) | (offset & 0x1fff)] = data;
+ }
+}
+
+void ti99_super_cartridge::crureadz(offs_t offset, UINT8 *value)
+{
+ // 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 (VERBOSE>2) LOG("ti99_super_cartridge: CRU accessed at %04x\n", offset);
+ UINT8 val = 0x02 << (m_ram_page << 1);
+ *value = (val >> ((offset - 0x0800)>>1)) & 0xff;
+ }
+}
+
+void ti99_super_cartridge::cruwrite(offs_t offset, UINT8 data)
+{
+ if ((offset & 0xfff0) == 0x0800)
+ {
+ if (VERBOSE>2) LOG("ti99_super_cartridge: CRU accessed at %04x\n", 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_AREA)
+ 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_AREA)
+ 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: 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;
+}
+
+void ti99_pagedcru_cartridge::crureadz(offs_t offset, UINT8 *value)
+{
+ 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);
+ }
+}
+
+void ti99_pagedcru_cartridge::cruwrite(offs_t offset, UINT8 data)
+{
+ if ((offset & 0xf800)==0x0800)
+ {
+ int bit = (offset & 0x001e)>>1;
+ if (data != 0 && bit > 0)
+ {
+ m_rom_page = (bit-1)/2;
+ }
+ }
+}
+
+/****************************************************************************
+
+ 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:
+ <?xml version="1.0" encoding="utf-8"?>
+ <romset>
+ <resources>
+ <rom id="gromimage" file="ed-assmg.bin" />
+ </resources>
+ <configuration>
+ <pcb type="standard">
+ <socket id="grom_socket" uses="gromimage"/>
+ </pcb>
+ </configuration>
+ </romset>
+
+DTD:
+ <!ELEMENT romset (resources, configuration)>
+ <!ELEMENT resources (rom|ram)+>
+ <!ELEMENT rom EMPTY>
+ <!ELEMENT ram EMPTY>
+ <!ELEMENT configuration (pcb)>
+ <!ELEMENT pcb (socket)+>
+ <!ELEMENT socket EMPTY>
+ <!ATTLIST romset version CDATA #IMPLIED>
+ <!ATTLIST rom id ID #REQUIRED
+ <!ATTLIST rom file CDATA #REQUIRED>
+ <!ATTLIST rom crc CDATA #IMPLIED>
+ <!ATTLIST rom sha1 CDATA #IMPLIED>
+ <!ATTLIST ram id ID #REQUIRED>
+ <!ATTLIST ram type (volatile|persistent) #IMPLIED>
+ <!ATTLIST ram store (internal|external) #IMPLIED>
+ <!ATTLIST ram file CDATA #IMPLIED>
+ <!ATTLIST ram length CDATA #REQUIRED>
+ <!ATTLIST pcb type CDATA #REQUIRED>
+ <!ATTLIST socket id ID #REQUIRED>
+ <!ATTLIST socket uses IDREF #REQUIRED>
+
+****************************************************************************/
+
+#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 (VERBOSE>6) LOG("rpk: Destroy RPK\n");
+}
+
+/*
+ Deliver the contents of the socket by name of the socket.
+*/
+void* 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, void* 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, void* 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;
+ void* 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, "<rom> must have a 'file' attribute");
+
+ if (VERBOSE>6) LOG("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 = malloc(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) 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;
+ int length;
+ void* 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 = malloc(length);
+ if (contents==NULL) throw rpk_exception(RPK_OUT_OF_MEMORY);
+
+ if (VERBOSE>6) LOG("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)
+ {
+ free(contents);
+ throw rpk_exception(RPK_INVALID_RAM_SPEC, "<ram type='persistent'> must have a 'file' attribute");
+ }
+ astring ram_pathname(system_name, PATH_SEPARATOR, ram_filename);
+ ram_pname = core_strdup(ram_pathname.cstr());
+ // load, and fill rest with 00
+ if (VERBOSE>6) LOG("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;
+
+ char *layout_text = NULL;
+ xml_data_node *layout_xml;
+ 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 = (char*)malloc(header->uncompressed_length + 1);
+ if (layout_text == NULL) throw rpk_exception(RPK_OUT_OF_MEMORY);
+
+ /* uncompress the layout text */
+ ziperr = zip_file_decompress(zipfile, layout_text, header->uncompressed_length);
+ if (ziperr != ZIPERR_NONE) 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, 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 <romset>");
+
+ // 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, "<romset> must have a <resources> 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, "<romset> must have a <configuration> 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, "<configuration> must have a <pcb> 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, "<pcb> must have a 'type' attribute");
+ if (VERBOSE>6) LOG("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, "<pcb> element has only <socket> children");
+ id = xml_get_attribute_string(socket_node, "id", NULL);
+ if (id == NULL) throw rpk_exception(RPK_INVALID_LAYOUT, "<socket> 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, "<socket> 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 <rom> or <ram>");
+ }
+ found = true;
+ }
+ }
+ if (!found) throw rpk_exception(RPK_INVALID_RESOURCE_REF, uses_name);
+ }
+ }
+ catch (rpk_exception &exp)
+ {
+ newrpk->close();
+ if (zipfile != NULL) zip_file_close(zipfile);
+ if (layout_text != NULL) free(layout_text);
+
+ // rethrow the exception
+ throw exp;
+ }
+
+ if (zipfile != NULL) zip_file_close(zipfile);
+ if (layout_text != NULL) free(layout_text);
+
+ return newrpk;
+}
+
diff --git a/src/mess/machine/ti99/gromport.h b/src/mess/machine/ti99/gromport.h
new file mode 100644
index 00000000000..e36476d84ef
--- /dev/null
+++ b/src/mess/machine/ti99/gromport.h
@@ -0,0 +1,497 @@
+/***************************************************************************
+ 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;
+
+#define GROMPORT_CONFIG(name) \
+ const gromport_config(name) =
+
+typedef struct _gromport_config
+{
+ devcb_write_line ready;
+ devcb_write_line reset;
+} gromport_config;
+
+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);
+ void crureadz(offs_t offset, UINT8 *value);
+ void cruwrite(offs_t offset, UINT8 data);
+ DECLARE_WRITE_LINE_MEMBER(ready_line);
+
+ void cartridge_inserted();
+
+protected:
+ void device_start();
+ void device_reset();
+ void device_config_complete();
+ ioport_constructor device_input_ports() const;
+
+private:
+ ti99_cartridge_connector_device* m_connector;
+ bool m_reset_on_insert;
+ devcb_resolved_write_line m_console_reset;
+ devcb_resolved_write_line m_console_ready;
+};
+
+SLOT_INTERFACE_EXTERN(gromport);
+
+#define MCFG_TI99_GROMPORT_ADD( _tag, _conf ) \
+ MCFG_DEVICE_ADD(_tag, GROMPORT, 0) \
+ MCFG_DEVICE_CONFIG(_conf) \
+ MCFG_DEVICE_SLOT_INTERFACE(gromport, "single", NULL, false)
+
+/****************************************************************************/
+
+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);
+ void crureadz(offs_t offset, UINT8 *value);
+ void cruwrite(offs_t offset, UINT8 data);
+ void ready_line(int state);
+ bool is_available() { return m_pcb != NULL; }
+ bool has_grom();
+ void set_slot(int i);
+
+protected:
+ void device_start() { };
+ void device_config_complete();
+ machine_config_constructor device_mconfig_additions() const;
+ 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(char *swlist, char *swname, 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 void crureadz(offs_t offset, UINT8 *value) =0;
+ virtual void cruwrite(offs_t offset, UINT8 data) =0;
+ void ready_line(int state);
+
+ virtual void insert(int index, ti99_cartridge_device* cart) { m_gromport->cartridge_inserted(); };
+ virtual void remove(int index) { };
+
+protected:
+ ti99_cartridge_connector_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
+ 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);
+ void crureadz(offs_t offset, UINT8 *value);
+ void cruwrite(offs_t offset, UINT8 data);
+
+protected:
+ void device_start() { };
+ void device_reset();
+ machine_config_constructor device_mconfig_additions() const;
+ void device_config_complete();
+
+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);
+ void crureadz(offs_t offset, UINT8 *value);
+ void cruwrite(offs_t offset, UINT8 data);
+
+ void insert(int index, ti99_cartridge_device* cart);
+ void remove(int index);
+
+protected:
+ void device_start();
+ void device_reset();
+ machine_config_constructor device_mconfig_additions() const;
+ ioport_constructor device_input_ports() const;
+
+private:
+ int m_active_slot;
+ int m_fixed_slot;
+ int m_next_free_slot;
+ int m_numcart;
+ 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);
+ void crureadz(offs_t offset, UINT8 *value);
+ void cruwrite(offs_t offset, UINT8 data);
+
+ void insert(int index, ti99_cartridge_device* cart);
+ void remove(int index);
+ DECLARE_INPUT_CHANGED_MEMBER( gk_changed );
+
+protected:
+ void device_start();
+ void device_reset();
+
+ machine_config_constructor device_mconfig_additions() const;
+ const rom_entry* device_rom_region() const;
+ 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 void crureadz(offs_t offset, UINT8 *value);
+ virtual void cruwrite(offs_t offset, UINT8 data);
+
+ DECLARE_READ8Z_MEMBER(gromreadz);
+ DECLARE_WRITE8_MEMBER(gromwrite);
+ inline void set_grom_pointer(int number, device_t *dev);
+
+ ti99_grom_device* m_grom[5];
+ int m_grom_size;
+ int m_rom_size;
+ int m_ram_size;
+
+ UINT8* m_rom_ptr;
+ UINT8* m_rom2_ptr;
+ UINT8* m_ram_ptr;
+
+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);
+
+private:
+ int m_rom_page;
+};
+
+/********************** 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);
+ void crureadz(offs_t offset, UINT8 *value);
+ void cruwrite(offs_t offset, UINT8 data);
+
+private:
+ int m_ram_page;
+};
+
+/************************* MBX ***************************************/
+
+class ti99_mbx_cartridge : public ti99_cartridge_pcb
+{
+public:
+ ~ti99_mbx_cartridge() { };
+ DECLARE_READ8Z_MEMBER(readz);
+ DECLARE_WRITE8_MEMBER(write);
+private:
+ int m_rom_page;
+};
+
+/********************** 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);
+ int m_rom_page;
+};
+
+/********************** Paged CRU ************************************/
+
+class ti99_pagedcru_cartridge : public ti99_cartridge_pcb
+{
+public:
+ ~ti99_pagedcru_cartridge() { };
+ DECLARE_READ8Z_MEMBER(readz);
+ DECLARE_WRITE8_MEMBER(write);
+ void crureadz(offs_t offset, UINT8 *value);
+ void cruwrite(offs_t offset, UINT8 data);
+private:
+ int m_rom_page;
+};
+
+
+typedef struct _pcb_type
+{
+ int id;
+ const char* name;
+} pcb_type;
+
+/*************************************************************************
+ RPK support
+*************************************************************************/
+class rpk;
+
+class rpk_socket
+{
+ friend class simple_list<rpk_socket>;
+ friend class rpk;
+
+public:
+ rpk_socket(const char *id, int length, void *contents);
+ rpk_socket(const char *id, int length, void *contents, const char *pathname);
+
+ const char* id() { return m_id; }
+ int get_content_length() { return m_length; }
+ void* 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) free(m_contents); }
+
+private:
+ const char *m_id;
+ UINT32 m_length;
+ rpk_socket *m_next;
+ void *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; }
+ void* 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<rpk_socket> 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_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
+};
+typedef enum _rpk_open_error rpk_open_error;
+
+static const char error_text[15][30] =
+{
+ "No error",
+ "Not a RPK (zip) file",
+ "Module definition corrupt",
+ "Out of memory",
+ "XML format error",
+ "Invalid file reference",
+ "Zip file error",
+ "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];
+ astring errormsg(error_text[(int)m_err], ": ", m_detail);
+ return core_strdup(errormsg.cstr());
+ }
+
+private:
+ rpk_open_error m_err;
+ const char* m_detail;
+};
+
+#endif
diff --git a/src/mess/machine/ti99/handset.c b/src/mess/machine/ti99/handset.c
new file mode 100644
index 00000000000..edf4b523875
--- /dev/null
+++ b/src/mess/machine/ti99/handset.c
@@ -0,0 +1,536 @@
+/****************************************************************************
+
+ 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)
+{
+ m_shortname = "handset";
+}
+
+#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)
+{
+ if (id==DELAY_TIMER)
+ {
+ 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();
+ }
+ else
+ {
+ // Poll timer
+ 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::device_start(void)
+{
+ m_delay_timer = timer_alloc(DELAY_TIMER);
+ m_poll_timer = timer_alloc(POLL_TIMER);
+ m_poll_timer->adjust(attotime::from_hz(m_joyport->clock()), 0, attotime::from_hz(m_joyport->clock()));
+}
+
+void ti99_handset_device::device_reset(void)
+{
+ if (VERBOSE>5) LOG("ti99_handset_device: Reset\n");
+ m_delay_timer->enable(true);
+ m_poll_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<ti99_handset_device>;
+
+/******************************************************************************
+ 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)
+{
+ m_shortname = "twinjoy";
+}
+
+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<ti99_twin_joystick>;
+
diff --git a/src/mess/machine/ti99/handset.h b/src/mess/machine/ti99/handset.h
new file mode 100644
index 00000000000..228ed3ac6fa
--- /dev/null
+++ b/src/mess/machine/ti99/handset.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+
+ 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);
+
+protected:
+ void device_start(void);
+ void device_reset(void);
+ ioport_constructor device_input_ports() const;
+
+ 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;
+ emu_timer *m_poll_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 );
+ void device_start(void);
+
+ UINT8 read_dev();
+ void write_dev(UINT8 data);
+
+protected:
+ 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/mess/machine/ti99/hfdc.c b/src/mess/machine/ti99/hfdc.c
new file mode 100644
index 00000000000..1ce03b6261a
--- /dev/null
+++ b/src/mess/machine/ti99/hfdc.c
@@ -0,0 +1,586 @@
+/****************************************************************************
+
+ Myarc Hard and Floppy Disk Controller
+ based on SMC9234
+ High Density, Double-sided
+
+ FIXME: HFDC does not work at CRU addresses other than 1100
+ (test shows
+ hfdc: reado 41f5 (00): 00
+ hfdc: reado 41f4 (00): 00 -> wrong rom page? (should be (02)))
+
+ Michael Zapf
+
+ February 2012: Rewritten as class
+
+*****************************************************************************/
+
+#include "hfdc.h"
+#include "imagedev/flopdrv.h"
+#include "machine/mm58274c.h"
+#include "formats/ti99_dsk.h" // Format
+
+#define BUFFER "ram"
+#define FDC_TAG "hdc9234"
+#define CLOCK_TAG "mm58274c"
+
+#define MOTOR_TIMER 1
+
+#define HFDC_MAX_FLOPPY 4
+#define HFDC_MAX_HARD 4
+
+#define TAPE_ADDR 0x0fc0
+#define HDC_R_ADDR 0x0fd0
+#define HDC_W_ADDR 0x0fd2
+#define CLK_ADDR 0x0fe0
+#define RAM_ADDR 0x1000
+
+#define VERBOSE 1
+#define LOG logerror
+
+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)
+{
+ m_shortname = "ti99_hfdc";
+}
+
+/*
+ read a byte in disk DSR space
+ HFDC manual, p. 44
+ Memory map as seen by the 99/4A PEB
+
+ 0x4000 - 0x4fbf one of four possible ROM pages
+ 0x4fc0 - 0x4fcf tape select
+ 0x4fd0 - 0x4fdf disk controller select
+ 0x4fe0 - 0x4fff time chip select
+
+ 0x5000 - 0x53ff static RAM page 0x10
+ 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
+*/
+READ8Z_MEMBER(myarc_hfdc_device::readz)
+{
+ if (m_selected && ((offset & m_select_mask)==m_select_value))
+ {
+ /* DSR region */
+ if ((offset & 0x1000)==0x0000)
+ {
+ if ((offset & 0x0fc0)==0x0fc0)
+ {
+ // Tape: 4fc0...4fcf
+ if ((offset & 0x1ff0)==TAPE_ADDR)
+ {
+ if (VERBOSE>0) LOG("ti99: HFDC: Tape support not available (access to address %04x)\n", offset&0xffff);
+ return;
+ }
+
+ // HDC9234: 4fd0..4fdf / read: 4fd0,4 (mirror 8,c)
+ // read: 0100 1111 1101 xx00
+ if ((offset & 0x1ff3)==HDC_R_ADDR)
+ {
+ *value = m_hdc9234->read(space, (offset>>2)&1, mem_mask);
+ if (VERBOSE>7) LOG("hfdc: read %04x: %02x\n", offset & 0xffff, *value);
+ return;
+ }
+
+ if ((offset & 0x1fe1)==CLK_ADDR)
+ {
+ *value = mm58274c_r(m_clock, (offset & 0x001e) >> 1);
+ if (VERBOSE>7) LOG("hfdc: read from clock address %04x: %02x\n", offset & 0xffff, *value);
+ return;
+ }
+ }
+ else
+ {
+ // ROM
+ *value = m_dsrrom[(m_rom_page << 12) | (offset & 0x0fff)];
+ if (VERBOSE>7) LOG("hfdc: reado %04x (%02x): %02x\n", offset & 0xffff, m_rom_page, *value);
+ return;
+ }
+ }
+
+ // RAM: 0101 xxxx xxxx xxxx
+ if ((offset & 0x1000)==RAM_ADDR)
+ {
+ // 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 = (offset & 0x0c00) >> 10;
+ *value = m_buffer_ram[(m_ram_page[bank]<<10) | (offset & 0x03ff)];
+ if (VERBOSE>7) LOG("hfdc: read %04x (%02x): %02x\n", offset & 0xffff, m_ram_page[bank], *value);
+ }
+ }
+}
+
+/*
+ Write a byte to the controller.
+*/
+WRITE8_MEMBER( myarc_hfdc_device::write )
+{
+ if (m_selected && ((offset & m_select_mask)==m_select_value))
+ {
+ // Tape: 4fc0...4fcf
+ if ((offset & 0x1ff0)==TAPE_ADDR)
+ {
+ if (VERBOSE>0) LOG("ti99: HFDC: Tape support not available (access to address %04x)\n", offset & 0xffff);
+ return;
+ }
+
+ // HDC9234: 4fd0..4fdf / write: 4fd2,6 (mirror a,e)
+ // write: 0100 1111 1101 xx10
+ if ((offset & 0x1ff3)==HDC_W_ADDR)
+ {
+ if (VERBOSE>7) LOG("hfdc: write to controller address %04x: %02x\n", offset & 0xffff, data);
+ m_hdc9234->write(space, (offset>>2)&1, data, mem_mask);
+ return;
+ }
+
+ if ((offset & 0x1fe1)==CLK_ADDR)
+ {
+ if (VERBOSE>7) LOG("hfdc: write to clock address %04x: %02x\n", offset & 0xffff, data);
+ mm58274c_w(m_clock, (offset & 0x001e) >> 1, data);
+ return;
+ }
+
+ // RAM: 0101 xxxx xxxx xxxx
+ if ((offset & 0x1000)==RAM_ADDR)
+ {
+ // 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 = (offset & 0x0c00) >> 10;
+ if (VERBOSE>7) LOG("hfdc: WRITE %04x (%02x): %02x\n", (offset & 0xffff), m_ram_page[bank], data);
+ m_buffer_ram[(m_ram_page[bank]<<10) | (offset & 0x03ff)] = data;
+ }
+ }
+}
+
+void myarc_hfdc_device::crureadz(offs_t offset, UINT8 *value)
+{
+ UINT8 reply;
+ if ((offset & 0xff00)==m_cru_base)
+ {
+ if ((offset & 0x00ff)==0) /* CRU bits 0-7 */
+ {
+ /* CRU bits */
+ if (m_cru_select)
+ {
+ // DIP switches. Logic levels are inverted (on->0, off->1). CRU
+ // bit order is the reverse of DIP-switch order, too (dip 1 -> bit 7,
+ // dip 8 -> bit 0).
+ // MZ: 00 should not be used since there is a bug in the
+ // DSR of the HFDC which causes problems with SD disks
+ // (controller tries DD and then fails to fall back to SD) */
+ reply = ~(ioport("HFDCDIP")->read());
+ }
+ else
+ {
+ reply = 0;
+
+ if (m_irq) reply |= 0x01;
+ if (m_dip) reply |= 0x02;
+ if (m_motor_running) reply |= 0x04;
+ }
+ *value = reply;
+ }
+ else /* CRU bits 8+ */
+ *value = 0;
+ if (VERBOSE>7) LOG("hfdc: reading from CRU %04x: %02x\n", offset, *value);
+ }
+}
+
+/*
+ Write disk CRU interface
+ HFDC manual p. 43
+
+ CRU rel. address Definition Active
+ 00 Device Service Routine Select HIGH
+ 02 Reset to controller chip LOW
+ 04 Floppy Motor on / CD0 HIGH
+ 06 ROM page select 0 / CD1
+ 08 ROM page select 1 / CRU input select
+ 12/4/6/8/A RAM page select at 0x5400
+ 1C/E/0/2/4 RAM page select at 0x5800
+ 26/8/A/C/E RAM page select at 0x5C00
+
+ RAM bank select: bank 0..31; 12 = LSB (accordingly for other two areas)
+ ROM bank select: bank 0..3; 06 = MSB, 07 = LSB
+ Bit number = (CRU_rel_address - base_address)/2
+ CD0 and CD1 are Clock Divider selections for the Floppy Data Separator (FDC9216)
+*/
+void myarc_hfdc_device::cruwrite(offs_t offset, UINT8 data)
+{
+ if ((offset & 0xff00)==m_cru_base)
+ {
+ if (VERBOSE>7) LOG("hfdc: writing to CRU %04x: %02x\n", offset, data);
+ int bit = (offset >> 1) & 0x1f;
+
+ if (bit >= 9 && bit < 24)
+ {
+ 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));
+
+ return;
+ }
+
+ switch (bit)
+ {
+ case 0:
+ m_selected = (data!=0);
+ if (VERBOSE>7) LOG("hfdc: selected = %d\n", m_selected);
+ break;
+
+ case 1:
+ if (data==0) m_hdc9234->reset(); // active low
+ break;
+
+ case 2:
+ m_CD0 = data;
+ if (data != 0) m_motor_running = true;
+ else
+ {
+ if (m_motor_running)
+ {
+ m_motor_on_timer->adjust(attotime::from_msec(4230));
+ }
+ }
+ break;
+
+ case 3:
+ m_CD1 = data;
+ if (data!=0) m_rom_page |= 2;
+ else m_rom_page &= 0xfd;
+ break;
+
+ case 4:
+ m_cru_select = (data!=0);
+ if (data!=0) m_rom_page |= 1;
+ else m_rom_page &= 0xfe;
+ break;
+
+ default:
+ if (VERBOSE>1) LOG("ti99: HFDC: Attempt to set undefined CRU bit %d\n", bit);
+ }
+ }
+}
+
+
+int myarc_hfdc_device::slog2(int value)
+{
+ int i=-1;
+ while (value!=0)
+ {
+ value >>= 1;
+ i++;
+ }
+ return i;
+}
+
+READ8_MEMBER( myarc_hfdc_device::auxbus_in )
+{
+ UINT8 reply = 0;
+ int index = 0;
+
+ if ((m_output1_latch & 0xf0)==0)
+ {
+ if (VERBOSE>4) LOG("hfdc: no drive selected, returning 0\n");
+ // No HD and no floppy
+ return 0; /* is that the correct default value? */
+ }
+
+ // If a floppy is selected, we have one line set among the four programmable outputs.
+ // Floppy selected <=> latch & 0x10 != 0; floppy number in last four bits
+ if ((m_output1_latch & 0x10)!=0)
+ {
+ index = slog2(m_output1_latch & 0x0f);
+ if (index==-1) return 0;
+
+ /* Get floppy status. */
+ if (floppy_drive_get_flag_state(m_floppy_unit[index], FLOPPY_DRIVE_INDEX) == FLOPPY_DRIVE_INDEX)
+ reply |= DS_INDEX;
+ if (floppy_tk00_r(m_floppy_unit[index]) == CLEAR_LINE)
+ reply |= DS_TRK00;
+ if (floppy_wpt_r(m_floppy_unit[index]) == CLEAR_LINE)
+ reply |= DS_WRPROT;
+
+ /* if (image_exists(disk_img)) */
+
+ reply |= DS_READY; /* Floppies don't have a READY line; line is pulled up */
+ reply |= DS_SKCOM; /* Same here. */
+ if (VERBOSE>4) LOG("hfdc: floppy selected, returning status %02x\n", reply);
+ }
+ else // one of the first three lines must be selected
+ {
+ UINT8 state;
+ index = slog2((m_output1_latch>>4) & 0x0f)-1;
+ mfm_harddisk_device *hd = static_cast<mfm_harddisk_device *>(m_harddisk_unit[index]);
+ state = hd->get_status();
+
+ if (state & MFMHD_TRACK00) reply |= DS_TRK00;
+ if (state & MFMHD_SEEKCOMP) reply |= DS_SKCOM;
+ if (state & MFMHD_WRFAULT) reply |= DS_WRFAULT;
+ if (state & MFMHD_INDEX) reply |= DS_INDEX;
+ if (state & MFMHD_READY) reply |= DS_READY;
+ if (VERBOSE>4) LOG("hfdc: hd selected, returning status %02x\n", reply);
+ }
+
+ return reply;
+}
+
+WRITE8_MEMBER( myarc_hfdc_device::auxbus_out )
+{
+ int index;
+ device_t* selected_drive = NULL;
+
+ switch (offset)
+ {
+ case INPUT_STATUS:
+ if (VERBOSE>1) LOG("ti99: HFDC: Invalid operation: S0=S1=0, but tried to write (expected: read drive status)\n");
+ break;
+
+ case OUTPUT_DMA_ADDR:
+ /* Value is dma address byte. Shift previous contents to the left. */
+ m_dma_address = ((m_dma_address << 8) + (data&0xff))&0xffffff;
+ break;
+
+ case OUTPUT_OUTPUT1:
+ // 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
+ if (data & 0x10)
+ {
+ // Floppy selected
+ index = slog2(data & 0x0f);
+ if (index>=0) selected_drive = m_floppy_unit[index];
+ }
+ else
+ {
+ // HD selected
+ index = slog2((data>>4) & 0x0f);
+ if (index>=0) selected_drive = m_harddisk_unit[index-1];
+ }
+
+ m_hdc9234->connect_drive(selected_drive);
+ m_output1_latch = data;
+ break;
+
+ case OUTPUT_OUTPUT2:
+ /* value is output2 */
+ m_output2_latch = data;
+ break;
+ }
+}
+
+/*
+ Read a byte from buffer in DMA mode
+*/
+READ8_MEMBER( myarc_hfdc_device::read_buffer )
+{
+ UINT8 value = m_buffer_ram[m_dma_address & 0x7fff];
+ m_dma_address++;
+ return value;
+}
+
+/*
+ Write a byte to buffer in DMA mode
+*/
+WRITE8_MEMBER( myarc_hfdc_device::write_buffer )
+{
+ m_buffer_ram[m_dma_address & 0x7fff] = data;
+ m_dma_address++;
+}
+
+/*
+ Called whenever the state of the sms9234 interrupt pin changes.
+*/
+WRITE_LINE_MEMBER( myarc_hfdc_device::intrq_w )
+{
+ m_irq = state;
+
+ // Set INTA*
+ // Signal from SMC is active high, INTA* is active low; board inverts signal
+ // Anyway, we keep with ASSERT_LINE and CLEAR_LINE
+ m_slot->set_inta(state);
+}
+
+
+/*
+ Called whenever the state of the sms9234 DMA in progress changes.
+*/
+WRITE_LINE_MEMBER( myarc_hfdc_device::dip_w )
+{
+ m_dip = state;
+}
+
+/*
+ Callback called at the end of DVENA pulse
+*/
+void myarc_hfdc_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ m_motor_running = false;
+ if (VERBOSE>6) LOG("hfdc: motor off\n");
+}
+
+const smc92x4_interface ti99_smc92x4_interface =
+{
+ FALSE, /* do not use the full track layout */
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, myarc_hfdc_device, intrq_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, myarc_hfdc_device, dip_w),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, myarc_hfdc_device, auxbus_out),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, myarc_hfdc_device, auxbus_in),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, myarc_hfdc_device, read_buffer),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, myarc_hfdc_device, write_buffer)
+};
+
+static const mm58274c_interface floppy_mm58274c_interface =
+{
+ 1, /* mode 24*/
+ 0 /* first day of week */
+};
+
+MACHINE_CONFIG_FRAGMENT( ti99_hfdc )
+ MCFG_SMC92X4_ADD(FDC_TAG, ti99_smc92x4_interface )
+ MCFG_MM58274C_ADD(CLOCK_TAG, floppy_mm58274c_interface)
+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
+
+INPUT_PORTS_START( ti99_hfdc )
+ 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( 0xff, 0x55, "HFDC drive config" )
+ PORT_DIPSETTING( 0x00, "40 track, 16 ms")
+ PORT_DIPSETTING( 0xaa, "40 track, 8 ms")
+ PORT_DIPSETTING( 0x55, "80 track, 2 ms")
+ PORT_DIPSETTING( 0xff, "80 track HD, 2 ms")
+
+ PORT_START( "DRVSPD" )
+ PORT_CONFNAME( 0x01, 0x01, "Floppy and HD speed" )
+ PORT_CONFSETTING( 0x00, "No delay")
+ PORT_CONFSETTING( 0x01, "Realistic")
+INPUT_PORTS_END
+
+void myarc_hfdc_device::device_start()
+{
+ if (VERBOSE>5) LOG("hfdc: start\n");
+ m_hdc9234 = static_cast<smc92x4_device *>(subdevice(FDC_TAG));
+ m_clock = subdevice(CLOCK_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
+}
+
+void myarc_hfdc_device::device_reset()
+{
+ if (VERBOSE>5) LOG("hfdc: reset\n");
+ 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();
+
+ // 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_dma_address = 0;
+ m_output1_latch = m_output2_latch = 0;
+ m_dip = m_irq = false;
+ m_cru_select = false;
+ m_CD0 = m_CD1 = 0;
+ m_motor_running = false;
+ m_selected = false;
+
+ // Find the floppies and hard disks
+ m_floppy_unit[0] = m_slot->get_drive(FLOPPY_0);
+ m_floppy_unit[1] = m_slot->get_drive(FLOPPY_1);
+ m_floppy_unit[2] = m_slot->get_drive(FLOPPY_2);
+ m_floppy_unit[3] = m_slot->get_drive(FLOPPY_3);
+
+ m_harddisk_unit[0] = m_slot->get_drive(MFMHD_0);
+ m_harddisk_unit[1] = m_slot->get_drive(MFMHD_1);
+ m_harddisk_unit[2] = m_slot->get_drive(MFMHD_2);
+
+ if (ioport("HFDCDIP")->read()&0x55)
+ ti99_set_80_track_drives(TRUE);
+ else
+ ti99_set_80_track_drives(FALSE);
+
+ m_hdc9234->set_timing(ioport("DRVSPD")->read()!=0);
+
+ floppy_type_t floptype = FLOPPY_STANDARD_5_25_DSHD;
+ // Again, need to re-adjust the floppy geometries
+ for (int i=0; i < HFDC_MAX_FLOPPY; i++)
+ {
+ if (m_floppy_unit[i] != NULL)
+ {
+ // floppy_drive_set_controller(card->floppy_unit[i], device);
+ // floppy_drive_set_index_pulse_callback(floppy_unit[i], smc92x4_index_pulse_callback);
+ floppy_drive_set_geometry(m_floppy_unit[i], floptype);
+ }
+ }
+
+ if (VERBOSE>2) LOG("hfdc: CRU base = %04x\n", m_cru_base);
+ // TODO: Check how to make use of floppy_mon_w(w->drive, CLEAR_LINE);
+}
+
+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<myarc_hfdc_device>;
diff --git a/src/mess/machine/ti99/hfdc.h b/src/mess/machine/ti99/hfdc.h
new file mode 100644
index 00000000000..9a06b9a9a65
--- /dev/null
+++ b/src/mess/machine/ti99/hfdc.h
@@ -0,0 +1,116 @@
+/****************************************************************************
+
+ Myarc Hard and Floppy Disk Controller
+ See hfdc.c for documentation
+
+ Michael Zapf, September 2010
+
+ January 2012: rewritten as class
+
+****************************************************************************/
+
+#ifndef __HFDC__
+#define __HFDC__
+
+#include "emu.h"
+#include "peribox.h"
+#include "ti99defs.h"
+#include "ti99_hd.h"
+#include "machine/smc92x4.h"
+
+#define HFDC_MAX_FLOPPY 4
+#define HFDC_MAX_HARD 4
+
+extern const device_type TI99_HFDC;
+
+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);
+ void crureadz(offs_t offset, UINT8 *value);
+ void cruwrite(offs_t offset, UINT8 value);
+
+ DECLARE_WRITE_LINE_MEMBER( intrq_w );
+ DECLARE_WRITE_LINE_MEMBER( drq_w );
+ DECLARE_WRITE_LINE_MEMBER( dip_w );
+ DECLARE_READ8_MEMBER( auxbus_in );
+ DECLARE_WRITE8_MEMBER( auxbus_out );
+ DECLARE_READ8_MEMBER( read_buffer );
+ DECLARE_WRITE8_MEMBER( write_buffer );
+
+protected:
+ void device_start(void);
+ void device_reset(void);
+ const rom_entry *device_rom_region() const;
+ machine_config_constructor device_mconfig_additions() const;
+ ioport_constructor device_input_ports() const;
+ void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+
+private:
+ // Calculates a simple version of a binary logarithm
+ int slog2(int value);
+
+ // When true, triggers motor monoflop.
+ bool m_trigger_motor;
+
+ // When true, motor monoflop is high
+ bool m_motor_running;
+
+ /* Clock divider bit 0. Unused in this emulation. */
+ int m_CD0;
+
+ /* Clock divider bit 1. Unused in this emulation. */
+ int m_CD1;
+
+ /* count 4.23s from rising edge of motor_on */
+ emu_timer* m_motor_on_timer;
+
+ // Link to the HDC9234 controller on the board. In fact, the proper name
+ // is HDC 9234, the manufacturer is Standard Microsystems Corp.
+ smc92x4_device* m_hdc9234;
+
+ /* Link to the clock chip on the board. */
+ device_t* m_clock;
+
+ /* Determines whether we have access to the CRU bits. */
+ bool m_cru_select;
+
+ /* IRQ state */
+ bool m_irq;
+
+ /* DMA in Progress state */
+ bool m_dip;
+
+ /* Output 1 latch */
+ UINT8 m_output1_latch;
+
+ /* Output 2 latch */
+ UINT8 m_output2_latch;
+
+ /* Connected floppy drives. */
+ device_t* m_floppy_unit[HFDC_MAX_FLOPPY];
+
+ /* Connected harddisk drives. */
+ device_t* m_harddisk_unit[HFDC_MAX_HARD];
+
+ /* DMA address latch */
+ UINT32 m_dma_address;
+
+ // Device Service Routine ROM
+ UINT8* m_dsrrom;
+
+ // ROM banks.
+ int m_rom_page;
+
+ // HFDC RAM
+ UINT8* m_buffer_ram;
+
+ // RAM page registers
+ int m_ram_page[4];
+};
+
+
+#endif
diff --git a/src/mess/machine/ti99/horizon.c b/src/mess/machine/ti99/horizon.c
new file mode 100644
index 00000000000..cfde420a788
--- /dev/null
+++ b/src/mess/machine/ti99/horizon.c
@@ -0,0 +1,448 @@
+/****************************************************************************
+
+ 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) ,device_nvram_interface(mconfig, *this)
+{
+ m_shortname = "ti99_horizon";
+}
+
+//-------------------------------------------------
+// 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);
+ }
+ }
+}
+
+void horizon_ramdisk_device::crureadz(offs_t offset, UINT8 *value)
+{
+ // 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;
+ }
+}
+
+void horizon_ramdisk_device::cruwrite(offs_t offset, UINT8 data)
+{
+ 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;
+}
+
+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<horizon_ramdisk_device>;
+
diff --git a/src/mess/machine/ti99/horizon.h b/src/mess/machine/ti99/horizon.h
new file mode 100644
index 00000000000..a99e60b221f
--- /dev/null
+++ b/src/mess/machine/ti99/horizon.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+
+ Horizon Ramdisk
+ See horizon.c for documentation
+
+ Michael Zapf
+
+ February 2012
+
+*****************************************************************************/
+
+#ifndef __HORIZON__
+#define __HORIZON__
+
+#include "emu.h"
+#include "peribox.h"
+#include "ti99defs.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);
+
+ void crureadz(offs_t offset, UINT8 *value);
+ void cruwrite(offs_t offset, UINT8 value);
+
+ DECLARE_INPUT_CHANGED_MEMBER( ks_changed );
+
+protected:
+ void device_start();
+ void device_reset();
+
+ const rom_entry *device_rom_region() const;
+ 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/mess/machine/ti99/hsgpl.c b/src/mess/machine/ti99/hsgpl.c
new file mode 100644
index 00000000000..eba0f19a4c9
--- /dev/null
+++ b/src/mess/machine/ti99/hsgpl.c
@@ -0,0 +1,628 @@
+/****************************************************************************
+
+ 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
+
+ Note: 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.
+
+ FIXME: Re-flashing the at29040 chips is only possible when the DSR Flashrom
+ U9 is deleted before. The file must be removed from the nvram directory.
+ May also be a bug of the loader program DSRLDR3.
+ (Detail: The DSRLDR program fails to flash part 3/8 of the flash rom.)
+
+ Raphael Nabet, 2003.
+
+ Michael Zapf
+ October 2010: Rewritten as device
+ February 2012: Rewritten as class
+
+*****************************************************************************/
+
+#include "hsgpl.h"
+
+#define CRU_BASE 0x1B00
+
+#define VERBOSE 1
+#define LOG logerror
+
+#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)
+{
+ m_shortname = "ti99_hsgpl";
+}
+
+/*
+ Read hsgpl CRU interface. None here.
+*/
+void snug_high_speed_gpl_device::crureadz(offs_t offset, UINT8 *value)
+{
+ return;
+}
+
+/*
+ Write hsgpl CRU interface
+*/
+void snug_high_speed_gpl_device::cruwrite(offs_t offset, UINT8 data)
+{
+ if ((offset & 0xff00)==CRU_BASE)
+ {
+ int bit = (offset >> 1) & 0x0f;
+ switch (bit)
+ {
+ case 0:
+ m_dsr_enabled = (data != 0);
+ if (VERBOSE>5) LOG("hsgpl: Set dsr_enabled=%x\n", data);
+ break;
+ case 1:
+ m_gram_enabled = (data != 0);
+ if (VERBOSE>5) LOG("hsgpl: Set gram_enabled=%x\n", data);
+ break;
+ case 2:
+ m_bank_enabled = (data != 0);
+ if (VERBOSE>5) LOG("hsgpl: Set bank_enabled=%x\n", 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 (VERBOSE>5) LOG("hsgpl: Set dsr_page=%d\n", m_dsr_page);
+ break;
+ case 9:
+ m_card_enabled = data;
+ if (VERBOSE>5) LOG("hsgpl: Set card_enabled=%x\n", data);
+ break;
+ case 10:
+ m_write_enabled = data;
+ if (VERBOSE>5) LOG("hsgpl: Set write_enabled=%x\n", data);
+ break;
+ case 11:
+ m_supercart_enabled = data;
+ if (VERBOSE>5) LOG("hsgpl: Set supercart_enabled=%x\n", data);
+ break;
+ case 12:
+ m_led_on = data;
+ if (VERBOSE>5) LOG("hsgpl: Set led_on=%x\n", data);
+ break;
+ case 13:
+ break;
+ case 14:
+ m_mbx_enabled = data;
+ if (VERBOSE>5) LOG("hsgpl: Set mbx_enabled=%x\n", data);
+ break;
+ case 15:
+ m_ram_enabled = data;
+ if (VERBOSE>5) LOG("hsgpl: Set ram_enabled=%x\n", 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 (VERBOSE>7) LOG("hsgpl: read dsr %04x[%02x] -> %02x\n", 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 (VERBOSE>6) LOG("hsgpl cart read ignored (enable=%02x)\n", m_card_enabled);
+ return;
+ }
+
+ if ((m_current_grom_port < 2) && (m_ram_enabled))
+ {
+ *value = m_ram6_memory[(offset & 0x1fff) | (m_current_bank<<13) | (m_current_grom_port<<15)];
+ if (VERBOSE>7) LOG("hsgpl cart ram read %04x -> %02x\n", offset, *value);
+ return;
+ }
+
+ if (m_current_grom_port < 16)
+ {
+ *value = m_rom6_eeprom->read(space, (offset & 0x1fff) | (m_current_bank<<13) | (m_current_grom_port<<15), mem_mask);
+ if (VERBOSE>7) LOG("hsgpl cart read %04x -> %02x\n", offset, *value);
+ }
+ else
+ {
+ if (m_current_grom_port==32 || m_current_grom_port==33)
+ {
+ *value = m_ram6_memory[(offset & 0x1fff) | (m_current_bank<<13) | ((m_current_grom_port-32)<<15)];
+ }
+ else
+ {
+ if (VERBOSE>1) LOG("unknown 0x6000 port\n");
+ }
+ }
+}
+
+/*
+ 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)
+{
+ int port;
+ //activedevice_adjust_icount(-4);
+
+ // 1001 10bb bbbb bba0
+ port = m_current_grom_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 */
+ // 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)];
+ }
+ else
+ {
+ if (port < 8)
+ {
+ if (!m_flash_mode)
+ {
+ *value = m_grom_a_eeprom->read(space, m_grom_address | (port<<16), mem_mask);
+ }
+ }
+ else
+ {
+ if (port < 16)
+ {
+ *value = m_grom_b_eeprom->read(space, m_grom_address | ((port-8)<<16), mem_mask);
+ }
+ 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);
+ }
+ 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);
+ }
+ else
+ {
+ // 9880, 9884
+ if (port==32 || port==33)
+ {
+ *value = m_gram_memory[m_grom_address | ((port-32)<<16)];
+ }
+ else
+ {
+ if (port==48 || port==49)
+ {
+// *value = m_ram6_memory[m_grom_address];
+ *value = m_ram6_memory[m_grom_address | ((port-48)<<16)];
+ }
+ else
+ {
+ if (VERBOSE>2) LOG("hsgpl: Attempt to read from undefined port 0x%0x; ignored.\n", 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 (VERBOSE>2) LOG("hsgpl cart write ignored: card_enabled=%02x\n", m_card_enabled);
+ return;
+ }
+
+ if (VERBOSE>7) LOG("hsgpl cart write %04x -> %02x\n", offset, data);
+
+ if (m_bank_enabled)
+ {
+ m_current_bank = (offset>>1) & 3;
+ if (VERBOSE>7) LOG("hsgpl cart select bank %02x\n", m_current_bank);
+ return; /* right??? */
+ }
+
+ if ((m_mbx_enabled) && (offset==0x6ffe))
+ { /* MBX: mapper at 0x6ffe */
+ m_current_bank = data & 0x03;
+ 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_current_grom_port < 2) && (m_ram_enabled))
+ {
+ m_ram6_memory[(offset & 0x1fff) | (m_current_bank<<13) | (m_current_grom_port<<15) ] = data;
+ }
+ else
+ { // keep in mind that these lines are also reached for port < 2
+ // and !ram_enabled
+ if (m_current_grom_port < 16)
+ {
+ // feeprom is normally written to using GPL ports, and I don't know
+ // 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_current_grom_port==32 || m_current_grom_port==33)
+ {
+ m_ram6_memory[(offset & 0x1fff) | (m_current_bank<<13) | ((m_current_grom_port-32)<<15)] = data;
+ }
+ else
+ {
+ if (VERBOSE>1) LOG("unknown 0x6000 port\n");
+ }
+ }
+ }
+ }
+}
+
+/*
+ Specific write access: grom_write
+*/
+void snug_high_speed_gpl_device::grom_write(address_space& space, offs_t offset, UINT8 data, UINT8 mem_mask)
+{
+ int port;
+
+ //activedevice_adjust_icount(-4);
+
+ // 1001 11bb bbbb bba0
+ port = m_current_grom_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
+ {
+ // 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;
+ }
+ else
+ {
+ if (port < 8)
+ {
+ m_grom_a_eeprom->write(space, m_grom_address | (port<<16), data, mem_mask);
+ }
+ else
+ {
+ if (port < 16)
+ {
+ m_grom_b_eeprom->write(space, m_grom_address | ((port-8)<<16), data, mem_mask);
+ }
+ else
+ {
+ if (port < 24)
+ {
+ m_dsr_eeprom->write(space, m_grom_address | ((port-16)<<16), data, mem_mask);
+ }
+ else
+ {
+ if (port < 32)
+ {
+ m_rom6_eeprom->write(space, m_grom_address | ((port-24)<<16), data, mem_mask);
+ }
+ else
+ {
+ if (port==32 || port==33)
+ {
+ m_gram_memory[m_grom_address | ((port-32)<<16)] = data;
+ }
+ else
+ {
+ if (port==48 || port==49)
+ {
+// m_ram6_memory[m_grom_address] = data;
+ m_ram6_memory[m_grom_address | ((port-48)<<16)] = data;
+ }
+ else
+ {
+ if (VERBOSE>1) LOG("hsgpl: Attempt to write to undefined port; ignored.\n");
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ // 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 = (UINT8*)malloc(RAMSIZE);
+ m_gram_memory = (UINT8*)malloc(GRAMSIZE);
+}
+
+void snug_high_speed_gpl_device::device_reset()
+{
+ if (VERBOSE>5) LOG("hsgpl: reset\n");
+ m_dsr_enabled = false;
+ m_gram_enabled = false;
+ m_bank_enabled = true; // important, assumed to be enabled by default (won't start up otherwise!)
+ 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;
+}
+
+void snug_high_speed_gpl_device::device_config_complete(void)
+{
+ m_dsr_eeprom = subdevice<at29040a_device>(DSR_EEPROM);
+ m_rom6_eeprom = subdevice<at29040a_device>(ROM6_EEPROM);
+ m_grom_a_eeprom = subdevice<at29040a_device>(GROM_A_EEPROM);
+ m_grom_b_eeprom = subdevice<at29040a_device>(GROM_B_EEPROM);
+}
+
+void snug_high_speed_gpl_device::device_stop()
+{
+ free(m_ram6_memory);
+ free(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_AT29040A_ADD( DSR_EEPROM )
+ MCFG_AT29040A_ADD( GROM_B_EEPROM )
+ MCFG_AT29040A_ADD( GROM_A_EEPROM )
+ MCFG_AT29040A_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<snug_high_speed_gpl_device>;
diff --git a/src/mess/machine/ti99/hsgpl.h b/src/mess/machine/ti99/hsgpl.h
new file mode 100644
index 00000000000..efa1efe2c95
--- /dev/null
+++ b/src/mess/machine/ti99/hsgpl.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+
+ 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 "ti99defs.h"
+#include "peribox.h"
+#include "machine/at29040a.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);
+
+ void crureadz(offs_t offset, UINT8 *value);
+ void cruwrite(offs_t offset, UINT8 data);
+
+protected:
+ void device_start(void);
+ void device_reset(void);
+ void device_stop(void);
+ void device_config_complete(void);
+ ioport_constructor device_input_ports() const;
+
+ machine_config_constructor device_mconfig_additions() const;
+
+private:
+ at29040a_device* m_dsr_eeprom;
+ at29040a_device* m_rom6_eeprom;
+ at29040a_device* m_grom_a_eeprom;
+ at29040a_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_enabled;
+ 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;
+
+ // GROM emulation
+ bool m_waddr_LSB;
+ bool m_raddr_LSB;
+ int m_grom_address;
+};
+
+#endif
+
diff --git a/src/mess/machine/ti99/joyport.c b/src/mess/machine/ti99/joyport.c
new file mode 100644
index 00000000000..3a53dd8ab52
--- /dev/null
+++ b/src/mess/machine/ti99/joyport.c
@@ -0,0 +1,104 @@
+/****************************************************************************
+
+ 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),
+ device_slot_interface(mconfig, *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);
+}
+
+/*
+ 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_config_complete()
+{
+ m_connected = static_cast<joyport_attached_device*>(first_subdevice());
+ const joyport_config *conf = reinterpret_cast<const joyport_config *>(static_config());
+
+ m_interrupt.resolve(conf->interrupt, *this);
+ m_clock = conf->vdp_clock;
+}
+
+/*****************************************************************************/
+
+void joyport_attached_device::device_config_complete()
+{
+ m_joyport = static_cast<joyport_device*>(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<joyport_device>;
+
diff --git a/src/mess/machine/ti99/joyport.h b/src/mess/machine/ti99/joyport.h
new file mode 100644
index 00000000000..f51c6a86599
--- /dev/null
+++ b/src/mess/machine/ti99/joyport.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+
+ 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;
+
+typedef struct _joyport_config
+{
+ devcb_write_line interrupt;
+ int vdp_clock;
+} joyport_config;
+
+#define JOYPORT_CONFIG(name) \
+ const joyport_config(name) =
+
+class joyport_device;
+
+/********************************************************************
+ Common parent class of all devices attached to the joystick port
+********************************************************************/
+class joyport_attached_device : public device_t
+{
+ friend class joyport_device;
+public:
+ joyport_attached_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) { }
+
+protected:
+ void device_config_complete();
+ joyport_device* m_joyport;
+
+private:
+ virtual UINT8 read_dev() =0;
+ virtual void write_dev(UINT8 data) =0;
+};
+
+/********************************************************************
+ 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);
+
+protected:
+ void device_start() { };
+ void device_config_complete();
+
+private:
+ devcb_resolved_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_GENEVE_JOYPORT_ADD( _tag, _conf ) \
+ MCFG_DEVICE_ADD(_tag, JOYPORT, 0) \
+ MCFG_DEVICE_CONFIG( _conf ) \
+ MCFG_DEVICE_SLOT_INTERFACE(joystick_port_gen, "twinjoy", NULL, false)
+
+#define MCFG_TI_JOYPORT4A_ADD( _tag, _conf ) \
+ MCFG_DEVICE_ADD(_tag, JOYPORT, 0) \
+ MCFG_DEVICE_CONFIG( _conf ) \
+ MCFG_DEVICE_SLOT_INTERFACE(joystick_port, "twinjoy", NULL, false)
+
+#define MCFG_TI_JOYPORT4_ADD( _tag, _conf ) \
+ MCFG_DEVICE_ADD(_tag, JOYPORT, 0) \
+ MCFG_DEVICE_CONFIG( _conf ) \
+ MCFG_DEVICE_SLOT_INTERFACE(joystick_port_994, "twinjoy", NULL, false)
+
+#endif /* __JOYPORT__ */
diff --git a/src/mess/machine/ti99/mapper8.c b/src/mess/machine/ti99/mapper8.c
new file mode 100644
index 00000000000..82943a74fd9
--- /dev/null
+++ b/src/mess/machine/ti99/mapper8.c
@@ -0,0 +1,570 @@
+/***************************************************************************
+
+ TI-99/8 Address decoder and mapper
+
+ 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"
+
+ 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
+
+ Informations taken from
+ [1] ARMADILLO PRODUCT SPECIFICATIONS
+ [2] TI-99/8 Graphics Programming Language interpreter
+
+ Michael Zapf, October 2010
+ February 2012: Rewritten as class
+
+***************************************************************************/
+
+#include "mapper8.h"
+
+#define VERBOSE 0
+#define LOG logerror
+
+// Pseudo devices which are not implemented by a proper device. We use these
+// constants in the read/write functions.
+#define MAP8_SRAM (void*)1L
+#define MAP8_ROM0 (void*)2L
+#define MAP8_ROM1 (void*)3L
+#define MAP8_ROM1A (void*)4L
+#define MAP8_DRAM (void*)5L
+#define MAP8_INTS (void*)6L
+
+ti998_mapper_device::ti998_mapper_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+: bus8z_device(mconfig, MAPPER8, "TI-99/8 Memory mapper", tag, owner, clock)
+{
+}
+
+/***************************************************************************
+ CRU access
+***************************************************************************/
+
+#define MAPPER_CRU_BASE 0x2700
+
+void ti998_mapper_device::crureadz(offs_t offset, UINT8 *value)
+{
+ if (VERBOSE>8) LOG("mapper8: read CRU %04x ignored\n", offset);
+ // Nothing here.
+}
+
+/*
+ CRU handling. We handle the internal device at CRU address 0x2700 via
+ this mapper component.
+*/
+void ti998_mapper_device::cruwrite(offs_t offset, UINT8 data)
+{
+ 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 (VERBOSE>7) LOG("mapper8: DSR select = %d\n", data);
+ break;
+ case 1:
+ if (VERBOSE>2) LOG("mapper8: System reset by CRU request\n");
+ machine().schedule_soft_reset();
+ break;
+ }
+ }
+}
+
+void ti998_mapper_device::CRUS_set(bool state)
+{
+ if (VERBOSE>7) LOG("mapper8: set CRUS=%d\n", state);
+ m_CRUS = state;
+}
+
+/*
+ Note that PTGEN is negative logic. We invert these semantics here.
+*/
+void ti998_mapper_device::PTGE_set(bool state)
+{
+ if (VERBOSE>7) LOG("mapper8: set PTGEN=%d\n", state? 1:0);
+ m_PTGE = state;
+}
+
+/***************************************************************************
+ Access by address map
+***************************************************************************/
+
+/*
+ This method is called via the address map.
+*/
+READ8_MEMBER( ti998_mapper_device::readm )
+{
+ UINT8 value = 0;
+ bool found = false;
+ if (VERBOSE>5) LOG("mapper8: read from %04x\n", offset);
+ found = search_logically_addressed_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
+ search_physically_addressed_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( ti998_mapper_device::writem )
+{
+ bool found = false;
+
+ // Look for components responding to the logical address
+ found = search_logically_addressed_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
+ search_physically_addressed_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( ti998_mapper_device::readz )
+{
+ if ((offset & 0xffe000)==0xff4000)
+ {
+ if (m_dsr_selected)
+ {
+ // Starts at 0x4000 in the image
+ *value = m_rom[0x4000 | (offset & 0x1fff)];
+ if (VERBOSE>7) LOG("mapper8: (DSR) %04x -> %02x\n", offset, *value);
+ }
+ }
+ else
+ {
+ if (((offset & 0xfff0)==0xf870 && m_CRUS==false)||(((offset & 0xfff0)==0x8810 && m_CRUS==true)))
+ {
+ if (VERBOSE>4) LOG("mapper8: read access to mapper ignored: %04x\n", offset);
+ }
+ }
+}
+
+/*
+ This method is called by the mapper itself for
+ ff4000 (PHYSIC): DSR. ignore
+
+*/
+WRITE8_MEMBER( ti998_mapper_device::write )
+{
+ if ((offset & 0xffe000)==0xff4000)
+ {
+ if (VERBOSE>4) LOG("mapper8: Write access to DSR space %06x ignored\n", 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
+*/
+void ti998_mapper_device::mapwrite(int offset, UINT8 data)
+{
+ if ((data & 0xf0)==0x00)
+ {
+ int bankindx = (data & 0x0e)>>1;
+ if (data & 1)
+ {
+ if (VERBOSE>7) LOG("mapper8: load mapper from SRAM, bank %d\n", 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]);
+ }
+ }
+ else
+ {
+ if (VERBOSE>7) LOG("mapper8: store mapper to SRAM, bank %d\n", 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;
+ }
+ }
+ }
+}
+
+/***************************************************************************
+ Lookup methods.
+***************************************************************************/
+
+bool ti998_mapper_device::search_logically_addressed_r(address_space& space, offs_t offset, UINT8 *value, UINT8 mem_mask )
+{
+ bool found = false;
+ log_addressed_device *dev = m_logcomp.first();
+
+ if (VERBOSE>8) LOG("mapper8: offset=%04x; CRUS=%d, PTGEN=%d\n", offset, m_CRUS? 1:0, m_PTGE? 0:1);
+ while (dev != NULL)
+ {
+ if (VERBOSE>5) LOG("mapper8: checking node=%s\n", dev->m_config->name);
+ // Check the mode
+ if (((dev->m_config->mode == NATIVE) && (m_CRUS==false))
+ || ((dev->m_config->mode == TI99EM) && (m_CRUS==true))
+ || ((dev->m_config->mode == PATGEN) && (m_PTGE==true)))
+ {
+ if ((offset & dev->m_config->address_mask)==dev->m_config->select_pattern)
+ {
+ if (dev->m_device == MAP8_SRAM)
+ {
+ *value = m_sram[offset & ~dev->m_config->address_mask];
+ if (VERBOSE>7) LOG("mapper8: (SRAM) %04x -> %02x\n", offset, *value);
+ }
+ else
+ {
+ if (dev->m_device == MAP8_ROM0)
+ {
+ // Starts at 0000
+ *value = m_rom[offset & ~dev->m_config->address_mask];
+ if (VERBOSE>7) LOG("mapper8: (ROM) %04x -> %02x\n", offset, *value);
+ }
+ else
+ {
+ // device
+ bus8z_device *bdev = static_cast<bus8z_device*>(dev->m_device);
+ bdev->readz(space, offset, value, mem_mask);
+ if (VERBOSE>7) LOG("mapper8: (dev %s) %04x -> %02x\n", dev->m_config->name, offset, *value);
+ }
+ }
+ found = true;
+ if (dev->m_config->stop==STOP) break;
+ }
+ }
+ dev = dev->m_next;
+ }
+ return found;
+}
+
+bool ti998_mapper_device::search_logically_addressed_w(address_space& space, offs_t offset, UINT8 data, UINT8 mem_mask )
+{
+ bool found = false;
+ log_addressed_device *dev = m_logcomp.first();
+
+ while (dev != NULL)
+ {
+ // Check the mode
+ if (((dev->m_config->mode == NATIVE) && (m_CRUS==false))
+ || ((dev->m_config->mode == TI99EM) && (m_CRUS==true))
+ || ((dev->m_config->mode == PATGEN) && (m_PTGE==true)))
+ {
+
+ if ((offset & dev->m_config->address_mask)==(dev->m_config->select_pattern | dev->m_config->write_select))
+ {
+ if (dev->m_device == MAP8_SRAM)
+ {
+ m_sram[offset & ~dev->m_config->address_mask] = data;
+ if (VERBOSE>7) LOG("mapper8: (SRAM) %04x <- %02x\n", offset, data);
+ }
+ else
+ {
+ if (dev->m_device == MAP8_ROM0)
+ {
+ if (VERBOSE>7) LOG("mapper8: (ROM) %04x <- %02x (ignored)\n", offset, data);
+ }
+ else
+ {
+ // device
+ bus8z_device *bdev = static_cast<bus8z_device*>(dev->m_device);
+ bdev->write(space, offset, data, mem_mask);
+ if (VERBOSE>7) LOG("mapper8: (dev %s) %04x <- %02x\n", dev->m_config->name, offset, data);
+ }
+ }
+ found = true;
+ if (dev->m_config->stop==STOP) break;
+ }
+ }
+ dev = dev->m_next;
+ }
+ return found;
+}
+
+
+void ti998_mapper_device::search_physically_addressed_r( address_space& space, offs_t pas_address, UINT8 *value, UINT8 mem_mask )
+{
+ phys_addressed_device *dev = m_physcomp.first();
+
+ while (dev != NULL)
+ {
+ if ((pas_address & dev->m_config->address_mask)==dev->m_config->select_pattern)
+ {
+ if (dev->m_device == MAP8_DRAM)
+ {
+ *value = m_dram[pas_address & ~dev->m_config->address_mask];
+ if (VERBOSE>3) LOG("mapper8: (DRAM) %06x -> %02x\n", pas_address, *value);
+ }
+ else
+ {
+ if (dev->m_device == MAP8_ROM1)
+ {
+ // Starts at 2000 in the image, 8K
+ *value = m_rom[0x2000 | (pas_address & 0x1fff)];
+ if (VERBOSE>3) LOG("mapper8: (ROM) %06x -> %02x\n", pas_address, *value);
+ }
+ else
+ {
+ if (dev->m_device == MAP8_ROM1A)
+ {
+ // Starts at 6000 in the image, 8K
+ *value = m_rom[0x6000 | (pas_address & 0x1fff)];
+ if (VERBOSE>3) LOG("mapper8: (ROM) %06x -> %02x\n", pas_address, *value);
+ }
+ else
+ {
+ if (dev->m_device == MAP8_INTS)
+ {
+ // Interrupt sense
+ if (VERBOSE>1) LOG("ti99_8: ILSENSE not implemented.\n");
+ }
+ else
+ {
+ // devices
+ bus8z_device *bdev = static_cast<bus8z_device*>(dev->m_device);
+ bdev->readz(space, pas_address, value, mem_mask);
+ if (VERBOSE>7) LOG("mapper8: (dev %s) %06x -> %02x\n", dev->m_config->name, pas_address, *value);
+ }
+ }
+ }
+ }
+ if (dev->m_config->stop==STOP) break;
+ }
+ dev = dev->m_next;
+ }
+}
+
+void ti998_mapper_device::search_physically_addressed_w( address_space& space, offs_t pas_address, UINT8 data, UINT8 mem_mask )
+{
+ phys_addressed_device *dev = m_physcomp.first();
+
+ while (dev != NULL)
+ {
+ if ((pas_address & dev->m_config->address_mask)==(dev->m_config->select_pattern | dev->m_config->write_select))
+ {
+ if (dev->m_device == MAP8_DRAM)
+ {
+ m_dram[pas_address & ~dev->m_config->address_mask] = data;
+ if (VERBOSE>3) LOG("mapper8: (DRAM) %06x <- %02x\n", pas_address, data);
+ }
+ else
+ {
+ if (dev->m_device == MAP8_ROM1 || dev->m_device == MAP8_ROM1A)
+ {
+ if (VERBOSE>7) LOG("mapper8: (ROM) %06x <- %02x (ignored)\n", pas_address, data);
+ }
+ else
+ {
+ if (dev->m_device == MAP8_INTS)
+ {
+ // Interrupt sense
+ if (VERBOSE>1) LOG("ti99_8: write to ilsense ignored\n");
+ }
+ else
+ {
+ // devices
+ bus8z_device *bdev = static_cast<bus8z_device*>(dev->m_device);
+ if (VERBOSE>7) LOG("mapper8: (dev %s) %06x <- %02x\n", dev->m_config->name, pas_address, data);
+ bdev->write(space, pas_address, data, mem_mask);
+ }
+ }
+ }
+ if (dev->m_config->stop==STOP) break;
+ }
+ dev = dev->m_next;
+ }
+}
+
+/*
+ The mapper is connected to the clock line in order to operate
+ the wait state counter.
+*/
+void ti998_mapper_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
+***************************************************************************/
+// String values of the pseudo constants, used in the configuration.
+static const char *const pseudodev[6] = { SRAMNAME, ROM0NAME, ROM1NAME, ROM1ANAME, DRAMNAME, INTSNAME };
+
+/*
+ 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 ti998_mapper_device::device_start()
+{
+ if (VERBOSE>5) LOG("ti99_8: Starting mapper\n");
+
+ const mapper8_config *conf = reinterpret_cast<const mapper8_config *>(static_config());
+
+ const mapper8_list_entry *entry = conf->devlist;
+ m_ready.resolve(conf->ready, *this);
+
+ m_sram = machine().root_device().memregion(SRAM_TAG)->base();
+ m_dram = machine().root_device().memregion(DRAM_TAG)->base();
+ m_rom = machine().root_device().memregion("maincpu")->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
+ {
+ // Here we replace the device names by their pointers and the pseudo device
+ // names by their constants MAP8_SRAM ... MAP8_INTS. */
+
+ // To make thing efficient, we abuse the pointers with special
+ // values for the ROM and RAM. (Otherwise we would have to
+ // build complete devices for ROM and RAM.)
+ void *dev = NULL;
+ for (long long j=1; (j < 7) && (dev == NULL); j++)
+ {
+ // Pseudo devices are enumerated as 1 ... 6 (see MAP8_SRAM etc.)
+ if (strcmp(entry[i].name, pseudodev[j-1])==0)
+ dev = (void *)j;
+ }
+ if (dev==NULL)
+ {
+ // This entry points to a "real" device, not to a special constant
+ dev = machine().device(entry[i].name);
+ }
+ if (dev != NULL)
+ {
+ if (entry[i].mode != PHYSIC)
+ {
+ log_addressed_device *ad = new log_addressed_device((device_t*)dev, entry[i]);
+ m_logcomp.append(*ad);
+ if (VERBOSE>6) LOG("mapper8: Device %s mounted into logical address space.\n", entry[i].name);
+ }
+ else
+ {
+ phys_addressed_device *ad = new phys_addressed_device((device_t*)dev, entry[i]);
+ m_physcomp.append(*ad);
+ if (VERBOSE>6) LOG("mapper8: Device %s mounted into physical address space.\n", entry[i].name);
+ }
+ }
+ else
+ {
+ if (VERBOSE>1) LOG("mapper8: Device %s not found.\n", entry[i].name);
+ }
+ }
+ }
+ }
+ if (VERBOSE>4) LOG("Mapper logical device count = %d\n", m_logcomp.count());
+ if (VERBOSE>4) LOG("Mapper physical device count = %d\n", 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 ti998_mapper_device::device_reset()
+{
+ m_dsr_selected = false;
+ m_CRUS = true;
+ m_PTGE = false;
+
+ // Clean mapper
+ for (int i=0; i < 16; i++) m_pas_offset[i] = 0;
+
+ m_ready(ASSERT_LINE);
+}
+
+const device_type MAPPER8 = &device_creator<ti998_mapper_device>;
diff --git a/src/mess/machine/ti99/mapper8.h b/src/mess/machine/ti99/mapper8.h
new file mode 100644
index 00000000000..8e164ef45bf
--- /dev/null
+++ b/src/mess/machine/ti99/mapper8.h
@@ -0,0 +1,169 @@
+/****************************************************************************
+
+ TI-99/8 Address decoder and mapper
+
+ See mapper8.c for documentation
+
+ Michael Zapf
+
+ February 2012: Rewritten as class
+
+*****************************************************************************/
+
+#ifndef __MAPPER8__
+#define __MAPPER8__
+
+#include "emu.h"
+#include "peribox.h"
+#include "ti99defs.h"
+
+extern const device_type MAPPER8;
+
+#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 ROM1NAME "ROM1"
+#define ROM1ANAME "ROM1A"
+#define INTSNAME "INTS"
+#define DRAMNAME "DRAM"
+
+#define SRAM_SIZE 2048
+#define DRAM_SIZE 65536
+
+typedef 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
+} mapper8_list_entry;
+
+#define MAPPER8_CONFIG(name) \
+ const mapper8_config(name) =
+
+typedef struct _mapper8_config
+{
+ devcb_write_line ready;
+ const mapper8_list_entry *devlist;
+} mapper8_config;
+
+/*
+ Device list of the mapper.
+*/
+class log_addressed_device
+{
+ friend class simple_list<log_addressed_device>;
+ friend class ti998_mapper_device;
+
+public:
+ log_addressed_device(device_t *busdevice, const mapper8_list_entry &entry)
+ : m_device(busdevice), m_config(&entry) { };
+
+private:
+ log_addressed_device *m_next; // needed for simple_list
+ device_t *m_device; // the actual device
+ const mapper8_list_entry *m_config;
+};
+
+/*
+ Device list of the mapper.
+*/
+class phys_addressed_device
+{
+ friend class simple_list<phys_addressed_device>;
+ friend class ti998_mapper_device;
+
+public:
+ phys_addressed_device(device_t *busdevice, const mapper8_list_entry &entry)
+ : m_device(busdevice), m_config(&entry) { };
+
+private:
+ phys_addressed_device *m_next; // needed for simple_list
+ device_t *m_device; // the actual device
+ const mapper8_list_entry *m_config;
+};
+
+/*
+ Main class
+*/
+class ti998_mapper_device : public bus8z_device
+{
+public:
+ ti998_mapper_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ DECLARE_READ8_MEMBER( readm); // used from address map
+ DECLARE_WRITE8_MEMBER( writem ); // used from address map
+
+ DECLARE_READ8Z_MEMBER( readz );
+ DECLARE_WRITE8_MEMBER( write );
+
+ void crureadz(offs_t offset, UINT8 *value);
+ void cruwrite(offs_t offset, UINT8 data);
+
+ void CRUS_set(bool state);
+ void PTGE_set(bool state);
+
+ void clock_in(int state);
+
+protected:
+ void device_start(void);
+ void device_reset(void);
+
+private:
+ bool search_logically_addressed_r(address_space& space, offs_t offset, UINT8 *value, UINT8 mem_mask );
+ bool search_logically_addressed_w(address_space& space, offs_t offset, UINT8 data, UINT8 mem_mask );
+ void search_physically_addressed_r(address_space& space, offs_t offset, UINT8 *value, UINT8 mem_mask );
+ void search_physically_addressed_w(address_space& space, offs_t offset, UINT8 data, UINT8 mem_mask );
+ void mapwrite(int offset, UINT8 data);
+
+ // Ready line to the CPU
+ devcb_resolved_write_line m_ready;
+
+ // All devices that are attached to the 16-bit address bus.
+ simple_list<log_addressed_device> m_logcomp;
+
+ // All devices that are attached to the 24-bit mapped address bus.
+ simple_list<phys_addressed_device> m_physcomp;
+
+ // Select bit for the internal DSR.
+ bool m_dsr_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 address decoder.
+ UINT8 *m_rom;
+};
+
+
+#define MCFG_MAPPER8_ADD(_tag, _devices) \
+ MCFG_DEVICE_ADD(_tag, MAPPER8, 0) \
+ MCFG_DEVICE_CONFIG( _devices )
+
+#endif
diff --git a/src/mess/machine/ti99/mecmouse.c b/src/mess/machine/ti99/mecmouse.c
new file mode 100644
index 00000000000..7cdf87d94d1
--- /dev/null
+++ b/src/mess/machine/ti99/mecmouse.c
@@ -0,0 +1,205 @@
+/****************************************************************************
+
+ 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)
+{
+ m_shortname = "mecmouse";
+}
+
+
+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);
+ m_poll_timer->adjust(attotime::from_hz(m_joyport->clock()), 0, attotime::from_hz(m_joyport->clock()));
+}
+
+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<mecmouse_device>;
diff --git a/src/mess/machine/ti99/mecmouse.h b/src/mess/machine/ti99/mecmouse.h
new file mode 100644
index 00000000000..dc78069ca3e
--- /dev/null
+++ b/src/mess/machine/ti99/mecmouse.h
@@ -0,0 +1,46 @@
+/****************************************************************************
+
+ 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:
+ void device_start(void);
+ void device_reset(void);
+ ioport_constructor device_input_ports() const;
+
+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;
+ void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+ emu_timer *m_poll_timer;
+};
+#endif
diff --git a/src/mess/machine/ti99/memex.c b/src/mess/machine/ti99/memex.c
new file mode 100644
index 00000000000..44380812059
--- /dev/null
+++ b/src/mess/machine/ti99/memex.c
@@ -0,0 +1,175 @@
+/***************************************************************************
+
+ 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)
+{
+ m_shortname = "ti99_memex";
+}
+
+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<geneve_memex_device>;
diff --git a/src/mess/machine/ti99/memex.h b/src/mess/machine/ti99/memex.h
new file mode 100644
index 00000000000..9971d98da28
--- /dev/null
+++ b/src/mess/machine/ti99/memex.h
@@ -0,0 +1,44 @@
+/****************************************************************************
+
+ 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 "ti99defs.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);
+
+ void crureadz(offs_t offset, UINT8 *value) { };
+ void cruwrite(offs_t offset, UINT8 value) { };
+
+protected:
+ void device_start();
+ void device_reset();
+ ioport_constructor device_input_ports() const;
+ 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/mess/machine/ti99/myarcmem.c b/src/mess/machine/ti99/myarcmem.c
new file mode 100644
index 00000000000..e8f51f298d8
--- /dev/null
+++ b/src/mess/machine/ti99/myarcmem.c
@@ -0,0 +1,209 @@
+/****************************************************************************
+
+ 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)
+{
+ m_shortname = "ti99_myarcmem";
+}
+
+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.
+*/
+void myarc_memory_expansion_device::crureadz(offs_t offset, UINT8 *value)
+{
+ return;
+}
+
+/*
+ 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)
+*/
+void myarc_memory_expansion_device::cruwrite(offs_t offset, UINT8 data)
+{
+ 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<myarc_memory_expansion_device>;
diff --git a/src/mess/machine/ti99/myarcmem.h b/src/mess/machine/ti99/myarcmem.h
new file mode 100644
index 00000000000..49d7016d38d
--- /dev/null
+++ b/src/mess/machine/ti99/myarcmem.h
@@ -0,0 +1,44 @@
+/****************************************************************************
+
+ 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"
+#include "ti99defs.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);
+
+ void crureadz(offs_t offset, UINT8 *value);
+ void cruwrite(offs_t offset, UINT8 data);
+
+protected:
+ void device_start(void);
+ void device_reset(void);
+ const rom_entry *device_rom_region(void) const;
+ 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/mess/machine/ti99/p_code.c b/src/mess/machine/ti99/p_code.c
new file mode 100644
index 00000000000..baec75cab96
--- /dev/null
+++ b/src/mess/machine/ti99/p_code.c
@@ -0,0 +1,325 @@
+/****************************************************************************
+
+ 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 "p_code.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)
+{
+ m_shortname = "ti99_pcode";
+}
+
+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.)
+*/
+void ti_pcode_card_device::crureadz(offs_t offset, UINT8 *value)
+{
+ // Nothing here.
+ return;
+}
+
+/*
+ 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.
+*/
+void ti_pcode_card_device::cruwrite(offs_t offset, UINT8 data)
+{
+ 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, DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ti_pcode_card_device, ready_line), GROMFREQ
+};
+static GROM_CONFIG(pgrom1_config)
+{
+ false, 1, PCODE_GROM_TAG, 0x2000, 0x1800, DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ti_pcode_card_device, ready_line), GROMFREQ
+};
+static GROM_CONFIG(pgrom2_config)
+{
+ false, 2, PCODE_GROM_TAG, 0x4000, 0x1800, DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ti_pcode_card_device, ready_line), GROMFREQ
+};
+static GROM_CONFIG(pgrom3_config)
+{
+ false, 3, PCODE_GROM_TAG, 0x6000, 0x1800, DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ti_pcode_card_device, ready_line), GROMFREQ
+};
+static GROM_CONFIG(pgrom4_config)
+{
+ false, 4, PCODE_GROM_TAG, 0x8000, 0x1800, DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ti_pcode_card_device, ready_line), GROMFREQ
+};
+static GROM_CONFIG(pgrom5_config)
+{
+ false, 5, PCODE_GROM_TAG, 0xa000, 0x1800, DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ti_pcode_card_device, ready_line), GROMFREQ
+};
+static GROM_CONFIG(pgrom6_config)
+{
+ false, 6, PCODE_GROM_TAG, 0xc000, 0x1800, DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ti_pcode_card_device, ready_line), GROMFREQ
+};
+static GROM_CONFIG(pgrom7_config)
+{
+ false, 7, PCODE_GROM_TAG, 0xe000, 0x1800, DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ti_pcode_card_device, ready_line), GROMFREQ
+};
+
+void ti_pcode_card_device::device_start()
+{
+ m_cru_base = 0x1f00;
+ m_grom[0] = static_cast<ti99_grom_device*>(subdevice(PGROM0_TAG));
+ m_grom[1] = static_cast<ti99_grom_device*>(subdevice(PGROM1_TAG));
+ m_grom[2] = static_cast<ti99_grom_device*>(subdevice(PGROM2_TAG));
+ m_grom[3] = static_cast<ti99_grom_device*>(subdevice(PGROM3_TAG));
+ m_grom[4] = static_cast<ti99_grom_device*>(subdevice(PGROM4_TAG));
+ m_grom[5] = static_cast<ti99_grom_device*>(subdevice(PGROM5_TAG));
+ m_grom[6] = static_cast<ti99_grom_device*>(subdevice(PGROM6_TAG));
+ m_grom[7] = static_cast<ti99_grom_device*>(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_ADD( PGROM1_TAG, pgrom1_config )
+ MCFG_GROM_ADD( PGROM2_TAG, pgrom2_config )
+ MCFG_GROM_ADD( PGROM3_TAG, pgrom3_config )
+ MCFG_GROM_ADD( PGROM4_TAG, pgrom4_config )
+ MCFG_GROM_ADD( PGROM5_TAG, pgrom5_config )
+ MCFG_GROM_ADD( PGROM6_TAG, pgrom6_config )
+ MCFG_GROM_ADD( PGROM7_TAG, pgrom7_config )
+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<ti_pcode_card_device>;
+
diff --git a/src/mess/machine/ti99/p_code.h b/src/mess/machine/ti99/p_code.h
new file mode 100644
index 00000000000..740c7785563
--- /dev/null
+++ b/src/mess/machine/ti99/p_code.h
@@ -0,0 +1,49 @@
+/****************************************************************************
+
+ 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 "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);
+ void crureadz(offs_t offset, UINT8 *value);
+ void cruwrite(offs_t offset, UINT8 data);
+
+ DECLARE_WRITE_LINE_MEMBER( ready_line );
+ DECLARE_INPUT_CHANGED_MEMBER( switch_changed );
+
+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:
+ ti99_grom_device* m_grom[8];
+ UINT8* m_rom;
+ int m_bank_select;
+ bool m_switch;
+};
+
+#endif
diff --git a/src/mess/machine/ti99/peribox.c b/src/mess/machine/ti99/peribox.c
new file mode 100644
index 00000000000..0f16bc73c14
--- /dev/null
+++ b/src/mess/machine/ti99/peribox.c
@@ -0,0 +1,664 @@
+/****************************************************************************
+
+ 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 : |
+ | | L | L | L | L | L | L | L | L : |
+ | Power | O | O | O | O | O | O | O | O : Floppy |
+ | unit | T | T | T | T | T | T | T | T | drive |
+ | and | | | | | | | | | compartment|
+ | ventilation | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
+ | | | | | | | | | | 1 full hgt |
+ | | | | | | | | | | or |
+ | | | | | | | | | | 2 "slim" |
+ | | | | | | | |LED |LED | |
+ | +----+----+----+----+----+----+-|--+-|--+ |
+ | : seen from above | | | |
+ +--------------+-------------------------------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) (obsoletes 99_peb.c)
+ January 2012: Reimplemented as class (MZ)
+
+*****************************************************************************/
+
+#include "emu.h"
+#include "peribox.h"
+
+// The cards
+#include "ti32kmem.h"
+#include "ti_fdc.h"
+#include "bwg.h"
+#include "hfdc.h"
+#include "p_code.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"
+
+#include "formats/ti99_dsk.h"
+
+#define LOG logerror
+#define VERBOSE 1
+
+#define PEBSLOT2 "slot2"
+#define PEBSLOT3 "slot3"
+#define PEBSLOT4 "slot4"
+#define PEBSLOT5 "slot5"
+#define PEBSLOT6 "slot6"
+#define PEBSLOT7 "slot7"
+#define PEBSLOT8 "slot8"
+
+// TODO: Connect other lines (think about how to propagate to the controller)
+static const floppy_interface ti99_4_floppy_interface =
+{
+ DEVCB_DEVICE_LINE_MEMBER( DEVICE_SELF_OWNER, peribox_device, indexhole ), // Index hole (floppy out, line)
+ DEVCB_NULL, // Motor (floppy in, line)
+ DEVCB_NULL, // Track 0 (out, line)
+ DEVCB_NULL, // Write protect (out, line)
+ DEVCB_NULL, // Ready (out, line)
+ FLOPPY_STANDARD_5_25_DSHD, // type
+ LEGACY_FLOPPY_OPTIONS_NAME(ti99), // image formats
+ NULL, // interface
+ NULL // display info
+};
+
+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)
+{
+ 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);
+ }
+}
+
+void peribox_device::crureadz(offs_t offset, UINT8 *value)
+{
+ for (int i=2; i <= 8; i++)
+ {
+ if (m_slot[i]!=NULL) m_slot[i]->crureadz(offset, value);
+ }
+}
+
+void peribox_device::cruwrite(offs_t offset, UINT8 data)
+{
+ for (int i=2; i <= 8; i++)
+ {
+ if (m_slot[i]!=NULL) m_slot[i]->cruwrite(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.
+*/
+void peribox_device::inta_join(int slot, int state)
+{
+ if (VERBOSE>7) LOG("Peribox propagating INTA from slot %d to console: %d\n", 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 (VERBOSE>7) LOG("Peribox propagating INTB from slot %d to console: %d\n", 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 (VERBOSE>7) LOG("peribox: Incoming READY=%d from slot %d\n", state, slot);
+ // We store the inverse state
+ if (state==CLEAR_LINE)
+ m_ready_flag |= (1 << slot);
+ else
+ m_ready_flag &= ~(1 << slot);
+
+ m_console_ready((m_ready_flag != 0)? CLEAR_LINE : ASSERT_LINE);
+}
+
+void peribox_device::set_slot_loaded(int slot, peribox_slot_device* slotdev)
+{
+ if (VERBOSE>6)
+ {
+ if (slotdev!=NULL) LOG("Setting slot %d to device %s\n", slot, slotdev->tag());
+ else LOG("Setting slot %d to EMPTY\n", slot);
+ }
+ m_slot[slot] = slotdev;
+}
+
+void peribox_device::device_start(void)
+{
+ if (VERBOSE>7) LOG("Peribox started\n");
+
+ floppy_drive_set_rpm(subdevice(FLOPPY_0), 300.);
+ floppy_drive_set_rpm(subdevice(FLOPPY_1), 300.);
+ floppy_drive_set_rpm(subdevice(FLOPPY_2), 300.);
+ floppy_drive_set_rpm(subdevice(FLOPPY_3), 300.);
+}
+
+void peribox_device::device_config_complete()
+{
+ // Resolve the callback lines to the console
+ const peribox_config *intf = reinterpret_cast<const peribox_config *>(static_config());
+ assert (intf != NULL);
+ m_console_inta.resolve(intf->inta, *this);
+ m_console_intb.resolve(intf->intb, *this);
+ m_console_ready.resolve(intf->ready, *this);
+
+ m_inta_flag = 0;
+ m_intb_flag = 0;
+ m_ready_flag = 0;
+
+ // The TI-99/4(A) Flex Cable Interface (slot 1) pulls up the AMA/AMB/AMC lines to 1/1/1.
+ m_address_prefix = intf->prefix;
+}
+
+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 )
+
+ MCFG_LEGACY_FLOPPY_4_DRIVES_ADD(ti99_4_floppy_interface)
+ MCFG_MFMHD_3_DRIVES_ADD()
+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, tag, owner, clock)
+{
+};
+
+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_slot7 )
+ MCFG_PERIBOX_SLOT_ADD( PEBSLOT8, peribox_slot8 )
+
+ MCFG_LEGACY_FLOPPY_4_DRIVES_ADD(ti99_4_floppy_interface)
+ MCFG_MFMHD_3_DRIVES_ADD()
+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 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, tag, owner, clock)
+{
+};
+
+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_slot7 )
+
+ MCFG_LEGACY_FLOPPY_4_DRIVES_ADD(ti99_4_floppy_interface)
+ MCFG_MFMHD_3_DRIVES_ADD()
+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, tag, owner, clock)
+{
+};
+
+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 )
+
+ MCFG_LEGACY_FLOPPY_4_DRIVES_ADD(ti99_4_floppy_interface)
+ MCFG_MFMHD_3_DRIVES_ADD()
+MACHINE_CONFIG_END
+
+machine_config_constructor peribox_ev_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( peribox_ev_device );
+}
+
+/***************************************************************************
+ Floppy interface
+****************************************************************************/
+
+// TODO: won't be called unless motor_on is triggered
+WRITE_LINE_MEMBER( peribox_device::indexhole )
+{
+ if (VERBOSE>4) LOG("peribox_device: indexhole\n");
+}
+
+/***************************************************************************
+ 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), 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);
+}
+
+void peribox_slot_device::crureadz(offs_t offset, UINT8 *value)
+{
+ m_card->crureadz(offset, value);
+}
+
+void peribox_slot_device::cruwrite(offs_t offset, UINT8 data)
+{
+ m_card->cruwrite(offset, data);
+}
+
+void peribox_slot_device::senila(int state)
+{
+ m_card->set_senila(state);
+}
+
+void peribox_slot_device::senilb(int state)
+{
+ 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)
+{
+ if (VERBOSE>7) LOG("Peribox slot started\n");
+}
+
+void peribox_slot_device::device_config_complete()
+{
+ m_slotnumber = get_index_from_tagname();
+ device_t *carddev = first_subdevice();
+ peribox_device *peb = static_cast<peribox_device*>(owner());
+ if (carddev != NULL)
+ {
+ peb->set_slot_loaded(m_slotnumber, this);
+ m_card = static_cast<ti_expansion_card_device*>(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<peribox_device*>(owner());
+ peb->inta_join(m_slotnumber, state);
+}
+
+WRITE_LINE_MEMBER( peribox_slot_device::set_intb )
+{
+ peribox_device *peb = static_cast<peribox_device*>(owner());
+ peb->intb_join(m_slotnumber, state);
+}
+
+WRITE_LINE_MEMBER( peribox_slot_device::set_ready )
+{
+ peribox_device *peb = static_cast<peribox_device*>(owner());
+ peb->ready_join(m_slotnumber, state);
+}
+
+/***************************************************************************/
+const device_type PERIBOX = &device_creator<peribox_device>;
+const device_type PERIBOX_SLOT = &device_creator<peribox_slot_device>;
+
+const device_type PERIBOX_EV = &device_creator<peribox_ev_device>;
+const device_type PERIBOX_SG = &device_creator<peribox_sg_device>;
+const device_type PERIBOX_GEN = &device_creator<peribox_gen_device>;
+
+
diff --git a/src/mess/machine/ti99/peribox.h b/src/mess/machine/ti99/peribox.h
new file mode 100644
index 00000000000..c7b163fdfbe
--- /dev/null
+++ b/src/mess/machine/ti99/peribox.h
@@ -0,0 +1,251 @@
+/****************************************************************************
+
+ Peripheral expansion box
+ See peribox.c for documentation
+
+ Michael Zapf
+
+ February 2012: Rewritten as class
+
+*****************************************************************************/
+
+#ifndef __PBOX__
+#define __PBOX__
+
+#include "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;
+
+#define DSRROM "dsrrom"
+
+typedef struct _peribox_config
+{
+ devcb_write_line inta;
+ devcb_write_line intb;
+ devcb_write_line ready;
+ int prefix;
+} peribox_config;
+
+#define PERIBOX_CONFIG(name) \
+ const peribox_config(name) =
+
+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);
+
+ // Next six methods are called from the console
+ DECLARE_READ8Z_MEMBER(readz);
+ DECLARE_WRITE8_MEMBER(write);
+ void crureadz(offs_t offset, UINT8 *value);
+ void cruwrite(offs_t offset, UINT8 value);
+ DECLARE_WRITE_LINE_MEMBER(senila);
+ DECLARE_WRITE_LINE_MEMBER(senilb);
+
+ // Floppy interface
+ DECLARE_WRITE_LINE_MEMBER( indexhole );
+
+ // Genmod support
+ DECLARE_INPUT_CHANGED_MEMBER( genmod_changed );
+ void set_genmod(bool set);
+
+protected:
+ void device_start(void);
+ void device_config_complete(void);
+
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+ // Next three methods call back the console
+ devcb_resolved_write_line m_console_inta; // INTA line (Box to console)
+ devcb_resolved_write_line m_console_intb; // INTB line
+ devcb_resolved_write_line m_console_ready; // READY line
+
+ 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;
+
+ 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:
+ 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:
+ 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:
+ machine_config_constructor device_mconfig_additions() const;
+};
+
+/*****************************************************************************
+ A single slot in the box.
+******************************************************************************/
+
+class peribox_slot_device : public bus8z_device, public device_slot_interface
+{
+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_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 );
+
+ void crureadz(offs_t offset, UINT8 *value);
+ void cruwrite(offs_t offset, UINT8 value);
+
+ // 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)
+ : bus8z_device(mconfig, type, name, tag, owner, clock),
+ device_slot_card_interface(mconfig, *this)
+ {
+ m_slot = static_cast<peribox_slot_device*>(owner);
+ m_senila = CLEAR_LINE;
+ m_senilb = CLEAR_LINE;
+ m_genmod = false;
+ }
+
+ virtual void crureadz(offs_t offset, UINT8 *value) =0;
+ virtual void cruwrite(offs_t offset, UINT8 data) =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_ADD(_tag, _config) \
+ MCFG_DEVICE_ADD(_tag, PERIBOX, 0) \
+ MCFG_DEVICE_CONFIG( _config )
+
+#define MCFG_PERIBOX_EV_ADD(_tag, _config) \
+ MCFG_DEVICE_ADD(_tag, PERIBOX_EV, 0) \
+ MCFG_DEVICE_CONFIG( _config )
+
+#define MCFG_PERIBOX_SG_ADD(_tag, _config) \
+ MCFG_DEVICE_ADD(_tag, PERIBOX_SG, 0) \
+ MCFG_DEVICE_CONFIG( _config )
+
+#define MCFG_PERIBOX_GEN_ADD(_tag, _config) \
+ MCFG_DEVICE_ADD(_tag, PERIBOX_GEN, 0) \
+ MCFG_DEVICE_CONFIG( _config )
+
+#define MCFG_PERIBOX_SLOT_ADD(_tag, _slot_intf) \
+ MCFG_DEVICE_ADD(_tag, PERIBOX_SLOT, 0) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, NULL, 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, NULL, false)
+
+/*
+ The following defines are required because the WD17xx DEVICE_START implementation
+ assumes that the floppy devices are either at root level or at the parent
+ level. Our floppy devices, however, are at the grandparent level as seen from
+ the controller.
+*/
+#define PFLOPPY_0 ":peb:floppy0"
+#define PFLOPPY_1 ":peb:floppy1"
+#define PFLOPPY_2 ":peb:floppy2"
+#define PFLOPPY_3 ":peb:floppy3"
+
+#endif /* __PBOX__ */
diff --git a/src/mess/machine/ti99/samsmem.c b/src/mess/machine/ti99/samsmem.c
new file mode 100644
index 00000000000..6f9ab7fb163
--- /dev/null
+++ b/src/mess/machine/ti99/samsmem.c
@@ -0,0 +1,133 @@
+/****************************************************************************
+
+ 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)
+{
+ m_shortname = "ti99_sams";
+}
+
+/*
+ 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.
+*/
+void sams_memory_expansion_device::crureadz(offs_t offset, UINT8 *value)
+{
+ return;
+}
+
+/*
+ CRU write. Turns on the mapper and allows to change it.
+*/
+void sams_memory_expansion_device::cruwrite(offs_t offset, UINT8 data)
+{
+ 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<sams_memory_expansion_device>;
diff --git a/src/mess/machine/ti99/samsmem.h b/src/mess/machine/ti99/samsmem.h
new file mode 100644
index 00000000000..6f5a6b5db53
--- /dev/null
+++ b/src/mess/machine/ti99/samsmem.h
@@ -0,0 +1,43 @@
+/****************************************************************************
+
+ 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"
+#include "ti99defs.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);
+
+ void crureadz(offs_t offset, UINT8 *value);
+ void cruwrite(offs_t offset, UINT8 data);
+
+protected:
+ void device_start(void);
+ void device_reset(void);
+ 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/mess/machine/ti99/spchsyn.c b/src/mess/machine/ti99/spchsyn.c
new file mode 100644
index 00000000000..10e38352932
--- /dev/null
+++ b/src/mess/machine/ti99/spchsyn.c
@@ -0,0 +1,308 @@
+/****************************************************************************
+
+ 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 TMS5200, aka 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"
+
+#define TMS5220_ADDRESS_MASK 0x3FFFFUL /* 18-bit mask for tms5220 address */
+
+#define VERBOSE 1
+#define LOG logerror
+
+#define SPEECHROM_TAG "speechrom"
+
+#define REAL_TIMING 0
+
+/****************************************************************************/
+
+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)
+{
+ m_shortname = "ti99_speech";
+}
+
+/*
+ Comments on real timing in the TMS5200 emulation
+
+ Real timing means that the synthesizer clears the /READY line (puts high)
+ whenever a read or write access is in progress. This is done by setting
+ /RS and /WS lines, according to the read or write operation. The /READY line
+ is asserted again after some time. Real timing is used once the tms5220_wsq_w
+ and tms5220_rsq_w are called.
+
+ Within the TI systems, the /RS and /WS lines are controlled directly by the
+ address bus. There is currently no way to insert wait states between
+ the address setting and the data bus sampling, since this is an atomic
+ operation in the emulator (read_byte). It would be necessary to somehow
+ announce the pending read before it actually happens so that devices
+ like this VSP may insert wait states before the read.
+
+ The TMS5220 implementation assumes that wait states are respected and
+ therefore delivers bad values when queried too early. It uses a latch that
+ gets the new value after some time has expired.
+
+ To fix this we have to modify the RS/WS methods in TMS5200 to immediately
+ set the status (after updating the sound status, or the status will be
+ outdated too early).
+
+ Also note that the /RS and /WS lines must be cleared (put to high) when the
+ read is done. Again, this is not possible with the current implementation.
+ So we do this in the ready callback.
+
+ On the bottom line we will stay with the not-REAL_TIMING for now and wait
+ for the core to allow for split read accesses.
+*/
+
+
+/*
+ Memory read
+*/
+#if REAL_TIMING
+// ====== This is the version with real timing =======
+READ8Z_MEMBER( ti_speech_synthesizer_device::readz )
+{
+ if ((offset & m_select_mask)==m_select_value)
+ {
+ m_vsp->wsq_w(TRUE);
+ m_vsp->rsq_w(FALSE);
+ *value = m_vsp->read(offset) & 0xff;
+ if (VERBOSE>4) LOG("spchsyn: read value = %02x\n", *value);
+ }
+}
+
+/*
+ Memory write
+*/
+WRITE8_MEMBER( ti_speech_synthesizer_device::write )
+{
+ if ((offset & m_select_mask)==(m_select_value | 0x0400))
+ {
+ m_vsp->rsq_w(m_vsp, TRUE);
+ m_vsp->wsq_w(m_vsp, FALSE);
+ if (VERBOSE>4) LOG("spchsyn: write value = %02x\n", data);
+ m_vsp->write(offset, data);
+ }
+}
+
+#else
+// ====== This is the version without real timing =======
+
+READ8Z_MEMBER( ti_speech_synthesizer_device::readz )
+{
+ if ((offset & m_select_mask)==m_select_value)
+ {
+ device_adjust_icount(machine().device("maincpu"),-(18+3)); /* this is just a minimum, it can be more */
+ *value = m_vsp->read(space, offset, 0xff) & 0xff;
+ if (VERBOSE>4) LOG("spchsyn: read value = %02x\n", *value);
+ }
+}
+
+/*
+ Memory write
+*/
+WRITE8_MEMBER( ti_speech_synthesizer_device::write )
+{
+ if ((offset & m_select_mask)==(m_select_value | 0x0400))
+ {
+ device_adjust_icount(machine().device("maincpu"),-(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())
+ {
+ attotime time_to_ready = attotime::from_double(m_vsp->time_to_ready());
+ int cycles_to_ready = machine().device<cpu_device>("maincpu")->attotime_to_cycles(time_to_ready);
+ if (VERBOSE>8) LOG("spchsyn: time to ready: %f -> %d\n", time_to_ready.as_double(), (int) cycles_to_ready);
+
+ device_adjust_icount(machine().device("maincpu"),-cycles_to_ready);
+ machine().scheduler().timer_set(attotime::zero, FUNC_NULL);
+ }
+ if (VERBOSE>4) LOG("spchsyn: write value = %02x\n", data);
+ m_vsp->write(space, offset, data);
+ }
+}
+#endif
+
+/****************************************************************************
+ Callbacks from TMS5220
+*****************************************************************************/
+/*
+ Read 'count' bits serially from speech ROM. The offset is used as the count.
+*/
+READ8_MEMBER( ti_speech_synthesizer_device::spchrom_read )
+{
+ int val;
+ int count = offset;
+
+ if (m_load_pointer != 0)
+ { // first read after load address is ignored
+ m_load_pointer = 0;
+ count--;
+ }
+
+ if (m_sprom_address < m_sprom_length)
+ {
+ if (count < m_rombits_count)
+ {
+ m_rombits_count -= count;
+ val = (m_speechrom[m_sprom_address] >> m_rombits_count) & (0xFF >> (8 - count));
+ }
+ else
+ {
+ val = ((int)m_speechrom[m_sprom_address]) << 8;
+
+ m_sprom_address = (m_sprom_address + 1) & TMS5220_ADDRESS_MASK;
+
+ if (m_sprom_address < m_sprom_length)
+ val |= m_speechrom[m_sprom_address];
+
+ m_rombits_count += 8 - count;
+
+ val = (val >> m_rombits_count) & (0xFF >> (8 - count));
+ }
+ }
+ else
+ val = 0;
+
+ return val;
+}
+
+/*
+ Write an address nibble to speech ROM. The address nibble is in the data,
+ the offset is ignored.
+*/
+WRITE8_MEMBER( ti_speech_synthesizer_device::spchrom_load_address )
+{
+ // tms5220 data sheet says that if we load only one 4-bit nibble, it won't work.
+ // This code does not care about this.
+ m_sprom_address = ((m_sprom_address & ~(0xf << m_load_pointer))
+ | (((unsigned long) (data & 0xf)) << m_load_pointer) ) & TMS5220_ADDRESS_MASK;
+ m_load_pointer += 4;
+ m_rombits_count = 8;
+}
+
+/*
+ Perform a read and branch command. We do not use the offset or data parameter.
+*/
+WRITE8_MEMBER( ti_speech_synthesizer_device::spchrom_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_sprom_address < m_sprom_length-1)
+ m_sprom_address = (m_sprom_address & 0x3c000UL)
+ | (((((unsigned long) m_speechrom[m_sprom_address]) << 8)
+ | m_speechrom[m_sprom_address+1]) & 0x3fffUL);
+ else if (m_sprom_address == m_sprom_length-1)
+ m_sprom_address = (m_sprom_address & 0x3c000UL)
+ | ((((unsigned long) m_speechrom[m_sprom_address]) << 8) & 0x3fffUL);
+ else
+ m_sprom_address = (m_sprom_address & 0x3c000UL);
+
+ m_rombits_count = 8;
+}
+
+/****************************************************************************/
+
+/*
+ Callback interface instance
+*/
+static const tms52xx_config ti99_4x_tms5200interface =
+{
+ DEVCB_NULL, // no IRQ callback
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ti_speech_synthesizer_device, speech_ready),
+
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ti_speech_synthesizer_device, spchrom_read), // speech ROM read handler
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ti_speech_synthesizer_device, spchrom_load_address), // speech ROM load address handler
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ti_speech_synthesizer_device, spchrom_read_and_branch) // speech ROM read and branch handler
+};
+
+/****************************************************************************/
+
+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 REAL_TIMING
+ // Need to do that here (see explanations above)
+ if (state==0)
+ {
+ m_vsp->rsq_w(TRUE);
+ m_vsp->wsq_w(TRUE);
+ }
+#endif
+}
+
+void ti_speech_synthesizer_device::device_start()
+{
+}
+
+void ti_speech_synthesizer_device::device_config_complete()
+{
+ m_vsp = subdevice<tmc0285n_device>("speechsyn");
+}
+
+void ti_speech_synthesizer_device::device_reset()
+{
+ m_speechrom = memregion(SPEECHROM_TAG)->base();
+ m_sprom_length = memregion(SPEECHROM_TAG)->bytes();
+ m_sprom_address = 0;
+ m_load_pointer = 0;
+ m_rombits_count = 0;
+
+ if (m_genmod)
+ {
+ m_select_mask = 0x1ffc01;
+ m_select_value = 0x179000;
+ }
+ else
+ {
+ m_select_mask = 0x7fc01;
+ m_select_value = 0x79000;
+ }
+}
+
+MACHINE_CONFIG_FRAGMENT( ti99_speech )
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+ MCFG_SOUND_ADD("speechsyn", TMC0285N, 640000L)
+ MCFG_SOUND_CONFIG(ti99_4x_tms5200interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+MACHINE_CONFIG_END
+
+ROM_START( ti99_speech )
+ ROM_REGION(0x8000, SPEECHROM_TAG, 0)
+ ROM_LOAD_OPTIONAL("spchrom.bin", 0x0000, 0x8000, CRC(58b155f7) SHA1(382292295c00dff348d7e17c5ce4da12a1d87763)) /* system speech ROM */
+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<ti_speech_synthesizer_device>;
diff --git a/src/mess/machine/ti99/spchsyn.h b/src/mess/machine/ti99/spchsyn.h
new file mode 100644
index 00000000000..695f61c8315
--- /dev/null
+++ b/src/mess/machine/ti99/spchsyn.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+
+ 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);
+
+ void crureadz(offs_t offset, UINT8 *value) { };
+ void cruwrite(offs_t offset, UINT8 value) { };
+
+ 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:
+ void device_start();
+ void device_reset(void);
+ const rom_entry *device_rom_region() const;
+ machine_config_constructor device_mconfig_additions() const;
+ void device_config_complete();
+
+private:
+ tmc0285n_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
+};
+
+#endif
diff --git a/src/mess/machine/ti99/speech8.c b/src/mess/machine/ti99/speech8.c
new file mode 100644
index 00000000000..0e725931b2e
--- /dev/null
+++ b/src/mess/machine/ti99/speech8.c
@@ -0,0 +1,261 @@
+/****************************************************************************
+
+ 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.
+
+ Michael Zapf
+ February 2012: Rewritten as class
+
+*****************************************************************************/
+
+#include "speech8.h"
+#include "sound/wave.h"
+
+#define TMS5220_ADDRESS_MASK 0x3FFFFUL /* 18-bit mask for tms5220 address */
+
+#define VERBOSE 1
+#define LOG logerror
+
+#define SPEECHSYN_TAG "speechsyn"
+#define SPEECHROM_TAG "speechrom"
+
+#define REAL_TIMING 0
+
+/*
+ For comments on real timing see ti99/spchsyn.c
+*/
+/****************************************************************************/
+
+ti998_spsyn_device::ti998_spsyn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+: bus8z_device(mconfig, TI99_SPEECH8, "TI-99/8 Speech synthesizer (onboard)", tag, owner, clock)
+{
+ m_shortname = "ti99_speech8";
+}
+
+/*
+ Memory read
+*/
+#if REAL_TIMING
+// ====== This is the version with real timing =======
+READ8Z_MEMBER( ti998_spsyn_device::readz )
+{
+ if ((offset & m_select_mask)==m_select_value)
+ {
+ m_vsp->wsq_w(TRUE);
+ m_vsp->rsq_w(FALSE);
+ *value = m_vsp->read(offset) & 0xff;
+ if (VERBOSE>4) LOG("speech8: read value = %02x\n", *value);
+ }
+}
+
+/*
+ Memory write
+*/
+WRITE8_MEMBER( ti998_spsyn_device::write )
+{
+ if ((offset & m_select_mask)==(m_select_value | 0x0400))
+ {
+ m_vsp->rsq_w(m_vsp, TRUE);
+ m_vsp->wsq_w(m_vsp, FALSE);
+ if (VERBOSE>4) LOG("speech8: write value = %02x\n", data);
+ m_vsp->write(offset, data);
+ }
+}
+
+#else
+// ====== This is the version without real timing =======
+
+READ8Z_MEMBER( ti998_spsyn_device::readz )
+{
+ if ((offset & m_select_mask)==m_select_value)
+ {
+ device_adjust_icount(machine().device("maincpu"),-(18+3)); /* this is just a minimum, it can be more */
+ *value = m_vsp->read(space, offset, 0xff) & 0xff;
+ if (VERBOSE>4) LOG("speech8: read value = %02x\n", *value);
+ }
+}
+
+/*
+ Memory write
+*/
+WRITE8_MEMBER( ti998_spsyn_device::write )
+{
+ if ((offset & m_select_mask)==(m_select_value | 0x0400))
+ {
+ device_adjust_icount(machine().device("maincpu"),-(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())
+ {
+ attotime time_to_ready = attotime::from_double(m_vsp->time_to_ready());
+ int cycles_to_ready = machine().device<cpu_device>("maincpu")->attotime_to_cycles(time_to_ready);
+ if (VERBOSE>8) LOG("speech8: time to ready: %f -> %d\n", time_to_ready.as_double(), (int) cycles_to_ready);
+
+ device_adjust_icount(machine().device("maincpu"),-cycles_to_ready);
+ machine().scheduler().timer_set(attotime::zero, FUNC_NULL);
+ }
+ if (VERBOSE>4) LOG("speech8: write value = %02x\n", data);
+ m_vsp->write(space, offset, data);
+ }
+}
+#endif
+
+/****************************************************************************
+ Callbacks from TMS5220
+*****************************************************************************/
+/*
+ Read 'count' bits serially from speech ROM
+*/
+READ8_MEMBER( ti998_spsyn_device::spchrom_read )
+{
+ int val;
+ int count = offset;
+
+ if (m_load_pointer != 0)
+ { // first read after load address is ignored
+ m_load_pointer = 0;
+ count--;
+ }
+
+ if (m_sprom_address < m_sprom_length)
+ {
+ if (count < m_rombits_count)
+ {
+ m_rombits_count -= count;
+ val = (m_speechrom[m_sprom_address] >> m_rombits_count) & (0xFF >> (8 - count));
+ }
+ else
+ {
+ val = ((int)m_speechrom[m_sprom_address]) << 8;
+
+ m_sprom_address = (m_sprom_address + 1) & TMS5220_ADDRESS_MASK;
+
+ if (m_sprom_address < m_sprom_length)
+ val |= m_speechrom[m_sprom_address];
+
+ m_rombits_count += 8 - count;
+
+ val = (val >> m_rombits_count) & (0xFF >> (8 - count));
+ }
+ }
+ else
+ val = 0;
+
+ return val;
+}
+
+/*
+ Write an address nibble to speech ROM
+*/
+WRITE8_MEMBER( ti998_spsyn_device::spchrom_load_address )
+{
+ // tms5220 data sheet says that if we load only one 4-bit nibble, it won't work.
+ // This code does not care about this.
+ m_sprom_address = ((m_sprom_address & ~(0xf << m_load_pointer))
+ | (((unsigned long) (data & 0xf)) << m_load_pointer) ) & TMS5220_ADDRESS_MASK;
+ m_load_pointer += 4;
+ m_rombits_count = 8;
+}
+
+/*
+ Perform a read and branch command
+*/
+WRITE8_MEMBER( ti998_spsyn_device::spchrom_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_sprom_address < m_sprom_length-1)
+ m_sprom_address = (m_sprom_address & 0x3c000UL)
+ | (((((unsigned long) m_speechrom[m_sprom_address]) << 8)
+ | m_speechrom[m_sprom_address+1]) & 0x3fffUL);
+ else if (m_sprom_address == m_sprom_length-1)
+ m_sprom_address = (m_sprom_address & 0x3c000UL)
+ | ((((unsigned long) m_speechrom[m_sprom_address]) << 8) & 0x3fffUL);
+ else
+ m_sprom_address = (m_sprom_address & 0x3c000UL);
+
+ m_rombits_count = 8;
+}
+
+/*****************************************************************************/
+/*
+ Callback interface instance
+*/
+static const tms52xx_config ti99_8_tms5200interface =
+{
+ DEVCB_NULL, // no IRQ callback
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ti998_spsyn_device, speech8_ready),
+
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ti998_spsyn_device, spchrom_read), // speech ROM read handler
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ti998_spsyn_device, spchrom_load_address), // speech ROM load address handler
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ti998_spsyn_device, spchrom_read_and_branch) // speech ROM read and branch handler
+};
+
+/**************************************************************************/
+
+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 (VERBOSE>5) LOG("spchsyn: READY = %d\n", (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()
+{
+ const speech8_config *conf = reinterpret_cast<const speech8_config *>(static_config());
+ m_ready.resolve(conf->ready, *this);
+ m_vsp = subdevice<tms5220n_device>(SPEECHSYN_TAG);
+}
+
+void ti998_spsyn_device::device_reset()
+{
+ m_speechrom = memregion(SPEECHROM_TAG)->base();
+ m_sprom_length = memregion(SPEECHROM_TAG)->bytes();
+ m_sprom_address = 0;
+ m_load_pointer = 0;
+ m_rombits_count = 0;
+
+ m_select_mask = 0xfc01;
+ m_select_value = 0x9000;
+ if (VERBOSE>4) LOG("speech8: reset\n");
+}
+
+// Unlike the TI-99/4A, the 99/8 uses the TMS5220
+MACHINE_CONFIG_FRAGMENT( ti998_speech )
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+ MCFG_SOUND_ADD(SPEECHSYN_TAG, TMS5220N, 640000L)
+ MCFG_SOUND_CONFIG(ti99_8_tms5200interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+MACHINE_CONFIG_END
+
+ROM_START( ti998_speech )
+ ROM_REGION(0x8000, SPEECHROM_TAG, 0)
+ ROM_LOAD_OPTIONAL("spchrom.bin", 0x0000, 0x8000, BAD_DUMP CRC(58b155f7) SHA1(382292295c00dff348d7e17c5ce4da12a1d87763)) /* system speech ROM */
+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 TI99_SPEECH8 = &device_creator<ti998_spsyn_device>;
+
diff --git a/src/mess/machine/ti99/speech8.h b/src/mess/machine/ti99/speech8.h
new file mode 100644
index 00000000000..1b0ab35d712
--- /dev/null
+++ b/src/mess/machine/ti99/speech8.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+
+ TI-99/8 Speech Synthesizer
+ See speech8.c for documentation
+
+ Michael Zapf
+ October 2010
+ February 2012: Rewritten as class
+
+*****************************************************************************/
+
+#ifndef __TISPEECH8__
+#define __TISPEECH8__
+
+#include "emu.h"
+#include "ti99defs.h"
+#include "sound/tms5220.h"
+
+extern const device_type TI99_SPEECH8;
+
+#define SPEECH8_CONFIG(name) \
+ const speech8_config(name) =
+
+typedef struct _speech8_config
+{
+ devcb_write_line ready;
+} speech8_config;
+
+
+class ti998_spsyn_device : public bus8z_device
+{
+public:
+ ti998_spsyn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ DECLARE_READ8Z_MEMBER(readz);
+ DECLARE_WRITE8_MEMBER(write);
+
+ void crureadz(offs_t offset, UINT8 *value) { };
+ void cruwrite(offs_t offset, UINT8 value) { };
+
+ DECLARE_WRITE_LINE_MEMBER( speech8_ready );
+
+ DECLARE_READ8_MEMBER( spchrom_read );
+ DECLARE_WRITE8_MEMBER( spchrom_load_address );
+ DECLARE_WRITE8_MEMBER( spchrom_read_and_branch );
+
+ int m_select_mask;
+ int m_select_value;
+
+protected:
+ void device_start();
+ void device_reset(void);
+ const rom_entry *device_rom_region() const;
+ machine_config_constructor device_mconfig_additions() const;
+
+private:
+ tms5220n_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_resolved_write_line m_ready;
+};
+
+#define MCFG_TISPEECH8_ADD(_tag, _conf) \
+ MCFG_DEVICE_ADD(_tag, TI99_SPEECH8, 0) \
+ MCFG_DEVICE_CONFIG(_conf)
+
+#endif
diff --git a/src/mess/machine/ti99/ti32kmem.c b/src/mess/machine/ti99/ti32kmem.c
new file mode 100644
index 00000000000..e66a3b066d7
--- /dev/null
+++ b/src/mess/machine/ti99/ti32kmem.c
@@ -0,0 +1,110 @@
+/****************************************************************************
+
+ 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 "ti32kmem.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)
+{
+ m_shortname = "ti99_32k";
+}
+
+READ8Z_MEMBER(ti_32k_expcard_device::readz)
+{
+ switch((offset & 0xe000)>>13)
+ {
+ case 1:
+ *value = m_ram_ptr[offset & 0x1fff];
+ break;
+ case 5:
+ *value = m_ram_ptr[(offset & 0x1fff) | 0x2000];
+ break;
+ case 6:
+ *value = m_ram_ptr[(offset & 0x1fff) | 0x4000];
+ break;
+ case 7:
+ *value = m_ram_ptr[(offset & 0x1fff) | 0x6000];
+ break;
+ default:
+ break;
+ }
+}
+
+WRITE8_MEMBER(ti_32k_expcard_device::write)
+{
+ switch((offset & 0xe000)>>13)
+ {
+ case 1:
+ m_ram_ptr[offset & 0x1fff] = data;
+ break;
+ case 5:
+ m_ram_ptr[(offset & 0x1fff) | 0x2000] = data;
+ break;
+ case 6:
+ m_ram_ptr[(offset & 0x1fff) | 0x4000] = data;
+ break;
+ case 7:
+ m_ram_ptr[(offset & 0x1fff) | 0x6000] = data;
+ break;
+ default:
+ break;
+ }
+}
+
+/*
+ 32K memory expansion does not have a CRU interface
+*/
+void ti_32k_expcard_device::crureadz(offs_t offset, UINT8 *value)
+{
+ return;
+}
+
+void ti_32k_expcard_device::cruwrite(offs_t offset, UINT8 value)
+{
+ return;
+}
+
+void ti_32k_expcard_device::device_start(void)
+{
+ m_ram_ptr = memregion(RAMREGION)->base();
+ m_cru_base = 0;
+}
+
+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<ti_32k_expcard_device>;
+
diff --git a/src/mess/machine/ti99/ti32kmem.h b/src/mess/machine/ti99/ti32kmem.h
new file mode 100644
index 00000000000..0082ad8bec6
--- /dev/null
+++ b/src/mess/machine/ti99/ti32kmem.h
@@ -0,0 +1,36 @@
+/****************************************************************************
+
+ TI-99 32K memory expansion
+ See ti32kmem.c for documentation
+
+ Michael Zapf
+
+ February 2012: Rewritten as class
+
+*****************************************************************************/
+
+#ifndef __TI32K__
+#define __TI32K__
+
+#include "ti99defs.h"
+
+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);
+
+ void crureadz(offs_t offset, UINT8 *value);
+ void cruwrite(offs_t offset, UINT8 value);
+
+protected:
+ void device_start();
+ const rom_entry *device_rom_region() const;
+private:
+ UINT8* m_ram_ptr;
+};
+
+#endif
diff --git a/src/mess/machine/ti99/ti99_hd.c b/src/mess/machine/ti99/ti99_hd.c
new file mode 100644
index 00000000000..336017ef438
--- /dev/null
+++ b/src/mess/machine/ti99/ti99_hd.c
@@ -0,0 +1,504 @@
+/*************************************************************************
+
+ Hard disk support
+
+ This device wraps the plain image device as that device does not allow
+ for internal states (like head position)
+ The plain device is a subdevice ("drive") of this device, so we
+ get names like "mfmhd0:drive"
+
+ Michael Zapf
+ April 2010
+ February 2012: Rewritten as class
+
+**************************************************************************/
+
+#include "emu.h"
+#include "formats/imageutl.h"
+#include "harddisk.h"
+#include "machine/smc92x4.h"
+
+#include "ti99_hd.h"
+
+#define TI99HD_BLOCKNOTFOUND -1
+
+#define LOG logerror
+#define VERBOSE 0
+
+#define GAP1 16
+#define GAP2 8
+#define GAP3 15
+#define GAP4 340
+#define SYNC 13
+
+mfm_harddisk_device::mfm_harddisk_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+: device_t(mconfig, TI99_MFMHD, "MFM Harddisk", tag, owner, clock)
+{
+}
+
+/*
+ Calculate the ident byte from the cylinder. The specification does not
+ define idents beyond cylinder 1023, but formatting programs seem to
+ continue with 0xfd for cylinders between 1024 and 2047.
+*/
+UINT8 mfm_harddisk_device::cylinder_to_ident(int cylinder)
+{
+ if (cylinder < 256) return 0xfe;
+ if (cylinder < 512) return 0xff;
+ if (cylinder < 768) return 0xfc;
+ if (cylinder < 1024) return 0xfd;
+ return 0xfd;
+}
+
+/*
+ Returns the linear sector number, given the CHS data.
+*/
+bool mfm_harddisk_device::harddisk_chs_to_lba(hard_disk_file *hdfile, int cylinder, int head, int sector, UINT32 *lba)
+{
+ const hard_disk_info *info;
+
+ if ( hdfile != NULL)
+ {
+ info = hard_disk_get_info(hdfile);
+
+ if ( (cylinder >= info->cylinders) ||
+ (head >= info->heads) ||
+ (sector >= info->sectors))
+ return false;
+
+ *lba = (cylinder * info->heads + head)
+ * info->sectors
+ + sector;
+ return true;
+ }
+ return false;
+}
+
+/* Accessor functions */
+void mfm_harddisk_device::read_sector(int cylinder, int head, int sector, UINT8 *buf)
+{
+ UINT32 lba;
+ if (VERBOSE>5) LOG("ti99_hd: read_sector(%d, %d, %d)\n", cylinder, head, sector);
+ hard_disk_file *file = m_drive->get_hard_disk_file();
+
+ if (cylinder != m_current_cylinder)
+ {
+ return;
+ }
+
+ if (file==NULL)
+ {
+ m_status &= ~MFMHD_READY;
+ return;
+ }
+
+ if (!harddisk_chs_to_lba(file, cylinder, head, sector, &lba))
+ {
+ m_status &= ~MFMHD_READY;
+ return;
+ }
+
+ if (!hard_disk_read(file, lba, buf))
+ {
+ m_status &= ~MFMHD_READY;
+ return;
+ }
+ /* printf("ti99_hd read sector c=%04d h=%02d s=%02d\n", cylinder, head, sector); */
+ m_status |= MFMHD_READY;
+}
+
+void mfm_harddisk_device::write_sector(int cylinder, int head, int sector, UINT8 *buf)
+{
+ UINT32 lba;
+ if (VERBOSE>5) LOG("ti99_hd: write_sector(%d, %d, %d)\n", cylinder, head, sector);
+ hard_disk_file *file = m_drive->get_hard_disk_file();
+
+ if (file==NULL)
+ {
+ m_status &= ~MFMHD_READY;
+ return;
+ }
+
+ if (!harddisk_chs_to_lba(file, cylinder, head, sector, &lba))
+ {
+ m_status &= ~MFMHD_READY;
+ m_status |= MFMHD_WRFAULT;
+ return;
+ }
+
+ if (!hard_disk_write(file, lba, buf))
+ {
+ m_status &= ~MFMHD_READY;
+ m_status |= MFMHD_WRFAULT;
+ return;
+ }
+
+ m_status |= MFMHD_READY;
+}
+
+/*
+ Searches a block containing number * byte, starting at the given
+ position. Returns the position of the first byte of the block.
+*/
+int mfm_harddisk_device::find_block(const UINT8 *buffer, int start, int stop, UINT8 byte, size_t number)
+{
+ int i = start;
+ size_t current = number;
+ while (i < stop && current > 0)
+ {
+ if (buffer[i++] != byte)
+ {
+ current = number;
+ }
+ else
+ {
+ current--;
+ }
+ }
+ if (current==0)
+ {
+ return i - number;
+ }
+ else
+ return TI99HD_BLOCKNOTFOUND;
+}
+
+int mfm_harddisk_device::get_track_length()
+{
+ int count;
+ int size;
+ hard_disk_file *file = m_drive->get_hard_disk_file();
+ const hard_disk_info *info;
+
+ if (file==NULL) return 0;
+ info = hard_disk_get_info(file);
+
+ count = info->sectors;
+ size = info->sectorbytes/128;
+ return GAP1 + count*(SYNC+12+GAP2+SYNC+size*128+GAP3)+GAP4;
+}
+
+/*
+ Reads a complete track. We have to rebuild the gaps. This is basically
+ done in the same way as in the SDF format in ti99_dsk.
+
+ WARNING: This function is untested! We need to create a suitable
+ application program for the TI which makes use of it.
+*/
+void mfm_harddisk_device::read_track(int head, UINT8 *trackdata)
+{
+ /* We assume an interleave of 3 for 32 sectors. */
+ int step = 3;
+ UINT32 lba;
+ int i;
+
+ int size;
+ int position = 0;
+ int sector;
+ int crc;
+ int count;
+
+ const hard_disk_info *info;
+ hard_disk_file *file = m_drive->get_hard_disk_file();
+
+ if (file==NULL)
+ {
+ m_status &= ~MFMHD_READY;
+ return;
+ }
+
+ info = hard_disk_get_info(file);
+
+ count = info->sectors;
+ size = info->sectorbytes/128;
+
+ /* Write lead-in. */
+ memset(trackdata, 0x4e, GAP1);
+
+ position += GAP1;
+ for (i=0; i < count; i++)
+ {
+ sector = (i*step) % info->sectors;
+ memset(&trackdata[position], 0x00, SYNC);
+ position += SYNC;
+
+ /* Write sync */
+ trackdata[position++] = 0xa1;
+
+ /* Write IDAM */
+ trackdata[position++] = cylinder_to_ident(m_current_cylinder);
+ trackdata[position++] = m_current_cylinder;
+ trackdata[position++] = head;
+ trackdata[position++] = sector;
+ trackdata[position++] = (size==1)? 0x00 : (0x01 << (size-1));
+
+ /* Set CRC16 */
+ crc = ccitt_crc16(0xffff, &trackdata[position-5], 5);
+ trackdata[position++] = (crc>>8)&0xff;
+ trackdata[position++] = crc & 0xff;
+
+ /* Write Gap2 */
+ memset(&trackdata[position], 0x4e, GAP2);
+ position += GAP2;
+
+ /* Write sync */
+ memset(&trackdata[position], 0x00, SYNC);
+ position += SYNC;
+ trackdata[position++] = 0xa1;
+
+ /* Write DAM */
+ trackdata[position++] = 0xfb;
+
+ /* Locate the sector content in the image and load it. */
+
+ if (!harddisk_chs_to_lba(file, m_current_cylinder, head, sector, &lba))
+ {
+ m_status &= ~MFMHD_READY;
+ return;
+ }
+
+ if (!hard_disk_read(file, lba, &trackdata[position]))
+ {
+ m_status &= ~MFMHD_READY;
+ return;
+ }
+
+ position += info->sectorbytes;
+
+ /* Set CRC16. Includes the address mark. */
+ crc = ccitt_crc16(0xffff, &trackdata[position-size-1], size+1);
+ trackdata[position++] = (crc>>8)&0xff;
+ trackdata[position++] = crc & 0xff;
+
+ /* Write remaining 3 bytes which would have been used for ECC. */
+ memset(&trackdata[position], 0x00, 3);
+ position += 3;
+
+ /* Write Gap3 */
+ memset(&trackdata[position], 0x4e, GAP3);
+ position += GAP3;
+ }
+ /* Write Gap 4 */
+ memset(&trackdata[position], 0x4e, GAP4);
+ position += GAP4;
+
+ m_status |= MFMHD_READY;
+}
+
+/*
+ Writes a track to the image. We need to isolate the sector contents.
+ This is basically done in the same way as in the SDF format in ti99_dsk.
+*/
+void mfm_harddisk_device::write_track(int head, UINT8 *track_image, int data_count)
+{
+ int current_pos = 0;
+ bool found;
+ // UINT8 wident;
+ UINT8 whead = 0, wsector = 0;
+ // UINT8 wsize;
+ UINT16 wcyl = 0;
+ int state;
+
+ /* Only search in the first 100 bytes for the start. */
+
+ UINT32 lba;
+ hard_disk_file *file = m_drive->get_hard_disk_file();
+
+ /* printf("ti99_hd write track c=%d h=%d\n", m_current_cylinder, head); */
+
+ if (file==NULL)
+ {
+ m_status &= ~MFMHD_READY;
+ return;
+ }
+
+ current_pos = find_block(track_image, 0, 100, 0x4e, GAP1);
+
+ // In case of defect formats, we continue as far as possible. This
+ // may lead to sectors not being written. */
+ if (current_pos==TI99HD_BLOCKNOTFOUND)
+ {
+ logerror("ti99_hd error: write track: Cannot find GAP1 for cylinder %d, head %d.\n", m_current_cylinder, head);
+ /* What now? The track data are illegal, so we refuse to continue. */
+ m_status |= MFMHD_WRFAULT;
+ return;
+ }
+
+ /* Get behind GAP1 */
+ current_pos += GAP1;
+ found = false;
+
+ while (current_pos < data_count)
+ {
+ /* We must find the address block to determine the sector. */
+ int new_pos = find_block(track_image, current_pos, data_count, 0x00, SYNC);
+ if (new_pos==TI99HD_BLOCKNOTFOUND)
+ {
+ /* Forget about the rest; we're done. */
+ if (found) break; /* we were already successful, so all ok */
+ logerror("ti99_hd error: write track: Cannot find sync for track %d, head %d.\n", m_current_cylinder, head);
+ m_status |= MFMHD_WRFAULT;
+ return;
+ }
+ found = true;
+
+ new_pos = new_pos + SYNC; /* skip sync bytes */
+
+ if (track_image[new_pos]==0xa1)
+ {
+ /* IDAM found. */
+ current_pos = new_pos + 1;
+ // wident = track_image[current_pos]; // unused
+ wcyl = track_image[current_pos+1] + ((track_image[current_pos+2]&0x70)<<4);
+ whead = track_image[current_pos+2]&0x0f;
+ wsector = track_image[current_pos+3];
+ // wsize = track_image[current_pos+4]; // unused
+
+ if (wcyl == m_current_cylinder && whead == head)
+ {
+ if (!harddisk_chs_to_lba(file, wcyl, whead, wsector, &lba))
+ {
+ m_status |= MFMHD_WRFAULT;
+ return;
+ }
+
+ /* Skip to the sector content. */
+ new_pos = find_block(track_image, current_pos, data_count, 0x00, SYNC);
+ current_pos = new_pos + SYNC;
+ if (track_image[current_pos]==0xa1)
+ {
+ current_pos += 2;
+ state = hard_disk_write(file, lba, track_image+current_pos);
+ if (state==0)
+ {
+ logerror("ti99_hd error: write track: Write error during formatting cylinder %d, head %d\n", wcyl, whead);
+ m_status |= MFMHD_WRFAULT;
+ return;
+ }
+ current_pos = current_pos+256+2; /* Skip contents and CRC */
+ }
+ else
+ {
+ logerror("ti99_hd error: write track: Cannot find DAM for cylinder %d, head %d, sector %d.\n", wcyl, whead, wsector);
+ m_status |= MFMHD_WRFAULT;
+ return;
+ }
+ }
+ else
+ {
+ logerror("ti99_hd error: write track: Cylinder/head mismatch. Drive is on cyl=%d, head=%d, track data say cyl=%d, head=%d\n", m_current_cylinder, head, wcyl, whead);
+ m_status |= MFMHD_WRFAULT;
+ }
+ }
+ else
+ {
+ logerror("ti99_hd error: write track: Invalid track image for cyl=%d, head=%d. Cannot find any IDAM in track data.\n", m_current_cylinder, head);
+ m_status |= MFMHD_WRFAULT;
+ return;
+ }
+ }
+}
+
+UINT8 mfm_harddisk_device::get_status()
+{
+ UINT8 status = 0;
+ hard_disk_file *file = m_drive->get_hard_disk_file();
+ if (file!=NULL)
+ status |= MFMHD_READY;
+
+ if (m_current_cylinder==0)
+ status |= MFMHD_TRACK00;
+
+ if (!m_seeking)
+ status |= MFMHD_SEEKCOMP;
+
+ if (m_id_index == 0)
+ status |= MFMHD_INDEX;
+
+ m_status = status;
+ if (VERBOSE>5) LOG("ti99_hd: request status reply = %02x\n", status);
+ return status;
+}
+
+void mfm_harddisk_device::seek(int direction)
+{
+ const hard_disk_info *info;
+ hard_disk_file *file = m_drive->get_hard_disk_file();
+
+ if (file==NULL) return;
+
+ info = hard_disk_get_info(file);
+
+ m_seeking = true;
+
+ if (direction<0)
+ {
+ if (m_current_cylinder>0)
+ m_current_cylinder--;
+ }
+ else
+ {
+ if (m_current_cylinder < info->cylinders)
+ m_current_cylinder++;
+ }
+
+ // TODO: Requires timer
+
+ m_seeking = false;
+}
+
+void mfm_harddisk_device::get_next_id(int head, chrn_id_hd *id)
+{
+ const hard_disk_info *info;
+ hard_disk_file *file;
+ int interleave = 3;
+
+ file = m_drive->get_hard_disk_file();
+
+ if (file==NULL)
+ {
+ m_status &= ~MFMHD_READY;
+ return;
+ }
+
+ info = hard_disk_get_info(file);
+
+ m_current_head = head;
+
+ /* TODO: implement an interleave suitable for the number of sectors in the track. */
+ m_id_index = (m_id_index + interleave) % info->sectors;
+
+ /* build a new info block. */
+ id->C = m_current_cylinder;
+ id->H = m_current_head;
+ id->R = m_id_index;
+ id->N = 1;
+ id->data_id = m_id_index;
+ id->flags = 0;
+}
+
+void mfm_harddisk_device::device_start()
+{
+ m_current_cylinder = 0;
+ m_current_head = 0;
+}
+
+void mfm_harddisk_device::device_reset()
+{
+ m_drive = static_cast<harddisk_image_device *>(subdevice("drive"));
+ m_seeking = false;
+ m_status = 0;
+ m_id_index = 0;
+}
+
+MACHINE_CONFIG_FRAGMENT( mfmhd )
+ MCFG_HARDDISK_ADD("drive")
+MACHINE_CONFIG_END
+
+machine_config_constructor mfm_harddisk_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( mfmhd );
+}
+
+const device_type TI99_MFMHD = &device_creator<mfm_harddisk_device>;
+
diff --git a/src/mess/machine/ti99/ti99_hd.h b/src/mess/machine/ti99/ti99_hd.h
new file mode 100644
index 00000000000..42ceaa892dc
--- /dev/null
+++ b/src/mess/machine/ti99/ti99_hd.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+
+ Hard disk support
+ See ti99_hd.c for documentation
+
+ Michael Zapf
+
+ February 2012: Rewritten as class
+
+*****************************************************************************/
+
+#ifndef __TI99_HD__
+#define __TI99_HD__
+
+#include "emu.h"
+#include "imagedev/harddriv.h"
+
+#define MFMHD_0 "mfmhd0"
+#define MFMHD_1 "mfmhd1"
+#define MFMHD_2 "mfmhd2"
+
+extern const device_type TI99_MFMHD;
+
+/*
+ Needed to adapt to higher cylinder numbers. Floppies do not have such
+ high numbers.
+*/
+typedef struct chrn_id_hd
+{
+ UINT16 C;
+ UINT8 H;
+ UINT8 R;
+ UINT8 N;
+ int data_id; // id for read/write data command
+ unsigned long flags;
+} chrn_id_hd;
+
+class mfm_harddisk_device : public device_t
+{
+public:
+ mfm_harddisk_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ void read_sector(int cylinder, int head, int sector, UINT8 *buf);
+ void write_sector(int cylinder, int head, int sector, UINT8 *buf);
+ void read_track(int head, UINT8 *buffer);
+ void write_track(int head, UINT8 *buffer, int data_count);
+ UINT8 get_status();
+ void seek(int direction);
+ void get_next_id(int head, chrn_id_hd *id);
+ int get_track_length();
+
+protected:
+ void device_start();
+ void device_reset();
+ machine_config_constructor device_mconfig_additions() const;
+
+private:
+ int find_block(const UINT8 *buffer, int start, int stop, UINT8 byte, size_t number);
+ UINT8 cylinder_to_ident(int cylinder);
+ bool harddisk_chs_to_lba(hard_disk_file *hdfile, int cylinder, int head, int sector, UINT32 *lba);
+
+ int m_current_cylinder;
+ int m_current_head;
+ bool m_seeking;
+ int m_status;
+ int m_id_index; /* position in track for seeking the sector; counts the sector number */
+
+ harddisk_image_device *m_drive;
+};
+
+class ide_harddisk_device : public device_t
+{
+public:
+ ide_harddisk_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+protected:
+ void device_start() { };
+ void device_reset() { };
+ machine_config_constructor device_mconfig_additions() const;
+};
+
+#define MCFG_MFMHD_3_DRIVES_ADD() \
+ MCFG_DEVICE_ADD(MFMHD_0, TI99_MFMHD, 0) \
+ MCFG_DEVICE_ADD(MFMHD_1, TI99_MFMHD, 0) \
+ MCFG_DEVICE_ADD(MFMHD_2, TI99_MFMHD, 0)
+
+#endif
+
diff --git a/src/mess/machine/ti99/ti99defs.h b/src/mess/machine/ti99/ti99defs.h
new file mode 100644
index 00000000000..01c82d6f481
--- /dev/null
+++ b/src/mess/machine/ti99/ti99defs.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+
+ 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 GROMFREQ 10700000.0/24
+
+// TI-99/8
+#define SRAM_TAG "sram8"
+#define DRAM_TAG "dram8"
+#define MAPPER_TAG "mapper"
+#define SPEECH_TAG "speech"
+
+// Geneve
+#define GKEYBOARD_TAG "gkeyboard"
+#define GMAPPER_TAG "gmapper"
+#define GMOUSE_TAG "gmouse"
+#define GCLOCK_TAG "mm58274c"
+
+#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)
+
+#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)
+ : device_t(mconfig, type, name, tag, owner, clock) { }
+ virtual DECLARE_READ8Z_MEMBER(readz) =0;
+ virtual DECLARE_WRITE8_MEMBER(write) =0;
+};
+
+class bus16z_device : device_t
+{
+public:
+ virtual DECLARE_READ16Z_MEMBER(read16z) =0;
+ virtual DECLARE_WRITE16_MEMBER(write16) =0;
+};
+
+/****************************************************************************
+ Constants
+****************************************************************************/
+
+enum
+{
+ GM_TURBO = 1,
+ GM_TIM = 2
+};
+
+enum
+{
+ GENEVE_098 = 0,
+ GENEVE_100 = 1
+};
+
+#endif
diff --git a/src/mess/machine/ti99/ti_fdc.c b/src/mess/machine/ti99/ti_fdc.c
new file mode 100644
index 00000000000..a5f199cba8c
--- /dev/null
+++ b/src/mess/machine/ti99/ti_fdc.c
@@ -0,0 +1,319 @@
+/****************************************************************************
+
+ 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 "machine/wd17xx.h"
+#include "formats/ti99_dsk.h"
+
+#define LOG logerror
+#define VERBOSE 1
+
+#define fdc_IRQ 1
+#define fdc_DRQ 2
+
+#define TI_FDC_TAG "ti_dssd_controller"
+
+#define FDC_TAG "wd1771"
+
+#define MOTOR_TIMER 1
+
+const wd17xx_interface ti_wd17xx_interface =
+{
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ti_fdc_device, intrq_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ti_fdc_device, drq_w),
+ { PFLOPPY_0, PFLOPPY_1, PFLOPPY_2, NULL }
+};
+
+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)
+{
+ m_shortname = "ti99_fdc";
+}
+
+/*
+ callback called at the end of DVENA pulse
+*/
+void ti_fdc_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ m_DVENA = CLEAR_LINE;
+ handle_hold();
+}
+
+READ8Z_MEMBER(ti_fdc_device::readz)
+{
+ if (m_selected)
+ {
+ if ((offset & m_select_mask)==m_select_value)
+ {
+ // only use the even addresses from 1ff0 to 1ff6.
+ // Note that data is inverted.
+ // 0101 1111 1111 0xx0
+ UINT8 reply = 0;
+
+ if ((offset & 0x1ff9)==0x1ff0)
+ {
+ reply = wd17xx_r(m_controller, (offset >> 1)&0x03);
+ }
+ else
+ {
+ reply = m_dsrrom[offset & 0x1fff];
+ }
+ *value = reply;
+ if (VERBOSE>5) LOG("ti_fdc: %04x -> %02x\n", offset & 0xffff, *value);
+ }
+ }
+}
+
+WRITE8_MEMBER(ti_fdc_device::write)
+{
+ if (m_selected)
+ {
+ if ((offset & m_select_mask)==m_select_value)
+ {
+ if (VERBOSE>5) LOG("ti_fdc: %04x <- %02x\n", offset & 0xffff, data);
+ // only use the even addresses from 1ff8 to 1ffe.
+ // Note that data is inverted.
+ // 0101 1111 1111 1xx0
+ if ((offset & 0x1ff9)==0x1ff8)
+ {
+ wd17xx_w(m_controller, (offset >> 1)&0x03, data);
+ }
+ }
+ }
+}
+
+/*
+ The CRU read handler.
+ bit 0: HLD pin
+ bit 1-3: drive n active
+ bit 4: 0: motor strobe on
+ bit 5: always 0
+ bit 6: always 1
+ bit 7: selected side
+*/
+void ti_fdc_device::crureadz(offs_t offset, UINT8 *value)
+{
+ if ((offset & 0xff00)==m_cru_base)
+ {
+ int addr = offset & 0x07;
+ UINT8 reply = 0;
+ if (addr == 0)
+ {
+ // deliver bits 0-7
+ // TODO: HLD pin
+ // The DVENA state is returned inverted
+ if (m_DVENA==ASSERT_LINE) reply |= ((m_DSEL)<<1);
+ else reply |= 0x10;
+ reply |= 0x40;
+ if (m_SIDSEL) reply |= 0x80;
+ }
+ *value = reply;
+ }
+}
+
+void ti_fdc_device::cruwrite(offs_t offset, UINT8 data)
+{
+ int drive, drivebit;
+
+ 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 (VERBOSE>4) LOG("ti_fdc: Map DSR = %d\n", m_selected);
+ break;
+ case 1:
+ /* Activate motor */
+ if (data && !m_strobe_motor)
+ { /* on rising edge, set motor_running for 4.23s */
+ m_DVENA = ASSERT_LINE;
+ handle_hold();
+ m_motor_on_timer->adjust(attotime::from_msec(4230));
+ }
+ m_strobe_motor = (data!=0);
+ 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
+ // This is not emulated and could cause the TI99 to lock up
+ m_hold = (data != 0);
+ handle_hold();
+ break;
+
+ case 3:
+ /* Load disk heads (HLT pin) (bit 3). Not implemented. */
+ break;
+
+ case 4:
+ case 5:
+ case 6:
+ /* Select drive X (bits 4-6) */
+ drive = bit-4; /* drive # (0-2) */
+ drivebit = 1<<drive;
+
+ if (data)
+ {
+ if ((m_DSEL & drivebit)!=0) /* select drive */
+ {
+ if (m_DSEL != 0)
+ LOG("ti_fdc: Multiple drives selected, %02x\n", m_DSEL);
+ m_DSEL |= drivebit;
+ wd17xx_set_drive(m_controller, drive);
+ /*wd17xx_set_side(DSKside);*/
+ }
+ }
+ else
+ m_DSEL &= ~drivebit;
+ break;
+
+ case 7:
+ /* Select side of disk (bit 7) */
+ m_SIDSEL = data;
+ wd17xx_set_side(m_controller, data);
+ break;
+ }
+ }
+}
+
+/*
+ Call this when the state of DSKhold or DRQ/IRQ or DVENA change
+
+ Emulation is faulty because the CPU is actually stopped in the midst of
+ instruction, at the end of the memory access
+
+ TODO: This has to be replaced by the proper READY handling that is already
+ prepared here. (Requires READY handling by the CPU.)
+*/
+void ti_fdc_device::handle_hold()
+{
+ line_state state;
+
+ if (m_hold && !m_DRQ && !m_IRQ && (m_DVENA==ASSERT_LINE))
+ state = ASSERT_LINE;
+ else
+ state = CLEAR_LINE;
+
+ m_slot->set_ready((state==CLEAR_LINE)? ASSERT_LINE : CLEAR_LINE);
+// cputag_set_input_line(machine(), "maincpu", INPUT_LINE_HALT, state);
+}
+
+/*
+ Resets the drive geometry. This is required because the heuristic of
+ the default implementation sets the drive geometry to the geometry
+ of the medium.
+*/
+void ti_fdc_device::set_geometry(device_t *drive, floppy_type_t type)
+{
+ // This assertion may fail when the names of the floppy devices change.
+ // Unfortunately, the wd17xx device assumes the floppy drives at root
+ // level, so we use an explicitly qualified tag. See peribox.h.
+ assert (drive!=NULL);
+ floppy_drive_set_geometry(drive, type);
+}
+
+void ti_fdc_device::set_all_geometries(floppy_type_t type)
+{
+ set_geometry(machine().device(PFLOPPY_0), type);
+ set_geometry(machine().device(PFLOPPY_1), type);
+ set_geometry(machine().device(PFLOPPY_2), type);
+}
+
+/*
+ Callback, called from the controller chip whenever DRQ/IRQ state change
+*/
+WRITE_LINE_MEMBER( ti_fdc_device::intrq_w )
+{
+ if (VERBOSE>8) LOG("ti_fdc: set irq = %02x\n", state);
+ m_IRQ = (state==ASSERT_LINE);
+ // Note that INTB is actually not used in the TI-99 family. But the
+ // controller asserts the line nevertheless, probably intended for
+ // use in another planned TI system
+ m_slot->set_intb(state);
+
+ handle_hold();
+}
+
+WRITE_LINE_MEMBER( ti_fdc_device::drq_w )
+{
+ if (VERBOSE>8) LOG("ti_fdc: set drq = %02x\n", state);
+ m_DRQ = (state == ASSERT_LINE);
+ handle_hold();
+}
+
+void ti_fdc_device::device_start(void)
+{
+ if (VERBOSE>5) LOG("ti_fdc: TI FDC start\n");
+ m_dsrrom = memregion(DSRROM)->base();
+ m_motor_on_timer = timer_alloc(MOTOR_TIMER);
+ m_controller = subdevice(FDC_TAG);
+
+ m_cru_base = 0x1100;
+}
+
+void ti_fdc_device::device_reset(void)
+{
+ if (VERBOSE>5) LOG("ti_fdc: TI FDC reset\n");
+ m_DSEL = 0;
+ m_SIDSEL = 0;
+ m_DVENA = CLEAR_LINE;
+ m_strobe_motor = false;
+ if (m_genmod)
+ {
+ m_select_mask = 0x1fe000;
+ m_select_value = 0x174000;
+ }
+ else
+ {
+ m_select_mask = 0x7e000;
+ m_select_value = 0x74000;
+ }
+ m_DRQ = false;
+ m_IRQ = false;
+ m_hold = false;
+ m_selected = false;
+
+ ti99_set_80_track_drives(FALSE);
+ floppy_type_t type = FLOPPY_STANDARD_5_25_DSDD_40;
+ set_all_geometries(type);
+}
+
+MACHINE_CONFIG_FRAGMENT( ti_fdc )
+ MCFG_FD1771_ADD(FDC_TAG, ti_wd17xx_interface )
+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<ti_fdc_device>;
+
diff --git a/src/mess/machine/ti99/ti_fdc.h b/src/mess/machine/ti99/ti_fdc.h
new file mode 100644
index 00000000000..f2cde94e548
--- /dev/null
+++ b/src/mess/machine/ti99/ti_fdc.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+
+ 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 "ti99defs.h"
+#include "imagedev/flopdrv.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_WRITE_LINE_MEMBER( intrq_w );
+ DECLARE_WRITE_LINE_MEMBER( drq_w );
+
+ void crureadz(offs_t offset, UINT8 *value);
+ void cruwrite(offs_t offset, UINT8 value);
+
+protected:
+ void device_start(void);
+ void device_reset(void);
+ const rom_entry *device_rom_region() const;
+ machine_config_constructor device_mconfig_additions() const;
+
+private:
+ void handle_hold(void);
+ void set_all_geometries(floppy_type_t type);
+ void set_geometry(device_t *drive, floppy_type_t type);
+ void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+
+ // Holds the status of the DRQ and IRQ lines.
+ bool m_DRQ, m_IRQ;
+
+ // When TRUE, keeps DVENA high.
+ bool m_strobe_motor;
+
+ // Signal DVENA. When TRUE, makes some drive turning.
+ line_state m_DVENA;
+
+ // When TRUE the CPU is halted while DRQ/IRQ are true.
+ bool m_hold;
+
+ // 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.
+ int 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.
+ device_t* m_controller;
+
+ // DSR ROM
+ UINT8* m_dsrrom;
+};
+
+#endif
+
diff --git a/src/mess/machine/ti99/ti_rs232.c b/src/mess/machine/ti99/ti_rs232.c
new file mode 100644
index 00000000000..eccf7ca5bc3
--- /dev/null
+++ b/src/mess/machine/ti99/ti_rs232.c
@@ -0,0 +1,1125 @@
+/****************************************************************************
+
+ 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)
+{
+ m_shortname = "ti99_rs232";
+}
+
+
+/**************************************************************************/
+/* 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),
+ 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),
+ 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
+ <name><number>, 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<ti_rs232_pio_device*>(owner());
+
+ int devnumber = get_index_from_tagname();
+ if (devnumber==0)
+ {
+ tms9902 = siblingdevice<tms9902_device>("tms9902_0");
+ // Turn on polling
+ tms9902->set_clock(true);
+ }
+ else if (devnumber==1)
+ {
+ tms9902 = siblingdevice<tms9902_device>("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_device>("tms9902_0");
+ // Turn off polling
+ tms9902->set_clock(false);
+ }
+ else if (devnumber==1)
+ {
+ tms9902 = siblingdevice<tms9902_device>("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<ti_rs232_pio_device*>(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<ti_rs232_pio_device*>(owner());
+
+ card->m_pio_writable = false;
+ card->m_pio_handshakein = true; /* receiver not ready */
+ card->m_pio_sparein = false;
+}
+
+/****************************************************************************/
+
+/*
+ CRU read
+*/
+void ti_rs232_pio_device::crureadz(offs_t offset, UINT8 *value)
+{
+ 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(*m_space, offset>>4, 0xff);
+ return;
+ }
+ if ((offset & 0x00c0)==0x0080)
+ {
+ *value = m_uart[1]->cruread(*m_space, offset>>1, 0xff);
+ return;
+ }
+ }
+}
+
+/*
+ CRU write
+*/
+void ti_rs232_pio_device::cruwrite(offs_t offset, UINT8 data)
+{
+ if ((offset & 0xff00)==m_cru_base)
+ {
+ if ((offset & 0x00c0)==0x0040)
+ {
+ m_uart[0]->cruwrite(*m_space, offset>>1, data, 0xff);
+ return;
+ }
+ if ((offset & 0x00c0)==0x0080)
+ {
+ m_uart[1]->cruwrite(*m_space, offset>>1, data, 0xff);
+ return;
+ }
+
+ device_image_interface *image = dynamic_cast<device_image_interface *>(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<device_image_interface *>(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;
+ int len = 0;
+
+ serial = dynamic_cast<device_image_interface *>(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)
+ {
+ len = serial->fread(&buffer, 1);
+ if (len==0) return;
+ }
+ 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<device_image_interface *>(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<device_image_interface *>(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<device_image_interface *>(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);
+}
+
+static const tms9902_interface tms9902_params0 =
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ti_rs232_pio_device, int0_callback), /* called when interrupt pin state changes */
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ti_rs232_pio_device, rcv0_callback), /* called when a character is received */
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ti_rs232_pio_device, xmit0_callback), /* called when a character is transmitted */
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ti_rs232_pio_device, ctrl0_callback)
+};
+
+static const tms9902_interface tms9902_params1 =
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ti_rs232_pio_device, int1_callback), /* called when interrupt pin state changes */
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ti_rs232_pio_device, rcv1_callback), /* called when a character is received */
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ti_rs232_pio_device, xmit1_callback), /* called when a character is transmitted */
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ti_rs232_pio_device, ctrl1_callback)
+};
+
+void ti_rs232_pio_device::device_start()
+{
+ m_dsrrom = memregion(DSRROM)->base();
+ m_uart[0] = subdevice<tms9902_device>("tms9902_0");
+ m_uart[1] = subdevice<tms9902_device>("tms9902_1");
+ m_serdev[0] = subdevice<ti_rs232_attached_device>("serdev0");
+ m_serdev[1] = subdevice<ti_rs232_attached_device>("serdev1");
+ m_piodev = subdevice<ti_pio_attached_device>("piodev");
+}
+
+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_pio_write = true;
+ m_recv_mode[0] = RECV_MODE_NORMAL;
+ m_recv_mode[1] = RECV_MODE_NORMAL;
+
+ if (m_genmod)
+ {
+ m_select_mask = 0x1fe000;
+ m_select_value = 0x174000;
+ }
+ else
+ {
+ m_select_mask = 0x7e000;
+ m_select_value = 0x74000;
+ }
+
+ m_space = machine().device("maincpu")->memory().space(AS_IO);
+ 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_TMS9902_ADD("tms9902_0", tms9902_params0, 3000000)
+ MCFG_TMS9902_ADD("tms9902_1", tms9902_params1, 3000000)
+ 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<ti_rs232_pio_device>;
+const device_type TI99_RS232_DEV = &device_creator<ti_rs232_attached_device>;
+const device_type TI99_PIO_DEV = &device_creator<ti_pio_attached_device>;
+
diff --git a/src/mess/machine/ti99/ti_rs232.h b/src/mess/machine/ti99/ti_rs232.h
new file mode 100644
index 00000000000..21180b1ceb4
--- /dev/null
+++ b/src/mess/machine/ti99/ti_rs232.h
@@ -0,0 +1,156 @@
+/****************************************************************************
+
+ 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 "ti99defs.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);
+
+ void crureadz(offs_t offset, UINT8 *value);
+ void cruwrite(offs_t offset, UINT8 data);
+
+ 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:
+ void device_start(void);
+ void device_reset(void);
+ const rom_entry *device_rom_region(void) const;
+ machine_config_constructor device_mconfig_additions() const;
+ 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);
+
+ tms9902_device* m_uart[2];
+ ti_rs232_attached_device* m_serdev[2];
+ ti_pio_attached_device* m_piodev;
+ address_space* m_space;
+ UINT8* m_dsrrom;
+
+ UINT8 m_signals[2]; // Latches the state of the output lines for UART0/UART1
+ 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:
+ void device_start(void);
+ bool call_load();
+ void call_unload();
+ 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:
+ void device_start(void);
+ bool call_load();
+ void call_unload();
+ void device_config_complete();
+};
+
+#endif
diff --git a/src/mess/machine/ti99/tn_ide.c b/src/mess/machine/ti99/tn_ide.c
new file mode 100644
index 00000000000..720f8689cd2
--- /dev/null
+++ b/src/mess/machine/ti99/tn_ide.c
@@ -0,0 +1,385 @@
+/****************************************************************************
+
+ 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 have been revised in
+ 2004.
+
+ The specs have been published in <http://www.nouspikel.com/ti99/ide.html>.
+
+ 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/idectrl.h"
+#include "tn_ide.h"
+#include "ti99_hd.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)
+{
+ m_shortname = "ti99_ide";
+}
+
+/*
+ CRU read
+*/
+void nouspikel_ide_interface_device::crureadz(offs_t offset, UINT8 *value)
+{
+ 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_ide_irq)
+ reply |= 1;
+ }
+ *value = reply;
+ }
+}
+
+/*
+ CRU write
+*/
+void nouspikel_ide_interface_device::cruwrite(offs_t offset, UINT8 data)
+{
+ 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_ide_irq);
+
+ if ((bit == 6) || (bit == 7))
+ if ((m_cru_register & cru_reg_int_en) && !(m_cru_register & cru_reg_reset))
+ m_ide->reset();
+ break;
+ }
+ }
+}
+
+/*
+ Memory read
+*/
+READ8Z_MEMBER(nouspikel_ide_interface_device::readz)
+{
+ UINT8 reply = 0;
+
+ 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().memory().first_space(),(addr & 0x1f) | 0x20);
+ else
+ /* RTC RAM read */
+ reply = m_rtc->xram_r(*machine().memory().first_space(),addr);
+ break;
+ case 1: /* RTC registers */
+ if (addr & 0x10)
+ /* register data */
+ reply = m_rtc->rtc_r(*machine().memory().first_space(),1);
+ else
+ /* register select */
+ reply = m_rtc->rtc_r(*machine().memory().first_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)) ? ide_bus_r(m_ide, 0, (addr >> 1) & 0x7) : 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)) ? ide_bus_r(m_ide, 1, (addr >> 1) & 0x7) : 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 (((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().memory().first_space(),(addr & 0x1f) | 0x20, data);
+ else
+ /* RTC RAM write */
+ m_rtc->xram_w(*machine().memory().first_space(),addr, data);
+ break;
+ case 1: /* RTC registers */
+ if (addr & 0x10)
+ /* register data */
+ m_rtc->rtc_w(*machine().memory().first_space(),1, data);
+ else
+ /* register select */
+ m_rtc->rtc_w(*machine().memory().first_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 */
+ ide_bus_w(m_ide, 0, (addr >> 1) & 0x7, m_output_latch);
+ }
+ 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 */
+ ide_bus_w(m_ide, 1, (addr >> 1) & 0x7, m_output_latch);
+ }
+ 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
+*/
+static void ide_interrupt_callback(device_t *device, int state)
+{
+ nouspikel_ide_interface_device *card = downcast<nouspikel_ide_interface_device *>(device->owner());
+ card->m_ide_irq = state;
+ if (card->m_cru_register & cru_reg_int_en)
+ card->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<rtc65271_device>("ide_rtc");
+ m_ide = subdevice("ide");
+
+ 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);
+}
+
+static const rtc65271_interface ide_rtc_cfg =
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, nouspikel_ide_interface_device, clock_interrupt_callback)
+};
+
+MACHINE_CONFIG_FRAGMENT( tn_ide )
+ MCFG_RTC65271_ADD( "ide_rtc", ide_rtc_cfg )
+ MCFG_IDE_CONTROLLER_ADD( "ide", ide_interrupt_callback, ide_image_devices, "hdd", NULL, false) // see idectrl.c
+// MCFG_IDE_CONTROLLER_REGIONS(":peribox:idehd0:drive", NULL)
+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<nouspikel_ide_interface_device>;
+
diff --git a/src/mess/machine/ti99/tn_ide.h b/src/mess/machine/ti99/tn_ide.h
new file mode 100644
index 00000000000..61eb24f9f23
--- /dev/null
+++ b/src/mess/machine/ti99/tn_ide.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+
+ 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 "ti99defs.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);
+
+ void crureadz(offs_t offset, UINT8 *value);
+ void cruwrite(offs_t offset, UINT8 value);
+
+ void do_inta(int state);
+ bool m_ide_irq;
+ int m_cru_register;
+
+ DECLARE_WRITE_LINE_MEMBER(clock_interrupt_callback);
+
+protected:
+ void device_start(void);
+ void device_reset(void);
+ const rom_entry *device_rom_region() const;
+ machine_config_constructor device_mconfig_additions() const;
+ ioport_constructor device_input_ports() const;
+
+private:
+ rtc65271_device* m_rtc;
+ device_t* m_ide;
+
+ 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/mess/machine/ti99/tn_usbsm.c b/src/mess/machine/ti99/tn_usbsm.c
new file mode 100644
index 00000000000..01e1fdbe338
--- /dev/null
+++ b/src/mess/machine/ti99/tn_usbsm.c
@@ -0,0 +1,344 @@
+/****************************************************************************
+
+ 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 <http://www.nouspikel.com/ti99/usb.html>.
+
+ 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"
+#include "machine/strata.h"
+
+#define BUFFER_TAG "ram"
+
+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)
+{
+ m_shortname = "ti99_usbsm";
+}
+
+/*
+ demultiplexed read in USB-SmartMedia DSR space
+*/
+UINT16 nouspikel_usb_smartmedia_device::usbsm_mem_16_r(offs_t offset)
+{
+ UINT16 reply = 0;
+
+ if (offset < 0x2800)
+ { /* 0x4000-0x4fff range */
+ if ((m_cru_register & IO_REGS_ENABLE) && (offset >= 0x27f8))
+ { /* SmartMedia interface */
+ if (offset == 0)
+ reply = m_smartmedia->data_r() << 8;
+ }
+ else
+ { /* FEEPROM */
+ if (!(m_cru_register & FEEPROM_WRITE_ENABLE))
+ reply = strataflash_16_r(m_strata, offset);
+ }
+ }
+ else
+ { /* 0x5000-0x5fff range */
+ if ((m_cru_register & IO_REGS_ENABLE) && (offset >= 0x2ff8))
+ { /* USB controller */
+ }
+ else
+ { /* SRAM */
+ reply = m_ram[m_sram_page*0x800+(offset-0x2800)];
+ }
+ }
+ return reply;
+}
+
+/*
+ demultiplexed write in USB-SmartMedia DSR space
+*/
+void nouspikel_usb_smartmedia_device::usbsm_mem_16_w(offs_t offset, UINT16 data)
+{
+ if (offset < 0x2800)
+ { /* 0x4000-0x4fff range */
+ if ((m_cru_register & IO_REGS_ENABLE) && (offset >= 0x27f8))
+ { /* SmartMedia interface */
+ switch (offset & 3)
+ {
+ case 0:
+ m_smartmedia->data_w(data >> 8);
+ break;
+ case 1:
+ m_smartmedia->address_w(data >> 8);
+ break;
+ case 2:
+ m_smartmedia->command_w(data >> 8);
+ break;
+ case 3:
+ /* bogus, don't use(?) */
+ break;
+ }
+ }
+ else
+ { /* FEEPROM */
+ if (m_cru_register & FEEPROM_WRITE_ENABLE)
+ strataflash_16_w(m_strata, offset, data);
+ }
+ }
+ else
+ { /* 0x5000-0x5fff range */
+ if ((m_cru_register & IO_REGS_ENABLE) && (offset >= 0x2ff8))
+ { /* USB controller */
+ }
+ else
+ { /* SRAM */
+ m_ram[m_sram_page*0x800+(offset-0x2800)] = data;
+ }
+ }
+}
+
+/*
+ CRU read
+*/
+void nouspikel_usb_smartmedia_device::crureadz(offs_t offset, UINT8 *value)
+{
+ 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
+*/
+void nouspikel_usb_smartmedia_device::cruwrite(offs_t offset, UINT8 data)
+{
+ 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 */
+ case 2: /* enable interrupts */
+ case 3: /* enable SmartMedia card */
+ case 4: /* enable FEEPROM writes (and disable reads) */
+ if (data)
+ m_cru_register |= 1 << bit;
+ else
+ m_cru_register &= ~ (1 << bit);
+ 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 (((offset & m_select_mask)==m_select_value) && m_selected)
+ {
+ if (m_tms9995_mode ? (!(offset & 1)) : (offset & 1))
+ { /* first read triggers 16-bit read cycle */
+ m_input_latch = usbsm_mem_16_r((offset >> 1)&0xffff);
+ }
+
+ /* 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 (((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 */
+ usbsm_mem_16_w((offset >> 1)&0xffff, m_output_latch);
+ }
+ }
+}
+
+void nouspikel_usb_smartmedia_device::device_start()
+{
+ m_ram = (UINT16*)(*memregion(BUFFER_TAG));
+ /* auto_alloc_array(device->machine(), UINT16, 0x100000/2); */
+ m_smartmedia = subdevice<smartmedia_image_device>("smartmedia");
+ m_strata = subdevice("strata");
+}
+
+void nouspikel_usb_smartmedia_device::device_reset()
+{
+ m_feeprom_page = 0;
+ m_sram_page = 0;
+ m_cru_register = 0;
+ // m_tms9995_mode = (device->type()==TMS9995);
+
+ 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();
+}
+
+ROM_START( tn_usbsm )
+ ROM_REGION16_BE(0x80000, BUFFER_TAG, 0) /* RAM buffer 512 KiB */
+ ROM_FILL(0x0000, 0x80000, 0x0000)
+ROM_END
+
+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" )
+INPUT_PORTS_END
+
+MACHINE_CONFIG_FRAGMENT( tn_usbsm )
+ MCFG_SMARTMEDIA_ADD( "smartmedia" )
+ MCFG_STRATAFLASH_ADD( "strata" )
+MACHINE_CONFIG_END
+
+machine_config_constructor nouspikel_usb_smartmedia_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( tn_usbsm );
+}
+
+const rom_entry *nouspikel_usb_smartmedia_device::device_rom_region() const
+{
+ return ROM_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<nouspikel_usb_smartmedia_device>;
+
diff --git a/src/mess/machine/ti99/tn_usbsm.h b/src/mess/machine/ti99/tn_usbsm.h
new file mode 100644
index 00000000000..5d5e9df59c9
--- /dev/null
+++ b/src/mess/machine/ti99/tn_usbsm.h
@@ -0,0 +1,55 @@
+/****************************************************************************
+
+ 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 "ti99defs.h"
+#include "peribox.h"
+#include "machine/smartmed.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);
+
+ void crureadz(offs_t offset, UINT8 *value);
+ void cruwrite(offs_t offset, UINT8 value);
+
+protected:
+ void device_start(void);
+ void device_reset(void);
+ const rom_entry *device_rom_region() const;
+ machine_config_constructor device_mconfig_additions() const;
+ ioport_constructor device_input_ports() const;
+
+private:
+ UINT16 usbsm_mem_16_r(offs_t offset);
+ void usbsm_mem_16_w(offs_t offset, UINT16 data);
+ smartmedia_image_device* m_smartmedia;
+ device_t* m_strata;
+
+ int m_feeprom_page;
+ int m_sram_page;
+ int m_cru_register;
+ bool m_tms9995_mode;
+
+ UINT16 m_input_latch;
+ UINT16 m_output_latch;
+ UINT16* m_ram;
+};
+
+#endif
diff --git a/src/mess/machine/ti99/videowrp.c b/src/mess/machine/ti99/videowrp.c
new file mode 100644
index 00000000000..e42fb8960ea
--- /dev/null
+++ b/src/mess/machine/ti99/videowrp.c
@@ -0,0 +1,236 @@
+/****************************************************************************
+
+ 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)
+: bus8z_device(mconfig, type, name, tag, owner, clock)
+{
+}
+
+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, "Video subsystem", tag, owner, clock)
+{
+}
+
+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, "Video subsystem", tag, owner, clock)
+{
+}
+
+/*****************************************************************************/
+/*
+ Memory access (TI-99/4A and TI-99/8)
+*/
+READ8Z_MEMBER( ti_std_video_device::readz )
+{
+ if (offset & 2)
+ { /* read VDP status */
+ *value = m_tms9928a->register_read(*(this->m_space), 0);
+ }
+ else
+ { /* read VDP RAM */
+ *value = m_tms9928a->vram_read(*(this->m_space), 0);
+ }
+}
+
+WRITE8_MEMBER( ti_std_video_device::write )
+{
+ if (offset & 2)
+ { /* write VDP address */
+ m_tms9928a->register_write(*(this->m_space), 0, data);
+ }
+ else
+ { /* write VDP data */
+ m_tms9928a->vram_write(*(this->m_space), 0, data);
+ }
+}
+
+/*****************************************************************************/
+
+/*
+ Memory access (EVPC) via 16 bit bus
+*/
+READ16_MEMBER( ti_exp_video_device::read16 )
+{
+ 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 )
+{
+ 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 (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 )
+{
+ 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<tms9928a_device*>(machine().device(VDP_TAG));
+}
+
+void ti_exp_video_device::device_start(void)
+{
+ m_v9938 = static_cast<v9938_device*>(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.
+*/
+static const sn76496_config sound_config =
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ti_sound_system_device, sound_ready),
+};
+
+WRITE8_MEMBER( ti_sound_system_device::write )
+{
+ m_sound_chip->write(space, 0, data);
+}
+
+void ti_sound_system_device::device_start(void)
+{
+ const ti_sound_config *conf = reinterpret_cast<const ti_sound_config *>(static_config());
+ m_console_ready.resolve(conf->ready, *this);
+ m_sound_chip = subdevice<sn76496_base_device>(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_NEW, 3579545/8) /* 3.579545 MHz */
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "sound_out", 0.75)
+ MCFG_SOUND_CONFIG(sound_config)
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_FRAGMENT( sn76496 )
+ MCFG_SPEAKER_STANDARD_MONO("sound_out")
+ MCFG_SOUND_ADD(TISOUNDCHIP_TAG, SN76496_NEW, 3579545) /* 3.579545 MHz */
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "sound_out", 0.75)
+ MCFG_SOUND_CONFIG(sound_config)
+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<ti_std_video_device>;
+const device_type V9938VIDEO = &device_creator<ti_exp_video_device>;
+const device_type TISOUND_94624 = &device_creator<ti_sound_sn94624_device>;
+const device_type TISOUND_76496 = &device_creator<ti_sound_sn76496_device>;
diff --git a/src/mess/machine/ti99/videowrp.h b/src/mess/machine/ti99/videowrp.h
new file mode 100644
index 00000000000..4433a5a72e9
--- /dev/null
+++ b/src/mess/machine/ti99/videowrp.h
@@ -0,0 +1,183 @@
+/****************************************************************************
+
+ 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:
+ address_space *m_space;
+ 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);
+ 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:
+ 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;
+
+typedef struct _ti_sound_config
+{
+ devcb_write_line ready;
+} ti_sound_config;
+
+#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 *tag, const char *name, device_t *owner, UINT32 clock)
+ : bus8z_device(mconfig, type, name, tag, owner, clock) { };
+
+ // 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
+
+protected:
+ void device_start(void);
+ virtual machine_config_constructor device_mconfig_additions() const =0;
+
+private:
+ sn76496_base_device* m_sound_chip;
+ devcb_resolved_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)
+ : ti_sound_system_device(mconfig, TISOUND_94624, tag, "Onboard sound (SN94624)", owner, clock) { }
+
+protected:
+ 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)
+ : ti_sound_system_device(mconfig, TISOUND_76496, tag, "Onboard sound (SN76496)", owner, clock) { }
+
+protected:
+ machine_config_constructor device_mconfig_additions() const;
+};
+
+
+/****************************************************************************/
+
+#define MCFG_TI_TMS991x_ADD_NTSC(_tag, _chip, _tmsparam) \
+ MCFG_DEVICE_ADD(_tag, TI99VIDEO, 0) \
+ MCFG_TMS9928A_ADD( VDP_TAG, _chip, _tmsparam ) \
+ 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, _tmsparam) \
+ MCFG_DEVICE_ADD(_tag, TI99VIDEO, 0) \
+ MCFG_TMS9928A_ADD( VDP_TAG, _chip, _tmsparam ) \
+ MCFG_TMS9928A_SCREEN_ADD_PAL( SCREEN_TAG ) \
+ MCFG_SCREEN_UPDATE_DEVICE( VDP_TAG, tms9928a_device, screen_update )
+
+#define MCFG_TI998_ADD_NTSC(_tag, _chip, _tmsparam) \
+ MCFG_DEVICE_ADD(_tag, TI99VIDEO, 0) \
+ MCFG_TMS9928A_ADD( VDP_TAG, _chip, _tmsparam ) \
+ MCFG_TMS9928A_SCREEN_ADD_NTSC( SCREEN_TAG ) \
+ MCFG_SCREEN_UPDATE_DEVICE( VDP_TAG, tms9928a_device, screen_update )
+
+#define MCFG_TI998_ADD_PAL(_tag, _chip, _tmsparam) \
+ MCFG_DEVICE_ADD(_tag, TI99VIDEO, 0) \
+ MCFG_TMS9928A_ADD( VDP_TAG, _chip, _tmsparam ) \
+ 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, _devtag, _class, _int) \
+ MCFG_DEVICE_ADD(_tag, V9938VIDEO, 0) \
+ MCFG_V9938_ADD(VDP_TAG, _screen, 0x20000) \
+ MCFG_V99X8_INTERRUPT_CALLBACK_DEVICE(_devtag, _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_PALETTE_LENGTH(512) \
+ MCFG_PALETTE_INIT(v9938)
+
+#define MCFG_TI_SOUND_94624_ADD(_tag, _conf) \
+ MCFG_DEVICE_ADD(_tag, TISOUND_94624, 0) \
+ MCFG_DEVICE_CONFIG( _conf )
+
+#define MCFG_TI_SOUND_76496_ADD(_tag, _conf) \
+ MCFG_DEVICE_ADD(_tag, TISOUND_76496, 0) \
+ MCFG_DEVICE_CONFIG( _conf )
+
+#endif /* __TIVIDEO__ */
+
diff --git a/src/mess/machine/ti990.c b/src/mess/machine/ti990.c
new file mode 100644
index 00000000000..be7487d0f06
--- /dev/null
+++ b/src/mess/machine/ti990.c
@@ -0,0 +1,177 @@
+/*
+ machine/ti990.c
+
+ Emulation for a few generic aspects of TI990
+*/
+
+#include "emu.h"
+#include "ti990.h"
+
+/*
+ Interrupt priority encoder. Actually part of the CPU board.
+*/
+static UINT16 intlines;
+
+void ti990_reset_int(void)
+{
+ intlines = 0;
+}
+
+void ti990_set_int_line(running_machine &machine, int line, int state)
+{
+ int level;
+
+
+ if (state)
+ intlines |= (1 << line);
+ else
+ intlines &= ~ (1 << line);
+
+ if (intlines)
+ {
+ for (level = 0; ! (intlines & (1 << level)); level++)
+ ;
+ cputag_set_input_line_and_vector(machine, "maincpu", 0, ASSERT_LINE, level); /* interrupt it, baby */
+ }
+ else
+ cputag_set_input_line(machine, "maincpu", 0, CLEAR_LINE);
+}
+
+void ti990_set_int2(device_t *device, int state)
+{
+ ti990_set_int_line(device->machine(), 2, state);
+}
+
+void ti990_set_int3(running_machine &machine, int state)
+{
+ ti990_set_int_line(machine, 3, state);
+}
+
+void ti990_set_int6(running_machine &machine, int state)
+{
+ ti990_set_int_line(machine, 6, state);
+}
+
+void ti990_set_int7(running_machine &machine, int state)
+{
+ ti990_set_int_line(machine, 7, state);
+}
+
+void ti990_set_int9(running_machine &machine, int state)
+{
+ ti990_set_int_line(machine, 9, state);
+}
+
+void ti990_set_int10(running_machine &machine, int state)
+{
+ ti990_set_int_line(machine, 10, state);
+}
+
+void ti990_set_int13(running_machine &machine, int state)
+{
+ ti990_set_int_line(machine, 13, state);
+}
+
+/*
+ hold and debounce load line (emulation is inaccurate)
+*/
+
+static TIMER_CALLBACK(clear_load)
+{
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_NMI, CLEAR_LINE);
+}
+
+void ti990_hold_load(running_machine &machine)
+{
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_NMI, ASSERT_LINE);
+ machine.scheduler().timer_set(attotime::from_msec(100), FUNC(clear_load));
+}
+
+/*
+ line interrupt
+*/
+
+/* ckon_state: 1 if line clock active (RTCLR flip-flop on TI990/10 schematics -
+SMI sheet 4) */
+static char ckon_state;
+
+void ti990_line_interrupt(running_machine &machine)
+{
+ if (ckon_state)
+ ti990_set_int_line(machine, 5, 1);
+}
+
+void ti990_ckon_ckof_callback(device_t *device, int state)
+{
+ ckon_state = state;
+ if (! ckon_state)
+ ti990_set_int_line(device->machine(), 5, 0);
+}
+
+
+
+/*
+ Control panel emulation
+
+ three panel types
+ * operator panel
+ * programmer panel
+ * MDU (external unit connected instead of the control panel, as seen in
+ 945401-9701 p. 2-5 though 2-15)
+
+ Operator panel:
+ * Power led
+ * Fault led
+ * Off/On/Load switch
+
+ Programmer panel:
+ * 16 status light, 32 switches, IDLE, RUN leds
+ * interface to a low-level debugger in ROMs
+
+ * MDU:
+ * includes a programmer panel, a tape unit, and a few parts
+ (diagnostic tape, diagnostic ROMs, etc.)
+
+ CRU output:
+ 0-7: lights 0-7
+ 8: increment scan
+ 9: clear scan (according to 990 handbook)
+ A: run light (additionally sets all data LEDs to 1s, the scan count to 0b10 and enables the HALT/SIE switch)
+ B: fault light
+ C: Memory Error Interrupt clear
+ D: Start panel timer
+ E: Set SIE function (interrupt after 2 instructions are executed)
+ F: flag (according to 990 handbook)
+
+ input :
+ 0-7: switches 0-7 (or data from MDU tape)
+ 8: scan count bit 1
+ 9: scan count bit 0
+ A: timer active
+ B: programmer panel not present or locked
+ C: char in MDU tape unit buffer?
+ D: unused?
+ E: if 0, MDU unit present
+ F: flag (according to 990 handbook)
+*/
+
+ READ8_HANDLER ( ti990_panel_read )
+{
+ if (offset == 1)
+ return 0x48;
+
+ return 0;
+}
+
+WRITE8_HANDLER ( ti990_panel_write )
+{
+}
+
+
+/*
+ CPU board soft reset (RSET instruction)
+*/
+void ti990_cpuboard_reset(void)
+{
+ ckon_state = 0;
+}
diff --git a/src/mess/machine/ti990.h b/src/mess/machine/ti990.h
new file mode 100644
index 00000000000..b26ccb47de7
--- /dev/null
+++ b/src/mess/machine/ti990.h
@@ -0,0 +1,23 @@
+/*
+ ti990.h: header file for ti990.c
+*/
+
+void ti990_reset_int(void);
+void ti990_set_int_line(running_machine &machine, int line, int state);
+void ti990_set_int2(device_t *device, int state);
+void ti990_set_int3(running_machine &machine, int state);
+void ti990_set_int6(running_machine &machine, int state);
+void ti990_set_int7(running_machine &machine, int state);
+void ti990_set_int9(running_machine &machine, int state);
+void ti990_set_int10(running_machine &machine, int state);
+void ti990_set_int13(running_machine &machine, int state);
+
+void ti990_hold_load(running_machine &machine);
+
+ READ8_HANDLER ( ti990_panel_read );
+WRITE8_HANDLER ( ti990_panel_write );
+
+void ti990_line_interrupt(running_machine &machine);
+void ti990_ckon_ckof_callback(device_t *device, int state);
+
+void ti990_cpuboard_reset(void);
diff --git a/src/mess/machine/tms5501.c b/src/mess/machine/tms5501.c
new file mode 100644
index 00000000000..1e09978a2d3
--- /dev/null
+++ b/src/mess/machine/tms5501.c
@@ -0,0 +1,463 @@
+/*********************************************************************
+
+ tms5501.c
+
+ TMS5501 input/output controller
+
+ Krzysztof Strzecha, Nathan Woods, 2003
+ Based on TMS9901 emulator by Raphael Nabet
+
+ 21-May-2004 - Fixed interrupt queue overflow bug (not really fixed
+ previously).
+ 06-Mar-2004 - Fixed bug in sensor input.
+ 01-Mar-2004 - Interrupt queue overrun problem fixed.
+ 19-Oct-2003 - Status register added. Reset fixed. Some cleanups.
+ INTA enable/disable.
+
+ TODO:
+ - SIO
+
+*********************************************************************/
+
+#include "emu.h"
+#include "tms5501.h"
+
+
+/***************************************************************************
+ PARAMETERS/MACROS
+***************************************************************************/
+
+#define DEBUG_TMS5501 0
+
+#define LOG_TMS5501(message, data) do { if (DEBUG_TMS5501) logerror ("\nTMS5501 %s: %s %02x", tag(), message, data); } while (0)
+
+/* status register */
+#define TMS5501_FRAME_ERROR 0x01
+#define TMS5501_OVERRUN_ERROR 0x02
+#define TMS5501_SERIAL_RCVD 0x04
+#define TMS5501_RCV_BUFFER_LOADED 0x08
+#define TMS5501_XMIT_BUFFER_EMPTY 0x10
+#define TMS5501_INTERRUPT_PENDING 0x20
+#define TMS5501_FULL_BIT_DETECT 0x40
+#define TMS5501_START_BIT_DETECT 0x80
+
+/* command */
+#define TMS5501_RESET 0x01
+#define TMS5501_BREAK 0x02
+#define TMS5501_INT_7_SELECT 0x04
+#define TMS5501_INT_ACK_ENABLE 0x08
+#define TMS5501_TEST_BIT_1 0x10
+#define TMS5501_TEST_BIT_2 0x20
+#define TMS5501_COMMAND_LATCHED_BITS 0x3e
+
+/* interrupt mask register */
+#define TMS5501_TIMER_0_INT 0x01
+#define TMS5501_TIMER_1_INT 0x02
+#define TMS5501_SENSOR_INT 0x04
+#define TMS5501_TIMER_2_INT 0x08
+#define TMS5501_SERIAL_RCV_LOADED_INT 0x10
+#define TMS5501_SERIAL_XMIT_EMPTY_INT 0x20
+#define TMS5501_TIMER_3_INT 0x40
+#define TMS5501_TIMER_4_INT 0x80
+#define TMS5501_INT_7_INT 0x80
+
+#define TMS5501_PIO_INT_7 0x80
+
+// device type definition
+const device_type TMS5501 = &device_creator<tms5501_device>;
+
+
+static const UINT8 timer_name[] = { TMS5501_TIMER_0_INT, TMS5501_TIMER_1_INT, TMS5501_TIMER_2_INT, TMS5501_TIMER_3_INT, TMS5501_TIMER_4_INT };
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+//-------------------------------------------------
+// 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)
+{
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void tms5501_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const tms5501_interface *intf = reinterpret_cast<const tms5501_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<tms5501_interface *>(this) = *intf;
+ }
+ // or initialize to defaults if none provided
+ else
+ {
+ m_interrupt_cb = NULL;
+ memset(&m_pio_read_cb, 0, sizeof(m_pio_read_cb));
+ memset(&m_pio_write_cb, 0, sizeof(m_pio_write_cb));
+ }
+}
+
+/*-------------------------------------------------
+ find_first_bit
+-------------------------------------------------*/
+
+int tms5501_device::find_first_bit(int value)
+{
+ int bit = 0;
+
+ if (! value)
+ return -1;
+
+ while (! (value & 1))
+ {
+ value >>= 1; /* try next bit */
+ bit++;
+ }
+ return bit;
+}
+
+
+/*-------------------------------------------------
+ tms5501_device::field_interrupts()
+-------------------------------------------------*/
+
+void tms5501_device::field_interrupts()
+{
+ static const UINT8 int_vectors[] = { 0xc7, 0xcf, 0xd7, 0xdf, 0xe7, 0xef, 0xf7, 0xff };
+ UINT8 current_ints = m_pending_interrupts;
+
+ /* disabling masked interrupts */
+ current_ints &= m_interrupt_mask;
+
+ LOG_TMS5501("Pending interrupts", m_pending_interrupts);
+ LOG_TMS5501("Interrupt mask", m_interrupt_mask);
+ LOG_TMS5501("Current interrupts", current_ints);
+
+ if (current_ints)
+ {
+ /* selecting interrupt with highest priority */
+ int level = find_first_bit(current_ints);
+ LOG_TMS5501("Interrupt level", level);
+
+ /* resetting proper bit in pending interrupts register */
+ m_pending_interrupts &= ~(1<<level);
+
+ /* selecting interrupt vector */
+ m_interrupt_address = int_vectors[level];
+ LOG_TMS5501("Interrupt vector", int_vectors[level]);
+
+ if ((m_command & TMS5501_INT_ACK_ENABLE))
+ {
+ if (m_interrupt_cb)
+ (m_interrupt_cb)(*this, 1, int_vectors[level]);
+ }
+ else
+ m_status |= TMS5501_INTERRUPT_PENDING;
+ }
+ else
+ {
+ if ((m_command & TMS5501_INT_ACK_ENABLE))
+ {
+ if (m_interrupt_cb)
+ (m_interrupt_cb)(*this, 0, 0);
+ }
+ else
+ m_status &= ~TMS5501_INTERRUPT_PENDING;
+ }
+}
+
+
+/*-------------------------------------------------
+ tms5501_device::timer_decrementer
+-------------------------------------------------*/
+
+void tms5501_device::timer_decrementer(UINT8 mask)
+{
+ if ((mask != TMS5501_TIMER_4_INT) || ((mask == TMS5501_TIMER_4_INT) && (!(m_command & TMS5501_INT_7_SELECT))))
+ m_pending_interrupts |= mask;
+
+ field_interrupts();
+}
+
+
+/*-------------------------------------------------
+ tms5501_device::timer_reload
+-------------------------------------------------*/
+
+void tms5501_device::timer_reload(int timer)
+{
+ if (m_timer_counter[timer])
+ { /* reset clock interval */
+ m_timer[timer]->adjust(attotime::from_double((double) m_timer_counter[timer] / (clock() / 128.)), timer_name[timer], attotime::from_double((double) m_timer_counter[timer] / (clock() / 128.)));
+ }
+ else
+ { /* clock interval == 0 -> no timer */
+ switch (timer)
+ {
+ case 0: timer_decrementer(TMS5501_TIMER_0_INT); break;
+ case 1: timer_decrementer(TMS5501_TIMER_1_INT); break;
+ case 2: timer_decrementer(TMS5501_TIMER_2_INT); break;
+ case 3: timer_decrementer(TMS5501_TIMER_3_INT); break;
+ case 4: timer_decrementer(TMS5501_TIMER_4_INT); break;
+ }
+ m_timer[timer]->enable(0);
+ }
+}
+
+
+/*-------------------------------------------------
+ DEVICE_RESET( tms5501 )
+-------------------------------------------------*/
+
+void tms5501_device::device_reset()
+{
+ m_status &= ~(TMS5501_RCV_BUFFER_LOADED|TMS5501_FULL_BIT_DETECT|TMS5501_START_BIT_DETECT|TMS5501_OVERRUN_ERROR);
+ m_status |= TMS5501_XMIT_BUFFER_EMPTY|TMS5501_SERIAL_RCVD;
+
+ m_pending_interrupts = TMS5501_SERIAL_XMIT_EMPTY_INT;
+
+ for (int i=0; i<5; i++)
+ {
+ m_timer_counter[i] = 0;
+ m_timer[i]->enable(0);
+ }
+
+ LOG_TMS5501("Reset", 0);
+}
+
+
+/*-------------------------------------------------
+ DEVICE_START( tms5501 )
+-------------------------------------------------*/
+
+void tms5501_device::device_start()
+{
+ // resolve callbacks
+ m_pio_read_func.resolve(m_pio_read_cb, *this);
+ m_pio_write_func.resolve(m_pio_write_cb, *this);
+
+ // allocate timers
+ for (int i = 0; i < 5; i++)
+ {
+ m_timer[i] = timer_alloc(TIMER_DECREMENTER);
+ m_timer[i]->set_param(i);
+ }
+
+ m_interrupt_mask = 0;
+ m_interrupt_address = 0;
+
+ m_sensor = 0;
+ m_sio_rate = 0;
+ m_sio_input_buffer = 0;
+ m_sio_output_buffer = 0;
+ m_pio_input_buffer = 0;
+ m_pio_output_buffer = 0;
+
+ m_command = 0;
+ LOG_TMS5501("Init", 0);
+}
+
+
+//-------------------------------------------------
+// device_timer - handler timer events
+//-------------------------------------------------
+
+void tms5501_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch (id)
+ {
+ case TIMER_DECREMENTER:
+ timer_decrementer((UINT8)param);
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+ tms5501_device::set_pio_bit_7
+-------------------------------------------------*/
+
+DECLARE_WRITE_LINE_MEMBER( tms5501_device::set_pio_bit_7 )
+{
+ if (m_command & TMS5501_INT_7_SELECT)
+ {
+ if (!(m_pio_input_buffer & TMS5501_PIO_INT_7) && state)
+ m_pending_interrupts |= TMS5501_INT_7_INT;
+ else
+ m_pending_interrupts &= ~TMS5501_INT_7_INT;
+ }
+
+ m_pio_input_buffer &= ~TMS5501_PIO_INT_7;
+ if (state)
+ m_pio_input_buffer |= TMS5501_PIO_INT_7;
+
+ if (m_pending_interrupts & TMS5501_INT_7_INT)
+ field_interrupts();
+}
+
+
+/*-------------------------------------------------
+ tms5501_device::set_sensor
+-------------------------------------------------*/
+
+WRITE_LINE_MEMBER(tms5501_device::set_sensor)
+{
+ if (!(m_sensor) && state)
+ m_pending_interrupts |= TMS5501_SENSOR_INT;
+ else
+ m_pending_interrupts &= ~TMS5501_SENSOR_INT;
+
+ m_sensor = state;
+
+ if (m_pending_interrupts &= TMS5501_SENSOR_INT)
+ field_interrupts();
+}
+
+
+/*-------------------------------------------------
+ READ8_DEVICE_HANDLER( tms5501_r )
+-------------------------------------------------*/
+
+READ8_MEMBER( tms5501_device::read )
+{
+ UINT8 data = 0x00;
+ offset &= 0x0f;
+
+ switch (offset)
+ {
+ case 0x00: /* Serial input buffer */
+ data = m_sio_input_buffer;
+ m_status &= ~TMS5501_RCV_BUFFER_LOADED;
+ LOG_TMS5501("Reading from serial input buffer", data);
+ break;
+ case 0x01: /* PIO input port */
+ if (!m_pio_read_func.isnull())
+ data = m_pio_read_func(0);
+ LOG_TMS5501("Reading from PIO", data);
+ break;
+ case 0x02: /* Interrupt address register */
+ data = m_interrupt_address;
+ m_status &= ~TMS5501_INTERRUPT_PENDING;
+ break;
+ case 0x03: /* Status register */
+ data = m_status;
+ break;
+ case 0x04: /* Command register */
+ data = m_command;
+ LOG_TMS5501("Command register read", data);
+ break;
+ case 0x05: /* Serial rate register */
+ data = m_sio_rate;
+ LOG_TMS5501("Serial rate read", data);
+ break;
+ case 0x06: /* Serial output buffer */
+ case 0x07: /* PIO output */
+ break;
+ case 0x08: /* Interrupt mask register */
+ data = m_interrupt_mask;
+ LOG_TMS5501("Interrupt mask read", data);
+ break;
+ case 0x09: /* Timer 0 address */
+ case 0x0a: /* Timer 1 address */
+ case 0x0b: /* Timer 2 address */
+ case 0x0c: /* Timer 3 address */
+ case 0x0d: /* Timer 4 address */
+ break;
+ }
+ return data;
+}
+
+
+/*-------------------------------------------------
+ WRITE8_DEVICE_HANDLER( tms5501_w )
+-------------------------------------------------*/
+
+WRITE8_MEMBER( tms5501_device::write )
+{
+ offset &= 0x0f;
+
+ switch (offset)
+ {
+ case 0x00: /* Serial input buffer */
+ case 0x01: /* Keyboard input port, Page blanking signal */
+ case 0x02: /* Interrupt address register */
+ case 0x03: /* Status register */
+ LOG_TMS5501("Writing to read only port", offset&0x000f);
+ LOG_TMS5501("Data", data);
+ break;
+ case 0x04:
+ /* Command register
+ bit 0: reset
+ bit 1: send break, '1' - serial output is high impedance
+ bit 2: int 7 select: '0' - timer 5, '1' - IN7 of the DCE-bus
+ bit 3: int ack enable, '0' - disabled, '1' - enabled
+ bits 4-5: test bits, normally '0'
+ bits 6-7: not used, normally '0'
+ bits 1-5 are latched */
+
+ m_command = data & TMS5501_COMMAND_LATCHED_BITS;
+ LOG_TMS5501("Command register write", data);
+
+ if (data & TMS5501_RESET)
+ reset();
+ break;
+ case 0x05:
+ /* Serial rate register
+ bit 0: 110 baud
+ bit 1: 150 baud
+ bit 2: 300 baud
+ bit 3: 1200 baud
+ bit 4: 2400 baud
+ bit 5: 4800 baud
+ bit 6: 9600 baud
+ bit 7: '0' - two stop bits, '1' - one stop bit */
+
+ m_sio_rate = data;
+ LOG_TMS5501("Serial rate write", data);
+ break;
+ case 0x06: /* Serial output buffer */
+ m_sio_output_buffer = data;
+ LOG_TMS5501("Serial output data", data);
+ break;
+ case 0x07: /* PIO output */
+ m_pio_output_buffer = data;
+ if (!m_pio_write_func.isnull())
+ m_pio_write_func(0, m_pio_output_buffer);
+ LOG_TMS5501("Writing to PIO", data);
+ break;
+ case 0x08:
+ /* Interrupt mask register
+ bit 0: Timer 1 has expired (UTIM)
+ bit 1: Timer 2 has expired
+ bit 2: External interrupt (STKIM)
+ bit 3: Timer 3 has expired (SNDIM)
+ bit 4: Serial receiver loaded
+ bit 5: Serial transmitter empty
+ bit 6: Timer 4 has expired (KBIM)
+ bit 7: Timer 5 has expired or IN7 (CLKIM) */
+
+ m_interrupt_mask = data;
+ LOG_TMS5501("Interrupt mask write", data);
+ break;
+ case 0x09: /* Timer 0 counter */
+ case 0x0a: /* Timer 1 counter */
+ case 0x0b: /* Timer 2 counter */
+ case 0x0c: /* Timer 3 counter */
+ case 0x0d: /* Timer 4 counter */
+ offset -= 9;
+ m_timer_counter[offset] = data;
+ timer_reload(offset);
+ LOG_TMS5501("Write timer", offset);
+ LOG_TMS5501("Timer counter set", data);
+ break;
+ }
+}
diff --git a/src/mess/machine/tms5501.h b/src/mess/machine/tms5501.h
new file mode 100644
index 00000000000..2ab13c9bd21
--- /dev/null
+++ b/src/mess/machine/tms5501.h
@@ -0,0 +1,101 @@
+/*********************************************************************
+
+ tms5501.h
+
+ TMS 5501 code
+
+*********************************************************************/
+
+#ifndef __TMS5501_H__
+#define __TMS5501_H__
+
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+#define MCFG_TMS5501_ADD(_tag, _clock, _intrf) \
+ MCFG_DEVICE_ADD(_tag, TMS5501, _clock) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#define TMS5501_INTERFACE(name) \
+ const tms5501_interface (name) =
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef void (*tms5501_interrupt_cb)(device_t &device, int intreq, UINT8 vector);
+#define TMS5501_IRQ_CALLBACK(name) void name(device_t &device, int intreq, UINT8 vector)
+
+
+// ======================> tms5501_interface
+
+struct tms5501_interface
+{
+ devcb_read8 m_pio_read_cb; // PIO read
+ devcb_write8 m_pio_write_cb; // PIO write
+ tms5501_interrupt_cb m_interrupt_cb; // interrupt callback
+};
+
+// ======================> tms5501_device
+
+class tms5501_device : public device_t,
+ public tms5501_interface
+{
+public:
+ // construction/destruction
+ tms5501_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( set_pio_bit_7 );
+ DECLARE_WRITE_LINE_MEMBER( set_sensor );
+
+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);
+
+public:
+ int find_first_bit(int value);
+ void field_interrupts();
+ void timer_decrementer(UINT8 mask);
+ void timer_reload(int timer);
+
+ static const device_timer_id TIMER_DECREMENTER = 0;
+
+ // internal registers
+ UINT8 m_status; // status register
+ UINT8 m_command; // command register, bits 1-5 are latched
+
+ UINT8 m_sio_rate; // SIO configuration register
+ UINT8 m_sio_input_buffer; // SIO input buffer
+ UINT8 m_sio_output_buffer; // SIO output buffer
+
+ UINT8 m_pio_input_buffer; // PIO input buffer
+ UINT8 m_pio_output_buffer; // PIO output buffer
+
+ UINT8 m_interrupt_mask; // interrupt mask register
+ UINT8 m_pending_interrupts; // pending interrupts register
+ UINT8 m_interrupt_address; // interrupt vector register
+
+ int m_sensor; // sensor input
+
+ // internal timers
+ UINT8 m_timer_counter[5];
+ emu_timer * m_timer[5];
+
+ // PIO callbacks
+ devcb_resolved_read8 m_pio_read_func;
+ devcb_resolved_write8 m_pio_write_func;
+};
+
+
+// device type definition
+extern const device_type TMS5501;
+
+#endif /* __TMS5501_H__ */
diff --git a/src/mess/machine/trs80.c b/src/mess/machine/trs80.c
new file mode 100644
index 00000000000..9eedfe17f81
--- /dev/null
+++ b/src/mess/machine/trs80.c
@@ -0,0 +1,904 @@
+/***************************************************************************
+
+ machine.c
+
+ Functions to emulate general aspects of the machine (RAM, ROM, interrupts,
+ I/O ports)
+
+MAX_LUMPS 192 crude storage units - don't know much about it
+MAX_GRANULES 8 lumps consisted of granules.. aha
+MAX_SECTORS 5 and granules of sectors
+
+***************************************************************************/
+
+#include "includes/trs80.h"
+
+
+#define IRQ_M1_RTC 0x80 /* RTC on Model I */
+#define IRQ_M1_FDC 0x40 /* FDC on Model I */
+#define IRQ_M4_RTC 0x04 /* RTC on Model 4 */
+#define CASS_RISE 0x01 /* high speed cass on Model III/4) */
+#define CASS_FALL 0x02 /* high speed cass on Model III/4) */
+#define MODEL4_MASTER_CLOCK 20275200
+
+
+static TIMER_CALLBACK( cassette_data_callback )
+{
+ trs80_state *state = machine.driver_data<trs80_state>();
+/* This does all baud rates. 250 baud (trs80), and 500 baud (all others) set bit 7 of "cassette_data".
+ 1500 baud (trs80m3, trs80m4) is interrupt-driven and uses bit 0 of "cassette_data" */
+
+ double new_val = (state->m_cass->input());
+
+ /* Check for HI-LO transition */
+ if ( state->m_old_cassette_val > -0.2 && new_val < -0.2 )
+ {
+ state->m_cassette_data |= 0x80; /* 500 baud */
+ if (state->m_mask & CASS_FALL) /* see if 1500 baud */
+ {
+ state->m_cassette_data = 0;
+ state->m_irq |= CASS_FALL;
+ cputag_set_input_line(machine, "maincpu", 0, HOLD_LINE);
+ }
+ }
+ else
+ if ( state->m_old_cassette_val < -0.2 && new_val > -0.2 )
+ {
+ if (state->m_mask & CASS_RISE) /* 1500 baud */
+ {
+ state->m_cassette_data = 1;
+ state->m_irq |= CASS_RISE;
+ cputag_set_input_line(machine, "maincpu", 0, HOLD_LINE);
+ }
+ }
+
+ state->m_old_cassette_val = new_val;
+}
+
+
+/*************************************
+ *
+ * Port handlers.
+ *
+ *************************************/
+
+
+READ8_MEMBER( trs80_state::trs80m4_e0_r )
+{
+/* Indicates which devices are interrupting - d6..d3 not emulated.
+ Whenever an interrupt occurs, this port is immediately read
+ to find out which device requires service. Lowest-numbered
+ bit takes precedence. We take this opportunity to clear the
+ cpu INT line.
+
+ d6 RS232 Error (Any of {FE, PE, OR} errors has occurred)
+ d5 RS232 Rcv (DAV indicates a char ready to be picked up from uart)
+ d4 RS232 Xmit (TBMT indicates ready to accept another char from cpu)
+ d3 I/O Bus
+ d2 RTC
+ d1 Cass 1500 baud Falling
+ d0 Cass 1500 baud Rising */
+
+ cputag_set_input_line(machine(), "maincpu", 0, CLEAR_LINE);
+ return ~(m_mask & m_irq);
+}
+
+READ8_MEMBER( trs80_state::trs80m4_e4_r )
+{
+/* Indicates which devices are interrupting - d6..d5 not emulated.
+ Whenever an NMI occurs, this port is immediately read
+ to find out which device requires service. Lowest-numbered
+ bit takes precedence. We take this opportunity to clear the
+ cpu NMI line.
+
+ d7 status of FDC INTREQ (0=true)
+ d6 status of Motor Timeout (0=true)
+ d5 status of Reset signal (0=true - this will reboot the computer) */
+
+ cputag_set_input_line(machine(), "maincpu", INPUT_LINE_NMI, CLEAR_LINE);
+
+ return ~(m_nmi_mask & m_nmi_data);
+}
+
+READ8_MEMBER( trs80_state::trs80m4_e8_r )
+{
+/* not emulated
+ d7 Clear-to-Send (CTS), Pin 5
+ d6 Data-Set-Ready (DSR), pin 6
+ d5 Carrier Detect (CD), pin 8
+ d4 Ring Indicator (RI), pin 22
+ d3,d2,d0 Not used
+ d1 UART Receiver Input, pin 20 (pin 20 is also DTR) */
+
+ return 0;
+}
+
+READ8_MEMBER( trs80_state::trs80m4_ea_r )
+{
+/* UART Status Register
+ d7 Data Received ('1'=condition true)
+ d6 Transmitter Holding Register empty ('1'=condition true)
+ d5 Overrun Error ('1'=condition true)
+ d4 Framing Error ('1'=condition true)
+ d3 Parity Error ('1'=condition true)
+ d2..d0 Not used */
+
+ UINT8 data=7;
+ ay31015_set_input_pin( m_ay31015, AY31015_SWE, 0 );
+ data |= ay31015_get_output_pin( m_ay31015, AY31015_TBMT ) ? 0x40 : 0;
+ data |= ay31015_get_output_pin( m_ay31015, AY31015_DAV ) ? 0x80 : 0;
+ data |= ay31015_get_output_pin( m_ay31015, AY31015_OR ) ? 0x20 : 0;
+ data |= ay31015_get_output_pin( m_ay31015, AY31015_FE ) ? 0x10 : 0;
+ data |= ay31015_get_output_pin( m_ay31015, AY31015_PE ) ? 0x08 : 0;
+ ay31015_set_input_pin( m_ay31015, AY31015_SWE, 1 );
+
+ return data;
+}
+
+READ8_MEMBER( trs80_state::trs80m4_eb_r )
+{
+/* UART received data */
+ UINT8 data = ay31015_get_received_data( m_ay31015 );
+ ay31015_set_input_pin( m_ay31015, AY31015_RDAV, 0 );
+ ay31015_set_input_pin( m_ay31015, AY31015_RDAV, 1 );
+ return data;
+}
+
+READ8_MEMBER( trs80_state::trs80m4_ec_r )
+{
+/* Reset the RTC interrupt */
+ m_irq &= ~IRQ_M4_RTC;
+ return 0;
+}
+
+READ8_MEMBER( trs80_state::sys80_f9_r )
+{
+/* UART Status Register - d6..d4 not emulated
+ d7 Transmit buffer empty (inverted)
+ d6 CTS pin
+ d5 DSR pin
+ d4 CD pin
+ d3 Parity Error
+ d2 Framing Error
+ d1 Overrun
+ d0 Data Available */
+
+ UINT8 data=70;
+ ay31015_set_input_pin( m_ay31015, AY31015_SWE, 0 );
+ data |= ay31015_get_output_pin( m_ay31015, AY31015_TBMT ) ? 0 : 0x80;
+ data |= ay31015_get_output_pin( m_ay31015, AY31015_DAV ) ? 0x01 : 0;
+ data |= ay31015_get_output_pin( m_ay31015, AY31015_OR ) ? 0x02 : 0;
+ data |= ay31015_get_output_pin( m_ay31015, AY31015_FE ) ? 0x04 : 0;
+ data |= ay31015_get_output_pin( m_ay31015, AY31015_PE ) ? 0x08 : 0;
+ ay31015_set_input_pin( m_ay31015, AY31015_SWE, 1 );
+
+ return data;
+}
+
+READ8_MEMBER( trs80_state::lnw80_fe_r )
+{
+ return ((m_mode & 0x78) >> 3) | 0xf0;
+}
+
+READ8_MEMBER( trs80_state::trs80_ff_r )
+{
+/* ModeSel and cassette data
+ d7 cassette data from tape
+ d2 modesel setting */
+
+ UINT8 data = (~m_mode & 1) << 5;
+ return data | m_cassette_data;
+}
+
+READ8_MEMBER( trs80_state::trs80m4_ff_r )
+{
+/* Return of cassette data stream from tape
+ d7 Low-speed data
+ d6..d1 info from write of port EC
+ d0 High-speed data */
+
+ m_irq &= 0xfc; /* clear cassette interrupts */
+
+ return m_port_ec | m_cassette_data;
+}
+
+
+WRITE8_MEMBER( trs80_state::trs80m4_84_w )
+{
+/* Hi-res graphics control - d6..d4 not emulated
+ d7 Page Control
+ d6 Fix upper memory
+ d5 Memory bit 1
+ d4 Memory bit 0
+ d3 Invert Video
+ d2 80/64 width
+ d1 Select bit 1
+ d0 Select bit 0 */
+
+ /* get address space instead of io space */
+ address_space *mem = m_maincpu->memory().space(AS_PROGRAM);
+ UINT8 *base = memregion("maincpu")->base();
+
+ m_mode = (m_mode & 0x73) | (data & 0x8c);
+
+ m_model4 &= 0xce;
+ m_model4 |= (data & 3) << 4;
+
+ switch (data & 3)
+ {
+ case 0: /* normal operation */
+
+ if (m_model4 & 4) /* Model 4P gets RAM while Model 4 gets ROM */
+ {
+ if (m_model4 & 8)
+ membank("bank1")->set_base(base);
+ else
+ membank("bank1")->set_base(base + 0x10000);
+
+ membank("bank2")->set_base(base + 0x11000);
+ membank("bank4")->set_base(base + 0x137ea);
+ }
+ else
+ {
+ membank("bank1")->set_base(base);
+ membank("bank2")->set_base(base + 0x01000);
+ membank("bank4")->set_base(base + 0x037ea);
+ }
+
+ membank("bank7")->set_base(base + 0x14000);
+ membank("bank8")->set_base(base + 0x1f400);
+ membank("bank9")->set_base(base + 0x1f800);
+ membank("bank11")->set_base(base + 0x05000);
+ membank("bank12")->set_base(base + 0x06000);
+ membank("bank14")->set_base(base + 0x09000);
+ membank("bank15")->set_base(base + 0x0a000);
+ membank("bank17")->set_base(base + 0x14000);
+ membank("bank18")->set_base(base + 0x1f400);
+ membank("bank19")->set_base(base + 0x1f800);
+ mem->install_readwrite_handler (0x37e8, 0x37e9, read8_delegate(FUNC(trs80_state::trs80_printer_r), this), write8_delegate(FUNC(trs80_state::trs80_printer_w), this)); /* 3 & 13 */
+ mem->install_read_handler (0x3800, 0x3bff, read8_delegate(FUNC(trs80_state::trs80_keyboard_r), this)); /* 5 */
+ mem->install_readwrite_handler (0x3c00, 0x3fff, read8_delegate(FUNC(trs80_state::trs80_videoram_r), this), write8_delegate(FUNC(trs80_state::trs80_videoram_w), this)); /* 6 & 16 */
+ break;
+
+ case 1: /* write-only ram backs up the rom */
+
+ if (m_model4 & 4) /* Model 4P gets RAM while Model 4 gets ROM */
+ {
+ if (m_model4 & 8)
+ membank("bank1")->set_base(base);
+ else
+ membank("bank1")->set_base(base + 0x10000);
+
+ membank("bank2")->set_base(base + 0x11000);
+ membank("bank3")->set_base(base + 0x137e8);
+ membank("bank4")->set_base(base + 0x137ea);
+ }
+ else
+ {
+ membank("bank1")->set_base(base);
+ membank("bank2")->set_base(base + 0x01000);
+ membank("bank3")->set_base(base + 0x037e8);
+ membank("bank4")->set_base(base + 0x037ea);
+ }
+
+ membank("bank7")->set_base(base + 0x14000);
+ membank("bank8")->set_base(base + 0x1f400);
+ membank("bank9")->set_base(base + 0x1f800);
+ membank("bank11")->set_base(base + 0x10000);
+ membank("bank12")->set_base(base + 0x11000);
+ membank("bank13")->set_base(base + 0x137e8);
+ membank("bank14")->set_base(base + 0x137ea);
+ membank("bank15")->set_base(base + 0x0a000);
+ membank("bank17")->set_base(base + 0x14000);
+ membank("bank18")->set_base(base + 0x1f400);
+ membank("bank19")->set_base(base + 0x1f800);
+ mem->install_read_handler (0x3800, 0x3bff, read8_delegate(FUNC(trs80_state::trs80_keyboard_r), this)); /* 5 */
+ mem->install_readwrite_handler (0x3c00, 0x3fff, read8_delegate(FUNC(trs80_state::trs80_videoram_r), this), write8_delegate(FUNC(trs80_state::trs80_videoram_w), this)); /* 6 & 16 */
+ break;
+
+ case 2: /* keyboard and video are moved to high memory, and the rest is ram */
+ membank("bank1")->set_base(base + 0x10000);
+ membank("bank2")->set_base(base + 0x11000);
+ membank("bank3")->set_base(base + 0x137e8);
+ membank("bank4")->set_base(base + 0x137ea);
+ membank("bank5")->set_base(base + 0x13800);
+ membank("bank6")->set_base(base + 0x13c00);
+ membank("bank7")->set_base(base + 0x14000);
+ membank("bank11")->set_base(base + 0x10000);
+ membank("bank12")->set_base(base + 0x11000);
+ membank("bank13")->set_base(base + 0x137e8);
+ membank("bank14")->set_base(base + 0x137ea);
+ membank("bank15")->set_base(base + 0x13800);
+ membank("bank16")->set_base(base + 0x13c00);
+ membank("bank17")->set_base(base + 0x14000);
+ membank("bank18")->set_base(base + 0x0a000);
+ mem->install_read_handler (0xf400, 0xf7ff, read8_delegate(FUNC(trs80_state::trs80_keyboard_r), this)); /* 8 */
+ mem->install_readwrite_handler (0xf800, 0xffff, read8_delegate(FUNC(trs80_state::trs80_videoram_r), this), write8_delegate(FUNC(trs80_state::trs80_videoram_w), this)); /* 9 & 19 */
+ m_model4++;
+ break;
+
+ case 3: /* 64k of ram */
+ membank("bank1")->set_base(base + 0x10000);
+ membank("bank2")->set_base(base + 0x11000);
+ membank("bank3")->set_base(base + 0x137e8);
+ membank("bank4")->set_base(base + 0x137ea);
+ membank("bank5")->set_base(base + 0x13800);
+ membank("bank6")->set_base(base + 0x13c00);
+ membank("bank7")->set_base(base + 0x14000);
+ membank("bank8")->set_base(base + 0x1f400);
+ membank("bank9")->set_base(base + 0x1f800);
+ membank("bank11")->set_base(base + 0x10000);
+ membank("bank12")->set_base(base + 0x11000);
+ membank("bank13")->set_base(base + 0x137e8);
+ membank("bank14")->set_base(base + 0x137ea);
+ membank("bank15")->set_base(base + 0x13800);
+ membank("bank16")->set_base(base + 0x13c00);
+ membank("bank17")->set_base(base + 0x14000);
+ membank("bank18")->set_base(base + 0x1f400);
+ membank("bank19")->set_base(base + 0x1f800);
+ break;
+ }
+}
+
+WRITE8_MEMBER( trs80_state::trs80m4_90_w )
+{
+ speaker_level_w(m_speaker, ~data & 1);
+}
+
+WRITE8_MEMBER( trs80_state::trs80m4p_9c_w ) /* model 4P only - swaps the ROM with read-only RAM */
+{
+ /* Meaning of model4 variable:
+ d5..d4 memory mode (as described in section above)
+ d3 rom switch (1=enabled) only effective in mode0 and 1
+ d2 this is a Model 4P
+ d1 this is a Model 4
+ d0 Video banking exists yes/no (1=not banked) */
+
+ m_model4 &= 0xf7;
+ m_model4 |= (data << 3);
+
+ if ((m_model4) && (~m_model4 & 0x20))
+ {
+ switch (m_model4 & 8)
+ {
+ case 0: /* Read-only RAM replaces rom */
+ membank("bank1")->set_base(machine().root_device().memregion("maincpu")->base() + 0x10000);
+ break;
+ case 8: /* Normal setup - rom enabled */
+ membank("bank1")->set_base(machine().root_device().memregion("maincpu")->base());
+ break;
+ }
+ }
+}
+
+WRITE8_MEMBER( trs80_state::trs80m4_e0_w )
+{
+/* Interrupt settings - which devices are allowed to interrupt - bits align with read of E0
+ d6 Enable Rec Err
+ d5 Enable Rec Data
+ d4 Enable Xmit Emp
+ d3 Enable I/O int
+ d2 Enable RT int
+ d1 C fall Int
+ d0 C Rise Int */
+
+ m_mask = data;
+}
+
+WRITE8_MEMBER( trs80_state::trs80m4_e4_w )
+{
+/* Disk to NMI interface
+ d7 1=enable disk INTRQ to generate NMI
+ d6 1=enable disk Motor Timeout to generate NMI */
+
+ m_nmi_mask = data;
+}
+
+WRITE8_MEMBER( trs80_state::trs80m4_e8_w )
+{
+/* d1 when '1' enables control register load (see below) */
+
+ m_reg_load = data & 2;
+}
+
+WRITE8_MEMBER( trs80_state::trs80m4_e9_w )
+{
+/* UART set baud rate. Rx = bits 0..3, Tx = bits 4..7
+ 00h 50
+ 11h 75
+ 22h 110
+ 33h 134.5
+ 44h 150
+ 55h 300
+ 66h 600
+ 77h 1200
+ 88h 1800
+ 99h 2000
+ AAh 2400
+ BBh 3600
+ CCh 4800
+ DDh 7200
+ EEh 9600
+ FFh 19200 */
+
+ static const int baud_clock[]={ 800, 1200, 1760, 2152, 2400, 4800, 9600, 19200, 28800, 32000, 38400, 57600, 76800, 115200, 153600, 307200 };
+ ay31015_set_receiver_clock( m_ay31015, baud_clock[data & 0x0f]);
+ ay31015_set_transmitter_clock( m_ay31015, baud_clock[data>>4]);
+}
+
+WRITE8_MEMBER( trs80_state::trs80m4_ea_w )
+{
+ if (m_reg_load)
+
+/* d2..d0 not emulated
+ d7 Even Parity Enable ('1'=even, '0'=odd)
+ d6='1',d5='1' for 8 bits
+ d6='0',d5='1' for 7 bits
+ d6='1',d5='0' for 6 bits
+ d6='0',d5='0' for 5 bits
+ d4 Stop Bit Select ('1'=two stop bits, '0'=one stop bit)
+ d3 Parity Inhibit ('1'=disable; No parity, '0'=parity enabled)
+ d2 Break ('0'=disable transmit data; continuous RS232 'SPACE' condition)
+ d1 Request-to-Send (RTS), pin 4
+ d0 Data-Terminal-Ready (DTR), pin 20 */
+
+ {
+ ay31015_set_input_pin( m_ay31015, AY31015_CS, 0 );
+ ay31015_set_input_pin( m_ay31015, AY31015_NB1, ( data & 0x40 ) ? 1 : 0 );
+ ay31015_set_input_pin( m_ay31015, AY31015_NB2, ( data & 0x20 ) ? 1 : 0 );
+ ay31015_set_input_pin( m_ay31015, AY31015_TSB, ( data & 0x10 ) ? 1 : 0 );
+ ay31015_set_input_pin( m_ay31015, AY31015_EPS, ( data & 0x80 ) ? 1 : 0 );
+ ay31015_set_input_pin( m_ay31015, AY31015_NP, ( data & 0x08 ) ? 1 : 0 );
+ ay31015_set_input_pin( m_ay31015, AY31015_CS, 1 );
+ }
+ else
+ {
+
+/* not emulated
+ d7,d6 Not used
+ d5 Secondary Unassigned, pin 18
+ d4 Secondary Transmit Data, pin 14
+ d3 Secondary Request-to-Send, pin 19
+ d2 Break ('0'=disable transmit data; continuous RS232 'SPACE' condition)
+ d1 Data-Terminal-Ready (DTR), pin 20
+ d0 Request-to-Send (RTS), pin 4 */
+
+ }
+}
+
+WRITE8_MEMBER( trs80_state::trs80m4_eb_w )
+{
+ ay31015_set_transmit_data( m_ay31015, data );
+}
+
+WRITE8_MEMBER( trs80_state::trs80m4_ec_w )
+{
+/* Hardware settings - d5..d4 not emulated
+ d6 CPU fast (1=4MHz, 0=2MHz)
+ d5 1=Enable Video Wait
+ d4 1=Enable External I/O bus
+ d3 1=Enable Alternate Character Set
+ d2 Mode Select (0=64 chars, 1=32chars)
+ d1 Cassette Motor (1=On) */
+
+ m_maincpu->set_unscaled_clock(data & 0x40 ? MODEL4_MASTER_CLOCK/5 : MODEL4_MASTER_CLOCK/10);
+
+ m_mode = (m_mode & 0xde) | ((data & 4) ? 1 : 0) | ((data & 8) ? 0x20 : 0);
+
+ m_cass->change_state(( data & 2 ) ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED,CASSETTE_MASK_MOTOR );
+
+ m_port_ec = data & 0x7e;
+}
+
+WRITE8_MEMBER( trs80_state::trs80m4_f4_w )
+{
+/* Selection of drive and parameters - d6..d5 not emulated.
+ A write also causes the selected drive motor to turn on for about 3 seconds.
+ When the motor turns off, the drive is deselected.
+ d7 1=MFM, 0=FM
+ d6 1=Wait
+ d5 1=Write Precompensation enabled
+ d4 0=Side 0, 1=Side 1
+ d3 1=select drive 3
+ d2 1=select drive 2
+ d1 1=select drive 1
+ d0 1=select drive 0 */
+
+ UINT8 drive = 255;
+
+ if (data & 1)
+ drive = 0;
+ else
+ if (data & 2)
+ drive = 1;
+ else
+ if (data & 4)
+ drive = 2;
+ else
+ if (data & 8)
+ drive = 3;
+
+ m_head = (data & 16) ? 1 : 0;
+
+ if (drive < 4)
+ {
+ wd17xx_set_drive(m_fdc,drive);
+ wd17xx_set_side(m_fdc,m_head);
+ }
+
+ wd17xx_dden_w(m_fdc, !BIT(data, 7));
+
+ /* CLEAR_LINE means to turn motors on */
+ floppy_mon_w(floppy_get_device(machine(), 0), (data & 0x0f) ? CLEAR_LINE : ASSERT_LINE);
+ floppy_mon_w(floppy_get_device(machine(), 1), (data & 0x0f) ? CLEAR_LINE : ASSERT_LINE);
+ floppy_mon_w(floppy_get_device(machine(), 2), (data & 0x0f) ? CLEAR_LINE : ASSERT_LINE);
+ floppy_mon_w(floppy_get_device(machine(), 3), (data & 0x0f) ? CLEAR_LINE : ASSERT_LINE);
+}
+
+WRITE8_MEMBER( trs80_state::sys80_f8_w )
+{
+/* not emulated
+ d2 reset UART (XR pin)
+ d1 DTR
+ d0 RTS */
+}
+
+WRITE8_MEMBER( trs80_state::sys80_fe_w )
+{
+/* not emulated
+ d4 select internal or external cassette player */
+
+ m_tape_unit = (data & 0x10) ? 2 : 1;
+}
+
+/* lnw80 can switch out all the devices, roms and video ram to be replaced by graphics ram. */
+WRITE8_MEMBER( trs80_state::lnw80_fe_w )
+{
+/* lnw80 video options
+ d3 bankswitch lower 16k between roms and hires ram (1=hires)
+ d2 enable colour \
+ d1 hres / these 2 are the bits from the MODE command of LNWBASIC
+ d0 inverse video (entire screen) */
+
+ /* get address space instead of io space */
+ address_space *mem = m_maincpu->memory().space(AS_PROGRAM);
+
+ m_mode = (m_mode & 0x87) | ((data & 0x0f) << 3);
+
+ if (data & 8)
+ {
+ mem->unmap_readwrite (0x0000, 0x3fff);
+ mem->install_readwrite_handler (0x0000, 0x3fff, read8_delegate(FUNC(trs80_state::trs80_gfxram_r), this), write8_delegate(FUNC(trs80_state::trs80_gfxram_w), this));
+ }
+ else
+ {
+ mem->unmap_readwrite (0x0000, 0x3fff);
+ mem->install_read_bank (0x0000, 0x2fff, "bank1");
+ membank("bank1")->set_base(machine().root_device().memregion("maincpu")->base());
+ mem->install_readwrite_handler (0x37e0, 0x37e3, read8_delegate(FUNC(trs80_state::trs80_irq_status_r), this), write8_delegate(FUNC(trs80_state::trs80_motor_w), this));
+ mem->install_readwrite_handler (0x37e8, 0x37eb, read8_delegate(FUNC(trs80_state::trs80_printer_r), this), write8_delegate(FUNC(trs80_state::trs80_printer_w), this));
+ mem->install_read_handler (0x37ec, 0x37ec, read8_delegate(FUNC(trs80_state::trs80_wd179x_r), this));
+ mem->install_legacy_write_handler (*m_fdc, 0x37ec, 0x37ec, FUNC(wd17xx_command_w));
+ mem->install_legacy_readwrite_handler (*m_fdc, 0x37ed, 0x37ed, FUNC(wd17xx_track_r), FUNC(wd17xx_track_w));
+ mem->install_legacy_readwrite_handler (*m_fdc, 0x37ee, 0x37ee, FUNC(wd17xx_sector_r), FUNC(wd17xx_sector_w));
+ mem->install_legacy_readwrite_handler (*m_fdc, 0x37ef, 0x37ef, FUNC(wd17xx_data_r), FUNC(wd17xx_data_w));
+ mem->install_read_handler (0x3800, 0x38ff, 0, 0x0300, read8_delegate(FUNC(trs80_state::trs80_keyboard_r), this));
+ mem->install_readwrite_handler (0x3c00, 0x3fff, read8_delegate(FUNC(trs80_state::trs80_videoram_r), this), write8_delegate(FUNC(trs80_state::trs80_videoram_w), this));
+ }
+}
+
+WRITE8_MEMBER( trs80_state::trs80_ff_w )
+{
+/* Standard output port of Model I
+ d3 ModeSel bit
+ d2 Relay
+ d1, d0 Cassette output */
+
+ static const double levels[4] = { 0.0, -1.0, 0.0, 1.0 };
+
+ m_cass->change_state(( data & 4 ) ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED,CASSETTE_MASK_MOTOR );
+ m_cass->output(levels[data & 3]);
+ m_cassette_data &= ~0x80;
+
+ m_mode = (m_mode & 0xfe) | ((data & 8) >> 3);
+
+ /* Speaker for System-80 MK II - only sounds if relay is off */
+ if (~data & 4)
+ speaker_level_w(m_speaker, data & 3);
+}
+
+WRITE8_MEMBER( trs80_state::trs80m4_ff_w )
+{
+/* Cassette port
+ d1, d0 Cassette output */
+
+ static const double levels[4] = { 0.0, -1.0, 0.0, 1.0 };
+ m_cass->output(levels[data & 3]);
+ m_cassette_data &= ~0x80;
+}
+
+
+/*************************************
+ *
+ * Interrupt handlers.
+ *
+ *************************************/
+
+INTERRUPT_GEN( trs80_rtc_interrupt )
+{
+ trs80_state *state = device->machine().driver_data<trs80_state>();
+/* This enables the processing of interrupts for the clock and the flashing cursor.
+ The OS counts one tick for each interrupt. The Model I has 40 ticks per
+ second, while the Model III/4 has 30. */
+
+ if (state->m_model4) // Model 4
+ {
+ if (state->m_mask & IRQ_M4_RTC)
+ {
+ state->m_irq |= IRQ_M4_RTC;
+ device_set_input_line(device, 0, HOLD_LINE);
+ }
+ }
+ else // Model 1
+ {
+ state->m_irq |= IRQ_M1_RTC;
+ device_set_input_line(device, 0, HOLD_LINE);
+ }
+}
+
+static void trs80_fdc_interrupt_internal(running_machine &machine)
+{
+ trs80_state *state = machine.driver_data<trs80_state>();
+ if (state->m_model4)
+ {
+ if (state->m_nmi_mask & 0x80) // Model 4 does a NMI
+ {
+ state->m_nmi_data = 0x80;
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_NMI, PULSE_LINE);
+ }
+ }
+ else // Model 1 does a IRQ
+ {
+ state->m_irq |= IRQ_M1_FDC;
+ cputag_set_input_line(machine, "maincpu", 0, HOLD_LINE);
+ }
+}
+
+INTERRUPT_GEN( trs80_fdc_interrupt ) /* not used - should it be? */
+{
+ trs80_fdc_interrupt_internal(device->machine());
+}
+
+static WRITE_LINE_DEVICE_HANDLER( trs80_fdc_intrq_w )
+{
+ trs80_state *drvstate = device->machine().driver_data<trs80_state>();
+ if (state)
+ {
+ trs80_fdc_interrupt_internal(device->machine());
+ }
+ else
+ {
+ if (drvstate->m_model4)
+ drvstate->m_nmi_data = 0;
+ else
+ drvstate->m_irq &= ~IRQ_M1_FDC;
+ }
+}
+
+const wd17xx_interface trs80_wd17xx_interface =
+{
+ DEVCB_NULL,
+ DEVCB_LINE(trs80_fdc_intrq_w),
+ DEVCB_NULL,
+ {FLOPPY_0, FLOPPY_1, FLOPPY_2, FLOPPY_3}
+};
+
+
+/*************************************
+ * *
+ * Memory handlers *
+ * *
+ *************************************/
+
+READ8_MEMBER( trs80_state::trs80_wd179x_r )
+{
+ UINT8 data = 0xff;
+ if (BIT(ioport("CONFIG")->read(), 7))
+ data = wd17xx_status_r(m_fdc, offset);
+
+ return data;
+}
+
+READ8_MEMBER( trs80_state::trs80_printer_r )
+{
+ /* Bit 7 - 1 = Busy; 0 = Not Busy
+ Bit 6 - 1 = Out of Paper; 0 = Paper
+ Bit 5 - 1 = Printer selected; 0 = Printer not selected
+ Bit 4 - 1 = No Fault; 0 = Fault
+ Bits 3..0 - Not used */
+
+ UINT8 data = 0;
+ data |= m_printer->busy_r() << 7;
+ data |= m_printer->pe_r() << 6;
+ data |= m_printer->vcc_r() << 5;
+ data |= m_printer->fault_r() << 4;
+
+ return data;
+}
+
+WRITE8_MEMBER( trs80_state::trs80_printer_w )
+{
+ m_printer->strobe_w(1);
+ m_printer->write(space, 0, data);
+ m_printer->strobe_w(0);
+}
+
+WRITE8_MEMBER( trs80_state::trs80_cassunit_w )
+{
+/* not emulated
+ 01 for unit 1 (default)
+ 02 for unit 2 */
+
+ m_tape_unit = data;
+}
+
+READ8_MEMBER( trs80_state::trs80_irq_status_r )
+{
+/* (trs80l2) Whenever an interrupt occurs, 37E0 is read to see what devices require service.
+ d7 = RTC
+ d6 = FDC
+ d2 = Communications (not emulated)
+ All interrupting devices are serviced in a single interrupt. There is a mask byte,
+ which is dealt with by the DOS. We take the opportunity to reset the cpu INT line. */
+
+ int result = m_irq;
+ cputag_set_input_line(machine(), "maincpu", 0, CLEAR_LINE);
+ m_irq = 0;
+ return result;
+}
+
+
+WRITE8_MEMBER( trs80_state::trs80_motor_w )
+{
+ UINT8 drive = 255;
+
+ switch (data)
+ {
+ case 1:
+ drive = 0;
+ m_head = 0;
+ break;
+ case 2:
+ drive = 1;
+ m_head = 0;
+ break;
+ case 4:
+ drive = 2;
+ m_head = 0;
+ break;
+ case 8:
+ drive = 3;
+ m_head = 0;
+ break;
+ /* These 3 combinations aren't official. Some manufacturers of double-sided disks
+ used drive select 4 to indicate the other side. */
+ case 9:
+ drive = 0;
+ m_head = 1;
+ break;
+ case 10:
+ drive = 1;
+ m_head = 1;
+ break;
+ case 12:
+ drive = 2;
+ m_head = 1;
+ break;
+ }
+
+ if (drive > 3)
+ { /* Turn motors off */
+ floppy_mon_w(floppy_get_device(machine(), 0), ASSERT_LINE);
+ floppy_mon_w(floppy_get_device(machine(), 1), ASSERT_LINE);
+ floppy_mon_w(floppy_get_device(machine(), 2), ASSERT_LINE);
+ floppy_mon_w(floppy_get_device(machine(), 3), ASSERT_LINE);
+ return;
+ }
+
+ wd17xx_set_drive(m_fdc,drive);
+ wd17xx_set_side(m_fdc,m_head);
+
+ /* Turn motors on */
+ floppy_mon_w(floppy_get_device(machine(), 0), CLEAR_LINE);
+ floppy_mon_w(floppy_get_device(machine(), 1), CLEAR_LINE);
+ floppy_mon_w(floppy_get_device(machine(), 2), CLEAR_LINE);
+ floppy_mon_w(floppy_get_device(machine(), 3), CLEAR_LINE);
+}
+
+/*************************************
+ * Keyboard *
+ *************************************/
+READ8_MEMBER( trs80_state::trs80_keyboard_r )
+{
+ UINT8 result = 0;
+
+ if (offset & 1)
+ result |= ioport("LINE0")->read();
+ if (offset & 2)
+ result |= ioport("LINE1")->read();
+ if (offset & 4)
+ result |= ioport("LINE2")->read();
+ if (offset & 8)
+ result |= ioport("LINE3")->read();
+ if (offset & 16)
+ result |= ioport("LINE4")->read();
+ if (offset & 32)
+ result |= ioport("LINE5")->read();
+ if (offset & 64)
+ result |= ioport("LINE6")->read();
+ if (offset & 128)
+ result |= ioport("LINE7")->read();
+
+ return result;
+}
+
+
+/*************************************
+ * Machine *
+ *************************************/
+
+MACHINE_START( trs80 )
+{
+ trs80_state *state = machine.driver_data<trs80_state>();
+ state->m_tape_unit=1;
+ state->m_reg_load=1;
+ state->m_nmi_data=0xff;
+
+ state->m_cassette_data_timer = machine.scheduler().timer_alloc(FUNC(cassette_data_callback));
+ state->m_cassette_data_timer->adjust( attotime::zero, 0, attotime::from_hz(11025) );
+}
+
+MACHINE_RESET( trs80 )
+{
+ trs80_state *state = machine.driver_data<trs80_state>();
+ state->m_cassette_data = 0;
+}
+
+MACHINE_RESET( trs80m4 )
+{
+ trs80_state *state = machine.driver_data<trs80_state>();
+ address_space *mem = state->m_maincpu->memory().space(AS_PROGRAM);
+ state->m_cassette_data = 0;
+
+ mem->install_read_bank (0x0000, 0x0fff, "bank1");
+ mem->install_read_bank (0x1000, 0x37e7, "bank2");
+ mem->install_read_bank (0x37e8, 0x37e9, "bank3");
+ mem->install_read_bank (0x37ea, 0x37ff, "bank4");
+ mem->install_read_bank (0x3800, 0x3bff, "bank5");
+ mem->install_read_bank (0x3c00, 0x3fff, "bank6");
+ mem->install_read_bank (0x4000, 0xf3ff, "bank7");
+ mem->install_read_bank (0xf400, 0xf7ff, "bank8");
+ mem->install_read_bank (0xf800, 0xffff, "bank9");
+
+ mem->install_write_bank (0x0000, 0x0fff, "bank11");
+ mem->install_write_bank (0x1000, 0x37e7, "bank12");
+ mem->install_write_bank (0x37e8, 0x37e9, "bank13");
+ mem->install_write_bank (0x37ea, 0x37ff, "bank14");
+ mem->install_write_bank (0x3800, 0x3bff, "bank15");
+ mem->install_write_bank (0x3c00, 0x3fff, "bank16");
+ mem->install_write_bank (0x4000, 0xf3ff, "bank17");
+ mem->install_write_bank (0xf400, 0xf7ff, "bank18");
+ mem->install_write_bank (0xf800, 0xffff, "bank19");
+ state->trs80m4p_9c_w(*mem, 0, 1); /* Enable the ROM */
+ state->trs80m4_84_w(*mem, 0, 0); /* switch in devices at power-on */
+}
+
+MACHINE_RESET( lnw80 )
+{
+ trs80_state *state = machine.driver_data<trs80_state>();
+ address_space *space = state->m_maincpu->memory().space(AS_PROGRAM);
+ state->m_cassette_data = 0;
+ state->m_reg_load = 1;
+ state->lnw80_fe_w(*space, 0, 0);
+}
+
diff --git a/src/mess/machine/trs80m2kb.c b/src/mess/machine/trs80m2kb.c
new file mode 100644
index 00000000000..218102c0327
--- /dev/null
+++ b/src/mess/machine/trs80m2kb.c
@@ -0,0 +1,389 @@
+/**********************************************************************
+
+ Tandy Radio Shack TRS-80 Model II keyboard emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "trs80m2kb.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define I8021_TAG "z4"
+
+
+enum
+{
+ LED_0 = 0,
+ LED_1
+};
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type TRS80M2_KEYBOARD = &device_creator<trs80m2_keyboard_device>;
+
+
+
+//-------------------------------------------------
+// ROM( trs80m2_keyboard )
+//-------------------------------------------------
+
+ROM_START( trs80m2_keyboard )
+ ROM_REGION( 0x400, I8021_TAG, 0 )
+ ROM_LOAD( "65-1991.z4", 0x0000, 0x0400, NO_DUMP )
+ROM_END
+
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *trs80m2_keyboard_device::device_rom_region() const
+{
+ return ROM_NAME( trs80m2_keyboard );
+}
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( kb_io )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( trs80m2_keyboard_io, AS_IO, 8, trs80m2_keyboard_device )
+ AM_RANGE(MCS48_PORT_T1, MCS48_PORT_T1) AM_READ(kb_t1_r)
+ AM_RANGE(MCS48_PORT_P0, MCS48_PORT_P0) AM_READ(kb_p0_r)
+ AM_RANGE(MCS48_PORT_P1, MCS48_PORT_P1) AM_WRITE(kb_p1_w)
+ AM_RANGE(MCS48_PORT_P2, MCS48_PORT_P2) AM_WRITE(kb_p2_w)
+ADDRESS_MAP_END
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( trs80m2_keyboard )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( trs80m2_keyboard )
+ MCFG_CPU_ADD(I8021_TAG, I8021, 3000000) // 1000uH inductor connected across the XTAL inputs
+ MCFG_CPU_IO_MAP(trs80m2_keyboard_io)
+ MCFG_DEVICE_DISABLE() // TODO
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor trs80m2_keyboard_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( trs80m2_keyboard );
+}
+
+
+//-------------------------------------------------
+// INPUT_PORTS( trs80m2_keyboard )
+//-------------------------------------------------
+
+INPUT_PORTS_START( trs80m2_keyboard )
+/*
+ PORT_START("X0")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("SPACE") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 0") PORT_CODE(KEYCODE_0_PAD)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("X1")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
+ PORT_BIT( 0x20, 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_B) PORT_CHAR('b') PORT_CHAR('B')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(UTF8_DOWN) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN))
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("X2")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("REPEAT")
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Right SHIFT") PORT_CODE(KEYCODE_RSHIFT)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("CAPS") PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK))
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Left SHIFT") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("LOCK")
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("CTRL") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL))
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("X3")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("cannot read label")
+ PORT_BIT( 0x40, 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( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad .") PORT_CODE(KEYCODE_DEL_PAD)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 3") PORT_CODE(KEYCODE_3_PAD)
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(UTF8_LEFT) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
+
+ PORT_START("X4")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("BACKSPACE") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8)
+ PORT_BIT( 0x40, 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_O) PORT_CHAR('o') PORT_CHAR('O')
+ PORT_BIT( 0x10, 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( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F2") PORT_CODE(KEYCODE_F2)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 5") PORT_CODE(KEYCODE_5_PAD)
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(UTF8_RIGHT) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT))
+
+ PORT_START("X5")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("HOLD")
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}')
+ PORT_BIT( 0x20, 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_6) PORT_CHAR('6') PORT_CHAR('^')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F1") PORT_CODE(KEYCODE_F1)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 2") PORT_CODE(KEYCODE_2_PAD)
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(UTF8_UP) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP))
+
+ PORT_START("X6")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("ENTER") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K')
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad ENTER") PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(13)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 9") PORT_CODE(KEYCODE_9_PAD)
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 7") PORT_CODE(KEYCODE_7_PAD)
+
+ PORT_START("X7")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('"')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*')
+ PORT_BIT( 0x10, 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_W) PORT_CHAR('w') PORT_CHAR('W')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 6") PORT_CODE(KEYCODE_6_PAD)
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 4") PORT_CODE(KEYCODE_4_PAD)
+
+ PORT_START("X8")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_')
+ PORT_BIT( 0x20, 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_5) PORT_CHAR('5') PORT_CHAR('%')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 8") PORT_CODE(KEYCODE_8_PAD)
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 1") PORT_CODE(KEYCODE_1_PAD)
+
+ PORT_START("X9")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{')
+ PORT_BIT( 0x20, 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_T) PORT_CHAR('t') PORT_CHAR('T')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("XA")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&')
+ PORT_BIT( 0x10, 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_1) PORT_CHAR('1') PORT_CHAR('!')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("ESC") PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC))
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("XB")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x40, 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_U) PORT_CHAR('u') PORT_CHAR('U')
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("TAB") PORT_CODE(KEYCODE_TAB) PORT_CHAR('\t')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED )
+*/
+INPUT_PORTS_END
+
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+ioport_constructor trs80m2_keyboard_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( trs80m2_keyboard );
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// trs80m2_keyboard_device - constructor
+//-------------------------------------------------
+
+trs80m2_keyboard_device::trs80m2_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, TRS80M2_KEYBOARD, "TRS-80 Model II Keyboard", tag, owner, clock),
+ m_maincpu(*this, I8021_TAG),
+ m_busy(1),
+ m_data(1),
+ m_clk(0)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void trs80m2_keyboard_device::device_start()
+{
+ // resolve callbacks
+ m_out_clock_func.resolve(m_out_clock_cb, *this);
+
+ // state saving
+ save_item(NAME(m_busy));
+ save_item(NAME(m_data));
+ save_item(NAME(m_clk));
+ save_item(NAME(m_y));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void trs80m2_keyboard_device::device_reset()
+{
+}
+
+
+//-------------------------------------------------
+// busy_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( trs80m2_keyboard_device::busy_w )
+{
+ m_busy = state;
+}
+
+
+//-------------------------------------------------
+// data_r -
+//-------------------------------------------------
+
+READ_LINE_MEMBER( trs80m2_keyboard_device::data_r )
+{
+ return m_data;
+}
+
+//-------------------------------------------------
+// kb_t1_r -
+//-------------------------------------------------
+
+READ8_MEMBER( trs80m2_keyboard_device::kb_t1_r )
+{
+ return m_busy;
+}
+
+
+//-------------------------------------------------
+// kb_p0_r -
+//-------------------------------------------------
+
+READ8_MEMBER( trs80m2_keyboard_device::kb_p0_r )
+{
+ UINT8 data = 0xff;
+
+ switch (m_y)
+ {
+ case 0: data &= ioport("X0")->read(); break;
+ case 1: data &= ioport("X1")->read(); break;
+ case 2: data &= ioport("X2")->read(); break;
+ case 3: data &= ioport("X3")->read(); break;
+ case 4: data &= ioport("X4")->read(); break;
+ case 5: data &= ioport("X5")->read(); break;
+ case 6: data &= ioport("X6")->read(); break;
+ case 7: data &= ioport("X7")->read(); break;
+ case 8: data &= ioport("X8")->read(); break;
+ case 9: data &= ioport("X9")->read(); break;
+ case 0xa: data &= ioport("XA")->read(); break;
+ case 0xb: data &= ioport("XB")->read(); break;
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// kb_p1_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( trs80m2_keyboard_device::kb_p1_w )
+{
+ /*
+
+ bit description
+
+ 0 DATA
+ 1 CLOCK
+ 2 LED
+ 3
+ 4 LED
+ 5
+ 6
+ 7
+
+ */
+
+ m_data = BIT(data, 0);
+ int clk = BIT(data, 1);
+
+ if (m_clk != clk)
+ {
+ m_out_clock_func(clk);
+ m_clk = clk;
+ }
+
+ output_set_led_value(LED_0, BIT(data, 2));
+ output_set_led_value(LED_1, BIT(data, 4));
+}
+
+
+//-------------------------------------------------
+// kb_p2_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( trs80m2_keyboard_device::kb_p2_w )
+{
+ /*
+
+ bit description
+
+ 0 D
+ 1 C
+ 2 B
+ 3 A
+ 4
+ 5
+ 6
+ 7
+
+ */
+
+ m_y = BITSWAP8(data, 7, 6, 5, 4, 0, 1, 2, 3) & 0x0f;
+}
diff --git a/src/mess/machine/trs80m2kb.h b/src/mess/machine/trs80m2kb.h
new file mode 100644
index 00000000000..10fae7659eb
--- /dev/null
+++ b/src/mess/machine/trs80m2kb.h
@@ -0,0 +1,103 @@
+/**********************************************************************
+
+ Tandy Radio Shack TRS-80 Model II keyboard emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __TRS80M2_KEYBOARD__
+#define __TRS80M2_KEYBOARD__
+
+
+#include "emu.h"
+#include "cpu/mcs48/mcs48.h"
+#include "sound/discrete.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define TRS80M2_KEYBOARD_TAG "trs80m2kb"
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_TRS80M2_KEYBOARD_ADD(_config) \
+ MCFG_DEVICE_ADD(TRS80M2_KEYBOARD_TAG, TRS80M2_KEYBOARD, 0) \
+ MCFG_DEVICE_CONFIG(_config)
+
+
+#define TRS80M2_KEYBOARD_INTERFACE(_name) \
+ const trs80m2_keyboard_interface (_name) =
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> trs80m2_keyboard_interface
+
+struct trs80m2_keyboard_interface
+{
+ devcb_write_line m_out_clock_cb;
+};
+
+
+// ======================> trs80m2_keyboard_device
+
+class trs80m2_keyboard_device : public device_t,
+ public trs80m2_keyboard_interface
+{
+public:
+ // construction/destruction
+ trs80m2_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_WRITE_LINE_MEMBER( busy_w );
+ DECLARE_READ_LINE_MEMBER( data_r );
+
+ // not really public
+ DECLARE_READ8_MEMBER( kb_t1_r );
+ DECLARE_READ8_MEMBER( kb_p0_r );
+ DECLARE_WRITE8_MEMBER( kb_p1_w );
+ DECLARE_WRITE8_MEMBER( kb_p2_w );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "trs80m2kb"; }
+
+private:
+ devcb_resolved_write_line m_out_clock_func;
+
+ required_device<cpu_device> m_maincpu;
+
+ int m_busy;
+ int m_data;
+ int m_clk;
+
+ UINT8 m_y;
+};
+
+
+// device type definition
+extern const device_type TRS80M2_KEYBOARD;
+
+
+
+#endif
diff --git a/src/mess/machine/tvc_hbf.c b/src/mess/machine/tvc_hbf.c
new file mode 100644
index 00000000000..4c5b03f9f7f
--- /dev/null
+++ b/src/mess/machine/tvc_hbf.c
@@ -0,0 +1,196 @@
+/***************************************************************************
+
+ tvc_hbf.c
+
+***************************************************************************/
+
+#include "emu.h"
+#include "tvc_hbf.h"
+
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+static LEGACY_FLOPPY_OPTIONS_START(tvc_hbf)
+ LEGACY_FLOPPY_OPTION(tvc_hbf, "img,dsk", "TVC DS disk image (720KB)", basicdsk_identify_default, basicdsk_construct_default, NULL,
+ HEADS([2])
+ TRACKS([80])
+ SECTORS([9])
+ SECTOR_LENGTH([512])
+ FIRST_SECTOR_ID([1]))
+ LEGACY_FLOPPY_OPTION(tvc_hbf, "img,dsk", "TVC SS disk image (360KB)", basicdsk_identify_default, basicdsk_construct_default, NULL,
+ HEADS([1])
+ TRACKS([80])
+ SECTORS([9])
+ SECTOR_LENGTH([512])
+ FIRST_SECTOR_ID([1]))
+LEGACY_FLOPPY_OPTIONS_END
+
+static const floppy_interface tvc_hbf_floppy_interface =
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ FLOPPY_STANDARD_5_25_DSDD,
+ LEGACY_FLOPPY_OPTIONS_NAME(tvc_hbf),
+ "floppy_5_25",
+ NULL
+};
+
+static MACHINE_CONFIG_FRAGMENT(tvc_hbf)
+ MCFG_FD1793_ADD("fdc", default_wd17xx_interface_2_drives)
+ MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(tvc_hbf_floppy_interface)
+MACHINE_CONFIG_END
+
+
+ROM_START( tvc_hbf )
+ ROM_REGION(0x4000, "hbf", 0)
+ // UPM version
+ ROM_LOAD_OPTIONAL("d_tvcupm.128", 0x0000, 0x4000, CRC(b3a567ad) SHA1(f92df6074b07f5f19e8c96ff1315da0cfeec9f74))
+
+ // VT-DOS v1.1 version
+ ROM_LOAD_OPTIONAL("d_tvcdos.128", 0x0000, 0x4000, CRC(2acf8477) SHA1(07bf39b633a564f98dd4b2e93bd889501b341550))
+
+ // VT-DOS v1.2 version
+ ROM_LOAD_OPTIONAL("d_dos12.128", 0x0000, 0x4000, CRC(f5c35597) SHA1(2fa44ad089a51f453b580e0b13e3be96a0f14649))
+
+ // Standalone version for use with BASIC
+ ROM_LOAD_OPTIONAL("hbf.rom", 0x0000, 0x4000, CRC(ae34982b) SHA1(96c4154c04086c537ae1272fe051a256d2f5be3f))
+
+ ROM_REGION(0x1000, "ram", ROMREGION_ERASE)
+ROM_END
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type TVC_HBF = &device_creator<tvc_hbf_device>;
+
+//**************************************************************************
+// 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),
+ 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 wd17xx_r(m_fdc, offset & 3);
+ case 0x01:
+ return (wd17xx_drq_r(m_fdc)<<7) | wd17xx_intrq_r(m_fdc);
+ default:
+ return 0x00;
+ }
+}
+
+//-------------------------------------------------
+// IO write
+//-------------------------------------------------
+
+WRITE8_MEMBER(tvc_hbf_device::io_write)
+{
+ switch((offset>>2) & 0x03)
+ {
+ case 0x00:
+ wd17xx_w(m_fdc, offset & 3, data);
+ break;
+ case 0x01:
+ // bit 0-3 drive select
+ // bit 5 DDEN
+ // bit 6 floppy motor
+ // bit 7 side select
+ if (BIT(data, 0))
+ wd17xx_set_drive(m_fdc, 0);
+ else if (BIT(data, 1))
+ wd17xx_set_drive(m_fdc, 1);
+ wd17xx_dden_w(m_fdc, BIT(data, 5));
+ floppy_mon_w(subdevice(FLOPPY_0), !BIT(data, 6));
+ floppy_mon_w(subdevice(FLOPPY_1), !BIT(data, 6));
+ wd17xx_set_side(m_fdc, BIT(data, 7));
+ break;
+ case 0x02:
+ m_rom_bank = (data>>4) & 0x03;
+ break;
+ }
+}
diff --git a/src/mess/machine/tvc_hbf.h b/src/mess/machine/tvc_hbf.h
new file mode 100644
index 00000000000..bb7515bf69a
--- /dev/null
+++ b/src/mess/machine/tvc_hbf.h
@@ -0,0 +1,57 @@
+#pragma once
+
+#ifndef __TVC_HBF_H__
+#define __TVC_HBF_H__
+
+#include "emu.h"
+#include "machine/tvcexp.h"
+#include "machine/wd17xx.h"
+#include "imagedev/flopdrv.h"
+#include "formats/basicdsk.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;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "tvc_hbf"; }
+
+ // 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<device_t> 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/mess/machine/tvcexp.c b/src/mess/machine/tvcexp.c
new file mode 100644
index 00000000000..67642d45885
--- /dev/null
+++ b/src/mess/machine/tvcexp.c
@@ -0,0 +1,187 @@
+/*********************************************************************
+
+ tvcexp.c
+
+*********************************************************************/
+
+#include "emu.h"
+#include "tvcexp.h"
+#include "emuopts.h"
+
+
+/***************************************************************************
+ PARAMETERS
+***************************************************************************/
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type TVCEXP_SLOT = &device_creator<tvcexp_slot_device>;
+
+
+//**************************************************************************
+// 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),
+ device_slot_interface(mconfig, *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<device_tvcexp_interface *>(get_card_device());
+
+ // resolve callbacks
+ m_out_irq_func.resolve(m_out_irq_cb, *this);
+ m_out_nmi_func.resolve(m_out_nmi_cb, *this);
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void tvcexp_slot_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const tvcexp_interface *intf = reinterpret_cast<const tvcexp_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<tvcexp_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_irq_cb, 0, sizeof(m_out_irq_cb));
+ memset(&m_out_nmi_cb, 0, sizeof(m_out_nmi_cb));
+ }
+}
+
+
+/*-------------------------------------------------
+ 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/mess/machine/tvcexp.h b/src/mess/machine/tvcexp.h
new file mode 100644
index 00000000000..d2becfad875
--- /dev/null
+++ b/src/mess/machine/tvcexp.h
@@ -0,0 +1,133 @@
+/*********************************************************************
+
+ tvcexp.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
+***************************************************************************/
+
+// ======================> tvcexp_interface
+
+struct tvcexp_interface
+{
+ devcb_write_line m_out_irq_cb;
+ devcb_write_line m_out_nmi_cb;
+};
+
+
+// ======================> 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 tvcexp_interface,
+ 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();
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_config_complete();
+
+ // 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_resolved_write_line m_out_irq_func;
+ devcb_resolved_write_line m_out_nmi_func;
+
+ device_tvcexp_interface* m_cart;
+};
+
+// device type definition
+extern const device_type TVCEXP_SLOT;
+
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+#define MCFG_TVC64_EXPANSION_ADD(_tag,_config,_slot_intf,_def_slot,_def_inp) \
+ MCFG_DEVICE_ADD(_tag, TVCEXP_SLOT, 0) \
+ MCFG_DEVICE_CONFIG(_config) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false) \
+
+#endif /* __TVCEXP_H__ */
diff --git a/src/mess/machine/upd65031.c b/src/mess/machine/upd65031.c
new file mode 100644
index 00000000000..a048d2f8ef0
--- /dev/null
+++ b/src/mess/machine/upd65031.c
@@ -0,0 +1,637 @@
+/**********************************************************************
+
+ NEC uPD65031 'BLINK' emulation
+
+ the uPD65031 manages almost everything in the Z88:
+ - memory bankswitch
+ - interrupts
+ - RTC
+ - LCD
+ - keyboard
+ - serial
+ - speaker
+
+ TODO:
+ - coma and snooze mode
+ - speaker controlled by txd
+ - EPROM programming
+ - UART
+
+*********************************************************************/
+
+
+#include "upd65031.h"
+
+
+// device type definition
+const device_type UPD65031 = &device_creator<upd65031_device>;
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LOG 0
+
+#define SPEAKER_ALARM_FREQ attotime::from_hz(3200)
+
+// internal registers
+enum
+{
+ // write registers
+ REG_PB0 = 0x70, // pixel base 0
+ REG_PB1 = 0x71, // pixel base 1
+ REG_PB2 = 0x72, // pixel base 2
+ REG_PB3 = 0x73, // pixel base 3
+ REG_SBR = 0x74, // screen base register
+
+ REG_COM = 0xb0, // command register
+ REG_INT = 0xb1, // interrupt control
+ REG_EPR = 0xb3, // EPROM programming
+ REG_TACK = 0xb4, // RTC acknowledge
+ REG_TMK = 0xb5, // RTC interrupt mask
+ REG_ACK = 0xb6, // interrupt acknowledge
+
+ REG_SR0 = 0xd0, // segment register 0
+ REG_SR1 = 0xd1, // segment register 1
+ REG_SR2 = 0xd2, // segment register 2
+ REG_SR3 = 0xd3, // segment register 3
+
+ REG_RXC = 0xe2, // UART receiver control
+ REG_TXD = 0xe3, // UART transmit data
+ REG_TXC = 0xe4, // UART transmit control
+ REG_UMK = 0xe5, // UART interrupt mask
+ REG_UAK = 0xe6, // UART interrupt acknowledge
+
+
+ // read registers
+ REG_STA = 0xb1, // interrupt status
+ REG_KBD = 0xb2, // keyboard read
+ REG_TSTA = 0xb5, // RTC interrupt status
+
+ REG_TIM0 = 0xd0, // RTC 5ms counter
+ REG_TIM1 = 0xd1, // RTC seconds counter (6 bits)
+ REG_TIM2 = 0xd2, // RTC minutes counter
+ REG_TIM3 = 0xd3, // RTC minutes/256 counter
+ REG_TIM4 = 0xd4, // RTC minutes/65536 counter (5 bits)
+
+ REG_RXD = 0xe0, // UART receive data register
+ REG_RXE = 0xe1, // UART extended receiver data
+ REG_UIT = 0xe5, // UART interrupt status
+};
+
+//mode
+enum
+{
+ STATE_AWAKE = 0,
+ STATE_SNOOZE,
+ STATE_COMA
+};
+
+// interrupt status
+#define STA_FLAPOPEN 0x80
+#define STA_A19 0x40
+#define STA_FLAP 0x20
+#define STA_UART 0x10
+#define STA_BTL 0x08
+#define STA_KEY 0x04
+#define STA_TIME 0x01
+
+// interrupt control
+#define INT_KWAIT 0x80
+#define INT_A19 0x40
+#define INT_FLAP 0x20
+#define INT_UART 0x10
+#define INT_BTL 0x08
+#define INT_KEY 0x04
+#define INT_TIME 0x02
+#define INT_GINT 0x01
+
+// command register
+#define COM_SRUN 0x80
+#define COM_SBIT 0x40
+#define COM_OVERP 0x20
+#define COM_RESTIM 0x10
+#define COM_PROGRAM 0x08
+#define COM_RAMS 0x04
+#define COM_VPPON 0x02
+#define COM_LCDON 0x01
+
+// EPROM programming register
+#define EPR_PD1 0x80
+#define EPR_PD0 0x40
+#define EPR_PGMD 0x20
+#define EPR_EOED 0x10
+#define EPR_SE3D 0x08
+#define EPR_PGMP 0x04
+#define EPR_EOEP 0x02
+#define EPR_SE3P 0x01
+
+// RTC interrupt status
+#define TSTA_MIN 0x04
+#define TSTA_SEC 0x02
+#define TSTA_TICK 0x01
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+inline void upd65031_device::interrupt_refresh()
+{
+ if ((m_int & INT_GINT) && ((m_int & m_sta & 0x7c) || ((m_int & INT_TIME) && (m_sta & STA_TIME))))
+ {
+ if (LOG) logerror("uPD65031 '%s': set int\n", tag());
+
+ m_out_int_func(ASSERT_LINE);
+ }
+ else
+ {
+ if (LOG) logerror("uPD65031 '%s': clear int\n", tag());
+
+ m_out_int_func(CLEAR_LINE);
+ }
+}
+
+
+inline void upd65031_device::update_rtc_interrupt()
+{
+ // any ints occurred?
+ if ((m_int & INT_GINT) && (m_int & INT_TIME) && (m_tsta & (TSTA_MIN | TSTA_SEC | TSTA_TICK)))
+ m_sta |= STA_TIME;
+ else
+ m_sta &= ~STA_TIME;
+}
+
+
+inline void upd65031_device::set_mode(int mode)
+{
+ if (m_mode != mode)
+ {
+ m_mode = mode;
+
+ switch(mode)
+ {
+ case STATE_AWAKE:
+ //TODO
+ break;
+ case STATE_SNOOZE:
+ //TODO
+ break;
+ case STATE_COMA:
+ //TODO
+ break;
+ }
+ }
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// upd65031_device - constructor
+//-------------------------------------------------
+
+upd65031_device::upd65031_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, UPD65031, "NEC uPD65031", tag, owner, clock)
+{
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void upd65031_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const upd65031_interface *intf = reinterpret_cast<const upd65031_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<upd65031_interface *>(this) = *intf;
+ }
+ // or initialize to defaults if none provided
+ else
+ {
+ m_screen_update_cb = NULL;
+ m_out_mem_cb = NULL;
+ memset(&m_in_kb_cb, 0, sizeof(m_in_kb_cb));
+ memset(&m_out_int_cb, 0, sizeof(m_out_int_cb));
+ memset(&m_out_nmi_cb, 0, sizeof(m_out_nmi_cb));
+ memset(&m_out_spkr_cb, 0, sizeof(m_out_spkr_cb));
+ }
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void upd65031_device::device_start()
+{
+ // resolve callbacks
+ m_out_int_func.resolve(m_out_int_cb, *this);
+ m_out_nmi_func.resolve(m_out_nmi_cb, *this);
+ m_out_spkr_func.resolve(m_out_spkr_cb, *this);
+ m_int_kb_func.resolve(m_in_kb_cb, *this);
+
+ // allocate timers
+ m_rtc_timer = timer_alloc(TIMER_RTC);
+ m_flash_timer = timer_alloc(TIMER_FLASH);
+ m_speaker_timer = timer_alloc(TIMER_SPEAKER);
+ m_rtc_timer->adjust(attotime::from_msec(5), 0, attotime::from_msec(5));
+ m_flash_timer->adjust(attotime::from_hz(2), 0, attotime::from_hz(2));
+ m_speaker_timer->reset();
+
+ // state saving
+ save_item(NAME(m_mode));
+ save_item(NAME(m_lcd_regs));
+ save_item(NAME(m_tim));
+ save_item(NAME(m_sr));
+ save_item(NAME(m_sta));
+ save_item(NAME(m_int));
+ save_item(NAME(m_ack));
+ save_item(NAME(m_tsta));
+ save_item(NAME(m_tmk));
+ save_item(NAME(m_tack));
+ save_item(NAME(m_com));
+ save_item(NAME(m_flash));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void upd65031_device::device_reset()
+{
+ memset(m_lcd_regs, 0, sizeof(m_lcd_regs));
+ memset(m_tim, 0, sizeof(m_tim));
+ memset(m_sr, 0, sizeof(m_sr));
+ m_sta = 0;
+ m_int = 0;
+ m_ack = 0;
+ m_tsta = 0;
+ m_tmk = TSTA_TICK | TSTA_SEC | TSTA_MIN;
+ m_tack = 0;
+ m_com = 0;
+ m_flash = 0;
+ set_mode(STATE_AWAKE);
+
+ if (m_out_mem_cb)
+ {
+ // reset bankswitch
+ (m_out_mem_cb)(*this, 0, 0, 0);
+ (m_out_mem_cb)(*this, 1, 0, 0);
+ (m_out_mem_cb)(*this, 2, 0, 0);
+ (m_out_mem_cb)(*this, 3, 0, 0);
+ }
+}
+
+
+//-------------------------------------------------
+// device_timer - handler timer events
+//-------------------------------------------------
+
+void upd65031_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch (id)
+ {
+ case TIMER_RTC:
+
+ // if a key is pressed sets the interrupt
+ if ((m_int & INT_GINT) && (m_int & INT_KEY) && m_int_kb_func(0) != 0xff)
+ {
+ if (LOG) logerror("uPD65031 '%s': Keyboard interrupt!\n", tag());
+
+ // awakes CPU from snooze on key down
+ if (m_mode == STATE_SNOOZE)
+ set_mode(STATE_AWAKE);
+
+ m_sta |= STA_KEY;
+ }
+ else
+ {
+ m_sta &= ~STA_KEY;
+ }
+
+ // hold clock at reset? - in this mode it doesn't update
+ if (!(m_com & COM_RESTIM))
+ {
+ bool irq_change = false;
+
+ // update 5 millisecond counter
+ m_tim[0]++;
+
+ // tick
+ if (m_tim[0] & 1)
+ {
+ // set tick int has occurred
+ if (m_tmk & TSTA_TICK)
+ {
+ m_tsta |= TSTA_TICK;
+ irq_change = true;
+ }
+ }
+
+ if (m_tim[0] == 200)
+ {
+ m_tim[0] = 0;
+
+ // set seconds int has occurred
+ if (m_tmk & TSTA_SEC)
+ {
+ m_tsta |= TSTA_SEC;
+ irq_change = true;
+ }
+
+ m_tim[1]++;
+
+ if (m_tim[1] == 60)
+ {
+ // set minutes int has occurred
+ if (m_tmk & TSTA_MIN)
+ {
+ m_tsta |= TSTA_MIN;
+ irq_change = true;
+ }
+ m_tim[1] = 0;
+ m_tim[2]++;
+
+ if (m_tim[2] == 0) // overflowed from 255
+ {
+ m_tim[3]++;
+
+ if (m_tim[3] == 0) // overflowed from 255
+ {
+ m_tim[4]++;
+
+ if (m_tim[4] == 32)
+ m_tim[4] = 0;
+ }
+ }
+ }
+ }
+
+ if ((m_int & INT_GINT) && (m_int & INT_TIME) && irq_change && !(m_sta & STA_FLAPOPEN))
+ {
+ set_mode(STATE_AWAKE);
+
+ update_rtc_interrupt();
+ }
+
+ // refresh interrupt
+ interrupt_refresh();
+ }
+ break;
+ case TIMER_FLASH:
+ m_flash = !m_flash;
+ break;
+ case TIMER_SPEAKER:
+ m_speaker_state = !m_speaker_state;
+ m_out_spkr_func(m_speaker_state ? 1 : 0);
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// screen_update
+//-------------------------------------------------
+
+UINT32 upd65031_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ if (m_screen_update_cb && (m_com & COM_LCDON))
+ (m_screen_update_cb)(*this, bitmap, m_lcd_regs[4], m_lcd_regs[2], m_lcd_regs[3], m_lcd_regs[0], m_lcd_regs[1], m_flash);
+ else
+ bitmap.fill(0, cliprect);
+
+ return 0;
+}
+
+//-------------------------------------------------
+// read -
+//-------------------------------------------------
+
+READ8_MEMBER( upd65031_device::read )
+{
+ UINT8 port = offset & 0xff;
+
+ switch (port)
+ {
+ case REG_STA: // read interrupt status
+ return m_sta;
+
+ case REG_KBD:
+ {
+ // if set, reading the keyboard will put into snooze
+ if (m_int & INT_KWAIT)
+ {
+ set_mode(STATE_SNOOZE);
+
+ if (LOG) logerror("uPD65031 '%s': entering snooze!\n", tag());
+ }
+
+ UINT8 data = m_int_kb_func(offset>>8);
+
+ if (LOG) logerror("uPD65031 '%s': key r %02x: %02x\n", tag(), offset>>8, data);
+
+ return data;
+ }
+
+ // read real time clock status
+ case REG_TSTA:
+ if (LOG) logerror("uPD65031 '%s': tsta r: %02x\n", tag(), m_tsta);
+ return m_tsta & 0x07;
+
+ // read real time clock counters
+ case REG_TIM0:
+ if (LOG) logerror("uPD65031 '%s': TIM0 r: %02x\n", tag(), m_tim[0]);
+ return m_tim[0];
+ case REG_TIM1:
+ if (LOG) logerror("uPD65031 '%s': TIM1 r: %02x\n", tag(), m_tim[1]);
+ return m_tim[1];
+ case REG_TIM2:
+ if (LOG) logerror("uPD65031 '%s': TIM2 r: %02x\n", tag(), m_tim[2]);
+ return m_tim[2];
+ case REG_TIM3:
+ if (LOG) logerror("uPD65031 '%s': TIM3 r: %02x\n", tag(), m_tim[3]);
+ return m_tim[3];
+ case REG_TIM4:
+ if (LOG) logerror("uPD65031 '%s': TIM4 r: %02x\n", tag(), m_tim[4]);
+ return m_tim[4];
+
+ // UART
+ case REG_RXD:
+ case REG_RXE:
+ case REG_UIT:
+ // TODO
+ return 0;
+
+ default:
+ logerror("uPD65031 '%s': blink r: %04x\n", tag(), offset);
+ return 0;
+ }
+}
+
+
+//-------------------------------------------------
+// write -
+//-------------------------------------------------
+
+WRITE8_MEMBER( upd65031_device::write )
+{
+ UINT8 port = offset & 0xff;
+
+ switch (port)
+ {
+ // gfx registers
+ case REG_PB0:
+ case REG_PB1:
+ case REG_PB2:
+ case REG_PB3:
+ case REG_SBR:
+ m_lcd_regs[port - REG_PB0] = ((offset & 0xff00) | data);
+ break;
+
+ case REG_COM: // command register
+ if (LOG) logerror("uPD65031 '%s': com w: %02x\n", tag(), data);
+
+ // reset clock?
+ if (data & COM_RESTIM)
+ m_tim[0] = m_tim[1] = m_tim[2] = m_tim[3] = m_tim[4] = 0;
+
+ if ((data & COM_SRUN) && !(data & COM_SBIT))
+ {
+ // constant tone used for keyclick and alarm
+ m_speaker_timer->adjust(SPEAKER_ALARM_FREQ, 0, SPEAKER_ALARM_FREQ);
+ }
+ else
+ {
+ if (!(data & COM_SRUN))
+ {
+ // speaker controlled by SBIT
+ m_speaker_state = BIT(data, 6);
+ m_out_spkr_func(m_speaker_state);
+ }
+ else
+ {
+ // speaker controlled by txd line
+ // TODO
+ }
+
+ m_speaker_timer->reset();
+ }
+
+ // bit 2 controls the lower 8kb of memory
+ if (BIT(m_com^data, 2) && m_out_mem_cb)
+ (m_out_mem_cb)(*this, 0, m_sr[0], BIT(data, 2));
+
+ m_com = data;
+ break;
+
+ case REG_INT: // interrupt control
+ if (LOG) logerror("uPD65031 '%s': int w: %02x\n", tag(), data);
+
+ m_int = data;
+
+ // refresh ints
+ update_rtc_interrupt();
+ interrupt_refresh();
+ break;
+
+ case REG_EPR: // EPROM programming register
+ if (LOG) logerror("uPD65031 '%s': epr w: %02x\n", tag(), data);
+ // TODO
+ break;
+
+ case REG_TACK: // rtc interrupt acknowledge
+ if (LOG) logerror("uPD65031 '%s': tack w: %02x\n", tag(), data);
+
+ // clear ints that have occurred
+ m_tsta &= ~(data & 0x07);
+ m_tack = data;
+
+ // refresh ints
+ update_rtc_interrupt();
+ interrupt_refresh();
+ break;
+
+ case REG_TMK: // write rtc interrupt mask
+ if (LOG) logerror("uPD65031 '%s': tmk w: %02x\n", tag(), data);
+
+ m_tmk = data & 0x07;
+ break;
+
+ case REG_ACK: // acknowledge ints
+ if (LOG) logerror("uPD65031 '%s': ack w: %02x\n", tag(), data);
+
+ m_ack = data;
+ m_sta &= ~(data & 0x7f);
+
+ // refresh ints
+ interrupt_refresh();
+ break;
+
+ // Segment registers
+ case REG_SR0:
+ case REG_SR1:
+ case REG_SR2:
+ case REG_SR3:
+ if (m_out_mem_cb && m_sr[port & 3] != data)
+ (m_out_mem_cb)(*this, port & 3, data, BIT(m_com, 2));
+
+ m_sr[port & 3] = data;
+ break;
+
+ // UART
+ case REG_RXC:
+ case REG_TXD:
+ case REG_TXC:
+ case REG_UMK:
+ case REG_UAK:
+ if (LOG) logerror("uPD65031 '%s': UART w: %02x %02x\n", tag(), port & 7 , data);
+ // TODO
+ break;
+
+ default:
+ logerror("uPD65031 '%s': blink w: %04x %02x\n", tag(), offset, data);
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// flp line
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( upd65031_device::flp_w )
+{
+ if (!(m_sta & STA_FLAPOPEN) && state)
+ {
+ // set interrupt on rising edge
+ m_sta |= STA_FLAP;
+
+ interrupt_refresh();
+ }
+
+ if (state)
+ m_sta |= STA_FLAPOPEN;
+ else
+ m_sta &= ~STA_FLAPOPEN;
+}
+
+//-------------------------------------------------
+// battery low line
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( upd65031_device::btl_w )
+{
+ if (state)
+ m_sta |= STA_BTL;
+ else
+ m_sta &= ~STA_BTL;
+}
diff --git a/src/mess/machine/upd65031.h b/src/mess/machine/upd65031.h
new file mode 100644
index 00000000000..e5bb348c635
--- /dev/null
+++ b/src/mess/machine/upd65031.h
@@ -0,0 +1,112 @@
+/**********************************************************************
+
+ NEC uPD65031 'BLINK' emulation
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __UPD65031__
+#define __UPD65031__
+
+#include "emu.h"
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_UPD65031_ADD(_tag, _clock, _config) \
+ MCFG_DEVICE_ADD((_tag), UPD65031, _clock) \
+ MCFG_DEVICE_CONFIG(_config)
+
+#define UPD65031_INTERFACE(name) \
+ const upd65031_interface (name) =
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+typedef void (*upd65031_screen_update_func)(device_t &device, bitmap_ind16 &bitmap, UINT16 sbf, UINT16 hires0, UINT16 hires1, UINT16 lores0, UINT16 lores1, int flash);
+#define UPD65031_SCREEN_UPDATE(name) void name(device_t &device, bitmap_ind16 &bitmap, UINT16 sbf, UINT16 hires0, UINT16 hires1, UINT16 lores0, UINT16 lores1, int flash)
+
+typedef void (*upd65031_memory_update_func)(device_t &device, int bank, UINT16 page, int rams);
+#define UPD65031_MEMORY_UPDATE(name) void name(device_t &device, int bank, UINT16 page, int rams)
+
+
+// ======================> upd65031_interface
+
+struct upd65031_interface
+{
+ upd65031_screen_update_func m_screen_update_cb; // callback for update the LCD
+ upd65031_memory_update_func m_out_mem_cb; // callback for update bankswitch
+ devcb_read8 m_in_kb_cb; // kb read input
+ devcb_write_line m_out_int_cb; // INT line out
+ devcb_write_line m_out_nmi_cb; // NMI line out
+ devcb_write_line m_out_spkr_cb; // Speaker line out
+};
+
+
+// ======================> upd65031_device
+
+class upd65031_device : public device_t,
+ public upd65031_interface
+{
+public:
+ // construction/destruction
+ upd65031_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( flp_w );
+ DECLARE_WRITE_LINE_MEMBER( btl_w );
+ UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+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);
+
+private:
+ inline void interrupt_refresh();
+ inline void update_rtc_interrupt();
+ inline void set_mode(int mode);
+ static const device_timer_id TIMER_RTC = 0;
+ static const device_timer_id TIMER_FLASH = 1;
+ static const device_timer_id TIMER_SPEAKER = 2;
+
+ devcb_resolved_write_line m_out_int_func;
+ devcb_resolved_write_line m_out_nmi_func;
+ devcb_resolved_write_line m_out_spkr_func;
+ devcb_resolved_read8 m_int_kb_func;
+
+ int m_mode;
+ UINT16 m_lcd_regs[5]; // LCD registers
+ UINT8 m_tim[5]; // RTC registers
+ UINT8 m_sr[4]; // segment registers
+ UINT8 m_sta; // interrupt status
+ UINT8 m_int; // interrupts mask
+ UINT8 m_ack; // interrupts acknowledge
+ UINT8 m_tsta; // timer interrupt status
+ UINT8 m_tmk; // timer interrupt mask
+ UINT8 m_tack; // timer interrupts acknowledge
+ UINT8 m_com; // command register
+ int m_flash; // cursor flash
+ int m_speaker_state; // spkr line
+
+ // timers
+ emu_timer *m_rtc_timer;
+ emu_timer *m_flash_timer;
+ emu_timer *m_speaker_timer;
+};
+
+
+// device type definition
+extern const device_type UPD65031;
+
+
+#endif
diff --git a/src/mess/machine/upd7002.c b/src/mess/machine/upd7002.c
new file mode 100644
index 00000000000..5b753ac9231
--- /dev/null
+++ b/src/mess/machine/upd7002.c
@@ -0,0 +1,234 @@
+/******************************************************************************
+ uPD7002 Analogue to Digital Converter
+
+ MESS Driver By:
+
+ Gordon Jefferyes
+ mess_bbc@gjeffery.dircon.co.uk
+
+******************************************************************************/
+
+#include "emu.h"
+#include "upd7002.h"
+
+
+typedef struct _uPD7002_t uPD7002_t;
+struct _uPD7002_t
+{
+ /* Pointer to our interface */
+ const uPD7002_interface *intf;
+
+ /* 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 status;
+
+ /* High data byte
+ This byte contains the 8 most significant bits of the analogue to digital conversion. */
+ int 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 data0;
+
+
+ /* temporary store of the next A to D conversion */
+ int 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 conversion_counter;
+};
+
+
+/*****************************************************************************
+ Implementation
+*****************************************************************************/
+
+INLINE uPD7002_t *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == UPD7002);
+
+ return (uPD7002_t *)downcast<legacy_device_base *>(device)->token();
+}
+
+READ8_DEVICE_HANDLER ( uPD7002_EOC_r )
+{
+ uPD7002_t *uPD7002 = get_safe_token(device);
+ return (uPD7002->status>>7)&0x01;
+}
+
+
+static TIMER_CALLBACK(uPD7002_conversioncomplete)
+{
+ device_t *device = (device_t *)ptr;
+ uPD7002_t *uPD7002 = get_safe_token(device);
+
+ int counter_value = param;
+ if (counter_value==uPD7002->conversion_counter)
+ {
+ // this really always does a 12 bit conversion
+ uPD7002->data1 = uPD7002->digitalvalue>>8;
+ uPD7002->data0 = uPD7002->digitalvalue&0xf0;
+
+ // set the status register with top 2 MSB, not busy and conversion complete
+ uPD7002->status = (uPD7002->status & 0x0f)|((uPD7002->data1 & 0xc0)>>2)|0x40;
+
+ // call the EOC function with EOC from status
+ // uPD7002_EOC_r(0) this has just been set to 0
+ if (uPD7002->intf->EOC_func) (uPD7002->intf->EOC_func)(device,0);
+ uPD7002->conversion_counter=0;
+ }
+}
+
+
+READ8_DEVICE_HANDLER ( uPD7002_r )
+{
+ uPD7002_t *uPD7002 = get_safe_token(device);
+
+ switch(offset&0x03)
+ {
+ case 0:
+ return uPD7002->status;
+
+ case 1:
+ return uPD7002->data1;
+
+ case 2: case 3:
+ return uPD7002->data0;
+ }
+ return 0;
+}
+
+
+
+WRITE8_DEVICE_HANDLER ( uPD7002_w )
+{
+ uPD7002_t *uPD7002 = get_safe_token(device);
+ /* 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 */
+ uPD7002->status=(data & 0x0f) | 0x80;
+
+ // call the EOC function with EOC from status
+ // uPD7002_EOC_r(0) this has just been set to 1
+ if (uPD7002->intf->EOC_func) uPD7002->intf->EOC_func(device, 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.
+ uPD7002->digitalvalue = uPD7002->intf->get_analogue_func(device, uPD7002->status & 0x03);
+
+ uPD7002->conversion_counter++;
+
+ // call a timer to start the conversion
+ if (uPD7002->status & 0x08)
+ {
+ // 12 bit conversion takes 10ms
+ device->machine().scheduler().timer_set(attotime::from_msec(10), FUNC(uPD7002_conversioncomplete), uPD7002->conversion_counter, (void *)device);
+ } else {
+ // 8 bit conversion takes 4ms
+ device->machine().scheduler().timer_set(attotime::from_msec(4), FUNC(uPD7002_conversioncomplete), uPD7002->conversion_counter, (void *)device);
+ }
+ 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;
+ }
+}
+
+/* Device Interface */
+
+static DEVICE_START( uPD7002 )
+{
+ uPD7002_t *uPD7002 = get_safe_token(device);
+ // validate arguments
+
+ assert(device != NULL);
+ assert(device->tag() != NULL);
+ assert(device->static_config() != NULL);
+
+ uPD7002->intf = (const uPD7002_interface*)device->static_config();
+ uPD7002->status = 0;
+ uPD7002->data1 = 0;
+ uPD7002->data0 = 0;
+ uPD7002->digitalvalue = 0;
+ uPD7002->conversion_counter = 0;
+
+ // register for state saving
+ state_save_register_item(device->machine(), "uPD7002", device->tag(), 0, uPD7002->status);
+ state_save_register_item(device->machine(), "uPD7002", device->tag(), 0, uPD7002->data1);
+ state_save_register_item(device->machine(), "uPD7002", device->tag(), 0, uPD7002->data0);
+ state_save_register_item(device->machine(), "uPD7002", device->tag(), 0, uPD7002->digitalvalue);
+ state_save_register_item(device->machine(), "uPD7002", device->tag(), 0, uPD7002->conversion_counter);
+}
+
+static DEVICE_RESET( uPD7002 )
+{
+ uPD7002_t *uPD7002 = get_safe_token(device);
+ uPD7002->status = 0;
+ uPD7002->data1 = 0;
+ uPD7002->data0 = 0;
+ uPD7002->digitalvalue = 0;
+ uPD7002->conversion_counter = 0;
+}
+
+DEVICE_GET_INFO( uPD7002 )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(uPD7002_t); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(uPD7002); break;
+ case DEVINFO_FCT_STOP: /* Nothing */ break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(uPD7002); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "uPD7002"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "uPD7002"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright MESS Team"); break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(UPD7002, uPD7002);
diff --git a/src/mess/machine/upd7002.h b/src/mess/machine/upd7002.h
new file mode 100644
index 00000000000..615b2cbf485
--- /dev/null
+++ b/src/mess/machine/upd7002.h
@@ -0,0 +1,58 @@
+/*****************************************************************************
+ *
+ * machine/upd7002.h
+ *
+ * uPD7002 Analogue to Digital Converter
+ *
+ * Driver by Gordon Jefferyes <mess_bbc@gjeffery.dircon.co.uk>
+ *
+ ****************************************************************************/
+
+#ifndef UPD7002_H_
+#define UPD7002_H_
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+DECLARE_LEGACY_DEVICE(UPD7002, uPD7002);
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef int (*uPD7002_get_analogue_func)(device_t *device, int channel_number);
+#define UPD7002_GET_ANALOGUE(name) int name(device_t *device, int channel_number )
+
+typedef void (*uPD7002_eoc_func)(device_t *device, int data);
+#define UPD7002_EOC(name) void name(device_t *device, int data )
+
+
+typedef struct _uPD7002_interface uPD7002_interface;
+struct _uPD7002_interface
+{
+ uPD7002_get_analogue_func get_analogue_func;
+ uPD7002_eoc_func EOC_func;
+};
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* Standard handlers */
+
+READ8_DEVICE_HANDLER ( uPD7002_EOC_r );
+READ8_DEVICE_HANDLER ( uPD7002_r );
+WRITE8_DEVICE_HANDLER ( uPD7002_w );
+
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+#define MCFG_UPD7002_ADD(_tag, _intrf) \
+ MCFG_DEVICE_ADD(_tag, UPD7002, 0) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+
+#endif /* UPD7002_H_ */
diff --git a/src/mess/machine/upd71071.c b/src/mess/machine/upd71071.c
new file mode 100644
index 00000000000..e5a3b1ccab0
--- /dev/null
+++ b/src/mess/machine/upd71071.c
@@ -0,0 +1,444 @@
+
+/*
+
+ 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.
+
+ 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
+
+
+*/
+
+#include "emu.h"
+#include "machine/upd71071.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;
+};
+
+typedef struct _upd71071_t upd71071_t;
+struct _upd71071_t
+{
+ struct upd71071_reg reg;
+ int selected_channel;
+ int buswidth;
+ int dmarq[4];
+ emu_timer* timer[4];
+ int in_progress[4];
+ int transfer_size[4];
+ int base;
+ const upd71071_intf* intf;
+};
+
+INLINE upd71071_t *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == UPD71071);
+
+ return (upd71071_t*)downcast<legacy_device_base *>(device)->token();
+}
+
+static TIMER_CALLBACK(dma_transfer_timer)
+{
+ // single byte or word transfer
+ device_t* device = (device_t*)ptr;
+ upd71071_t* dmac = get_safe_token(device);
+ address_space* space = device->machine().device(dmac->intf->cputag)->memory().space(AS_PROGRAM);
+ int channel = param;
+ UINT16 data = 0; // data to transfer
+
+ switch(dmac->reg.mode_control[channel] & 0x0c)
+ {
+ case 0x00: // Verify
+ break;
+ case 0x04: // I/O -> memory
+ if(dmac->intf->dma_read[channel])
+ data = dmac->intf->dma_read[channel](device->machine());
+ space->write_byte(dmac->reg.address_current[channel],data & 0xff);
+ if(dmac->reg.mode_control[channel] & 0x20) // Address direction
+ dmac->reg.address_current[channel]--;
+ else
+ dmac->reg.address_current[channel]++;
+ if(dmac->reg.count_current[channel] == 0)
+ {
+ if(dmac->reg.mode_control[channel] & 0x10) // auto-initialise
+ {
+ dmac->reg.address_current[channel] = dmac->reg.address_base[channel];
+ dmac->reg.count_current[channel] = dmac->reg.count_base[channel];
+ }
+ // TODO: send terminal count
+ }
+ else
+ dmac->reg.count_current[channel]--;
+ break;
+ case 0x08: // memory -> I/O
+ data = space->read_byte(dmac->reg.address_current[channel]);
+ if(dmac->intf->dma_read[channel])
+ dmac->intf->dma_write[channel](device->machine(),data);
+ if(dmac->reg.mode_control[channel] & 0x20) // Address direction
+ dmac->reg.address_current[channel]--;
+ else
+ dmac->reg.address_current[channel]++;
+ if(dmac->reg.count_current[channel] == 0)
+ {
+ if(dmac->reg.mode_control[channel] & 0x10) // auto-initialise
+ {
+ dmac->reg.address_current[channel] = dmac->reg.address_base[channel];
+ dmac->reg.count_current[channel] = dmac->reg.count_base[channel];
+ }
+ // TODO: send terminal count
+ }
+ else
+ dmac->reg.count_current[channel]--;
+ break;
+ case 0x0c: // Invalid
+ break;
+ }
+}
+
+static void upd71071_soft_reset(device_t* device)
+{
+ upd71071_t* dmac = get_safe_token(device);
+ int x;
+
+ // Does not change base/current address, count, or buswidth
+ dmac->selected_channel = 0;
+ dmac->base = 0;
+ for(x=0;x<4;x++)
+ dmac->reg.mode_control[x] = 0;
+ dmac->reg.device_control = 0;
+ dmac->reg.temp_h = 0;
+ dmac->reg.temp_l = 0;
+ dmac->reg.mask = 0x0f; // mask all channels
+ dmac->reg.status &= ~0x0f; // clears bits 0-3 only
+ dmac->reg.request = 0;
+}
+
+int upd71071_dmarq(device_t* device, int state,int channel)
+{
+ upd71071_t* dmac = get_safe_token(device);
+
+ if(state != 0)
+ {
+ if(dmac->reg.device_control & 0x0004)
+ return 2;
+
+ if(dmac->reg.mask & (1 << channel)) // is channel masked?
+ return 1;
+
+ dmac->dmarq[channel] = 1; // DMARQ line is set
+ dmac->reg.status |= (0x10 << channel);
+
+ // start transfer
+ switch(dmac->reg.mode_control[channel] & 0xc0)
+ {
+ case 0x00: // Demand
+ // TODO
+ break;
+ case 0x40: // Single
+ dmac->timer[channel]->adjust(attotime::from_hz(dmac->intf->clock),channel);
+ break;
+ case 0x80: // Block
+ // TODO
+ break;
+ case 0xc0: // Cascade
+ // TODO
+ break;
+
+ }
+ }
+ else
+ {
+ dmac->dmarq[channel] = 0; // clear DMARQ line
+ dmac->reg.status &= ~(0x10 << channel);
+ dmac->reg.status |= (0x01 << channel); // END or TC
+ }
+ return 0;
+}
+
+static DEVICE_START(upd71071)
+{
+ upd71071_t* dmac = get_safe_token(device);
+ int x;
+
+ dmac->intf = (const upd71071_intf*)device->static_config();
+ for(x=0;x<4;x++)
+ {
+ dmac->timer[x] = device->machine().scheduler().timer_alloc(FUNC(dma_transfer_timer), (void*)device);
+ }
+ dmac->selected_channel = 0;
+}
+
+static READ8_DEVICE_HANDLER(upd71071_read)
+{
+ upd71071_t* dmac = get_safe_token(device);
+ UINT8 ret = 0;
+
+ logerror("DMA: read from register %02x\n",offset);
+ switch(offset)
+ {
+ case 0x01: // Channel
+ ret = (1 << dmac->selected_channel);
+ if(dmac->base != 0)
+ ret |= 0x10;
+ break;
+ case 0x02: // Count (low)
+ if(dmac->base != 0)
+ ret = dmac->reg.count_base[dmac->selected_channel] & 0xff;
+ else
+ ret = dmac->reg.count_current[dmac->selected_channel] & 0xff;
+ break;
+ case 0x03: // Count (high)
+ if(dmac->base != 0)
+ ret = (dmac->reg.count_base[dmac->selected_channel] >> 8) & 0xff;
+ else
+ ret = (dmac->reg.count_current[dmac->selected_channel] >> 8) & 0xff;
+ break;
+ case 0x04: // Address (low)
+ if(dmac->base != 0)
+ ret = dmac->reg.address_base[dmac->selected_channel] & 0xff;
+ else
+ ret = dmac->reg.address_current[dmac->selected_channel] & 0xff;
+ break;
+ case 0x05: // Address (mid)
+ if(dmac->base != 0)
+ ret = (dmac->reg.address_base[dmac->selected_channel] >> 8) & 0xff;
+ else
+ ret = (dmac->reg.address_current[dmac->selected_channel] >> 8) & 0xff;
+ break;
+ case 0x06: // Address (high)
+ if(dmac->base != 0)
+ ret = (dmac->reg.address_base[dmac->selected_channel] >> 16) & 0xff;
+ else
+ ret = (dmac->reg.address_current[dmac->selected_channel] >> 16) & 0xff;
+ break;
+ case 0x07: // Address (highest)
+ if(dmac->base != 0)
+ ret = (dmac->reg.address_base[dmac->selected_channel] >> 24) & 0xff;
+ else
+ ret = (dmac->reg.address_current[dmac->selected_channel] >> 24) & 0xff;
+ break;
+ case 0x08: // Device control (low)
+ ret = dmac->reg.device_control & 0xff;
+ break;
+ case 0x09: // Device control (high)
+ ret = (dmac->reg.device_control >> 8) & 0xff;
+ break;
+ case 0x0a: // Mode control
+ ret = dmac->reg.mode_control[dmac->selected_channel];
+ break;
+ case 0x0b: // Status
+ ret = dmac->reg.status;
+ dmac->reg.status &= ~0x0f; // resets END/TC?
+ break;
+ case 0x0c: // Temporary (low)
+ ret = dmac->reg.temp_h;
+ break;
+ case 0x0d: // Temporary (high)
+ ret = dmac->reg.temp_l;
+ break;
+ case 0x0e: // Request
+ ret = dmac->reg.request;
+ break;
+ case 0x0f: // Mask
+ ret = dmac->reg.mask;
+ break;
+ }
+ return ret;
+}
+
+static WRITE8_DEVICE_HANDLER(upd71071_write)
+{
+ upd71071_t* dmac = get_safe_token(device);
+
+ switch(offset)
+ {
+ case 0x00: // Initialise
+ // TODO: reset (bit 0)
+ dmac->buswidth = data & 0x02;
+ if(data & 0x01)
+ upd71071_soft_reset(device);
+ logerror("DMA: Initialise [%02x]\n",data);
+ break;
+ case 0x01: // Channel
+ dmac->selected_channel = data & 0x03;
+ dmac->base = data & 0x04;
+ logerror("DMA: Channel selected [%02x]\n",data);
+ break;
+ case 0x02: // Count (low)
+ dmac->reg.count_base[dmac->selected_channel] =
+ (dmac->reg.count_base[dmac->selected_channel] & 0xff00) | data;
+ if(dmac->base == 0)
+ dmac->reg.count_current[dmac->selected_channel] =
+ (dmac->reg.count_current[dmac->selected_channel] & 0xff00) | data;
+ logerror("DMA: Channel %i Counter set [%04x]\n",dmac->selected_channel,dmac->reg.count_base[dmac->selected_channel]);
+ break;
+ case 0x03: // Count (high)
+ dmac->reg.count_base[dmac->selected_channel] =
+ (dmac->reg.count_base[dmac->selected_channel] & 0x00ff) | (data << 8);
+ if(dmac->base == 0)
+ dmac->reg.count_current[dmac->selected_channel] =
+ (dmac->reg.count_current[dmac->selected_channel] & 0x00ff) | (data << 8);
+ logerror("DMA: Channel %i Counter set [%04x]\n",dmac->selected_channel,dmac->reg.count_base[dmac->selected_channel]);
+ break;
+ case 0x04: // Address (low)
+ dmac->reg.address_base[dmac->selected_channel] =
+ (dmac->reg.address_base[dmac->selected_channel] & 0xffffff00) | data;
+ if(dmac->base == 0)
+ dmac->reg.address_current[dmac->selected_channel] =
+ (dmac->reg.address_current[dmac->selected_channel] & 0xffffff00) | data;
+ logerror("DMA: Channel %i Address set [%08x]\n",dmac->selected_channel,dmac->reg.address_base[dmac->selected_channel]);
+ break;
+ case 0x05: // Address (mid)
+ dmac->reg.address_base[dmac->selected_channel] =
+ (dmac->reg.address_base[dmac->selected_channel] & 0xffff00ff) | (data << 8);
+ if(dmac->base == 0)
+ dmac->reg.address_current[dmac->selected_channel] =
+ (dmac->reg.address_current[dmac->selected_channel] & 0xffff00ff) | (data << 8);
+ logerror("DMA: Channel %i Address set [%08x]\n",dmac->selected_channel,dmac->reg.address_base[dmac->selected_channel]);
+ break;
+ case 0x06: // Address (high)
+ dmac->reg.address_base[dmac->selected_channel] =
+ (dmac->reg.address_base[dmac->selected_channel] & 0xff00ffff) | (data << 16);
+ if(dmac->base == 0)
+ dmac->reg.address_current[dmac->selected_channel] =
+ (dmac->reg.address_current[dmac->selected_channel] & 0xff00ffff) | (data << 16);
+ logerror("DMA: Channel %i Address set [%08x]\n",dmac->selected_channel,dmac->reg.address_base[dmac->selected_channel]);
+ break;
+ case 0x07: // Address (highest)
+ dmac->reg.address_base[dmac->selected_channel] =
+ (dmac->reg.address_base[dmac->selected_channel] & 0x00ffffff) | (data << 24);
+ if(dmac->base == 0)
+ dmac->reg.address_current[dmac->selected_channel] =
+ (dmac->reg.address_current[dmac->selected_channel] & 0x00ffffff) | (data << 24);
+ logerror("DMA: Channel %i Address set [%08x]\n",dmac->selected_channel,dmac->reg.address_base[dmac->selected_channel]);
+ break;
+ case 0x08: // Device control (low)
+ dmac->reg.device_control = (dmac->reg.device_control & 0xff00) | data;
+ logerror("DMA: Device control set [%04x]\n",dmac->reg.device_control);
+ break;
+ case 0x09: // Device control (high)
+ dmac->reg.device_control = (dmac->reg.device_control & 0x00ff) | (data << 8);
+ logerror("DMA: Device control set [%04x]\n",dmac->reg.device_control);
+ break;
+ case 0x0a: // Mode control
+ dmac->reg.mode_control[dmac->selected_channel] = data;
+ logerror("DMA: Channel %i Mode control set [%02x]\n",dmac->selected_channel,dmac->reg.mode_control[dmac->selected_channel]);
+ break;
+ case 0x0e: // Request
+ dmac->reg.request = data;
+ logerror("DMA: Request set [%02x]\n",data);
+ break;
+ case 0x0f: // Mask
+ dmac->reg.mask = data;
+ logerror("DMA: Mask set [%02x]\n",data);
+ break;
+ }
+}
+
+DEVICE_GET_INFO(upd71071)
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(upd71071_t); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(upd71071); break;
+ case DEVINFO_FCT_STOP: /* Nothing */ break;
+ case DEVINFO_FCT_RESET: /* Nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "NEC uPD71071"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "DMA Controller"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright the MESS Team"); break;
+ }
+}
+
+READ8_DEVICE_HANDLER(upd71071_r) { return upd71071_read(device,offset); }
+WRITE8_DEVICE_HANDLER(upd71071_w) { upd71071_write(device,offset,data); }
+
+DEFINE_LEGACY_DEVICE(UPD71071, upd71071);
diff --git a/src/mess/machine/upd71071.h b/src/mess/machine/upd71071.h
new file mode 100644
index 00000000000..a5b644a557f
--- /dev/null
+++ b/src/mess/machine/upd71071.h
@@ -0,0 +1,26 @@
+#ifndef UPD71071_H_
+#define UPD71071_H_
+
+#include "emu.h"
+
+typedef struct _upd71071_interface upd71071_intf;
+struct _upd71071_interface
+{
+ const char* cputag;
+ int clock;
+ UINT16 (*dma_read[4])(running_machine &machine);
+ void (*dma_write[4])(running_machine &machine, UINT16 data);
+};
+
+int upd71071_dmarq(device_t* device,int state,int channel);
+
+DECLARE_LEGACY_DEVICE(UPD71071, upd71071);
+
+#define MCFG_UPD71071_ADD(_tag, _config) \
+ MCFG_DEVICE_ADD(_tag, UPD71071, 0) \
+ MCFG_DEVICE_CONFIG(_config)
+
+READ8_DEVICE_HANDLER(upd71071_r);
+WRITE8_DEVICE_HANDLER(upd71071_w);
+
+#endif /*UPD71071_H_*/
diff --git a/src/mess/machine/upd765.c b/src/mess/machine/upd765.c
new file mode 100644
index 00000000000..8b1fc92f97f
--- /dev/null
+++ b/src/mess/machine/upd765.c
@@ -0,0 +1,2547 @@
+/***************************************************************************
+
+ machine/upd765.c
+
+ Functions to emulate a UPD765/Intel 8272 compatible floppy disk controller
+
+ Code by Kevin Thacker.
+
+ TODO:
+
+ - overrun condition
+ - Scan Commands
+ - crc error in id field and crc error in data field errors
+ - disc not present, and no sectors on track for data, deleted data, write, write deleted,
+ read a track etc
+ - end of cylinder condition - almost working, needs fixing with
+ PCW and PC drivers
+ - resolve "ready" state stuff (ready state when reset for PC, ready state change while processing command AND
+ while idle)
+
+ Changes:
+ 091006 (Mariusz Wojcieszek, changes needed by QX-10):
+ - allowed "Sense Interrupt Status" command when Seek is active
+ - DIO bit in status register (0x40) is cleared when "Read Data" command is executed,
+ it is later set during result phase.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "machine/upd765.h"
+
+
+typedef enum
+{
+ UPD765_COMMAND_PHASE_FIRST_BYTE,
+ UPD765_COMMAND_PHASE_BYTES,
+ UPD765_RESULT_PHASE,
+ UPD765_EXECUTION_PHASE_READ,
+ UPD765_EXECUTION_PHASE_WRITE
+} UPD765_PHASE;
+
+/* supported versions */
+typedef enum
+{
+ TYPE_UPD765A = 0,
+ TYPE_UPD765B = 1,
+ TYPE_SMC37C78 = 2,
+ TYPE_UPD72065 = 3
+} UPD765_VERSION;
+
+
+/* uncomment the following line for verbose information */
+#define LOG_VERBOSE 0
+#define LOG_COMMAND 0
+#define LOG_EXTRA 0
+#define LOG_INTERRUPT 0
+
+/* uncomment this to not allow end of cylinder "error" */
+#define NO_END_OF_CYLINDER
+
+
+
+/* state of upd765 Interrupt (INT) output */
+#define UPD765_INT 0x02
+/* data rate for floppy discs (MFM data) */
+#define UPD765_DATA_RATE 32
+/* state of upd765 terminal count input*/
+#define UPD765_TC 0x04
+
+#define UPD765_DMA_MODE 0x08
+
+#define UPD765_SEEK_OPERATION_IS_RECALIBRATE 0x01
+
+#define UPD765_SEEK_ACTIVE 0x010
+/* state of upd765 DMA DRQ output */
+#define UPD765_DMA_DRQ 0x020
+/* state of upd765 FDD READY input */
+#define UPD765_FDD_READY 0x040
+
+#define UPD765_MF 0x40
+#define UPD765_MT 0x80
+
+#define UPD765_RESET 0x080
+
+#define UPD765_BAD_MEDIA 0x100
+
+typedef struct _upd765_t upd765_t;
+struct _upd765_t
+{
+ devcb_resolved_write_line out_int_func;
+ devcb_resolved_write_line out_drq_func;
+
+ unsigned long sector_counter;
+ /* version of fdc to emulate */
+ UPD765_VERSION version;
+
+ /* main status register */
+ unsigned char FDC_main;
+ /* data register */
+ unsigned char upd765_data_reg;
+
+ unsigned char c,h,r,n;
+
+ int sector_id;
+
+ int data_type;
+
+ char format_data[4];
+
+ UPD765_PHASE upd765_phase;
+ unsigned int upd765_command_bytes[16];
+ unsigned int upd765_result_bytes[16];
+ unsigned int upd765_transfer_bytes_remaining;
+ unsigned int upd765_transfer_bytes_count;
+ unsigned int upd765_status[4];
+ /* present cylinder number per drive */
+ unsigned int pcn[4];
+
+ /* drive being accessed. drive outputs from fdc */
+ unsigned int drive;
+ /* side being accessed: side output from fdc */
+ unsigned int side;
+
+
+ /* step rate time in us */
+ unsigned long srt_in_ms;
+
+ unsigned int ncn;
+
+// unsigned int upd765_id_index;
+ char *execution_phase_data;
+ unsigned int upd765_flags;
+
+// unsigned char specify[2];
+// unsigned char perpendicular_mode[1];
+
+ int command;
+
+ UINT8 ready_changed;
+
+ emu_timer *seek_timer;
+ emu_timer *timer;
+ int timer_type;
+
+ emu_timer *command_timer;
+
+ char *data_buffer;
+ const upd765_interface *intf;
+
+ bool pool;
+};
+
+//static void upd765_setup_data_request(unsigned char Data);
+static void upd765_setup_command(device_t *device);
+static TIMER_CALLBACK(upd765_continue_command);
+static int upd765_sector_count_complete(device_t *device);
+static void upd765_increment_sector(device_t *device);
+static void upd765_update_state(device_t *device);
+static void upd765_set_dma_drq(device_t *device,int state);
+static void upd765_set_int(device_t *device,int state);
+
+static const INT8 upd765_cmd_size[32] =
+{
+ 1,1,9,3,2,9,9,2,1,9,2,1,9,6,1,3,
+ 1,9,1,1,1,1,9,1,1,9,1,1,1,9,1,1
+};
+
+INLINE upd765_t *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == UPD765A || device->type() == UPD765B ||
+ device->type() == SMC37C78 || device->type() == UPD72065);
+
+ return (upd765_t *)downcast<legacy_device_base *>(device)->token();
+}
+
+static device_t *current_image(device_t *device)
+{
+ device_t *image = NULL;
+ upd765_t *fdc = get_safe_token(device);
+
+ if (!fdc->intf->get_image)
+ {
+ if (fdc->intf->floppy_drive_tags[fdc->drive] != NULL)
+ {
+ if (device->owner() != NULL)
+ image = device->owner()->subdevice(fdc->intf->floppy_drive_tags[fdc->drive]);
+ else
+ image = device->machine().device(fdc->intf->floppy_drive_tags[fdc->drive]);
+ }
+ }
+ else
+ {
+ image = fdc->intf->get_image(device, fdc->drive);
+ }
+ return image;
+}
+
+static void upd765_setup_drive_and_side(device_t *device)
+{
+ upd765_t *fdc = get_safe_token(device);
+ /* drive index upd765 sees */
+ fdc->drive = fdc->upd765_command_bytes[1] & 0x03;
+ /* side index upd765 sees */
+ fdc->side = (fdc->upd765_command_bytes[1]>>2) & 0x01;
+}
+
+
+/* setup status register 0 based on data in status register 1 and 2 */
+static void upd765_setup_st0(device_t *device)
+{
+ upd765_t *fdc = get_safe_token(device);
+ /* clear completition status bits, drive bits and side bits */
+ fdc->upd765_status[0] &= ~((1<<7) | (1<<6) | (1<<2) | (1<<1) | (1<<0));
+ /* fill in drive */
+ fdc->upd765_status[0] |= fdc->drive | (fdc->side<<2);
+
+ /* fill in completion status bits based on bits in st0, st1, st2 */
+ /* no error bits set */
+ if ((fdc->upd765_status[1] | fdc->upd765_status[2])==0)
+ {
+ return;
+ }
+
+ fdc->upd765_status[0] |= 0x040;
+}
+
+
+static int upd765_n_to_bytes(int n)
+{
+ /* 0-> 128 bytes, 1->256 bytes, 2->512 bytes etc */
+ /* data_size = ((1<<(N+7)) */
+ return 1<<(n+7);
+}
+
+static void upd765_set_data_request(device_t *device)
+{
+ upd765_t *fdc = get_safe_token(device);
+ fdc->FDC_main |= 0x080;
+}
+
+static void upd765_clear_data_request(device_t *device)
+{
+ upd765_t *fdc = get_safe_token(device);
+ fdc->FDC_main &= ~0x080;
+}
+
+static int upd765_get_rdy(device_t *device)
+{
+ upd765_t *fdc = get_safe_token(device);
+
+ if (fdc->intf->rdy_pin == UPD765_RDY_PIN_CONNECTED)
+ {
+ device_t *img = current_image(device);
+ if (img!=NULL) {
+ return floppy_drive_get_flag_state(img, FLOPPY_DRIVE_READY);
+ } else {
+ return 0;
+ }
+ }
+ else
+ return 1;
+}
+
+static void upd765_seek_complete(device_t *device)
+{
+ /* tested on Amstrad CPC */
+
+ /* if a seek is done without drive connected: */
+ /* abnormal termination of command,
+ seek complete,
+ not ready
+ */
+
+ /* if a seek is done with drive connected, but disc missing: */
+ /* abnormal termination of command,
+ seek complete,
+ not ready */
+
+ /* if a seek is done with drive connected and disc in drive */
+ /* seek complete */
+
+
+ /* On the PC however, it appears that recalibrates and seeks can be performed without
+ a disc in the drive. */
+
+ /* Therefore, the above output is dependant on the state of the drive */
+
+ /* In the Amstrad CPC, the drive select is provided by the UPD765. A single port is also
+ assigned for setting the drive motor state. The motor state controls the motor of the selected
+ drive */
+
+ /* On the PC the drive can be selected with the DIGITAL OUTPUT REGISTER, and the motor of each
+ of the 4 possible drives is also settable using the same register */
+
+ /* Assumption for PC: (NOT TESTED - NEEDS VERIFICATION) */
+
+ /* If a seek is done without drive connected: */
+ /* abnormal termination of command,
+ seek complete,
+ fault
+ */
+
+ /* if a seek is done with drive connected, but disc missing: */
+ /* seek complete */
+
+ /* if a seek is done with drive connected and disc in drive: */
+ /* seek complete */
+
+ /* On Amstrad CPC:
+ If drive not connected, or drive connected but disc not in drive, not ready!
+ If drive connected and drive motor on, ready!
+ On PC:
+ Drive is always ready!
+
+ In 37c78 docs, the ready bits of the upd765 are marked as unused.
+ This indicates it is always ready!!!!!
+ */
+
+ device_t *img = current_image(device);
+ upd765_t *fdc = get_safe_token(device);
+
+ fdc->pcn[fdc->drive] = fdc->ncn;
+
+ fdc->upd765_status[0] = 0x20;
+
+ /* drive ready? */
+ if (img != NULL && upd765_get_rdy(device))
+ {
+ /* recalibrate? */
+ if (fdc->upd765_flags & UPD765_SEEK_OPERATION_IS_RECALIBRATE)
+ {
+ /* not at track 0? */
+ if (fdc->pcn[fdc->drive] != 0)
+ /* no, track 0 failed after 77 steps */
+ fdc->upd765_status[0] |= 0x40 | 0x10;
+ }
+ }
+ else
+ {
+ /* abnormal termination, not ready */
+ fdc->upd765_status[0] |= 0x40 | 0x08;
+ }
+
+ /* set drive and side. note: commented out side to avoid problems with the tf20 */
+ fdc->upd765_status[0] |= fdc->drive; //| (fdc->side<<2);
+
+ upd765_set_int(device,0);
+ upd765_set_int(device,1);
+
+ fdc->upd765_flags &= ~UPD765_SEEK_ACTIVE;
+
+ upd765_idle(device);
+}
+
+static TIMER_CALLBACK(upd765_seek_timer_callback)
+{
+ device_t *device = (device_t *)ptr;
+ upd765_t *fdc = get_safe_token(device);
+ /* seek complete */
+ upd765_seek_complete(device);
+
+ fdc->seek_timer->reset();
+}
+
+static void upd765_timer_func(device_t *device, int timer_type)
+{
+ upd765_t *fdc = get_safe_token(device);
+ /* type 0 = data transfer mode in execution phase */
+ if (fdc->timer_type == 0)
+ {
+ /* set data request */
+ upd765_set_data_request(device);
+
+ fdc->timer_type = 4;
+
+ if (!(fdc->upd765_flags & UPD765_DMA_MODE))
+ {
+ if (fdc->upd765_command_bytes[0] & UPD765_MF)
+ {
+ /* MFM */
+ fdc->timer->reset(attotime::from_usec(13));
+ }
+ else
+ {
+ /* FM */
+ fdc->timer->reset(attotime::from_usec(27));
+ }
+ }
+ else
+ {
+ upd765_timer_func(device, fdc->timer_type);
+ }
+ }
+ else if (fdc->timer_type==2)
+ {
+ /* result phase begin */
+
+ /* generate a int for specific commands */
+ switch (fdc->command) {
+ case 2: /* read a track */
+ case 5: /* write data */
+ case 6: /* read data */
+ case 9: /* write deleted data */
+ case 10: /* read id */
+ case 12: /* read deleted data */
+ case 13: /* format at track */
+ case 17: /* scan equal */
+ case 19: /* scan low or equal */
+ case 29: /* scan high or equal */
+ upd765_set_int(device,1);
+ break;
+
+ default:
+ break;
+ }
+
+ upd765_set_data_request(device);
+
+ fdc->timer->reset();
+ }
+ else if (fdc->timer_type == 4)
+ {
+ /* if in dma mode, a int is not generated per byte. If not in DMA mode
+ a int is generated per byte */
+ if (fdc->upd765_flags & UPD765_DMA_MODE)
+ {
+ upd765_set_dma_drq(device,1);
+ }
+ else
+ {
+ if (fdc->FDC_main & (1<<7))
+ {
+ /* set int to indicate data is ready */
+ upd765_set_int(device,1);
+ }
+ }
+
+ fdc->timer->reset();
+ }
+}
+
+static TIMER_CALLBACK(upd765_timer_callback)
+{
+ device_t *device = (device_t *)ptr;
+ upd765_timer_func(device,param);
+}
+
+/* after (32-27) the DRQ is set, then 27 us later, the int is set.
+I don't know if this is correct, but it is required for the PCW driver.
+In this driver, the first NMI calls the handler function, furthur NMI's are
+effectively disabled by reading the data before the NMI int can be set.
+*/
+
+static void upd765_setup_timed_generic(device_t *device, int timer_type, attotime duration)
+{
+ upd765_t *fdc = get_safe_token(device);
+
+ fdc->timer_type = timer_type;
+
+ if (!(fdc->upd765_flags & UPD765_DMA_MODE))
+ {
+ fdc->timer->adjust(duration);
+ }
+ else
+ {
+ upd765_timer_func(device,fdc->timer_type);
+ fdc->timer->reset();
+ }
+}
+
+/* setup data request */
+static void upd765_setup_timed_data_request(device_t *device, int bytes)
+{
+ /* setup timer to trigger in UPD765_DATA_RATE us */
+ upd765_setup_timed_generic(device, 0, attotime::from_usec(32-27) /*UPD765_DATA_RATE)*bytes*/);
+}
+
+/* setup result data request */
+static void upd765_setup_timed_result_data_request(device_t *device)
+{
+ upd765_setup_timed_generic(device, 2, attotime::from_usec(UPD765_DATA_RATE*2));
+}
+
+
+/* sets up a timer to issue a seek complete in signed_tracks time */
+static void upd765_setup_timed_int(device_t *device,int signed_tracks)
+{
+ upd765_t *fdc = get_safe_token(device);
+ /* setup timer to signal after seek time is complete */
+ fdc->seek_timer->adjust(attotime::from_double(fdc->srt_in_ms*abs(signed_tracks)*0.001));
+}
+
+static void upd765_seek_setup(device_t *device, int is_recalibrate)
+{
+ device_t *img;
+ int signed_tracks;
+ upd765_t *fdc = get_safe_token(device);
+
+ fdc->upd765_flags |= UPD765_SEEK_ACTIVE;
+
+ if (is_recalibrate)
+ {
+ /* head cannot be specified with recalibrate */
+ fdc->upd765_command_bytes[1] &=~0x04;
+ }
+
+ upd765_setup_drive_and_side(device);
+
+ img = current_image(device);
+
+ fdc->FDC_main |= (1<<fdc->drive);
+ fdc->FDC_main |= 0x20; // execution phase
+ fdc->FDC_main &= ~0x10; // not busy, can send another seek/recalibrate
+ // for a different drive, or sense int status
+
+ /* recalibrate command? */
+ if (is_recalibrate)
+ {
+ fdc->upd765_flags |= UPD765_SEEK_OPERATION_IS_RECALIBRATE;
+
+ fdc->ncn = 0;
+
+ /* if drive is already at track 0, or drive is not ready */
+ if (img == NULL || floppy_tk00_r(img) == CLEAR_LINE || (!upd765_get_rdy(device)))
+ {
+ /* seek completed */
+// upd765_seek_complete(device);
+ // delay for the time of 1 step, the PCW does not like immediate recalibrates
+ upd765_setup_timed_int(device,1);
+ }
+ else
+ {
+ /* is drive present? */
+ if (1) //image_slotexists(img)) //fix me
+ {
+ /* yes - calculate real number of tracks to seek */
+
+ int current_track;
+
+ /* get current track */
+ current_track = floppy_drive_get_current_track(img);
+
+ /* get number of tracks to seek */
+ signed_tracks = -current_track;
+ }
+ else
+ {
+ /* no, seek 77 tracks and then stop */
+ /* true for UPD765A, but not for other variants */
+ signed_tracks = -77;
+ }
+
+ /* perform seek - if drive isn't present it will not do anything */
+ floppy_drive_seek(img, signed_tracks);
+
+ if (signed_tracks!=0)
+ {
+ upd765_setup_timed_int(device,signed_tracks);
+ }
+ else
+ {
+ upd765_seek_complete(device);
+ }
+ }
+ }
+ else
+ {
+
+ fdc->upd765_flags &= ~UPD765_SEEK_OPERATION_IS_RECALIBRATE;
+
+ fdc->ncn = fdc->upd765_command_bytes[2];
+
+ /* get signed tracks */
+ signed_tracks = fdc->ncn - fdc->pcn[fdc->drive];
+
+ /* perform seek - if drive isn't present it will not do anything */
+ floppy_drive_seek(img, signed_tracks);
+
+ /* if no tracks to seek, or drive is not ready, seek is complete */
+ if (img == NULL || (signed_tracks==0) || (!upd765_get_rdy(device)))
+ {
+ upd765_seek_complete(device);
+ }
+ else
+ {
+ /* seek complete - issue an interrupt */
+ upd765_setup_timed_int(device,signed_tracks);
+ }
+ }
+// upd765_idle(device);
+}
+
+
+
+static void upd765_setup_execution_phase_read(device_t *device, char *ptr, int size)
+{
+ upd765_t *fdc = get_safe_token(device);
+
+// fdc->FDC_main &= ~0x040; /* FDC->CPU */
+ fdc->FDC_main |= 0x040; /* FDC->CPU */
+
+ fdc->upd765_transfer_bytes_count = 0;
+ fdc->upd765_transfer_bytes_remaining = size;
+ fdc->execution_phase_data = ptr;
+ fdc->upd765_phase = UPD765_EXECUTION_PHASE_READ;
+
+ upd765_setup_timed_data_request(device, 1);
+}
+
+static void upd765_setup_execution_phase_write(device_t *device, char *ptr, int size)
+{
+ upd765_t *fdc = get_safe_token(device);
+
+ fdc->FDC_main &= ~0x040; /* FDC->CPU */
+
+ fdc->upd765_transfer_bytes_count = 0;
+ fdc->upd765_transfer_bytes_remaining = size;
+ fdc->execution_phase_data = ptr;
+ fdc->upd765_phase = UPD765_EXECUTION_PHASE_WRITE;
+
+ /* setup a data request with first byte */
+ upd765_setup_timed_data_request(device,1);
+}
+
+
+static void upd765_setup_result_phase(device_t *device, int byte_count)
+{
+ upd765_t *fdc = get_safe_token(device);
+
+ fdc->FDC_main |= 0x040; /* FDC->CPU */
+ fdc->FDC_main &= ~0x020; /* not execution phase */
+
+ fdc->upd765_transfer_bytes_count = 0;
+ fdc->upd765_transfer_bytes_remaining = byte_count;
+ fdc->upd765_phase = UPD765_RESULT_PHASE;
+
+ upd765_setup_timed_result_data_request(device);
+}
+
+void upd765_idle(device_t *device)
+{
+ upd765_t *fdc = get_safe_token(device);
+
+ fdc->FDC_main &= ~0x040; /* CPU->FDC */
+ fdc->FDC_main &= ~0x020; /* not execution phase */
+ fdc->FDC_main &= ~0x010; /* not busy */
+ fdc->upd765_phase = UPD765_COMMAND_PHASE_FIRST_BYTE;
+
+ upd765_set_data_request(device);
+}
+
+
+
+/* change flags */
+static void upd765_change_flags(device_t *device,unsigned int flags, unsigned int mask)
+{
+ unsigned int new_flags;
+ unsigned int changed_flags;
+ upd765_t *fdc = get_safe_token(device);
+
+ assert((flags & ~mask) == 0);
+
+ /* compute the new flags and which ones have changed */
+ new_flags = fdc->upd765_flags & ~mask;
+ new_flags |= flags;
+ changed_flags = fdc->upd765_flags ^ new_flags;
+ fdc->upd765_flags = new_flags;
+
+ /* if interrupt changed, call the handler */
+ if (changed_flags & UPD765_INT)
+ fdc->out_int_func((fdc->upd765_flags & UPD765_INT) ? 1 : 0);
+
+ /* if DRQ changed, call the handler */
+ if (changed_flags & UPD765_DMA_DRQ)
+ fdc->out_drq_func((fdc->upd765_flags & UPD765_DMA_DRQ) ? 1 : 0);
+}
+
+
+
+/* set int output */
+static void upd765_set_int(device_t *device, int state)
+{
+ if (LOG_INTERRUPT)
+ logerror("upd765_set_int(): state=%d\n", state);
+ upd765_change_flags(device, state ? UPD765_INT : 0, UPD765_INT);
+}
+
+
+
+/* set dma request output */
+static void upd765_set_dma_drq(device_t *device, int state)
+{
+ upd765_change_flags(device, state ? UPD765_DMA_DRQ : 0, UPD765_DMA_DRQ);
+}
+
+READ_LINE_DEVICE_HANDLER( upd765_int_r )
+{
+ upd765_t *fdc = get_safe_token(device);
+
+ return (fdc->upd765_flags & UPD765_INT) ? 1 : 0;
+}
+
+READ_LINE_DEVICE_HANDLER( upd765_drq_r )
+{
+ upd765_t *fdc = get_safe_token(device);
+
+ return (fdc->upd765_flags & UPD765_DMA_DRQ) ? 1 : 0;
+}
+
+
+/* Drive ready */
+
+/*
+
+A drive will report ready if:
+- drive is selected
+- disc is in the drive
+- disk is rotating at a constant speed (normally 300rpm)
+
+On more modern PCs, a ready signal is not provided by the drive.
+This signal is not used in the PC design and was eliminated to save costs
+If you look at the datasheets for the modern UPD765 variants, you will see the Ready
+signal is not mentioned.
+
+On the original UPD765A, ready signal is required, and some commands will fail if the drive
+is not ready.
+
+
+
+
+*/
+
+
+
+
+/* done when ready state of drive changes */
+/* this ignores if command is active, in which case command should terminate immediatly
+with error */
+static void upd765_set_ready_change_callback(device_t *controller, device_t *img, int state)
+{
+ upd765_t *fdc = get_safe_token(controller);
+ int drive = floppy_get_drive(img);
+
+ if (LOG_EXTRA)
+ logerror("upd765: ready state change\n");
+
+ /* drive that changed state */
+ fdc->upd765_status[0] = 0x0c0 | drive;
+
+ /* not ready */
+ if (state==0 && fdc->intf->rdy_pin == UPD765_RDY_PIN_CONNECTED )
+ fdc->upd765_status[0] |= 8;
+
+ /* trigger an int */
+ upd765_set_int(controller, 1);
+}
+
+
+/* terminal count input */
+WRITE_LINE_DEVICE_HANDLER( upd765_tc_w )
+{
+ int old_state;
+ upd765_t *fdc = get_safe_token(device);
+
+ old_state = fdc->upd765_flags;
+
+ /* clear drq */
+ upd765_set_dma_drq(device, 0);
+
+ fdc->upd765_flags &= ~UPD765_TC;
+ if (state)
+ {
+ fdc->upd765_flags |= UPD765_TC;
+ }
+
+ /* changed state? */
+ if (((fdc->upd765_flags^old_state) & UPD765_TC)!=0)
+ {
+ /* now set? */
+ if ((fdc->upd765_flags & UPD765_TC)!=0)
+ {
+ /* yes */
+ if (fdc->timer)
+ {
+ if (fdc->timer_type==0)
+ {
+ fdc->timer->reset();
+
+
+ }
+ }
+
+#ifdef NO_END_OF_CYLINDER
+ fdc->command_timer->adjust(attotime::zero);
+#else
+ upd765_update_state(device);
+#endif
+ }
+ }
+}
+
+READ8_DEVICE_HANDLER( upd765_status_r )
+{
+ upd765_t *fdc = get_safe_token(device);
+ if (LOG_EXTRA)
+ logerror("%s: upd765_status_r: %02x\n", device->machine().describe_context(), fdc->FDC_main);
+ return fdc->FDC_main;
+}
+
+
+/* control mark handling code */
+
+/* if SK==1, and we are executing a read data command, and a deleted data mark is found,
+skip it.
+if SK==1, and we are executing a read deleted data command, and a data mark is found,
+skip it. */
+
+static int upd765_read_skip_sector(device_t *device)
+{
+ upd765_t *fdc = get_safe_token(device);
+ /* skip set? */
+ if ((fdc->upd765_command_bytes[0] & (1<<5))!=0)
+ {
+ /* read data? */
+ if (fdc->command == 0x06)
+ {
+ /* did we just find a sector with deleted data mark? */
+ if (fdc->data_type == UPD765_DAM_DELETED_DATA)
+ {
+ /* skip it */
+ return TRUE;
+ }
+ }
+ /* deleted data? */
+ else
+ if (fdc->command == 0x0c)
+ {
+ /* did we just find a sector with data mark ? */
+ if (fdc->data_type == UPD765_DAM_DATA)
+ {
+ /* skip it */
+ return TRUE;
+ }
+ }
+ }
+
+ /* do not skip */
+ return FALSE;
+}
+
+/* this is much closer to how the upd765 actually gets sectors */
+/* used by read data, read deleted data, write data, write deleted data */
+/* What the upd765 does:
+
+ - get next sector id from disc
+ - if sector id matches id specified in command, it will
+ search for next data block and read data from it.
+
+ - if the index is seen twice while it is searching for a sector, then the sector cannot be found
+*/
+
+static void upd765_get_next_id(device_t *device, chrn_id *id)
+{
+ upd765_t *fdc = get_safe_token(device);
+ device_t *img = current_image(device);
+
+ /* get next id from disc */
+ floppy_drive_get_next_id(img, fdc->side,id);
+
+ fdc->sector_id = id->data_id;
+
+ /* set correct data type */
+ fdc->data_type = UPD765_DAM_DATA;
+ if (id->flags & ID_FLAG_DELETED_DATA)
+ {
+ fdc->data_type = UPD765_DAM_DELETED_DATA;
+ }
+}
+
+static int upd765_get_matching_sector(device_t *device)
+{
+ upd765_t *fdc = get_safe_token(device);
+ device_t *img = current_image(device);
+ chrn_id id;
+
+ /* number of times we have seen index hole */
+ int index_count = 0;
+
+ if (fdc->upd765_flags & UPD765_BAD_MEDIA) {
+ fdc->upd765_status[1] |= 1;
+ return FALSE;
+ }
+
+ /* get sector id's */
+ do
+ {
+ upd765_get_next_id(device, &id);
+
+ /* tested on Amstrad CPC - All bytes must match, otherwise
+ a NO DATA error is reported */
+ if (id.R == fdc->upd765_command_bytes[4])
+ {
+ if (id.C == fdc->upd765_command_bytes[2])
+ {
+ if (id.H == fdc->upd765_command_bytes[3])
+ {
+ if (id.N == fdc->upd765_command_bytes[5])
+ {
+ /* end of cylinder is set if:
+ 1. sector data is read completely (i.e. no other errors occur like
+ no data.
+ 2. sector being read is same specified by EOT
+ 3. terminal count is not received */
+ if (fdc->upd765_command_bytes[4]==fdc->upd765_command_bytes[6])
+ {
+ /* set end of cylinder */
+ fdc->upd765_status[1] |= UPD765_ST1_END_OF_CYLINDER;
+ }
+
+ return TRUE;
+ }
+ }
+ }
+ else
+ {
+ /* the specified sector ID was found, however, the C value specified
+ in the read/write command did not match the C value read from the disc */
+
+ /* no data - checked on Amstrad CPC */
+ fdc->upd765_status[1] |= UPD765_ST1_NO_DATA;
+ /* bad C value */
+ fdc->upd765_status[2] |= UPD765_ST2_WRONG_CYLINDER;
+
+ if (id.C == 0x0ff)
+ {
+ /* the C value is 0x0ff which indicates a bad track in the IBM soft-sectored
+ format */
+ fdc->upd765_status[2] |= UPD765_ST2_BAD_CYLINDER;
+ }
+
+ return FALSE;
+ }
+ }
+
+ /* index set? */
+ if (floppy_drive_get_flag_state(img, FLOPPY_DRIVE_INDEX))
+ {
+ index_count++;
+ }
+
+ }
+ while (index_count!=2);
+
+ if (fdc->upd765_command_bytes[4] != fdc->upd765_command_bytes[6])
+ {
+ /* no data - specified sector ID was not found */
+ fdc->upd765_status[1] |= UPD765_ST1_NO_DATA;
+ }
+
+ return 0;
+}
+
+static void upd765_read_complete(device_t *device)
+{
+ upd765_t *fdc = get_safe_token(device);
+/* causes problems!!! - need to fix */
+#ifdef NO_END_OF_CYLINDER
+ /* set end of cylinder */
+ fdc->upd765_status[1] &= ~UPD765_ST1_END_OF_CYLINDER;
+#else
+ /* completed read command */
+
+ /* end of cylinder is set when:
+ - a whole sector has been read
+ - terminal count input is not set
+ - AND the the sector specified by EOT was read
+ */
+
+ /* if end of cylinder is set, and we did receive a terminal count, then clear it */
+ if ((fdc->upd765_flags & UPD765_TC)!=0)
+ {
+ /* set end of cylinder */
+ fdc->upd765_status[1] &= ~UPD765_ST1_END_OF_CYLINDER;
+ }
+#endif
+
+ upd765_setup_st0(device);
+
+ fdc->upd765_result_bytes[0] = fdc->upd765_status[0];
+ fdc->upd765_result_bytes[1] = fdc->upd765_status[1];
+ fdc->upd765_result_bytes[2] = fdc->upd765_status[2];
+ fdc->upd765_result_bytes[3] = fdc->upd765_command_bytes[2]; /* C */
+ fdc->upd765_result_bytes[4] = fdc->upd765_command_bytes[3]; /* H */
+ fdc->upd765_result_bytes[5] = fdc->upd765_command_bytes[4]; /* R */
+ fdc->upd765_result_bytes[6] = fdc->upd765_command_bytes[5]; /* N */
+
+ upd765_setup_result_phase(device,7);
+}
+
+static void upd765_read_data(device_t *device)
+{
+ upd765_t *fdc = get_safe_token(device);
+ device_t *img = current_image(device);
+
+ if (!upd765_get_rdy(device))
+ {
+ fdc->upd765_status[0] = 0x0c0 | (1<<4) | fdc->drive | (fdc->side<<2);
+ fdc->upd765_status[1] = 0x00;
+ fdc->upd765_status[2] = 0x00;
+
+ fdc->upd765_result_bytes[0] = fdc->upd765_status[0];
+ fdc->upd765_result_bytes[1] = fdc->upd765_status[1];
+ fdc->upd765_result_bytes[2] = fdc->upd765_status[2];
+ fdc->upd765_result_bytes[3] = fdc->upd765_command_bytes[2]; /* C */
+ fdc->upd765_result_bytes[4] = fdc->upd765_command_bytes[3]; /* H */
+ fdc->upd765_result_bytes[5] = fdc->upd765_command_bytes[4]; /* R */
+ fdc->upd765_result_bytes[6] = fdc->upd765_command_bytes[5]; /* N */
+ upd765_setup_result_phase(device,7);
+ return;
+ }
+
+ if (LOG_VERBOSE)
+ logerror("sector c: %02x h: %02x r: %02x n: %02x\n",fdc->upd765_command_bytes[2], fdc->upd765_command_bytes[3],fdc->upd765_command_bytes[4], fdc->upd765_command_bytes[5]);
+
+ /* find a sector to read data from */
+ {
+ int found_sector_to_read;
+
+ found_sector_to_read = 0;
+ /* check for finished reading sectors */
+ do
+ {
+ /* get matching sector */
+ if (upd765_get_matching_sector(device))
+ {
+
+ /* skip it? */
+ if (upd765_read_skip_sector(device))
+ {
+ /* yes */
+
+ /* check that we haven't finished reading all sectors */
+ if (upd765_sector_count_complete(device))
+ {
+ /* read complete */
+ upd765_read_complete(device);
+ return;
+ }
+
+ /* read not finished */
+
+ /* increment sector count */
+ upd765_increment_sector(device);
+ }
+ else
+ {
+ /* found a sector to read */
+ found_sector_to_read = 1;
+ }
+ }
+ else
+ {
+ /* error in finding sector */
+ upd765_read_complete(device);
+ return;
+ }
+ }
+ while (found_sector_to_read==0);
+ }
+
+ {
+ int data_size;
+
+ data_size = upd765_n_to_bytes(fdc->upd765_command_bytes[5]);
+
+ floppy_drive_read_sector_data(img, fdc->side, fdc->sector_id,fdc->data_buffer,data_size);
+
+ upd765_setup_execution_phase_read(device,fdc->data_buffer, data_size);
+ }
+}
+
+
+static void upd765_format_track(device_t *device)
+{
+ upd765_t *fdc = get_safe_token(device);
+ device_t *img = current_image(device);
+
+ /* write protected? */
+ if (floppy_wpt_r(img) == CLEAR_LINE)
+ {
+ fdc->upd765_status[1] |= UPD765_ST1_NOT_WRITEABLE;
+
+ upd765_setup_st0(device);
+ /* TODO: Check result is correct */
+ fdc->upd765_result_bytes[0] = fdc->upd765_status[0];
+ fdc->upd765_result_bytes[1] = fdc->upd765_status[1];
+ fdc->upd765_result_bytes[2] = fdc->upd765_status[2];
+ fdc->upd765_result_bytes[3] = fdc->format_data[0];
+ fdc->upd765_result_bytes[4] = fdc->format_data[1];
+ fdc->upd765_result_bytes[5] = fdc->format_data[2];
+ fdc->upd765_result_bytes[6] = fdc->format_data[3];
+ upd765_setup_result_phase(device,7);
+
+ return;
+ }
+
+ upd765_setup_execution_phase_write(device, &fdc->format_data[0], 4);
+}
+
+static void upd765_read_a_track(device_t *device)
+{
+ upd765_t *fdc = get_safe_token(device);
+ int data_size;
+
+ /* SKIP not allowed with this command! */
+
+ /* get next id */
+ chrn_id id;
+
+ upd765_get_next_id(device, &id);
+
+ /* TO BE CONFIRMED! */
+ /* check id from disc */
+ if (id.C==fdc->upd765_command_bytes[2])
+ {
+ if (id.H==fdc->upd765_command_bytes[3])
+ {
+ if (id.R==fdc->upd765_command_bytes[4])
+ {
+ if (id.N==fdc->upd765_command_bytes[5])
+ {
+ /* if ID found, then no data is not set */
+ /* otherwise no data will remain set */
+ fdc->upd765_status[1] &=~UPD765_ST1_NO_DATA;
+ }
+ }
+ }
+ }
+
+
+ data_size = upd765_n_to_bytes(id.N);
+
+ floppy_drive_read_sector_data(current_image(device), fdc->side, fdc->sector_id,fdc->data_buffer,data_size);
+
+ upd765_setup_execution_phase_read(device,fdc->data_buffer, data_size);
+}
+
+static int upd765_just_read_last_sector_on_track(device_t *device)
+{
+ if (floppy_drive_get_flag_state(current_image(device), FLOPPY_DRIVE_INDEX))
+ return 1;
+ return 0;
+}
+
+static void upd765_write_complete(device_t *device)
+{
+ upd765_t *fdc = get_safe_token(device);
+
+/* causes problems!!! - need to fix */
+#ifdef NO_END_OF_CYLINDER
+ /* set end of cylinder */
+ fdc->upd765_status[1] &= ~UPD765_ST1_END_OF_CYLINDER;
+#else
+ /* completed read command */
+
+ /* end of cylinder is set when:
+ - a whole sector has been read
+ - terminal count input is not set
+ - AND the the sector specified by EOT was read
+ */
+
+ /* if end of cylinder is set, and we did receive a terminal count, then clear it */
+ if ((fdc->upd765_flags & UPD765_TC)!=0)
+ {
+ /* set end of cylinder */
+ fdc->upd765_status[1] &= ~UPD765_ST1_END_OF_CYLINDER;
+ }
+#endif
+
+ upd765_setup_st0(device);
+
+ fdc->upd765_result_bytes[0] = fdc->upd765_status[0];
+ fdc->upd765_result_bytes[1] = fdc->upd765_status[1];
+ fdc->upd765_result_bytes[2] = fdc->upd765_status[2];
+ fdc->upd765_result_bytes[3] = fdc->upd765_command_bytes[2]; /* C */
+ fdc->upd765_result_bytes[4] = fdc->upd765_command_bytes[3]; /* H */
+ fdc->upd765_result_bytes[5] = fdc->upd765_command_bytes[4]; /* R */
+ fdc->upd765_result_bytes[6] = fdc->upd765_command_bytes[5]; /* N */
+
+ upd765_setup_result_phase(device,7);
+}
+
+
+static void upd765_write_data(device_t *device)
+{
+ upd765_t *fdc = get_safe_token(device);
+ if (!upd765_get_rdy(device))
+ {
+ fdc->upd765_status[0] = 0x0c0 | (1<<4) | fdc->drive | (fdc->side<<2);
+ fdc->upd765_status[1] = 0x00;
+ fdc->upd765_status[2] = 0x00;
+
+ fdc->upd765_result_bytes[0] = fdc->upd765_status[0];
+ fdc->upd765_result_bytes[1] = fdc->upd765_status[1];
+ fdc->upd765_result_bytes[2] = fdc->upd765_status[2];
+ fdc->upd765_result_bytes[3] = fdc->upd765_command_bytes[2]; /* C */
+ fdc->upd765_result_bytes[4] = fdc->upd765_command_bytes[3]; /* H */
+ fdc->upd765_result_bytes[5] = fdc->upd765_command_bytes[4]; /* R */
+ fdc->upd765_result_bytes[6] = fdc->upd765_command_bytes[5]; /* N */
+ upd765_setup_result_phase(device,7);
+ return;
+ }
+
+ /* write protected? */
+ if (floppy_wpt_r(current_image(device)) == CLEAR_LINE)
+ {
+ fdc->upd765_status[1] |= UPD765_ST1_NOT_WRITEABLE;
+
+ upd765_write_complete(device);
+ return;
+ }
+
+ if (upd765_get_matching_sector(device))
+ {
+ int data_size;
+
+ data_size = upd765_n_to_bytes(fdc->upd765_command_bytes[5]);
+
+ upd765_setup_execution_phase_write(device,fdc->data_buffer, data_size);
+ }
+ else
+ {
+ upd765_setup_result_phase(device,7);
+ }
+}
+
+
+/* return true if we have read all sectors, false if not */
+static int upd765_sector_count_complete(device_t *device)
+{
+ upd765_t *fdc = get_safe_token(device);
+/* this is not correct?? */
+#if 1
+ /* if terminal count has been set - yes */
+ if (fdc->upd765_flags & UPD765_TC)
+ {
+ /* completed */
+ return 1;
+ }
+
+
+
+ /* multi-track? */
+ if (fdc->upd765_command_bytes[0] & UPD765_MT)
+ {
+ /* it appears that in multi-track mode,
+ the EOT parameter of the command is ignored!? -
+ or is it ignored the first time and not the next, so that
+ if it is started on side 0, it will end at EOT on side 1,
+ but if started on side 1 it will end at end of track????
+
+ PC driver requires this to end at last sector on side 1, and
+ ignore EOT parameter.
+
+ To be checked!!!!
+ */
+
+ /* if just read last sector and on side 1 - finish */
+ if (upd765_just_read_last_sector_on_track(device))
+ {
+ if (floppy_get_heads_per_disk(flopimg_get_image(current_image(device)))==1) {
+ return 2;
+ } else {
+ if (fdc->side==1)
+ return 2;
+ return 1; // do not advance to next cylinder
+ }
+ }
+
+ /* if not on second side then we haven't finished yet */
+ if (fdc->side!=1)
+ {
+ /* haven't finished yet */
+ return 0;
+ }
+ }
+ else
+ {
+ /* sector id == EOT? */
+ if (fdc->upd765_command_bytes[4]==fdc->upd765_command_bytes[6])
+ {
+
+ /* completed */
+ return 2;
+ }
+ }
+#else
+
+ /* if terminal count has been set - yes */
+ if (fdc->upd765_flags & UPD765_TC)
+ {
+ /* completed */
+ return 1;
+ }
+
+ /* Multi-Track operation:
+
+ Verified on Amstrad CPC.
+
+ disc format used:
+ 9 sectors per track
+ 2 sides
+ Sector IDs: &01, &02, &03, &04, &05, &06, &07, &08, &09
+
+ Command specified:
+ SIDE = 0,
+ C = 0,H = 0,R = 1, N = 2, EOT = 1
+ Sectors read:
+ Sector 1 side 0
+ Sector 1 side 1
+
+ Command specified:
+ SIDE = 0,
+ C = 0,H = 0,R = 1, N = 2, EOT = 3
+ Sectors read:
+ Sector 1 side 0
+ Sector 2 side 0
+ Sector 3 side 0
+ Sector 1 side 1
+ Sector 2 side 1
+ Sector 3 side 1
+
+
+ Command specified:
+ SIDE = 0,
+ C = 0, H = 0, R = 7, N = 2, EOT = 3
+ Sectors read:
+ Sector 7 side 0
+ Sector 8 side 0
+ Sector 9 side 0
+ Sector 10 not found. Error "No Data"
+
+ Command specified:
+ SIDE = 1,
+ C = 0, H = 1, R = 1, N = 2, EOT = 1
+ Sectors read:
+ Sector 1 side 1
+
+ Command specified:
+ SIDE = 1,
+ C = 0, H = 1, R = 1, N = 2, EOT = 2
+ Sectors read:
+ Sector 1 side 1
+ Sector 1 side 2
+
+ */
+
+ /* sector id == EOT? */
+ if ((fdc->upd765_command_bytes[4]==fdc->upd765_command_bytes[6]))
+ {
+ /* multi-track? */
+ if (fdc->upd765_command_bytes[0] & 0x080)
+ {
+ /* if we have reached EOT (fdc->upd765_command_bytes[6])
+ on side 1, then read is complete */
+ if (fdc->side==1)
+ return 1;
+
+ return 0;
+
+ }
+
+ /* completed */
+ return 1;
+ }
+#endif
+ /* not complete */
+ return 0;
+}
+
+static void upd765_increment_sector(device_t *device)
+{
+ upd765_t *fdc = get_safe_token(device);
+
+ /* multi-track? */
+ if (fdc->upd765_command_bytes[0] & UPD765_MT)
+ {
+ /* reached EOT? */
+ if (fdc->upd765_command_bytes[4] == fdc->upd765_command_bytes[6])
+ {
+ if (fdc->side == 1)
+ {
+ fdc->upd765_command_bytes[2]++;
+ }
+
+ fdc->upd765_command_bytes[3] ^= 0x01;
+ fdc->upd765_command_bytes[4] = 1;
+ fdc->side = fdc->upd765_command_bytes[3] & 0x01;
+ }
+ else
+ {
+ fdc->upd765_command_bytes[4]++;
+ }
+ }
+ else
+ {
+ if (fdc->upd765_command_bytes[4] == fdc->upd765_command_bytes[6])
+ {
+ fdc->upd765_command_bytes[2]++;
+ fdc->upd765_command_bytes[4] = 1;
+ }
+ else
+ {
+ fdc->upd765_command_bytes[4]++;
+ }
+ }
+}
+
+/* control mark handling code */
+
+/* if SK==0, and we are executing a read data command, and a deleted data sector is found,
+the data is not skipped. The data is read, but the control mark is set and the read is stopped */
+/* if SK==0, and we are executing a read deleted data command, and a data sector is found,
+the data is not skipped. The data is read, but the control mark is set and the read is stopped */
+static int upd765_read_data_stop(device_t *device)
+{
+ upd765_t *fdc = get_safe_token(device);
+ /* skip not set? */
+ if ((fdc->upd765_command_bytes[0] & (1<<5))==0)
+ {
+ /* read data? */
+ if (fdc->command == 0x06)
+ {
+ /* did we just read a sector with deleted data? */
+ if (fdc->data_type == UPD765_DAM_DELETED_DATA)
+ {
+ /* set control mark */
+ fdc->upd765_status[2] |= UPD765_ST2_CONTROL_MARK;
+
+ /* quit */
+ return TRUE;
+ }
+ }
+ /* deleted data? */
+ else
+ if (fdc->command == 0x0c)
+ {
+ /* did we just read a sector with data? */
+ if (fdc->data_type == UPD765_DAM_DATA)
+ {
+ /* set control mark */
+ fdc->upd765_status[2] |= UPD765_ST2_CONTROL_MARK;
+
+ /* quit */
+ return TRUE;
+ }
+ }
+ }
+
+ /* continue */
+ return FALSE;
+}
+
+static TIMER_CALLBACK(upd765_continue_command)
+{
+ device_t *device = (device_t *)ptr;
+ upd765_t *fdc = get_safe_token(device);
+ if ((fdc->upd765_phase == UPD765_EXECUTION_PHASE_READ) ||
+ (fdc->upd765_phase == UPD765_EXECUTION_PHASE_WRITE))
+ {
+ switch (fdc->command)
+ {
+ /* read a track */
+ case 0x02:
+ {
+ fdc->sector_counter++;
+
+ /* sector counter == EOT */
+ if (fdc->sector_counter==fdc->upd765_command_bytes[6])
+ {
+ /* TODO: Add correct info here */
+
+ fdc->upd765_status[1] |= UPD765_ST1_END_OF_CYLINDER;
+
+ upd765_setup_st0(device);
+
+ fdc->upd765_result_bytes[0] = fdc->upd765_status[0];
+ fdc->upd765_result_bytes[1] = fdc->upd765_status[1];
+ fdc->upd765_result_bytes[2] = fdc->upd765_status[2];
+ fdc->upd765_result_bytes[3] = fdc->upd765_command_bytes[2]; /* C */
+ fdc->upd765_result_bytes[4] = fdc->upd765_command_bytes[3]; /* H */
+ fdc->upd765_result_bytes[5] = fdc->upd765_command_bytes[4]; /* R */
+ fdc->upd765_result_bytes[6] = fdc->upd765_command_bytes[5]; /* N */
+
+ upd765_setup_result_phase(device,7);
+ }
+ else
+ {
+ upd765_read_a_track(device);
+ }
+ }
+ break;
+
+ /* format track */
+ case 0x0d:
+ {
+ floppy_drive_format_sector(current_image(device), fdc->side, fdc->sector_counter,
+ fdc->format_data[0], fdc->format_data[1],
+ fdc->format_data[2], fdc->format_data[3],
+ fdc->upd765_command_bytes[5]);
+
+ fdc->sector_counter++;
+
+ /* sector_counter = SC */
+ if (fdc->sector_counter == fdc->upd765_command_bytes[3])
+ {
+ /* TODO: Check result is correct */
+ fdc->upd765_result_bytes[0] = fdc->upd765_status[0];
+ fdc->upd765_result_bytes[1] = fdc->upd765_status[1];
+ fdc->upd765_result_bytes[2] = fdc->upd765_status[2];
+ fdc->upd765_result_bytes[3] = fdc->format_data[0];
+ fdc->upd765_result_bytes[4] = fdc->format_data[1];
+ fdc->upd765_result_bytes[5] = fdc->format_data[2];
+ fdc->upd765_result_bytes[6] = fdc->format_data[3];
+ upd765_setup_result_phase(device,7);
+ }
+ else
+ {
+ upd765_format_track(device);
+ }
+ }
+ break;
+
+ /* write data, write deleted data */
+ case 0x09:
+ case 0x05:
+ {
+ /* sector id == EOT */
+ UINT8 ddam;
+
+ ddam = 0;
+ if (fdc->command == 0x09)
+ {
+ ddam = 1;
+ }
+
+ /* write data to disc */
+ // logerror("floppy_drive_write_sector_data side=%d sector=%d tc=%x\n", fdc->side, fdc->sector_id, fdc->upd765_flags & UPD765_TC);
+ floppy_drive_write_sector_data(current_image(device), fdc->side, fdc->sector_id,fdc->data_buffer,upd765_n_to_bytes(fdc->upd765_command_bytes[5]),ddam);
+
+ /* nothing to write */
+ if ((fdc->upd765_transfer_bytes_remaining==0) && (fdc->upd765_flags & UPD765_DMA_MODE))
+ {
+ if (fdc->upd765_flags & UPD765_TC)
+ {
+ upd765_write_complete(device);
+ break;
+ }
+ }
+
+ if (upd765_sector_count_complete(device))
+ {
+ upd765_increment_sector(device);
+ upd765_write_complete(device);
+ }
+ else
+ {
+ upd765_increment_sector(device);
+ upd765_write_data(device);
+ }
+ }
+ break;
+
+ /* read data, read deleted data */
+ case 0x0c:
+ case 0x06:
+ {
+
+ int cause;
+ /* read all sectors? */
+
+ /* sector id == EOT */
+ if ((cause = upd765_sector_count_complete(device)) || upd765_read_data_stop(device))
+ {
+ if (cause == 2)
+ upd765_increment_sector(device); // advance to next cylinder if EOT
+
+ upd765_read_complete(device);
+ }
+ else
+ {
+ upd765_increment_sector(device);
+ upd765_read_data(device);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+
+static int upd765_get_command_byte_count(device_t *device)
+{
+ upd765_t *fdc = get_safe_token(device);
+ fdc->command = fdc->upd765_command_bytes[0] & 0x01f;
+
+ if (fdc->version==TYPE_UPD765A)
+ {
+ return upd765_cmd_size[fdc->command];
+ }
+ else
+ {
+ if (fdc->version==TYPE_UPD72065)
+ {
+ switch(fdc->upd765_command_bytes[0])
+ {
+ case 0x34: // Reset Standby
+ case 0x35: // Set Standby
+ case 0x36: // Software Reset
+ return 1;
+ default:
+ return upd765_cmd_size[fdc->command];
+ }
+ }
+ if (fdc->version==TYPE_SMC37C78)
+ {
+ switch (fdc->command)
+ {
+ /* version */
+ case 0x010:
+ return 1;
+
+ /* verify */
+ case 0x016:
+ return 9;
+
+ /* configure */
+ case 0x013:
+ return 4;
+
+ /* dumpreg */
+ case 0x0e:
+ return 1;
+
+ /* perpendicular mode */
+ case 0x012:
+ return 1;
+
+ /* lock */
+ case 0x014:
+ return 1;
+
+ /* seek/relative seek are together! */
+
+ default:
+ return upd765_cmd_size[fdc->command];
+ }
+ }
+ }
+
+ return upd765_cmd_size[fdc->command];
+}
+
+
+
+
+
+void upd765_update_state(device_t *device)
+{
+ upd765_t *fdc = get_safe_token(device);
+ switch (fdc->upd765_phase) {
+ case UPD765_RESULT_PHASE:
+ /* set data reg */
+ fdc->upd765_data_reg = fdc->upd765_result_bytes[fdc->upd765_transfer_bytes_count];
+
+ if (fdc->upd765_transfer_bytes_count == 0)
+ {
+ /* clear int for specific commands */
+ switch (fdc->command) {
+ case 2: /* read a track */
+ case 5: /* write data */
+ case 6: /* read data */
+ case 9: /* write deleted data */
+ case 10: /* read id */
+ case 12: /* read deleted data */
+ case 13: /* format at track */
+ case 17: /* scan equal */
+ case 19: /* scan low or equal */
+ case 29: /* scan high or equal */
+ upd765_set_int(device, 0);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (LOG_VERBOSE)
+ logerror("UPD765: RESULT: %02x\n", fdc->upd765_data_reg);
+
+ fdc->upd765_transfer_bytes_count++;
+ fdc->upd765_transfer_bytes_remaining--;
+
+ if (fdc->upd765_transfer_bytes_remaining==0)
+ {
+ upd765_idle(device);
+ }
+ else
+ {
+ upd765_set_data_request(device);
+ }
+ break;
+
+ case UPD765_EXECUTION_PHASE_READ:
+ /* setup data register */
+ fdc->upd765_data_reg = fdc->execution_phase_data[fdc->upd765_transfer_bytes_count];
+ fdc->upd765_transfer_bytes_count++;
+ fdc->upd765_transfer_bytes_remaining--;
+
+ if (LOG_EXTRA)
+ logerror("EXECUTION PHASE READ: %02x\n", fdc->upd765_data_reg);
+
+ if ((fdc->upd765_transfer_bytes_remaining==0) || (fdc->upd765_flags & UPD765_TC))
+ {
+ fdc->command_timer->adjust(attotime::zero);
+ }
+ else
+ {
+ /* trigger int */
+ upd765_setup_timed_data_request(device,1);
+ }
+ break;
+
+ case UPD765_COMMAND_PHASE_FIRST_BYTE:
+ fdc->FDC_main |= 0x10; /* set BUSY */
+
+ if (LOG_VERBOSE)
+ logerror("%s: upd765(): command=0x%02x\n", device->machine().describe_context(), fdc->upd765_data_reg);
+
+ /* seek in progress? */
+ if (fdc->upd765_flags & UPD765_SEEK_ACTIVE)
+ {
+ /* any command results in a invalid - I think that seek, recalibrate and
+ sense interrupt status may work*/
+ if (fdc->upd765_data_reg != 8) /* Sense Interrupt Status */
+ fdc->upd765_data_reg = 0;
+ }
+
+ fdc->upd765_command_bytes[0] = fdc->upd765_data_reg;
+
+ fdc->upd765_transfer_bytes_remaining = upd765_get_command_byte_count(device);
+
+ fdc->upd765_transfer_bytes_count = 1;
+ fdc->upd765_transfer_bytes_remaining--;
+
+ if (fdc->upd765_transfer_bytes_remaining==0)
+ {
+ upd765_setup_command(device);
+ }
+ else
+ {
+ /* request more data */
+ upd765_set_data_request(device);
+ fdc->upd765_phase = UPD765_COMMAND_PHASE_BYTES;
+ }
+ break;
+
+ case UPD765_COMMAND_PHASE_BYTES:
+ if (LOG_VERBOSE)
+ logerror("%s: upd765(): command=0x%02x\n", device->machine().describe_context(), fdc->upd765_data_reg);
+
+ fdc->upd765_command_bytes[fdc->upd765_transfer_bytes_count] = fdc->upd765_data_reg;
+ fdc->upd765_transfer_bytes_count++;
+ fdc->upd765_transfer_bytes_remaining--;
+
+ if (fdc->upd765_transfer_bytes_remaining==0)
+ {
+ upd765_setup_command(device);
+ }
+ else
+ {
+ /* request more data */
+ upd765_set_data_request(device);
+ }
+ break;
+
+ case UPD765_EXECUTION_PHASE_WRITE:
+ fdc->execution_phase_data[fdc->upd765_transfer_bytes_count]=fdc->upd765_data_reg;
+ fdc->upd765_transfer_bytes_count++;
+ fdc->upd765_transfer_bytes_remaining--;
+
+ if ((fdc->upd765_transfer_bytes_remaining == 0) || (fdc->upd765_flags & UPD765_TC))
+ {
+ fdc->command_timer->adjust(attotime::zero);
+ }
+ else
+ {
+ upd765_setup_timed_data_request(device,1);
+ }
+ break;
+ }
+}
+
+
+READ8_DEVICE_HANDLER(upd765_data_r)
+{
+ upd765_t *fdc = get_safe_token(device);
+
+// if ((fdc->FDC_main & 0x0c0) == 0x0c0)
+ if ((fdc->FDC_main & 0x080) == 0x080)
+ {
+ if (
+ (fdc->upd765_phase == UPD765_EXECUTION_PHASE_READ) ||
+ (fdc->upd765_phase == UPD765_EXECUTION_PHASE_WRITE))
+ {
+
+ /* reading the data byte clears the interrupt */
+ upd765_set_int(device,CLEAR_LINE);
+ }
+
+ /* reset data request */
+ upd765_clear_data_request(device);
+
+ /* update state */
+ upd765_update_state(device);
+ }
+
+ if (LOG_EXTRA)
+ logerror("DATA R: %02x\n", fdc->upd765_data_reg);
+
+ return fdc->upd765_data_reg;
+}
+
+WRITE8_DEVICE_HANDLER(upd765_data_w)
+{
+ upd765_t *fdc = get_safe_token(device);
+
+ if (LOG_EXTRA)
+ logerror("DATA W: %02x\n", data);
+
+ /* write data to data reg */
+ fdc->upd765_data_reg = data;
+
+ if ((fdc->FDC_main & 0x0c0)==0x080)
+ {
+ if (
+ (fdc->upd765_phase == UPD765_EXECUTION_PHASE_READ) ||
+ (fdc->upd765_phase == UPD765_EXECUTION_PHASE_WRITE))
+ {
+
+ /* reading the data byte clears the interrupt */
+ upd765_set_int(device, CLEAR_LINE);
+ }
+
+ /* reset data request */
+ upd765_clear_data_request(device);
+
+ /* update state */
+ upd765_update_state(device);
+ }
+}
+
+static void upd765_setup_invalid(device_t *device)
+{
+ upd765_t *fdc = get_safe_token(device);
+
+ fdc->command = 0;
+ fdc->upd765_result_bytes[0] = 0x080;
+ upd765_setup_result_phase(device,1);
+}
+
+static void upd765_setup_command(device_t *device)
+{
+ upd765_t *fdc = get_safe_token(device);
+
+ static const char *const commands[] =
+ {
+ NULL, /* [00] */
+ NULL, /* [01] */
+ "Read Track", /* [02] */
+ "Specify", /* [03] */
+ "Sense Drive Status", /* [04] */
+ "Write Data", /* [05] */
+ "Read Data", /* [06] */
+ "Recalibrate", /* [07] */
+ "Sense Interrupt Status", /* [08] */
+ "Write Deleted Data", /* [09] */
+ "Read ID", /* [0A] */
+ NULL, /* [0B] */
+ "Read Deleted Data", /* [0C] */
+ "Format Track", /* [0D] */
+ "Dump Registers", /* [0E] */
+ "Seek", /* [0F] */
+ "Version", /* [10] */
+ NULL, /* [11] */
+ "Perpendicular Mode", /* [12] */
+ "Configure", /* [13] */
+ "Lock" /* [14] */
+ };
+
+ device_t *img;
+ const char *cmd = NULL;
+ chrn_id id;
+
+ /* if not in dma mode set execution phase bit */
+ if (!(fdc->upd765_flags & UPD765_DMA_MODE))
+ {
+ fdc->FDC_main |= 0x020; /* execution phase */
+ }
+
+ if (LOG_COMMAND)
+ {
+ if ((fdc->upd765_command_bytes[0] & 0x1f) < ARRAY_LENGTH(commands))
+ cmd = commands[fdc->upd765_command_bytes[0] & 0x1f];
+ logerror("upd765_setup_command(): Setting up command 0x%02X (%s)\n",
+ fdc->upd765_command_bytes[0] & 0x1f, cmd ? cmd : "???");
+ }
+
+ switch (fdc->upd765_command_bytes[0] & 0x1f)
+ {
+ case 0x03: /* specify */
+ /* setup step rate */
+ fdc->srt_in_ms = 16-((fdc->upd765_command_bytes[1]>>4) & 0x0f);
+
+ fdc->upd765_flags &= ~UPD765_DMA_MODE;
+
+ if ((fdc->upd765_command_bytes[2] & 0x01)==0)
+ {
+ fdc->upd765_flags |= UPD765_DMA_MODE;
+ }
+
+ upd765_idle(device);
+ break;
+
+ case 0x04: /* sense drive status */
+ upd765_setup_drive_and_side(device);
+ img = current_image(device);
+
+ fdc->upd765_status[3] = fdc->drive | (fdc->side<<2);
+
+ if (img)
+ {
+ fdc->upd765_status[3] |= !floppy_tk00_r(img) << 4;
+ fdc->upd765_status[3] |= !floppy_wpt_r(img) << 6;
+
+ if (upd765_get_rdy(device))
+ {
+ fdc->upd765_status[3] |= 0x20;
+ }
+ }
+
+ fdc->upd765_status[3] |= 0x08;
+
+ /* two side and fault not set but should be? */
+ fdc->upd765_result_bytes[0] = fdc->upd765_status[3];
+ upd765_setup_result_phase(device,1);
+ break;
+
+ case 0x07: /* recalibrate */
+ upd765_seek_setup(device, 1);
+ break;
+
+ case 0x0f: /* seek */
+ upd765_seek_setup(device, 0);
+ break;
+
+ case 0x0a: /* read id */
+ upd765_setup_drive_and_side(device);
+ img = current_image(device);
+
+ fdc->upd765_status[0] = fdc->drive | (fdc->side<<2);
+ fdc->upd765_status[1] = 0;
+ fdc->upd765_status[2] = 0;
+
+ /* drive ready? */
+ if (upd765_get_rdy(device))
+ {
+ /* is disk inserted? */
+ device_image_interface *image = dynamic_cast<device_image_interface *>( img);
+ if (image!=NULL && image->exists())
+ {
+ int index_count = 0;
+
+ /* floppy drive is ready and disc is inserted */
+
+ /* this is the id that appears when a disc is not formatted */
+ /* to be checked on Amstrad */
+ id.C = 0;
+ id.H = 0;
+ id.R = 0x01;
+ id.N = 0x02;
+
+ /* repeat for two index counts before quitting */
+ do
+ {
+ /* get next id from disc */
+ if (floppy_drive_get_next_id(img, fdc->side, &id))
+ {
+ /* got an id */
+ /* if bad media keep going until failure */
+ if (!(fdc->upd765_flags & UPD765_BAD_MEDIA)) break;
+ }
+
+ if (floppy_drive_get_flag_state(img, FLOPPY_DRIVE_INDEX))
+ {
+ /* update index count */
+ index_count++;
+ }
+ }
+ while (index_count!=2);
+
+ if (fdc->upd765_flags & UPD765_BAD_MEDIA)
+ {
+ fdc->upd765_status[0] |= 0x40;
+ fdc->upd765_status[1] |= 1;
+ }
+
+ /* at this point, we have seen a id or two index pulses have occurred! */
+ fdc->upd765_result_bytes[0] = fdc->upd765_status[0];
+ fdc->upd765_result_bytes[1] = fdc->upd765_status[1];
+ fdc->upd765_result_bytes[2] = fdc->upd765_status[2];
+ fdc->upd765_result_bytes[3] = id.C; /* C */
+ fdc->upd765_result_bytes[4] = id.H; /* H */
+ fdc->upd765_result_bytes[5] = id.R; /* R */
+ fdc->upd765_result_bytes[6] = id.N; /* N */
+
+ upd765_setup_result_phase(device,7);
+ }
+ else
+ {
+ /* floppy drive is ready, but no disc is inserted */
+ /* this occurs on the PC */
+ /* in this case, the command never quits! */
+ /* there are no index pulses to stop the command! */
+ }
+ }
+ else
+ {
+ /* what are id values when drive not ready? */
+
+ /* not ready, abnormal termination */
+ fdc->upd765_status[0] |= (1<<3) | (1<<6);
+ fdc->upd765_result_bytes[0] = fdc->upd765_status[0];
+ fdc->upd765_result_bytes[1] = fdc->upd765_status[1];
+ fdc->upd765_result_bytes[2] = fdc->upd765_status[2];
+ fdc->upd765_result_bytes[3] = 0; /* C */
+ fdc->upd765_result_bytes[4] = 0; /* H */
+ fdc->upd765_result_bytes[5] = 0; /* R */
+ fdc->upd765_result_bytes[6] = 0; /* N */
+ }
+ break;
+
+
+ case 0x08: /* sense interrupt status */
+ /* interrupt pending? */
+ if (fdc->upd765_flags & UPD765_INT)
+ {
+ /* clear ready changed bit */
+ fdc->ready_changed &= ~(1 << fdc->drive);
+
+ if (!fdc->pool) {
+ fdc->ready_changed = 0;
+ }
+
+ /* clear drive seek bits */
+ fdc->FDC_main &= ~(1 | 2 | 4 | 8);
+
+ /* return status */
+ fdc->upd765_result_bytes[0] = fdc->upd765_status[0];
+ /* return pcn */
+ fdc->upd765_result_bytes[1] = fdc->pcn[fdc->drive];
+
+ /* return result */
+ upd765_setup_result_phase(device,2);
+
+ if (fdc->ready_changed)
+ {
+ fdc->drive++;
+ fdc->upd765_status[0] = 0xc0 | fdc->drive;
+ }
+ else
+ {
+ /* Clear int */
+ upd765_set_int(device, CLEAR_LINE);
+ }
+ }
+ else
+ {
+ if(fdc->version == TYPE_UPD72065 && (fdc->FDC_main & 0x0f) == 0x00)
+ { // based on XM6
+ upd765_setup_invalid(device);
+ }
+ else
+ {
+ /* no int */
+ fdc->upd765_result_bytes[0] = 0x80;
+ /* return pcn */
+ fdc->upd765_result_bytes[1] = fdc->pcn[fdc->drive];
+
+ /* return result */
+ upd765_setup_result_phase(device,2);
+ }
+ }
+ break;
+
+ case 0x06: /* read data */
+ upd765_setup_drive_and_side(device);
+
+ fdc->upd765_status[0] = fdc->drive | (fdc->side<<2);
+ fdc->upd765_status[1] = 0;
+ fdc->upd765_status[2] = 0;
+
+ upd765_read_data(device);
+ break;
+
+ case 0x0c:
+ /* read deleted data */
+ upd765_setup_drive_and_side(device);
+
+ fdc->upd765_status[0] = fdc->drive | (fdc->side<<2);
+ fdc->upd765_status[1] = 0;
+ fdc->upd765_status[2] = 0;
+
+ /* .. for now */
+ upd765_read_data(device);
+ break;
+
+ case 0x09:
+ /* write deleted data */
+ upd765_setup_drive_and_side(device);
+
+ fdc->upd765_status[0] = fdc->drive | (fdc->side<<2);
+ fdc->upd765_status[1] = 0;
+ fdc->upd765_status[2] = 0;
+
+ /* ... for now */
+ upd765_write_data(device);
+ break;
+
+ case 0x02:
+ /* read a track */
+ upd765_setup_drive_and_side(device);
+ img = current_image(device);
+ fdc->upd765_status[0] = fdc->drive | (fdc->side<<2);
+ fdc->upd765_status[1] = 0;
+ fdc->upd765_status[2] = 0;
+
+ fdc->upd765_status[0] |= UPD765_ST1_NO_DATA;
+
+ /* wait for index */
+ do
+ {
+ /* get next id from disc */
+ floppy_drive_get_next_id(img, fdc->side,&id);
+ }
+ while ((floppy_drive_get_flag_state(img, FLOPPY_DRIVE_INDEX))==0);
+
+ fdc->sector_counter = 0;
+
+ upd765_read_a_track(device);
+ break;
+
+ case 0x05: /* write data */
+ upd765_setup_drive_and_side(device);
+
+ fdc->upd765_status[0] = fdc->drive | (fdc->side<<2);
+ fdc->upd765_status[1] = 0;
+ fdc->upd765_status[2] = 0;
+
+ upd765_write_data(device);
+ break;
+
+ case 0x0d: /* format a track */
+ upd765_setup_drive_and_side(device);
+
+ fdc->upd765_status[0] = fdc->drive | (fdc->side<<2);
+ fdc->upd765_status[1] = 0;
+ fdc->upd765_status[2] = 0;
+
+ fdc->sector_counter = 0;
+
+ upd765_format_track(device);
+ break;
+
+ default: /* invalid */
+ switch (fdc->version)
+ {
+ case TYPE_UPD765A:
+ upd765_setup_invalid(device);
+ break;
+
+ case TYPE_UPD765B:
+ /* from upd765b data sheet */
+ if ((fdc->upd765_command_bytes[0] & 0x01f)==0x010)
+ {
+ /* version */
+ fdc->upd765_status[0] = 0x090;
+ fdc->upd765_result_bytes[0] = fdc->upd765_status[0];
+ upd765_setup_result_phase(device,1);
+ }
+ break;
+
+ case TYPE_UPD72065:
+ switch(fdc->upd765_command_bytes[0] & 0x3f)
+ {
+ case 0x36: // Software Reset
+ upd765_reset(device,0);
+ upd765_idle(device);
+ if(LOG_COMMAND)
+ logerror("upd72065: command - Software Reset\n");
+ break;
+ default:
+ upd765_setup_invalid(device);
+ break;
+ }
+ break;
+
+ case TYPE_SMC37C78:
+ /* TO BE COMPLETED!!! !*/
+ switch (fdc->upd765_command_bytes[0] & 0x1f)
+ {
+ case 0x10: /* version */
+ fdc->upd765_status[0] = 0x90;
+ fdc->upd765_result_bytes[0] = fdc->upd765_status[0];
+ upd765_setup_result_phase(device,1);
+ break;
+
+ case 0x13: /* configure */
+ fdc->pool = fdc->upd765_command_bytes[1] & 0x10;
+ upd765_idle(device);
+ break;
+
+ case 0x0e: /* dump reg */
+ fdc->upd765_result_bytes[0] = fdc->pcn[0];
+ fdc->upd765_result_bytes[1] = fdc->pcn[1];
+ fdc->upd765_result_bytes[2] = fdc->pcn[2];
+ fdc->upd765_result_bytes[3] = fdc->pcn[3];
+
+ upd765_setup_result_phase(device,10);
+ break;
+
+ case 0x12: /* perpendicular mode */
+ upd765_idle(device);
+ break;
+
+ case 0x14: /* lock */
+ upd765_setup_result_phase(device,1);
+ break;
+ }
+ break;
+ }
+ }
+}
+
+
+/* dma acknowledge write */
+WRITE8_DEVICE_HANDLER(upd765_dack_w)
+{
+ /* clear request */
+ upd765_set_dma_drq(device, CLEAR_LINE);
+
+ /* write data */
+ upd765_data_w(device, offset, data);
+}
+
+READ8_DEVICE_HANDLER(upd765_dack_r)
+{
+ /* clear data request */
+ upd765_set_dma_drq(device,CLEAR_LINE);
+
+ /* read data */
+ return upd765_data_r(device, offset);
+}
+
+static TIMER_CALLBACK( interrupt_callback )
+{
+ device_t* device = (device_t*)ptr;
+ upd765_set_int(device, 1);
+}
+
+void upd765_set_bad(device_t *device, int state)
+{
+ upd765_t *fdc = get_safe_token(device);
+ if (state) fdc->upd765_flags |= UPD765_BAD_MEDIA;
+ else fdc->upd765_flags &= ~UPD765_BAD_MEDIA;
+}
+
+void upd765_reset(device_t *device, int offset)
+{
+ upd765_t *fdc = get_safe_token(device);
+
+ /* upd765 in idle state - ready to accept commands */
+ upd765_idle(device);
+
+ /* set int low */
+ upd765_set_int(device, 0);
+ /* set dma drq output */
+ upd765_set_dma_drq(device,0);
+
+ /* tandy 100hx assumes that after NEC is reset, it is in DMA mode */
+ fdc->upd765_flags |= UPD765_DMA_MODE;
+
+ /* if ready input is set during reset generate an int */
+ if (upd765_get_rdy(device))
+ {
+ int i;
+ int a_drive_is_ready;
+
+ fdc->upd765_status[0] = 0x080 | 0x040;
+
+ // HACK signal ready changed for all drives
+ fdc->ready_changed = 0x0f;
+ fdc->drive = 0;
+
+ /* for the purpose of pc-xt. If any of the drives have a disk inserted,
+ do not set not-ready - need to check with pc_fdc.c whether all drives
+ are checked or only the drive selected with the drive select bits?? */
+
+ a_drive_is_ready = 0;
+ for (i = 0; i < 4; i++)
+ {
+ if (fdc->intf->floppy_drive_tags[i]!=NULL)
+ {
+ device_t *img;
+
+ if (device->owner() != NULL)
+ img = device->owner()->subdevice(fdc->intf->floppy_drive_tags[i]);
+ else
+ img = device->machine().device(fdc->intf->floppy_drive_tags[i]);
+
+ device_image_interface *image = dynamic_cast<device_image_interface *>( img);
+ if (image->exists())
+ {
+ a_drive_is_ready = 1;
+ break;
+ }
+ }
+
+ }
+
+ if (!a_drive_is_ready && fdc->intf->rdy_pin == UPD765_RDY_PIN_CONNECTED )
+ {
+ fdc->upd765_status[0] |= 0x08;
+ }
+
+ device->machine().scheduler().timer_set(attotime::from_usec(5), FUNC(interrupt_callback),0,device);
+ }
+}
+
+WRITE_LINE_DEVICE_HANDLER( upd765_reset_w )
+{
+ upd765_t *fdc = get_safe_token(device);
+
+ int flags;
+
+ /* get previous reset state */
+ flags = fdc->upd765_flags;
+
+ /* set new reset state */
+ /* clear reset */
+ fdc->upd765_flags &= ~UPD765_RESET;
+
+ /* reset */
+ if (state)
+ {
+ fdc->upd765_flags |= UPD765_RESET;
+
+ upd765_set_int(device, 0);
+ }
+
+ /* reset changed state? */
+ if (((flags^fdc->upd765_flags) & UPD765_RESET)!=0)
+ {
+ /* yes */
+
+ /* no longer reset */
+ if ((fdc->upd765_flags & UPD765_RESET)==0)
+ {
+ /* reset nec */
+ upd765_reset(device, 0);
+ }
+ }
+}
+
+
+WRITE_LINE_DEVICE_HANDLER( upd765_ready_w )
+{
+ upd765_t *fdc = get_safe_token(device);
+
+ /* clear ready state */
+ fdc->upd765_flags &= ~UPD765_FDD_READY;
+
+ if (state)
+ {
+ fdc->upd765_flags |= UPD765_FDD_READY;
+ }
+}
+
+
+/* Device Interface */
+
+static void common_start(device_t *device, int device_type)
+{
+ upd765_t *fdc = get_safe_token(device);
+ // validate arguments
+
+ assert(device != NULL);
+ assert(device->tag() != NULL);
+ assert(device->static_config() != NULL);
+
+ fdc->intf = (const upd765_interface*)device->static_config();
+
+ fdc->version = (UPD765_VERSION)device_type;
+ fdc->timer = device->machine().scheduler().timer_alloc(FUNC(upd765_timer_callback), (void*)device);
+ fdc->seek_timer = device->machine().scheduler().timer_alloc(FUNC(upd765_seek_timer_callback), (void*)device);
+ fdc->command_timer = device->machine().scheduler().timer_alloc(FUNC(upd765_continue_command), (void*)device);
+
+ fdc->upd765_flags &= UPD765_FDD_READY;
+ fdc->data_buffer = auto_alloc_array(device->machine(), char, 32*1024);
+
+ fdc->out_int_func.resolve(fdc->intf->out_int_func, *device);
+ fdc->out_drq_func.resolve(fdc->intf->out_drq_func, *device);
+
+ // plain upd765 is doing pooling
+ fdc->pool = true;
+ // register for state saving
+ //state_save_register_item(device->machine(), "upd765", device->tag(), 0, upd765->number);
+}
+
+static DEVICE_START( upd765a )
+{
+ common_start(device, TYPE_UPD765A);
+}
+
+static DEVICE_START( upd765b )
+{
+ common_start(device, TYPE_UPD765B);
+}
+
+static DEVICE_START( smc37c78 )
+{
+ common_start(device, TYPE_SMC37C78);
+ // specified in documentation that by default is off
+ upd765_t *fdc = get_safe_token(device);
+ fdc->pool = false;
+}
+
+static DEVICE_START( upd72065 )
+{
+ common_start(device, TYPE_UPD72065);
+}
+
+static DEVICE_RESET( upd765 )
+{
+ int i;
+ upd765_t *fdc = get_safe_token(device);
+ for (i = 0; i < 4; i++) {
+ if (fdc->intf->floppy_drive_tags[i]!=NULL)
+ {
+ device_t *img;
+
+ if (device->owner() != NULL)
+ img = device->owner()->subdevice(fdc->intf->floppy_drive_tags[i]);
+ else
+ img = device->machine().device(fdc->intf->floppy_drive_tags[i]);
+
+ floppy_drive_set_controller(img, device);
+ floppy_drive_set_ready_state_change_callback(img, upd765_set_ready_change_callback);
+ }
+ }
+
+ upd765_reset(device,0);
+}
+
+DEVICE_GET_INFO( upd765a )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(upd765_t); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(upd765a); break;
+ case DEVINFO_FCT_STOP: /* Nothing */ break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(upd765); break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "UPD765A"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "UPD765A"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright MESS Team"); break;
+ }
+}
+
+
+DEVICE_GET_INFO( upd765b )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "UPD765B"); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(upd765b); break;
+
+ default: DEVICE_GET_INFO_CALL(upd765a); break;
+ }
+}
+
+DEVICE_GET_INFO( smc37c78 )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "SMC37C78"); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(smc37c78); break;
+
+ default: DEVICE_GET_INFO_CALL(upd765a); break;
+ }
+}
+
+DEVICE_GET_INFO( upd72065 )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "UPD72065"); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(upd72065); break;
+
+ default: DEVICE_GET_INFO_CALL(upd765a); break;
+ }
+}
+
+DEFINE_LEGACY_DEVICE(UPD765A, upd765a);
+DEFINE_LEGACY_DEVICE(UPD765B, upd765b);
+DEFINE_LEGACY_DEVICE(SMC37C78, smc37c78);
+DEFINE_LEGACY_DEVICE(UPD72065, upd72065);
diff --git a/src/mess/machine/upd765.h b/src/mess/machine/upd765.h
new file mode 100644
index 00000000000..3b15fae150e
--- /dev/null
+++ b/src/mess/machine/upd765.h
@@ -0,0 +1,165 @@
+/***************************************************************************
+
+ machine/upd765.h
+
+ Functions to emulate a NEC upd765/Intel 8272 compatible
+ floppy disk controller
+
+***************************************************************************/
+
+#ifndef __UPD765_H__
+#define __UPD765_H__
+
+#include "devcb.h"
+#include "imagedev/flopdrv.h"
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+DECLARE_LEGACY_DEVICE(UPD765A, upd765a);
+DECLARE_LEGACY_DEVICE(UPD765B, upd765b);
+DECLARE_LEGACY_DEVICE(SMC37C78, smc37c78);
+DECLARE_LEGACY_DEVICE(UPD72065, upd72065);
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* RDY pin connected state */
+typedef enum
+{
+ UPD765_RDY_PIN_NOT_CONNECTED = 0,
+ UPD765_RDY_PIN_CONNECTED = 1
+} UPD765_RDY_PIN;
+
+#define UPD765_DAM_DELETED_DATA 0x0f8
+#define UPD765_DAM_DATA 0x0fb
+
+typedef device_t *(*upd765_get_image_func)(device_t *device, int floppy_index);
+#define UPD765_GET_IMAGE(name) device_t *name(device_t *device, int floppy_index )
+
+
+typedef struct upd765_interface
+{
+ /* interrupt issued */
+ devcb_write_line out_int_func;
+
+ /* dma data request */
+ devcb_write_line out_drq_func;
+
+ /* image lookup */
+ upd765_get_image_func get_image;
+
+ UPD765_RDY_PIN rdy_pin;
+
+ const char *floppy_drive_tags[4];
+} upd765_interface;
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* read of data register */
+READ8_DEVICE_HANDLER(upd765_data_r);
+/* write to data register */
+WRITE8_DEVICE_HANDLER(upd765_data_w);
+/* read of main status register */
+READ8_DEVICE_HANDLER(upd765_status_r);
+
+/* dma acknowledge with write */
+WRITE8_DEVICE_HANDLER(upd765_dack_w);
+/* dma acknowledge with read */
+READ8_DEVICE_HANDLER(upd765_dack_r);
+
+/* reset upd765 */
+void upd765_reset(device_t *device, int);
+
+/* reset pin of upd765 */
+WRITE_LINE_DEVICE_HANDLER(upd765_reset_w);
+
+/* set upd765 terminal count input state */
+WRITE_LINE_DEVICE_HANDLER(upd765_tc_w);
+
+/* set upd765 ready input*/
+WRITE_LINE_DEVICE_HANDLER(upd765_ready_w);
+
+void upd765_idle(device_t *device);
+void upd765_set_bad(device_t *device, int state);
+
+READ_LINE_DEVICE_HANDLER( upd765_int_r );
+READ_LINE_DEVICE_HANDLER( upd765_drq_r );
+
+/*********************/
+/* STATUS REGISTER 1 */
+
+/* this is set if a TC signal was not received after the sector data was read */
+#define UPD765_ST1_END_OF_CYLINDER (1<<7)
+/* this is set if the sector ID being searched for is not found */
+#define UPD765_ST1_NO_DATA (1<<2)
+/* set if disc is write protected and a write/format operation was performed */
+#define UPD765_ST1_NOT_WRITEABLE (1<<1)
+
+/*********************/
+/* STATUS REGISTER 2 */
+
+/* C parameter specified did not match C value read from disc */
+#define UPD765_ST2_WRONG_CYLINDER (1<<4)
+/* C parameter specified did not match C value read from disc, and C read from disc was 0x0ff */
+#define UPD765_ST2_BAD_CYLINDER (1<<1)
+/* this is set if the FDC encounters a Deleted Data Mark when executing a read data
+command, or FDC encounters a Data Mark when executing a read deleted data command */
+#define UPD765_ST2_CONTROL_MARK (1<<6)
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+#define MCFG_UPD765A_ADD(_tag, _intrf) \
+ MCFG_DEVICE_ADD(_tag, UPD765A, 0) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#define MCFG_UPD765A_MODIFY(_tag, _intrf) \
+ MCFG_DEVICE_MODIFY(_tag) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#define MCFG_UPD765A_REMOVE(_tag) \
+ MCFG_DEVICE_REMOVE(_tag)
+
+#define MCFG_UPD765B_ADD(_tag, _intrf) \
+ MCFG_DEVICE_ADD(_tag, UPD765B, 0) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#define MCFG_UPD765B_MODIFY(_tag, _intrf) \
+ MCFG_DEVICE_MODIFY(_tag) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#define MCFG_UPD765B_REMOVE(_tag) \
+ MCFG_DEVICE_REMOVE(_tag)
+
+#define MCFG_SMC37C78_ADD(_tag, _intrf) \
+ MCFG_DEVICE_ADD(_tag, SMC37C78, 0) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#define MCFG_SMC37C78_MODIFY(_tag, _intrf) \
+ MCFG_DEVICE_MODIFY(_tag) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#define MCFG_SMC37C78_REMOVE(_tag) \
+ MCFG_DEVICE_REMOVE(_tag)
+
+#define MCFG_UPD72065_ADD(_tag, _intrf) \
+ MCFG_DEVICE_ADD(_tag, UPD72065, 0) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#define MCFG_UPD72065_MODIFY(_tag, _intrf) \
+ MCFG_DEVICE_MODIFY(_tag) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#define MCFG_UPD72065_REMOVE(_tag) \
+ MCFG_DEVICE_REMOVE(_tag)
+
+
+#endif /* __UPD765_H__ */
diff --git a/src/mess/machine/ut88.c b/src/mess/machine/ut88.c
new file mode 100644
index 00000000000..3f0bf7c6764
--- /dev/null
+++ b/src/mess/machine/ut88.c
@@ -0,0 +1,176 @@
+/***************************************************************************
+
+ UT88 machine driver by Miodrag Milanovic
+
+ 06/03/2008 Preliminary driver.
+
+****************************************************************************/
+
+
+#include "emu.h"
+#include "cpu/i8085/i8085.h"
+#include "sound/dac.h"
+#include "imagedev/cassette.h"
+#include "machine/i8255.h"
+#include "includes/ut88.h"
+
+
+/* Driver initialization */
+DRIVER_INIT_MEMBER(ut88_state,ut88)
+{
+ /* set initially ROM to be visible on first bank */
+ UINT8 *RAM = memregion("maincpu")->base();
+ memset(RAM,0x0000,0x0800); // make first page empty by default
+ membank("bank1")->configure_entries(1, 2, RAM, 0x0000);
+ membank("bank1")->configure_entries(0, 2, RAM, 0xf800);
+}
+
+READ8_MEMBER( ut88_state::ut88_8255_portb_r )
+{
+ UINT8 i, data = 0xff;
+ char kbdrow[12];
+ for (i = 0; i < 8; i++)
+ {
+ if (BIT(m_keyboard_mask, i))
+ {
+ sprintf(kbdrow,"LINE%d", i);
+ data &= ioport(kbdrow)->read();
+ }
+ }
+ return data;
+}
+
+READ8_MEMBER( ut88_state::ut88_8255_portc_r )
+{
+ return ioport("LINE8")->read();
+}
+
+WRITE8_MEMBER( ut88_state::ut88_8255_porta_w )
+{
+ m_keyboard_mask = data ^ 0xff;
+}
+
+I8255A_INTERFACE( ut88_ppi8255_interface )
+{
+ DEVCB_NULL,
+ DEVCB_DRIVER_MEMBER(ut88_state, ut88_8255_porta_w),
+ DEVCB_DRIVER_MEMBER(ut88_state, ut88_8255_portb_r),
+ DEVCB_NULL,
+ DEVCB_DRIVER_MEMBER(ut88_state, ut88_8255_portc_r),
+ DEVCB_NULL,
+};
+
+static TIMER_CALLBACK( ut88_reset )
+{
+ ut88_state *state = machine.driver_data<ut88_state>();
+ state->membank("bank1")->set_entry(0);
+}
+
+MACHINE_RESET( ut88 )
+{
+ ut88_state *state = machine.driver_data<ut88_state>();
+ machine.scheduler().timer_set(attotime::from_usec(10), FUNC(ut88_reset));
+ state->membank("bank1")->set_entry(1);
+ state->m_keyboard_mask = 0;
+}
+
+
+READ8_MEMBER( ut88_state::ut88_keyboard_r )
+{
+ return m_ppi->read(space, offset^0x03);
+}
+
+
+WRITE8_MEMBER( ut88_state::ut88_keyboard_w )
+{
+ m_ppi->write(space, offset^0x03, data);
+}
+
+WRITE8_MEMBER( ut88_state::ut88_sound_w )
+{
+ m_dac->write_unsigned8(data); //beeper
+ m_cass->output(BIT(data, 0) ? 1 : -1);
+}
+
+
+READ8_MEMBER( ut88_state::ut88_tape_r )
+{
+ double level = m_cass->input();
+ return (level < 0) ? 0 : 0xff;
+}
+
+READ8_MEMBER( ut88_state::ut88mini_keyboard_r )
+{
+ // This is real keyboard implementation
+ UINT8 *keyrom1 = memregion("proms")->base();
+ UINT8 *keyrom2 = memregion("proms")->base()+100;
+
+ UINT8 key = keyrom2[ioport("LINE1")->read()];
+
+ // if keyboard 2nd part returned 0 on 4th bit, output from
+ // first part is used
+
+ if (!BIT(key, 3))
+ key = keyrom1[ioport("LINE0")->read()];
+
+ // for delete key there is special key producing code 0x80
+
+ key = (BIT(ioport("LINE2")->read(), 7)) ? key : 0x80;
+
+ // If key 0 is pressed its value is 0x10 this is done by additional
+ // discrete logic
+
+ key = (BIT(ioport("LINE0")->read(), 0)) ? key : 0x10;
+ return key;
+}
+
+
+WRITE8_MEMBER( ut88_state::ut88mini_write_led )
+{
+ switch(offset)
+ {
+ case 0: m_lcd_digit[4] = (data >> 4) & 0x0f;
+ m_lcd_digit[5] = data & 0x0f;
+ break;
+ case 1: m_lcd_digit[2] = (data >> 4) & 0x0f;
+ m_lcd_digit[3] = data & 0x0f;
+ break;
+ case 2: m_lcd_digit[0] = (data >> 4) & 0x0f;
+ m_lcd_digit[1] = data & 0x0f;
+ break;
+ }
+}
+
+static const UINT8 hex_to_7seg[16] =
+{
+ 0x3F, 0x06, 0x5B, 0x4F,
+ 0x66, 0x6D, 0x7D, 0x07,
+ 0x7F, 0x6F, 0x77, 0x7c,
+ 0x39, 0x5e, 0x79, 0x71
+};
+
+static TIMER_CALLBACK( update_display )
+{
+ ut88_state *state = machine.driver_data<ut88_state>();
+ int i;
+ for (i=0;i<6;i++)
+ output_set_digit_value(i, hex_to_7seg[state->m_lcd_digit[i]]);
+}
+
+
+DRIVER_INIT_MEMBER(ut88_state,ut88mini)
+{
+}
+
+MACHINE_START( ut88mini )
+{
+ machine.scheduler().timer_pulse(attotime::from_hz(60), FUNC(update_display));
+}
+
+MACHINE_RESET( ut88mini )
+{
+ ut88_state *state = machine.driver_data<ut88_state>();
+ state->m_lcd_digit[0] = state->m_lcd_digit[1] = state->m_lcd_digit[2] = 0;
+ state->m_lcd_digit[3] = state->m_lcd_digit[4] = state->m_lcd_digit[5] = 0;
+}
+
diff --git a/src/mess/machine/v1050kb.c b/src/mess/machine/v1050kb.c
new file mode 100644
index 00000000000..315a55a7c1e
--- /dev/null
+++ b/src/mess/machine/v1050kb.c
@@ -0,0 +1,424 @@
+/**********************************************************************
+
+ Visual 1050 keyboard emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#include "v1050kb.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define I8049_TAG "z5"
+#define DISCRETE_TAG "ls1"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type V1050_KEYBOARD = &device_creator<v1050_keyboard_device>;
+
+
+
+//-------------------------------------------------
+// ROM( v1050_keyboard )
+//-------------------------------------------------
+
+ROM_START( v1050_keyboard )
+ ROM_REGION( 0x800, I8049_TAG, 0 )
+ ROM_LOAD( "20-08049-410.z5", 0x0000, 0x0800, NO_DUMP ) // internal 8049 ROM
+ ROM_LOAD( "22-02716-074.z8", 0x0000, 0x0800, NO_DUMP ) // external ROM for 8039 version
+ROM_END
+
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *v1050_keyboard_device::device_rom_region() const
+{
+ return ROM_NAME( v1050_keyboard );
+}
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( kb_io )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( v1050_keyboard_io, AS_IO, 8, v1050_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)
+ADDRESS_MAP_END
+
+
+//-------------------------------------------------
+// DISCRETE_SOUND_START( v1050kb )
+//-------------------------------------------------
+
+static const discrete_555_desc v1050_ne555 =
+{
+ DISC_555_OUT_SQW | DISC_555_OUT_DC,
+ 5, // B+ voltage of 555
+ DEFAULT_555_VALUES
+};
+
+static DISCRETE_SOUND_START( v1050kb )
+ DISCRETE_INPUT_LOGIC(NODE_01)
+ DISCRETE_555_ASTABLE(NODE_02, NODE_01, RES_K(68) /* can't read on schematic */ , RES_K(3), CAP_N(10), &v1050_ne555)
+ DISCRETE_OUTPUT(NODE_02, 5000)
+DISCRETE_SOUND_END
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( v1050_keyboard )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( v1050_keyboard )
+ MCFG_CPU_ADD(I8049_TAG, I8049, XTAL_4_608MHz)
+ MCFG_CPU_IO_MAP(v1050_keyboard_io)
+ MCFG_DEVICE_DISABLE() // TODO
+
+ // discrete sound
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+ MCFG_SOUND_ADD(DISCRETE_TAG, DISCRETE, 0)
+ MCFG_SOUND_CONFIG_DISCRETE(v1050kb)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.80)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor v1050_keyboard_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( v1050_keyboard );
+}
+
+
+//-------------------------------------------------
+// INPUT_PORTS( v1050_keyboard )
+//-------------------------------------------------
+
+INPUT_PORTS_START( v1050_keyboard )
+ PORT_START("X0")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Left Shift") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Ctrl") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL))
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Caps Lock") PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK))
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Right Shift") PORT_CODE(KEYCODE_RSHIFT)
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Help")
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Esc") PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC))
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Tab") PORT_CODE(KEYCODE_TAB) PORT_CHAR(UCHAR_MAMEKEY(TAB))
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("No Scrl")
+
+ PORT_START("X1")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad Enter DelCh") PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD))
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 6 Pg Dn") PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD))
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 3 \xE2\x86\x92") PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD))
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad - DelLn") PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD))
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 9 End") PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD))
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad , DelWd")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad . Wd\xE2\x86\x92") PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD))
+
+ PORT_START("X2")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F14 OnSer")
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F16 Print")
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F12 Copy") PORT_CODE(KEYCODE_F12) PORT_CHAR(UCHAR_MAMEKEY(F12))
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F10 End") PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10))
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F15 Quick")
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F11 Move") PORT_CODE(KEYCODE_F11) PORT_CHAR(UCHAR_MAMEKEY(F11))
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F17 Block")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F13 Hide")
+
+ PORT_START("X3")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Line Feed")
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('|') PORT_CHAR('\\')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Retn") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Num Lock") PORT_CODE(KEYCODE_NUMLOCK) PORT_CHAR(UCHAR_MAMEKEY(NUMLOCK))
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Break Stop")
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Back Space") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Del") PORT_CODE(KEYCODE_DEL) PORT_CHAR(UCHAR_MAMEKEY(DEL))
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 0 Wd\xE2\x86\x90") PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD))
+
+ PORT_START("X4")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 5 \xE2\x86\x91") PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD))
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 1 \xE2\x86\x90") PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD))
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED )
+ 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_KEYBOARD ) PORT_NAME("Keypad 8 Last") PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD))
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 4 PgUp") PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD))
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 2 \xE2\x86\x93") PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD))
+
+ PORT_START("X5")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K')
+ 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_H) PORT_CHAR('h') PORT_CHAR('H')
+ 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_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U')
+ 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_O) PORT_CHAR('o') PORT_CHAR('O')
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J')
+
+ PORT_START("X6")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^')
+ 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_N) PORT_CHAR('n') PORT_CHAR('N')
+ 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_SPACE) PORT_CHAR(' ')
+ 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_8) PORT_CHAR('8') PORT_CHAR('*')
+
+ PORT_START("X7")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F8 Insert") PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8))
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F5") PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5))
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F6 InsCr") PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6))
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F9 Begin") PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9))
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F3 Rept") PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3))
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F2 Find") PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2))
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F4 Again") PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4))
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F7 Refs") PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7))
+
+ PORT_START("X8")
+ 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_R) PORT_CHAR('r') PORT_CHAR('R')
+ 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("F1 Save") PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1))
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E')
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S')
+
+ PORT_START("X9")
+ 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_W) PORT_CHAR('w') PORT_CHAR('W')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
+ 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_CODE(KEYCODE_2) PORT_CHAR('2') 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_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q')
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')
+
+ PORT_START("XA")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('~') PORT_CHAR('\'')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('0') PORT_CHAR(')')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('9') 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_6) PORT_CHAR('6') PORT_CHAR('^')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_')
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*')
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&')
+
+ PORT_START("XB")
+ 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_COLON) 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_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?')
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}')
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("SW1")
+ PORT_DIPNAME( 0x01, 0x01, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x01, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x02, 0x02, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x02, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x04, 0x04, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x04, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x08, 0x08, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x08, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x10, 0x10, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x10, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x20, 0x20, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x20, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x40, 0x40, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x40, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x80, 0x80, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x80, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+
+ PORT_START("SW2")
+ PORT_DIPNAME( 0x01, 0x01, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x01, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x02, 0x02, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x02, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x04, 0x04, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x04, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x08, 0x08, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x08, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x10, 0x10, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x10, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x20, 0x20, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x20, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x40, 0x40, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x40, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x80, 0x80, DEF_STR( Unknown ) )
+ PORT_DIPSETTING( 0x80, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+INPUT_PORTS_END
+
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+ioport_constructor v1050_keyboard_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( v1050_keyboard );
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// v1050_keyboard_device - constructor
+//-------------------------------------------------
+
+v1050_keyboard_device::v1050_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, V1050_KEYBOARD, "Visual 1050 Keyboard", tag, owner, clock),
+ m_maincpu(*this, I8049_TAG),
+ m_discrete(*this, DISCRETE_TAG),
+ m_y(0),
+ m_so(1)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void v1050_keyboard_device::device_start()
+{
+ // state saving
+ save_item(NAME(m_y));
+ save_item(NAME(m_so));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void v1050_keyboard_device::device_reset()
+{
+}
+
+
+//-------------------------------------------------
+// si_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( v1050_keyboard_device::si_w )
+{
+ m_maincpu->set_input_line(MCS48_INPUT_IRQ, state ? CLEAR_LINE : ASSERT_LINE);
+}
+
+
+//-------------------------------------------------
+// so_r -
+//-------------------------------------------------
+
+READ_LINE_MEMBER( v1050_keyboard_device::so_r )
+{
+ return m_so;
+}
+
+
+//-------------------------------------------------
+// kb_p1_r -
+//-------------------------------------------------
+
+READ8_MEMBER( v1050_keyboard_device::kb_p1_r )
+{
+ UINT8 data = 0xff;
+
+ switch (m_y)
+ {
+ case 0: data &= ioport("X0")->read(); break;
+ case 1: data &= ioport("X1")->read(); break;
+ case 2: data &= ioport("X2")->read(); break;
+ case 3: data &= ioport("X3")->read(); break;
+ case 4: data &= ioport("X4")->read(); break;
+ case 5: data &= ioport("X5")->read(); break;
+ case 6: data &= ioport("X6")->read(); break;
+ case 7: data &= ioport("X7")->read(); break;
+ case 8: data &= ioport("X8")->read(); break;
+ case 9: data &= ioport("X9")->read(); break;
+ case 0xa: data &= ioport("XA")->read(); break;
+ case 0xb: data &= ioport("XB")->read(); break;
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// kb_p1_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( v1050_keyboard_device::kb_p1_w )
+{
+ m_y = data & 0x0f;
+}
+
+
+//-------------------------------------------------
+// kb_p2_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( v1050_keyboard_device::kb_p2_w )
+{
+ /*
+
+ bit description
+
+ P20 Z8 A8 (8039 external ROM)
+ P21 Z8 A9
+ P22 Z8 A10
+ P23
+ P24
+ P25 led output
+ P26 speaker (NE555) output
+ P27 serial output
+
+ */
+
+ // led output
+ output_set_led_value(0, BIT(data, 5));
+
+ // speaker output
+ discrete_sound_w(m_discrete, NODE_01, BIT(data, 6));
+
+ // serial output
+ m_so = BIT(data, 7);
+}
diff --git a/src/mess/machine/v1050kb.h b/src/mess/machine/v1050kb.h
new file mode 100644
index 00000000000..63a21041d22
--- /dev/null
+++ b/src/mess/machine/v1050kb.h
@@ -0,0 +1,88 @@
+/**********************************************************************
+
+ Visual 1050 keyboard emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#pragma once
+
+#ifndef __V1050_KEYBOARD__
+#define __V1050_KEYBOARD__
+
+
+#include "emu.h"
+#include "cpu/mcs48/mcs48.h"
+#include "sound/discrete.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define V1050_KEYBOARD_TAG "v1050kb"
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_V1050_KEYBOARD_ADD() \
+ MCFG_DEVICE_ADD(V1050_KEYBOARD_TAG, V1050_KEYBOARD, 0)
+
+
+#define V1050_KEYBOARD_INTERFACE(_name) \
+ const V1050_keyboard_interface (_name) =
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> V1050_keyboard_device
+
+class v1050_keyboard_device : public device_t
+{
+public:
+ // construction/destruction
+ v1050_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_WRITE_LINE_MEMBER( si_w );
+ DECLARE_READ_LINE_MEMBER( so_r );
+
+ // not really public
+ DECLARE_READ8_MEMBER( kb_p1_r );
+ DECLARE_WRITE8_MEMBER( kb_p1_w );
+ DECLARE_WRITE8_MEMBER( kb_p2_w );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "v1050kb"; }
+
+private:
+ required_device<cpu_device> m_maincpu;
+ required_device<device_t> m_discrete;
+
+ UINT8 m_y;
+ int m_so;
+};
+
+
+// device type definition
+extern const device_type V1050_KEYBOARD;
+
+
+
+#endif
diff --git a/src/mess/machine/vb_money_minder.c b/src/mess/machine/vb_money_minder.c
new file mode 100644
index 00000000000..b7a6b174d0a
--- /dev/null
+++ b/src/mess/machine/vb_money_minder.c
@@ -0,0 +1,77 @@
+/**********************************************************************
+
+ VideoBrain Money Minder cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "vb_money_minder.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type VB_MONEY_MINDER = &device_creator<videobrain_money_minder_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ 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/mess/machine/vb_money_minder.h b/src/mess/machine/vb_money_minder.h
new file mode 100644
index 00000000000..b1fd886d28a
--- /dev/null
+++ b/src/mess/machine/vb_money_minder.h
@@ -0,0 +1,49 @@
+/**********************************************************************
+
+ VideoBrain Money Minder cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __VIDEOBRAIN_MONEY_MINDER_CARTRIDGE__
+#define __VIDEOBRAIN_MONEY_MINDER_CARTRIDGE__
+
+
+#include "emu.h"
+#include "machine/vidbrain_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_config_complete() { m_shortname = "vb_money_minder"; }
+ 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/mess/machine/vb_std.c b/src/mess/machine/vb_std.c
new file mode 100644
index 00000000000..029085271eb
--- /dev/null
+++ b/src/mess/machine/vb_std.c
@@ -0,0 +1,63 @@
+/**********************************************************************
+
+ VideoBrain Standard 2K/4K cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "vb_std.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type VB_STD = &device_creator<videobrain_standard_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ 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/mess/machine/vb_std.h b/src/mess/machine/vb_std.h
new file mode 100644
index 00000000000..bb9876f74f8
--- /dev/null
+++ b/src/mess/machine/vb_std.h
@@ -0,0 +1,48 @@
+/**********************************************************************
+
+ VideoBrain Standard 2K/4K cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __VIDEOBRAIN_STANDARD_CARTRIDGE__
+#define __VIDEOBRAIN_STANDARD_CARTRIDGE__
+
+
+#include "emu.h"
+#include "machine/vidbrain_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_config_complete() { m_shortname = "vb_std"; }
+ 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/mess/machine/vb_timeshare.c b/src/mess/machine/vb_timeshare.c
new file mode 100644
index 00000000000..fd76cca939e
--- /dev/null
+++ b/src/mess/machine/vb_timeshare.c
@@ -0,0 +1,76 @@
+/**********************************************************************
+
+ VideoBrain Timeshare cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "vb_timeshare.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type VB_TIMESHARE = &device_creator<videobrain_timeshare_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ 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/mess/machine/vb_timeshare.h b/src/mess/machine/vb_timeshare.h
new file mode 100644
index 00000000000..efcfd373c48
--- /dev/null
+++ b/src/mess/machine/vb_timeshare.h
@@ -0,0 +1,49 @@
+/**********************************************************************
+
+ VideoBrain Timeshare cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __VIDEOBRAIN_TIMESHARE_CARTRIDGE__
+#define __VIDEOBRAIN_TIMESHARE_CARTRIDGE__
+
+
+#include "emu.h"
+#include "machine/vidbrain_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_config_complete() { m_shortname = "vb_timeshare"; }
+ 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/mess/machine/vcs_joy.c b/src/mess/machine/vcs_joy.c
new file mode 100644
index 00000000000..d7fa55f5fad
--- /dev/null
+++ b/src/mess/machine/vcs_joy.c
@@ -0,0 +1,74 @@
+/**********************************************************************
+
+ Atari Video Computer System digital joystick emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "vcs_joy.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type VCS_JOYSTICK = &device_creator<vcs_joystick_device>;
+
+
+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, "Digital joystick", tag, owner, clock),
+ device_vcs_control_port_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void vcs_joystick_device::device_start()
+{
+}
+
+
+//-------------------------------------------------
+// c64_pb_r - port B read
+//-------------------------------------------------
+
+UINT8 vcs_joystick_device::vcs_joy_r()
+{
+ return ioport("JOY")->read();
+}
diff --git a/src/mess/machine/vcs_joy.h b/src/mess/machine/vcs_joy.h
new file mode 100644
index 00000000000..5873903d056
--- /dev/null
+++ b/src/mess/machine/vcs_joy.h
@@ -0,0 +1,51 @@
+/**********************************************************************
+
+ Atari Video Computer System digital joystick emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __VCS_JOYSTICK__
+#define __VCS_JOYSTICK__
+
+
+#include "emu.h"
+#include "machine/vcsctrl.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_config_complete() { m_shortname = "vcs_joystick"; }
+ virtual void device_start();
+
+ // device_vcs_control_port_interface overrides
+ virtual UINT8 vcs_joy_r();
+};
+
+
+// device type definition
+extern const device_type VCS_JOYSTICK;
+
+
+#endif
diff --git a/src/mess/machine/vcsctrl.c b/src/mess/machine/vcsctrl.c
new file mode 100644
index 00000000000..d64fb07bb61
--- /dev/null
+++ b/src/mess/machine/vcsctrl.c
@@ -0,0 +1,83 @@
+/**********************************************************************
+
+ Atari Video Computer System controller port emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "machine/vcsctrl.h"
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type VCS_CONTROL_PORT = &device_creator<vcs_control_port_device>;
+
+
+
+//**************************************************************************
+// 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<vcs_control_port_device *>(device.owner());
+}
+
+
+//-------------------------------------------------
+// ~device_vcs_control_port_interface - destructor
+//-------------------------------------------------
+
+device_vcs_control_port_interface::~device_vcs_control_port_interface()
+{
+}
+
+
+
+//**************************************************************************
+// 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),
+ device_slot_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// vcs_control_port_device - destructor
+//-------------------------------------------------
+
+vcs_control_port_device::~vcs_control_port_device()
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void vcs_control_port_device::device_start()
+{
+ m_device = dynamic_cast<device_vcs_control_port_interface *>(get_card_device());
+}
+
+
+READ8_MEMBER( vcs_control_port_device::joy_r ) { UINT8 data = 0xff; if (m_device != NULL) data = m_device->vcs_joy_r(); return data; }
+READ8_MEMBER( vcs_control_port_device::pot_x_r ) { UINT8 data = 0xff; if (m_device != NULL) data = m_device->vcs_pot_x_r(); return data; }
+READ8_MEMBER( vcs_control_port_device::pot_y_r ) { UINT8 data = 0xff; if (m_device != NULL) data = m_device->vcs_pot_y_r(); return data; }
diff --git a/src/mess/machine/vcsctrl.h b/src/mess/machine/vcsctrl.h
new file mode 100644
index 00000000000..7f3ca0c7301
--- /dev/null
+++ b/src/mess/machine/vcsctrl.h
@@ -0,0 +1,85 @@
+/**********************************************************************
+
+ Atari Video Computer System controller port emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+
+
+**********************************************************************/
+
+#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, _def_inp) \
+ MCFG_DEVICE_ADD(_tag, VCS_CONTROL_PORT, 0) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false)
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> vcs_control_port_device
+
+class device_vcs_control_port_interface;
+
+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();
+
+ // computer interface
+ DECLARE_READ8_MEMBER( joy_r );
+ DECLARE_READ8_MEMBER( pot_x_r );
+ DECLARE_READ8_MEMBER( pot_y_r );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+
+ device_vcs_control_port_interface *m_device;
+};
+
+
+// ======================> device_vcs_control_port_interface
+
+// class representing interface-specific live vcs_expansion card
+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; };
+
+protected:
+ vcs_control_port_device *m_port;
+};
+
+
+// device type definition
+extern const device_type VCS_CONTROL_PORT;
+
+
+
+#endif
diff --git a/src/mess/machine/vector06.c b/src/mess/machine/vector06.c
new file mode 100644
index 00000000000..32c18d598b8
--- /dev/null
+++ b/src/mess/machine/vector06.c
@@ -0,0 +1,190 @@
+/***************************************************************************
+
+ Vector06c driver by Miodrag Milanovic
+
+ 10/07/2008 Preliminary driver.
+
+****************************************************************************/
+
+
+#include "includes/vector06.h"
+
+
+READ8_MEMBER( vector06_state::vector06_8255_portb_r )
+{
+ UINT8 key = 0xff;
+ if (BIT(m_keyboard_mask, 0)) key &= ioport("LINE0")->read();
+ if (BIT(m_keyboard_mask, 1)) key &= ioport("LINE1")->read();
+ if (BIT(m_keyboard_mask, 2)) key &= ioport("LINE2")->read();
+ if (BIT(m_keyboard_mask, 3)) key &= ioport("LINE3")->read();
+ if (BIT(m_keyboard_mask, 4)) key &= ioport("LINE4")->read();
+ if (BIT(m_keyboard_mask, 5)) key &= ioport("LINE5")->read();
+ if (BIT(m_keyboard_mask, 6)) key &= ioport("LINE6")->read();
+ if (BIT(m_keyboard_mask, 7)) key &= ioport("LINE7")->read();
+ return key;
+}
+
+READ8_MEMBER( vector06_state::vector06_8255_portc_r )
+{
+ UINT8 ret = ioport("LINE8")->read();
+
+ if (m_cass->input() > 0)
+ ret |= 0x10;
+
+ return ret;
+}
+
+WRITE8_MEMBER( vector06_state::vector06_8255_porta_w )
+{
+ m_keyboard_mask = data ^ 0xff;
+}
+
+void vector06_state::vector06_set_video_mode(int width)
+{
+ rectangle visarea(0, width+64-1, 0, 256+64-1);
+ machine().primary_screen->configure(width+64, 256+64, visarea, machine().primary_screen->frame_period().attoseconds);
+}
+
+WRITE8_MEMBER( vector06_state::vector06_8255_portb_w )
+{
+ m_color_index = data & 0x0f;
+ if ((data & 0x10) != m_video_mode)
+ {
+ m_video_mode = data & 0x10;
+ vector06_set_video_mode((m_video_mode==0x10) ? 512 : 256);
+ }
+}
+
+WRITE8_MEMBER( vector06_state::vector06_color_set )
+{
+ UINT8 r = (data & 7) << 5;
+ UINT8 g = ((data >> 3) & 7) << 5;
+ UINT8 b = ((data >>6) & 3) << 6;
+ palette_set_color( machine(), m_color_index, MAKE_RGB(r,g,b) );
+}
+
+
+READ8_MEMBER( vector06_state::vector06_romdisk_portb_r )
+{
+ UINT8 *romdisk = memregion("maincpu")->base() + 0x18000;
+ UINT16 addr = (m_romdisk_msb | m_romdisk_lsb) & 0x7fff;
+ return romdisk[addr];
+}
+
+WRITE8_MEMBER( vector06_state::vector06_romdisk_porta_w )
+{
+ m_romdisk_lsb = data;
+}
+
+WRITE8_MEMBER( vector06_state::vector06_romdisk_portc_w )
+{
+ m_romdisk_msb = data << 8;
+}
+
+I8255A_INTERFACE( vector06_ppi8255_2_interface )
+{
+ DEVCB_NULL,
+ DEVCB_DRIVER_MEMBER(vector06_state, vector06_romdisk_porta_w),
+ DEVCB_DRIVER_MEMBER(vector06_state, vector06_romdisk_portb_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DRIVER_MEMBER(vector06_state, vector06_romdisk_portc_w)
+};
+
+
+I8255A_INTERFACE( vector06_ppi8255_interface )
+{
+ DEVCB_NULL,
+ DEVCB_DRIVER_MEMBER(vector06_state, vector06_8255_porta_w),
+ DEVCB_DRIVER_MEMBER(vector06_state, vector06_8255_portb_r),
+ DEVCB_DRIVER_MEMBER(vector06_state, vector06_8255_portb_w),
+ DEVCB_DRIVER_MEMBER(vector06_state, vector06_8255_portc_r),
+ DEVCB_NULL
+};
+
+READ8_MEMBER( vector06_state::vector06_8255_1_r )
+{
+ return m_ppi->read(space, offset^3);
+}
+
+WRITE8_MEMBER( vector06_state::vector06_8255_1_w )
+{
+ m_ppi->write(space, offset^3, data);
+}
+
+READ8_MEMBER( vector06_state::vector06_8255_2_r )
+{
+ return m_ppi2->read(space, offset^3);
+}
+
+WRITE8_MEMBER( vector06_state::vector06_8255_2_w )
+{
+ m_ppi2->write(space, offset^3, data);
+}
+
+INTERRUPT_GEN( vector06_interrupt )
+{
+ vector06_state *state = device->machine().driver_data<vector06_state>();
+ state->m_vblank_state++;
+ if (state->m_vblank_state>1) state->m_vblank_state=0;
+ device_set_input_line(device,0,state->m_vblank_state ? HOLD_LINE : CLEAR_LINE);
+
+}
+
+static IRQ_CALLBACK( vector06_irq_callback )
+{
+ // Interupt is RST 7
+ return 0xff;
+}
+
+static TIMER_CALLBACK( reset_check_callback )
+{
+ vector06_state *state = machine.driver_data<vector06_state>();
+ UINT8 val = machine.root_device().ioport("RESET")->read();
+
+ if (BIT(val, 0))
+ {
+ state->membank("bank1")->set_base(machine.root_device().memregion("maincpu")->base() + 0x10000);
+ machine.device("maincpu")->reset();
+ }
+
+ if (BIT(val, 1))
+ {
+ state->membank("bank1")->set_base(machine.device<ram_device>(RAM_TAG)->pointer() + 0x0000);
+ machine.device("maincpu")->reset();
+ }
+}
+
+WRITE8_MEMBER( vector06_state::vector06_disc_w )
+{
+// something here needs to turn the motor on
+
+ wd17xx_set_side (m_fdc,BIT(data, 2) ^ 1);
+ wd17xx_set_drive(m_fdc,BIT(data, 0));
+}
+
+MACHINE_START( vector06 )
+{
+ machine.scheduler().timer_pulse(attotime::from_hz(50), FUNC(reset_check_callback));
+}
+
+MACHINE_RESET( vector06 )
+{
+ vector06_state *state = machine.driver_data<vector06_state>();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ device_set_irq_callback(machine.device("maincpu"), vector06_irq_callback);
+ space->install_read_bank (0x0000, 0x7fff, "bank1");
+ space->install_write_bank(0x0000, 0x7fff, "bank2");
+ space->install_read_bank (0x8000, 0xffff, "bank3");
+ space->install_write_bank(0x8000, 0xffff, "bank4");
+
+ state->membank("bank1")->set_base(state->memregion("maincpu")->base() + 0x10000);
+ state->membank("bank2")->set_base(machine.device<ram_device>(RAM_TAG)->pointer() + 0x0000);
+ state->membank("bank3")->set_base(machine.device<ram_device>(RAM_TAG)->pointer() + 0x8000);
+ state->membank("bank4")->set_base(machine.device<ram_device>(RAM_TAG)->pointer() + 0x8000);
+
+ state->m_keyboard_mask = 0;
+ state->m_color_index = 0;
+ state->m_video_mode = 0;
+}
diff --git a/src/mess/machine/vic1010.c b/src/mess/machine/vic1010.c
new file mode 100644
index 00000000000..ac88bd64cfe
--- /dev/null
+++ b/src/mess/machine/vic1010.c
@@ -0,0 +1,162 @@
+/**********************************************************************
+
+ Commodore VIC-1010 Expansion Module emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "vic1010.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type VIC1010 = &device_creator<vic1010_device>;
+
+
+//-------------------------------------------------
+// VIC20_EXPANSION_INTERFACE( expansion_intf )
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( vic1010_device::irq_w )
+{
+ m_slot->irq_w(state);
+}
+
+WRITE_LINE_MEMBER( vic1010_device::nmi_w )
+{
+ m_slot->nmi_w(state);
+}
+
+WRITE_LINE_MEMBER( vic1010_device::res_w )
+{
+ m_slot->res_w(state);
+}
+
+static VIC20_EXPANSION_INTERFACE( expansion_intf )
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, vic1010_device, irq_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, vic1010_device, nmi_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, vic1010_device, res_w)
+};
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( vic1010 )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( vic1010 )
+ MCFG_VIC20_EXPANSION_SLOT_ADD("slot1", expansion_intf, vic20_expansion_cards, NULL, NULL)
+ MCFG_VIC20_EXPANSION_SLOT_ADD("slot2", expansion_intf, vic20_expansion_cards, NULL, NULL)
+ MCFG_VIC20_EXPANSION_SLOT_ADD("slot3", expansion_intf, vic20_expansion_cards, NULL, NULL)
+ MCFG_VIC20_EXPANSION_SLOT_ADD("slot4", expansion_intf, vic20_expansion_cards, NULL, NULL)
+ MCFG_VIC20_EXPANSION_SLOT_ADD("slot5", expansion_intf, vic20_expansion_cards, NULL, NULL)
+ MCFG_VIC20_EXPANSION_SLOT_ADD("slot6", expansion_intf, vic20_expansion_cards, NULL, NULL)
+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),
+ device_vic20_expansion_card_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void vic1010_device::device_start()
+{
+ // find devices
+ m_expansion_slot[0] = dynamic_cast<vic20_expansion_slot_device *>(subdevice("slot1"));
+ m_expansion_slot[1] = dynamic_cast<vic20_expansion_slot_device *>(subdevice("slot2"));
+ m_expansion_slot[2] = dynamic_cast<vic20_expansion_slot_device *>(subdevice("slot3"));
+ m_expansion_slot[3] = dynamic_cast<vic20_expansion_slot_device *>(subdevice("slot4"));
+ m_expansion_slot[4] = dynamic_cast<vic20_expansion_slot_device *>(subdevice("slot5"));
+ m_expansion_slot[5] = dynamic_cast<vic20_expansion_slot_device *>(subdevice("slot6"));
+}
+
+
+//-------------------------------------------------
+// vic20_cd_r - cartridge data read
+//-------------------------------------------------
+
+UINT8 vic1010_device::vic20_cd_r(address_space &space, offs_t offset, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3)
+{
+ UINT8 data = 0;
+
+ for (int i = 0; i < MAX_SLOTS; i++)
+ {
+ data |= m_expansion_slot[i]->cd_r(space, offset, ram1, ram2, ram3, blk1, blk2, blk3, blk5, io2, io3);
+ }
+
+ 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);
+ }
+}
+
+
+//-------------------------------------------------
+// vic20_screen_update - screen update
+//-------------------------------------------------
+
+UINT32 vic1010_device::vic20_screen_update(screen_device &screen, bitmap_ind16 &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;
+}
+
+
+//-------------------------------------------------
+// vic20_res_w - reset write
+//-------------------------------------------------
+
+void vic1010_device::vic20_res_w(int state)
+{
+ for (int i = 0; i < MAX_SLOTS; i++)
+ {
+ m_expansion_slot[i]->port_res_w(state);
+ }
+}
diff --git a/src/mess/machine/vic1010.h b/src/mess/machine/vic1010.h
new file mode 100644
index 00000000000..2c90e75b4a4
--- /dev/null
+++ b/src/mess/machine/vic1010.h
@@ -0,0 +1,72 @@
+/**********************************************************************
+
+ Commodore VIC-1010 Expansion Module emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __VIC1010__
+#define __VIC1010__
+
+
+#include "emu.h"
+#include "machine/cbmipt.h"
+#include "machine/vic20exp.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);
+
+ // not really public
+ DECLARE_WRITE_LINE_MEMBER( irq_w );
+ DECLARE_WRITE_LINE_MEMBER( nmi_w );
+ DECLARE_WRITE_LINE_MEMBER( res_w );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_config_complete() { m_shortname = "vic1010"; }
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+ // device_vic20_expansion_card_interface overrides
+ virtual UINT8 vic20_cd_r(address_space &space, offs_t offset, 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);
+ virtual UINT32 vic20_screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+ virtual void vic20_res_w(int state);
+
+private:
+ vic20_expansion_slot_device *m_expansion_slot[MAX_SLOTS];
+};
+
+
+// device type definition
+extern const device_type VIC1010;
+
+
+
+#endif
diff --git a/src/mess/machine/vic10exp.c b/src/mess/machine/vic10exp.c
new file mode 100644
index 00000000000..806a26804f2
--- /dev/null
+++ b/src/mess/machine/vic10exp.c
@@ -0,0 +1,326 @@
+/**********************************************************************
+
+ Commodore VIC-10 Expansion Port emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "emu.h"
+#include "emuopts.h"
+#include "machine/vic10exp.h"
+#include "formats/cbm_crt.h"
+#include "formats/imageutl.h"
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type VIC10_EXPANSION_SLOT = &device_creator<vic10_expansion_slot_device>;
+
+
+
+//**************************************************************************
+// 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_exram(NULL),
+ m_lorom(NULL),
+ m_uprom(NULL)
+{
+ m_slot = dynamic_cast<vic10_expansion_slot_device *>(device.owner());
+}
+
+
+//-------------------------------------------------
+// ~device_vic10_expansion_card_interface - destructor
+//-------------------------------------------------
+
+device_vic10_expansion_card_interface::~device_vic10_expansion_card_interface()
+{
+}
+
+
+
+//-------------------------------------------------
+// vic10_lorom_pointer - get lower ROM pointer
+//-------------------------------------------------
+
+UINT8* device_vic10_expansion_card_interface::vic10_lorom_pointer(running_machine &machine, size_t size)
+{
+ if (m_lorom == NULL)
+ {
+ m_lorom = auto_alloc_array(machine, UINT8, size);
+ }
+
+ return m_lorom;
+}
+
+
+//-------------------------------------------------
+// vic10_uprom_pointer - get upper ROM pointer
+//-------------------------------------------------
+
+UINT8* device_vic10_expansion_card_interface::vic10_uprom_pointer(running_machine &machine, size_t size)
+{
+ if (m_uprom == NULL)
+ {
+ m_uprom = auto_alloc_array(machine, UINT8, size);
+ }
+
+ return m_uprom;
+}
+
+
+//-------------------------------------------------
+// vic10_exram_pointer - get expanded RAM pointer
+//-------------------------------------------------
+
+UINT8* device_vic10_expansion_card_interface::vic10_exram_pointer(running_machine &machine, size_t size)
+{
+ if (m_exram == NULL)
+ {
+ m_exram = auto_alloc_array(machine, UINT8, size);
+ }
+
+ return m_exram;
+}
+
+
+
+//**************************************************************************
+// 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),
+ device_slot_interface(mconfig, *this),
+ device_image_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// vic10_expansion_slot_device - destructor
+//-------------------------------------------------
+
+vic10_expansion_slot_device::~vic10_expansion_slot_device()
+{
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void vic10_expansion_slot_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const vic10_expansion_slot_interface *intf = reinterpret_cast<const vic10_expansion_slot_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<vic10_expansion_slot_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_irq_cb, 0, sizeof(m_out_irq_cb));
+ memset(&m_out_sp_cb, 0, sizeof(m_out_sp_cb));
+ memset(&m_out_cnt_cb, 0, sizeof(m_out_cnt_cb));
+ memset(&m_out_res_cb, 0, sizeof(m_out_res_cb));
+ }
+
+ // set brief and instance name
+ update_names();
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void vic10_expansion_slot_device::device_start()
+{
+ m_cart = dynamic_cast<device_vic10_expansion_card_interface *>(get_card_device());
+
+ // resolve callbacks
+ m_out_irq_func.resolve(m_out_irq_cb, *this);
+ m_out_sp_func.resolve(m_out_sp_cb, *this);
+ m_out_cnt_func.resolve(m_out_cnt_cb, *this);
+ m_out_res_func.resolve(m_out_res_cb, *this);
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void vic10_expansion_slot_device::device_reset()
+{
+ res_w(ASSERT_LINE);
+ res_w(CLEAR_LINE);
+}
+
+
+//-------------------------------------------------
+// call_load -
+//-------------------------------------------------
+
+bool vic10_expansion_slot_device::call_load()
+{
+ if (m_cart)
+ {
+ size_t size = 0;
+
+ if (software_entry() == NULL)
+ {
+ size = length();
+
+ if (!mame_stricmp(filetype(), "80"))
+ {
+ fread(m_cart->vic10_lorom_pointer(machine(), 0x2000), 0x2000);
+
+ if (size == 0x4000)
+ {
+ fread(m_cart->vic10_uprom_pointer(machine(), 0x2000), 0x2000);
+ }
+ }
+ else if (!mame_stricmp(filetype(), "e0")) fread(m_cart->vic10_uprom_pointer(machine(), size), size);
+ else if (!mame_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;
+
+ if (roml_size) roml = m_cart->vic10_lorom_pointer(machine(), roml_size);
+ if (romh_size) romh = m_cart->vic10_uprom_pointer(machine(), romh_size);
+
+ cbm_crt_read_data(m_file, roml, romh);
+ }
+ }
+ }
+ else
+ {
+ size = get_software_region_length("lorom");
+ if (size) memcpy(m_cart->vic10_lorom_pointer(machine(), size), get_software_region("lorom"), size);
+
+ size = get_software_region_length("uprom");
+ if (size) memcpy(m_cart->vic10_uprom_pointer(machine(), size), get_software_region("uprom"), size);
+
+ size = get_software_region_length("exram");
+ if (size) m_cart->vic10_exram_pointer(machine(), size);
+ }
+ }
+
+ return IMAGE_INIT_PASS;
+}
+
+
+//-------------------------------------------------
+// call_softlist_load -
+//-------------------------------------------------
+
+bool vic10_expansion_slot_device::call_softlist_load(char *swlist, char *swname, rom_entry *start_entry)
+{
+ load_software_part_region(this, swlist, swname, start_entry);
+
+ return true;
+}
+
+
+//-------------------------------------------------
+// get_default_card_software -
+//-------------------------------------------------
+
+const char * vic10_expansion_slot_device::get_default_card_software(const machine_config &config, emu_options &options)
+{
+ if (open_image_file(options))
+ {
+ if (!mame_stricmp(filetype(), "crt"))
+ {
+ return cbm_crt_get_card(m_file);
+ }
+
+ clear();
+ }
+
+ return software_get_default_slot(config, options, this, "standard");
+}
+
+
+//-------------------------------------------------
+// screen_update -
+//-------------------------------------------------
+
+UINT32 vic10_expansion_slot_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ bool value = false;
+
+ if (m_cart != NULL)
+ {
+ value = m_cart->vic10_screen_update(screen, bitmap, cliprect);
+ }
+
+ return value;
+}
+
+
+//-------------------------------------------------
+// cd_r - cartridge data read
+//-------------------------------------------------
+
+UINT8 vic10_expansion_slot_device::cd_r(address_space &space, offs_t offset, int lorom, int uprom, int exram)
+{
+ UINT8 data = 0;
+
+ if (m_cart != NULL)
+ {
+ data = m_cart->vic10_cd_r(space, offset, 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_cart != NULL)
+ {
+ m_cart->vic10_cd_w(space, offset, data, lorom, uprom, exram);
+ }
+}
+
+WRITE_LINE_MEMBER( vic10_expansion_slot_device::port_res_w ) { if (m_cart != NULL) m_cart->vic10_res_w(state); }
+
+READ_LINE_MEMBER( vic10_expansion_slot_device::p0_r ) { int state = 0; if (m_cart != NULL) state = m_cart->vic10_p0_r(); return state; }
+WRITE_LINE_MEMBER( vic10_expansion_slot_device::p0_w ) { if (m_cart != NULL) m_cart->vic10_p0_w(state); }
+WRITE_LINE_MEMBER( vic10_expansion_slot_device::irq_w ) { m_out_irq_func(state); }
+WRITE_LINE_MEMBER( vic10_expansion_slot_device::sp_w ) { m_out_sp_func(state); if (m_cart != NULL) m_cart->vic10_sp_w(state); }
+WRITE_LINE_MEMBER( vic10_expansion_slot_device::cnt_w ) { m_out_cnt_func(state); if (m_cart != NULL) m_cart->vic10_cnt_w(state); }
+WRITE_LINE_MEMBER( vic10_expansion_slot_device::res_w ) { m_out_res_func(state); }
diff --git a/src/mess/machine/vic10exp.h b/src/mess/machine/vic10exp.h
new file mode 100644
index 00000000000..298df7b6f7c
--- /dev/null
+++ b/src/mess/machine/vic10exp.h
@@ -0,0 +1,186 @@
+/**********************************************************************
+
+ Commodore VIC-10 Expansion Port emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+
+ 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 VIC10_EXPANSION_INTERFACE(_name) \
+ const vic10_expansion_slot_interface (_name) =
+
+
+#define MCFG_VIC10_EXPANSION_SLOT_ADD(_tag, _config, _slot_intf, _def_slot, _def_inp) \
+ MCFG_DEVICE_ADD(_tag, VIC10_EXPANSION_SLOT, 0) \
+ MCFG_DEVICE_CONFIG(_config) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false)
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> vic10_expansion_slot_interface
+
+struct vic10_expansion_slot_interface
+{
+ devcb_write_line m_out_irq_cb;
+ devcb_write_line m_out_sp_cb;
+ devcb_write_line m_out_cnt_cb;
+ devcb_write_line m_out_res_cb;
+};
+
+
+// ======================> vic10_expansion_slot_device
+
+class device_vic10_expansion_card_interface;
+
+class vic10_expansion_slot_device : public device_t,
+ public vic10_expansion_slot_interface,
+ 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);
+ virtual ~vic10_expansion_slot_device();
+
+ // computer interface
+ UINT8 cd_r(address_space &space, offs_t offset, 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 );
+ DECLARE_WRITE_LINE_MEMBER( port_res_w );
+
+ // cartridge interface
+ DECLARE_WRITE_LINE_MEMBER( irq_w );
+ DECLARE_WRITE_LINE_MEMBER( sp_w );
+ DECLARE_WRITE_LINE_MEMBER( cnt_w );
+ DECLARE_WRITE_LINE_MEMBER( res_w );
+
+ UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+ virtual void device_start();
+ virtual void device_reset();
+
+ // image-level overrides
+ virtual bool call_load();
+ virtual bool call_softlist_load(char *swlist, char *swname, 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 const char * get_default_card_software(const machine_config &config, emu_options &options);
+
+ devcb_resolved_write_line m_out_irq_func;
+ devcb_resolved_write_line m_out_sp_func;
+ devcb_resolved_write_line m_out_cnt_func;
+ devcb_resolved_write_line m_out_res_func;
+
+ device_vic10_expansion_card_interface *m_cart;
+};
+
+
+// ======================> 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();
+
+protected:
+ // initialization
+ virtual UINT8* vic10_exram_pointer(running_machine &machine, size_t size);
+ virtual UINT8* vic10_lorom_pointer(running_machine &machine, size_t size);
+ virtual UINT8* vic10_uprom_pointer(running_machine &machine, size_t size);
+
+ // runtime
+ virtual UINT8 vic10_cd_r(address_space &space, offs_t offset, int lorom, int uprom, int exram) { return 0; };
+ 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) { };
+ virtual UINT32 vic10_screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { return false; }
+ virtual void vic10_res_w(int state) { };
+
+ vic10_expansion_slot_device *m_slot;
+
+ UINT8 *m_exram;
+ UINT8 *m_lorom;
+ UINT8 *m_uprom;
+};
+
+
+// device type definition
+extern const device_type VIC10_EXPANSION_SLOT;
+
+
+
+#endif
diff --git a/src/mess/machine/vic10std.c b/src/mess/machine/vic10std.c
new file mode 100644
index 00000000000..4465e7bf955
--- /dev/null
+++ b/src/mess/machine/vic10std.c
@@ -0,0 +1,81 @@
+/**********************************************************************
+
+ Commodore VIC-10 Standard 8K/16K ROM Cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "vic10std.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type VIC10_STD = &device_creator<vic10_standard_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ 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, int lorom, int uprom, int exram)
+{
+ UINT8 data = 0;
+
+ if (!lorom && (m_lorom != NULL))
+ {
+ data = m_lorom[offset & 0x1fff];
+ }
+ else if (!exram && (m_exram != NULL))
+ {
+ data = m_exram[offset & 0x7ff];
+ }
+ else if (!uprom && (m_uprom != NULL))
+ {
+ data = m_uprom[offset & 0x1fff];
+ }
+
+ 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 != NULL))
+ {
+ m_exram[offset & 0x7ff] = data;
+ }
+}
diff --git a/src/mess/machine/vic10std.h b/src/mess/machine/vic10std.h
new file mode 100644
index 00000000000..c4c716414af
--- /dev/null
+++ b/src/mess/machine/vic10std.h
@@ -0,0 +1,50 @@
+/**********************************************************************
+
+ Commodore VIC-10 Standard 8K/16K ROM Cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __VIC10_STD__
+#define __VIC10_STD__
+
+
+#include "emu.h"
+#include "machine/vic10exp.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();
+ virtual void device_config_complete() { m_shortname = "vic10_standard"; }
+
+ // device_vic10_expansion_card_interface overrides
+ virtual UINT8 vic10_cd_r(address_space &space, offs_t offset, 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/mess/machine/vic1110.c b/src/mess/machine/vic1110.c
new file mode 100644
index 00000000000..f164585528e
--- /dev/null
+++ b/src/mess/machine/vic1110.c
@@ -0,0 +1,117 @@
+/**********************************************************************
+
+ Commodore VIC-1110 8K RAM Expansion Cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "vic1110.h"
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+enum
+{
+ BLK1 = 0x07,
+ BLK2 = 0x0b,
+ BLK3 = 0x0d,
+ BLK5 = 0x0e
+};
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type VIC1110 = &device_creator<vic1110_device>;
+
+
+
+//-------------------------------------------------
+// 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),
+ device_vic20_expansion_card_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void vic1110_device::device_start()
+{
+ // allocate memory
+ m_ram = auto_alloc_array(machine(), UINT8, 0x2000);
+}
+
+
+//-------------------------------------------------
+// vic20_cd_r - cartridge data read
+//-------------------------------------------------
+
+UINT8 vic1110_device::vic20_cd_r(address_space &space, offs_t offset, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3)
+{
+ UINT8 data = 0;
+ UINT8 sw = ioport("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 = ioport("SW")->read();
+
+ if ((!blk1 && (sw == BLK1)) || (!blk2 && (sw == BLK2)) || (!blk3 && (sw == BLK3)) || (!blk5 && (sw == BLK5)))
+ {
+ m_ram[offset & 0x1fff] = data;
+ }
+}
diff --git a/src/mess/machine/vic1110.h b/src/mess/machine/vic1110.h
new file mode 100644
index 00000000000..d9315291a79
--- /dev/null
+++ b/src/mess/machine/vic1110.h
@@ -0,0 +1,53 @@
+/**********************************************************************
+
+ Commodore VIC-1110 8K RAM Expansion Cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __VIC1110__
+#define __VIC1110__
+
+
+#include "emu.h"
+#include "machine/vic20exp.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();
+ virtual void device_config_complete() { m_shortname = "vic1110"; }
+
+ // device_vic20_expansion_card_interface overrides
+ virtual UINT8 vic20_cd_r(address_space &space, offs_t offset, 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);
+};
+
+
+// device type definition
+extern const device_type VIC1110;
+
+
+
+#endif
diff --git a/src/mess/machine/vic1111.c b/src/mess/machine/vic1111.c
new file mode 100644
index 00000000000..dcd2d3b56c7
--- /dev/null
+++ b/src/mess/machine/vic1111.c
@@ -0,0 +1,75 @@
+/**********************************************************************
+
+ Commodore VIC-1111 16K RAM Expansion Cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "vic1111.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type VIC1111 = &device_creator<vic1111_device>;
+
+
+
+//**************************************************************************
+// 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),
+ device_vic20_expansion_card_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void vic1111_device::device_start()
+{
+ // allocate memory
+ m_ram = auto_alloc_array(machine(), UINT8, 0x4000);
+}
+
+
+//-------------------------------------------------
+// vic20_cd_r - cartridge data read
+//-------------------------------------------------
+
+UINT8 vic1111_device::vic20_cd_r(address_space &space, offs_t offset, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3)
+{
+ UINT8 data = 0;
+
+ if (!blk1 || !blk2)
+ {
+ data = m_ram[offset & 0x3fff];
+ }
+
+ 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 || !blk2)
+ {
+ m_ram[offset & 0x3fff] = data;
+ }
+}
diff --git a/src/mess/machine/vic1111.h b/src/mess/machine/vic1111.h
new file mode 100644
index 00000000000..21772433fa4
--- /dev/null
+++ b/src/mess/machine/vic1111.h
@@ -0,0 +1,50 @@
+/**********************************************************************
+
+ Commodore VIC-1111 16K RAM Expansion Cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __VIC1111__
+#define __VIC1111__
+
+
+#include "emu.h"
+#include "machine/vic20exp.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();
+ virtual void device_config_complete() { m_shortname = "vic1111"; }
+
+ // device_vic20_expansion_card_interface overrides
+ virtual UINT8 vic20_cd_r(address_space &space, offs_t offset, 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);
+};
+
+
+// device type definition
+extern const device_type VIC1111;
+
+
+
+#endif
diff --git a/src/mess/machine/vic1112.c b/src/mess/machine/vic1112.c
new file mode 100644
index 00000000000..ede461171e0
--- /dev/null
+++ b/src/mess/machine/vic1112.c
@@ -0,0 +1,272 @@
+/**********************************************************************
+
+ Commodore VIC-1112 IEEE-488 Interface Cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "vic1112.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define M6522_0_TAG "u4"
+#define M6522_1_TAG "u5"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type VIC1112 = &device_creator<vic1112_device>;
+
+
+//-------------------------------------------------
+// IEEE488_INTERFACE( ieee488_intf )
+//-------------------------------------------------
+
+static IEEE488_INTERFACE( ieee488_intf )
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(M6522_1_TAG, via6522_device, write_cb1),
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// via6522_interface via0_intf
+//-------------------------------------------------
+
+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));
+}
+
+static const via6522_interface via0_intf =
+{
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, vic1112_device, via0_pb_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, vic1112_device, via0_pb_w),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, vic1112_device, via0_irq_w)
+};
+
+
+//-------------------------------------------------
+// via6522_interface via1_intf
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( vic1112_device::via1_irq_w )
+{
+ m_via1_irq = state;
+
+ m_slot->irq_w(m_via0_irq | m_via1_irq);
+}
+
+static const via6522_interface via1_intf =
+{
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(IEEE488_TAG, ieee488_device, dio_r),
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(IEEE488_TAG, ieee488_device, srq_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+
+ DEVCB_DEVICE_MEMBER(IEEE488_TAG, ieee488_device, dio_w),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(IEEE488_TAG, ieee488_device, atn_w),
+ DEVCB_DEVICE_LINE_MEMBER(IEEE488_TAG, ieee488_device, eoi_w),
+
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, vic1112_device, via1_irq_w)
+};
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( vic1112 )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( vic1112 )
+ MCFG_VIA6522_ADD(M6522_0_TAG, 0, via0_intf)
+ MCFG_VIA6522_ADD(M6522_1_TAG, 0, via1_intf)
+
+ MCFG_CBM_IEEE488_ADD(ieee488_intf, NULL)
+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),
+ 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, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3)
+{
+ UINT8 data = 0;
+
+ 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/mess/machine/vic1112.h b/src/mess/machine/vic1112.h
new file mode 100644
index 00000000000..5abf545b535
--- /dev/null
+++ b/src/mess/machine/vic1112.h
@@ -0,0 +1,76 @@
+/**********************************************************************
+
+ Commodore VIC-1112 IEEE-488 Interface Cartridge emulation
+
+ SYS 45065 to start
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __VIC1112__
+#define __VIC1112__
+
+
+#include "emu.h"
+#include "cpu/m6502/m6502.h"
+#include "machine/6522via.h"
+#include "machine/cbmipt.h"
+#include "machine/ieee488.h"
+#include "machine/vic20exp.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();
+ virtual void device_config_complete() { m_shortname = "vic1112"; }
+
+ // device_vic20_expansion_card_interface overrides
+ virtual UINT8 vic20_cd_r(address_space &space, offs_t offset, 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<via6522_device> m_via0;
+ required_device<via6522_device> m_via1;
+ required_device<ieee488_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/mess/machine/vic1210.c b/src/mess/machine/vic1210.c
new file mode 100644
index 00000000000..d578728c21e
--- /dev/null
+++ b/src/mess/machine/vic1210.c
@@ -0,0 +1,80 @@
+/**********************************************************************
+
+ Commodore VIC-1210 3K RAM Expansion Cartridge emulation
+ Commodore VIC-1211A Super Expander with 3K RAM Cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "vic1210.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type VIC1210 = &device_creator<vic1210_device>;
+
+
+
+//**************************************************************************
+// 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),
+ device_vic20_expansion_card_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void vic1210_device::device_start()
+{
+ // allocate memory
+ m_ram = auto_alloc_array(machine(), UINT8, 0xc00);
+}
+
+
+//-------------------------------------------------
+// vic20_cd_r - cartridge data read
+//-------------------------------------------------
+
+UINT8 vic1210_device::vic20_cd_r(address_space &space, offs_t offset, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3)
+{
+ UINT8 data = 0;
+
+ 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/mess/machine/vic1210.h b/src/mess/machine/vic1210.h
new file mode 100644
index 00000000000..2c154835eed
--- /dev/null
+++ b/src/mess/machine/vic1210.h
@@ -0,0 +1,51 @@
+/**********************************************************************
+
+ Commodore VIC-1210 3K RAM Expansion Cartridge emulation
+ Commodore VIC-1211A Super Expander with 3K RAM Cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __VIC1210__
+#define __VIC1210__
+
+
+#include "emu.h"
+#include "machine/vic20exp.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();
+ virtual void device_config_complete() { m_shortname = "vic1210"; }
+
+ // device_vic20_expansion_card_interface overrides
+ virtual UINT8 vic20_cd_r(address_space &space, offs_t offset, 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);
+};
+
+
+// device type definition
+extern const device_type VIC1210;
+
+
+
+#endif
diff --git a/src/mess/machine/vic20_megacart.c b/src/mess/machine/vic20_megacart.c
new file mode 100644
index 00000000000..66181262e3e
--- /dev/null
+++ b/src/mess/machine/vic20_megacart.c
@@ -0,0 +1,131 @@
+/**********************************************************************
+
+ Mega-Cart cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "vic20_megacart.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type VIC20_MEGACART = &device_creator<vic20_megacart_device>;
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( vic1112 )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( vic1112 )
+
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor vic20_megacart_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( vic1112 );
+}
+
+
+
+//**************************************************************************
+// 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),
+ 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()
+{
+ // 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, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3)
+{
+ UINT8 data = 0;
+
+ 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/mess/machine/vic20_megacart.h b/src/mess/machine/vic20_megacart.h
new file mode 100644
index 00000000000..fbc113c82f2
--- /dev/null
+++ b/src/mess/machine/vic20_megacart.h
@@ -0,0 +1,63 @@
+/**********************************************************************
+
+ Mega-Cart cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __VIC20_MEGACART__
+#define __VIC20_MEGACART__
+
+
+#include "emu.h"
+#include "machine/vic20exp.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();
+ virtual void device_config_complete() { m_shortname = "megacart"; }
+
+ // 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_size); } }
+ virtual void nvram_write(emu_file &file) { if (m_nvram != NULL) { file.write(m_nvram, m_nvram_size); } }
+
+ // device_vic20_expansion_card_interface overrides
+ virtual UINT8 vic20_cd_r(address_space &space, offs_t offset, 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/mess/machine/vic20exp.c b/src/mess/machine/vic20exp.c
new file mode 100644
index 00000000000..f63b40ed08d
--- /dev/null
+++ b/src/mess/machine/vic20exp.c
@@ -0,0 +1,375 @@
+/**********************************************************************
+
+ Commodore VIC-20 Expansion Port emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "emu.h"
+#include "emuopts.h"
+#include "formats/cbm_crt.h"
+#include "machine/vic20exp.h"
+#include "formats/imageutl.h"
+
+
+
+//**************************************************************************
+// MACROS/CONSTANTS
+//**************************************************************************
+
+#define LOG 0
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type VIC20_EXPANSION_SLOT = &device_creator<vic20_expansion_slot_device>;
+
+
+//**************************************************************************
+// 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(NULL),
+ m_blk2(NULL),
+ m_blk3(NULL),
+ m_blk5(NULL),
+ m_ram(NULL),
+ m_nvram(NULL),
+ m_nvram_size(0)
+{
+ m_slot = dynamic_cast<vic20_expansion_slot_device *>(device.owner());
+}
+
+
+//-------------------------------------------------
+// vic20_blk1_pointer - get block 1 pointer
+//-------------------------------------------------
+
+UINT8* device_vic20_expansion_card_interface::vic20_blk1_pointer(running_machine &machine, size_t size)
+{
+ if (m_blk1 == NULL)
+ {
+ m_blk1 = auto_alloc_array(machine, UINT8, size);
+ }
+
+ return m_blk1;
+}
+
+
+//-------------------------------------------------
+// vic20_blk2_pointer - get block 2 pointer
+//-------------------------------------------------
+
+UINT8* device_vic20_expansion_card_interface::vic20_blk2_pointer(running_machine &machine, size_t size)
+{
+ if (m_blk2 == NULL)
+ {
+ m_blk2 = auto_alloc_array(machine, UINT8, size);
+ }
+
+ return m_blk2;
+}
+
+
+//-------------------------------------------------
+// vic20_blk3_pointer - get block 3 pointer
+//-------------------------------------------------
+
+UINT8* device_vic20_expansion_card_interface::vic20_blk3_pointer(running_machine &machine, size_t size)
+{
+ if (m_blk3 == NULL)
+ {
+ m_blk3 = auto_alloc_array(machine, UINT8, size);
+ }
+
+ return m_blk3;
+}
+
+
+//-------------------------------------------------
+// vic20_blk5_pointer - get block 5 pointer
+//-------------------------------------------------
+
+UINT8* device_vic20_expansion_card_interface::vic20_blk5_pointer(running_machine &machine, size_t size)
+{
+ if (m_blk5 == NULL)
+ {
+ m_blk5 = auto_alloc_array(machine, UINT8, size);
+ }
+
+ return m_blk5;
+}
+
+
+//-------------------------------------------------
+// vic20_ram_pointer - get RAM pointer
+//-------------------------------------------------
+
+UINT8* device_vic20_expansion_card_interface::vic20_ram_pointer(running_machine &machine, size_t size)
+{
+ if (m_ram == NULL)
+ {
+ m_ram = auto_alloc_array(machine, UINT8, size);
+ }
+
+ return m_ram;
+}
+
+
+//-------------------------------------------------
+// vic20_nvram_pointer - get NVRAM pointer
+//-------------------------------------------------
+
+UINT8* device_vic20_expansion_card_interface::vic20_nvram_pointer(running_machine &machine, size_t size)
+{
+ if (m_nvram == NULL)
+ {
+ m_nvram = auto_alloc_array(machine, UINT8, size);
+
+ m_nvram_mask = size - 1;
+ m_nvram_size = size;
+ }
+
+ return m_nvram;
+}
+
+
+//-------------------------------------------------
+// ~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),
+ device_slot_interface(mconfig, *this),
+ device_image_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// vic20_expansion_slot_device - destructor
+//-------------------------------------------------
+
+vic20_expansion_slot_device::~vic20_expansion_slot_device()
+{
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void vic20_expansion_slot_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const vic20_expansion_slot_interface *intf = reinterpret_cast<const vic20_expansion_slot_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<vic20_expansion_slot_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_irq_cb, 0, sizeof(m_out_irq_cb));
+ memset(&m_out_nmi_cb, 0, sizeof(m_out_nmi_cb));
+ memset(&m_out_res_cb, 0, sizeof(m_out_res_cb));
+ }
+
+ // set brief and instance name
+ update_names();
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void vic20_expansion_slot_device::device_start()
+{
+ m_cart = dynamic_cast<device_vic20_expansion_card_interface *>(get_card_device());
+
+ // resolve callbacks
+ m_out_irq_func.resolve(m_out_irq_cb, *this);
+ m_out_nmi_func.resolve(m_out_nmi_cb, *this);
+ m_out_res_func.resolve(m_out_res_cb, *this);
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void vic20_expansion_slot_device::device_reset()
+{
+ port_res_w(ASSERT_LINE);
+ port_res_w(CLEAR_LINE);
+}
+
+
+//-------------------------------------------------
+// call_load -
+//-------------------------------------------------
+
+bool vic20_expansion_slot_device::call_load()
+{
+ if (m_cart)
+ {
+ size_t size = 0;
+
+ if (software_entry() == NULL)
+ {
+ if (!mame_stricmp(filetype(), "20")) fread(m_cart->vic20_blk1_pointer(machine(), 0x2000), 0x2000);
+ else if (!mame_stricmp(filetype(), "40")) fread(m_cart->vic20_blk2_pointer(machine(), 0x2000), 0x2000);
+ else if (!mame_stricmp(filetype(), "60")) fread(m_cart->vic20_blk3_pointer(machine(), 0x2000), 0x2000);
+ else if (!mame_stricmp(filetype(), "70")) fread(m_cart->vic20_blk3_pointer(machine(), 0x2000) + 0x1000, 0x1000);
+ else if (!mame_stricmp(filetype(), "a0")) fread(m_cart->vic20_blk5_pointer(machine(), 0x2000), 0x2000);
+ else if (!mame_stricmp(filetype(), "b0")) fread(m_cart->vic20_blk5_pointer(machine(), 0x2000) + 0x1000, 0x1000);
+ else if (!mame_stricmp(filetype(), "crt"))
+ {
+ // read the header
+ UINT8 header[2];
+ fread(&header, 2);
+ UINT16 address = pick_integer_le(header, 0, 2);
+
+ if (LOG) logerror("Address %04x\n", address);
+
+ switch (address)
+ {
+ case 0x2000: fread(m_cart->vic20_blk1_pointer(machine(), 0x2000), 0x2000); break;
+ case 0x4000: fread(m_cart->vic20_blk2_pointer(machine(), 0x2000), 0x2000); break;
+ case 0x6000: fread(m_cart->vic20_blk3_pointer(machine(), 0x2000), 0x2000); break;
+ case 0x7000: fread(m_cart->vic20_blk3_pointer(machine(), 0x2000) + 0x1000, 0x1000); break;
+ case 0xa000: fread(m_cart->vic20_blk5_pointer(machine(), 0x2000), 0x2000); break;
+ case 0xb000: fread(m_cart->vic20_blk5_pointer(machine(), 0x2000) + 0x1000, 0x1000); break;
+ default: return IMAGE_INIT_FAIL;
+ }
+ }
+ }
+ else
+ {
+ size = get_software_region_length("blk1");
+ if (size) memcpy(m_cart->vic20_blk1_pointer(machine(), size), get_software_region("blk1"), size);
+
+ size = get_software_region_length("blk2");
+ if (size) memcpy(m_cart->vic20_blk2_pointer(machine(), size), get_software_region("blk2"), size);
+
+ size = get_software_region_length("blk3");
+ if (size) memcpy(m_cart->vic20_blk3_pointer(machine(), size), get_software_region("blk3"), size);
+
+ size = get_software_region_length("blk5");
+ if (size) memcpy(m_cart->vic20_blk5_pointer(machine(), size), get_software_region("blk5"), size);
+
+ size = get_software_region_length("ram");
+ if (size) memcpy(m_cart->vic20_ram_pointer(machine(), size), get_software_region("ram"), size);
+
+ size = get_software_region_length("nvram");
+ if (size) memcpy(m_cart->vic20_nvram_pointer(machine(), size), get_software_region("nvram"), size);
+
+ }
+ }
+
+ return IMAGE_INIT_PASS;
+}
+
+
+//-------------------------------------------------
+// call_softlist_load -
+//-------------------------------------------------
+
+bool vic20_expansion_slot_device::call_softlist_load(char *swlist, char *swname, rom_entry *start_entry)
+{
+ load_software_part_region(this, swlist, swname, start_entry);
+
+ return true;
+}
+
+
+//-------------------------------------------------
+// get_default_card_software -
+//-------------------------------------------------
+
+const char * vic20_expansion_slot_device::get_default_card_software(const machine_config &config, emu_options &options)
+{
+ return software_get_default_slot(config, options, this, "standard");
+}
+
+
+//-------------------------------------------------
+// cd_r - cartridge data read
+//-------------------------------------------------
+
+UINT8 vic20_expansion_slot_device::cd_r(address_space &space, offs_t offset, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3)
+{
+ UINT8 data = 0;
+
+ if (m_cart != NULL)
+ {
+ data = m_cart->vic20_cd_r(space, offset, 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_cart != NULL)
+ {
+ m_cart->vic20_cd_w(space, offset, data, ram1, ram2, ram3, blk1, blk2, blk3, blk5, io2, io3);
+ }
+}
+
+
+//-------------------------------------------------
+// screen_update -
+//-------------------------------------------------
+
+UINT32 vic20_expansion_slot_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ bool value = false;
+
+ if (m_cart != NULL)
+ {
+ value = m_cart->vic20_screen_update(screen, bitmap, cliprect);
+ }
+
+ return value;
+}
+
+WRITE_LINE_MEMBER( vic20_expansion_slot_device::port_res_w ) { if (m_cart != NULL) m_cart->vic20_res_w(state); }
+
+WRITE_LINE_MEMBER( vic20_expansion_slot_device::irq_w ) { m_out_irq_func(state); }
+WRITE_LINE_MEMBER( vic20_expansion_slot_device::nmi_w ) { m_out_nmi_func(state); }
+WRITE_LINE_MEMBER( vic20_expansion_slot_device::res_w ) { m_out_res_func(state); }
diff --git a/src/mess/machine/vic20exp.h b/src/mess/machine/vic20exp.h
new file mode 100644
index 00000000000..963235e48d6
--- /dev/null
+++ b/src/mess/machine/vic20exp.h
@@ -0,0 +1,185 @@
+/**********************************************************************
+
+ Commodore VIC-20 Expansion Port emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+
+ 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 VIC20_EXPANSION_INTERFACE(_name) \
+ const vic20_expansion_slot_interface (_name) =
+
+
+#define MCFG_VIC20_EXPANSION_SLOT_ADD(_tag, _config, _slot_intf, _def_slot, _def_inp) \
+ MCFG_DEVICE_ADD(_tag, VIC20_EXPANSION_SLOT, 0) \
+ MCFG_DEVICE_CONFIG(_config) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false)
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> vic20_expansion_slot_interface
+
+struct vic20_expansion_slot_interface
+{
+ devcb_write_line m_out_irq_cb;
+ devcb_write_line m_out_nmi_cb;
+ devcb_write_line m_out_res_cb;
+};
+
+
+// ======================> vic20_expansion_slot_device
+
+class device_vic20_expansion_card_interface;
+
+class vic20_expansion_slot_device : public device_t,
+ public vic20_expansion_slot_interface,
+ 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);
+ virtual ~vic20_expansion_slot_device();
+
+ // computer interface
+ UINT8 cd_r(address_space &space, offs_t offset, 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);
+ UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+ DECLARE_WRITE_LINE_MEMBER( port_res_w );
+
+ // cartridge interface
+ DECLARE_WRITE_LINE_MEMBER( irq_w );
+ DECLARE_WRITE_LINE_MEMBER( nmi_w );
+ DECLARE_WRITE_LINE_MEMBER( res_w );
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+ virtual void device_start();
+ virtual void device_reset();
+
+ // image-level overrides
+ virtual bool call_load();
+ virtual bool call_softlist_load(char *swlist, char *swname, 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 const char * get_default_card_software(const machine_config &config, emu_options &options);
+
+ devcb_resolved_write_line m_out_irq_func;
+ devcb_resolved_write_line m_out_nmi_func;
+ devcb_resolved_write_line m_out_res_func;
+
+ device_vic20_expansion_card_interface *m_cart;
+};
+
+
+// ======================> 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();
+
+protected:
+ // initialization
+ virtual UINT8* vic20_blk1_pointer(running_machine &machine, size_t size);
+ virtual UINT8* vic20_blk2_pointer(running_machine &machine, size_t size);
+ virtual UINT8* vic20_blk3_pointer(running_machine &machine, size_t size);
+ virtual UINT8* vic20_blk5_pointer(running_machine &machine, size_t size);
+ virtual UINT8* vic20_ram_pointer(running_machine &machine, size_t size);
+ virtual UINT8* vic20_nvram_pointer(running_machine &machine, size_t size);
+
+ // runtime
+ virtual UINT8 vic20_cd_r(address_space &space, offs_t offset, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3) { return 0; };
+ 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) { };
+ virtual UINT32 vic20_screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { return 0; }
+ virtual void vic20_res_w(int state) { };
+
+ vic20_expansion_slot_device *m_slot;
+
+ UINT8 *m_blk1;
+ UINT8 *m_blk2;
+ UINT8 *m_blk3;
+ UINT8 *m_blk5;
+ UINT8 *m_ram;
+ UINT8 *m_nvram;
+
+ size_t m_nvram_size;
+
+ size_t m_nvram_mask;
+};
+
+
+// device type definition
+extern const device_type VIC20_EXPANSION_SLOT;
+
+
+
+#endif
diff --git a/src/mess/machine/vic20std.c b/src/mess/machine/vic20std.c
new file mode 100644
index 00000000000..59f27529b87
--- /dev/null
+++ b/src/mess/machine/vic20std.c
@@ -0,0 +1,72 @@
+/**********************************************************************
+
+ Commodore VIC-20 Standard 8K/16K ROM Cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "vic20std.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type VIC20_STD = &device_creator<vic20_standard_cartridge_device>;
+
+
+
+//**************************************************************************
+// 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),
+ 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, int ram1, int ram2, int ram3, int blk1, int blk2, int blk3, int blk5, int io2, int io3)
+{
+ UINT8 data = 0;
+
+ if (!blk1 && (m_blk1 != NULL))
+ {
+ data = m_blk1[offset & 0x1fff];
+ }
+ else if (!blk2 && (m_blk2 != NULL))
+ {
+ data = m_blk2[offset & 0x1fff];
+ }
+ else if (!blk3 && (m_blk3 != NULL))
+ {
+ data = m_blk3[offset & 0x1fff];
+ }
+ else if (!blk5 && (m_blk5 != NULL))
+ {
+ data = m_blk5[offset & 0x1fff];
+ }
+
+ return data;
+}
diff --git a/src/mess/machine/vic20std.h b/src/mess/machine/vic20std.h
new file mode 100644
index 00000000000..10ffa985fea
--- /dev/null
+++ b/src/mess/machine/vic20std.h
@@ -0,0 +1,49 @@
+/**********************************************************************
+
+ Commodore VIC-20 Standard 8K/16K ROM Cartridge emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __VIC20_STD__
+#define __VIC20_STD__
+
+
+#include "emu.h"
+#include "machine/vic20exp.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();
+ virtual void device_config_complete() { m_shortname = "vic20_standard"; }
+
+ // device_vic20_expansion_card_interface overrides
+ virtual UINT8 vic20_cd_r(address_space &space, offs_t offset, 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/mess/machine/vic20user.c b/src/mess/machine/vic20user.c
new file mode 100644
index 00000000000..41ee8c2ed1b
--- /dev/null
+++ b/src/mess/machine/vic20user.c
@@ -0,0 +1,136 @@
+/**********************************************************************
+
+ Commodore VIC-20 User Port emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "machine/vic20user.h"
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type VIC20_USER_PORT = &device_creator<vic20_user_port_device>;
+
+
+
+//**************************************************************************
+// CARD INTERFACE
+//**************************************************************************
+
+//-------------------------------------------------
+// device_vic20_user_port_interface - constructor
+//-------------------------------------------------
+
+device_vic20_user_port_interface::device_vic20_user_port_interface(const machine_config &mconfig, device_t &device)
+ : device_slot_card_interface(mconfig,device)
+{
+ m_slot = dynamic_cast<vic20_user_port_device *>(device.owner());
+}
+
+
+//-------------------------------------------------
+// ~device_vic20_user_port_interface - destructor
+//-------------------------------------------------
+
+device_vic20_user_port_interface::~device_vic20_user_port_interface()
+{
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// vic20_user_port_device - constructor
+//-------------------------------------------------
+
+vic20_user_port_device::vic20_user_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, VIC20_USER_PORT, "VIC-20 user port", tag, owner, clock),
+ device_slot_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// vic20_user_port_device - destructor
+//-------------------------------------------------
+
+vic20_user_port_device::~vic20_user_port_device()
+{
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void vic20_user_port_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const vic20_user_port_interface *intf = reinterpret_cast<const vic20_user_port_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<vic20_user_port_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_cb1_cb, 0, sizeof(m_out_cb1_cb));
+ memset(&m_out_cb2_cb, 0, sizeof(m_out_cb2_cb));
+ memset(&m_out_reset_cb, 0, sizeof(m_out_reset_cb));
+ }
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void vic20_user_port_device::device_start()
+{
+ m_cart = dynamic_cast<device_vic20_user_port_interface *>(get_card_device());
+
+ // resolve callbacks
+ m_out_cb1_func.resolve(m_out_cb1_cb, *this);
+ m_out_cb2_func.resolve(m_out_cb2_cb, *this);
+ m_out_reset_func.resolve(m_out_reset_cb, *this);
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void vic20_user_port_device::device_reset()
+{
+ port_reset_w(ASSERT_LINE);
+ port_reset_w(CLEAR_LINE);
+}
+
+
+READ8_MEMBER( vic20_user_port_device::pb_r ) { UINT8 data = 0xff; if (m_cart != NULL) data = m_cart->vic20_pb_r(space, offset); return data; }
+WRITE8_MEMBER( vic20_user_port_device::pb_w ) { if (m_cart != NULL) m_cart->vic20_pb_w(space, offset, data); }
+READ_LINE_MEMBER( vic20_user_port_device::joy0_r ) { int state = 1; if (m_cart != NULL) state = m_cart->vic20_joy0_r(); return state; }
+READ_LINE_MEMBER( vic20_user_port_device::joy1_r ) { int state = 1; if (m_cart != NULL) state = m_cart->vic20_joy1_r(); return state; }
+READ_LINE_MEMBER( vic20_user_port_device::joy2_r ) { int state = 1; if (m_cart != NULL) state = m_cart->vic20_joy2_r(); return state; }
+READ_LINE_MEMBER( vic20_user_port_device::light_pen_r ) { int state = 1; if (m_cart != NULL) state = m_cart->vic20_light_pen_r(); return state; }
+READ_LINE_MEMBER( vic20_user_port_device::cassette_switch_r ) { int state = 1; if (m_cart != NULL) state = m_cart->vic20_cassette_switch_r(); return state; }
+WRITE_LINE_MEMBER( vic20_user_port_device::cb1_w ) { if (m_cart != NULL) m_cart->vic20_cb1_w(state); }
+WRITE_LINE_MEMBER( vic20_user_port_device::cb2_w ) { if (m_cart != NULL) m_cart->vic20_cb2_w(state); }
+WRITE_LINE_MEMBER( vic20_user_port_device::atn_w ) { if (m_cart != NULL) m_cart->vic20_atn_w(state); }
+WRITE_LINE_MEMBER( vic20_user_port_device::port_reset_w ) { if (m_cart != NULL) m_cart->vic20_reset_w(state); }
+
+WRITE_LINE_MEMBER( vic20_user_port_device::via_cb1_w ) { m_out_cb1_func(state); }
+WRITE_LINE_MEMBER( vic20_user_port_device::via_cb2_w ) { m_out_cb2_func(state); }
+WRITE_LINE_MEMBER( vic20_user_port_device::reset_w ) { m_out_reset_func(state); }
diff --git a/src/mess/machine/vic20user.h b/src/mess/machine/vic20user.h
new file mode 100644
index 00000000000..62bc5f47a02
--- /dev/null
+++ b/src/mess/machine/vic20user.h
@@ -0,0 +1,151 @@
+/**********************************************************************
+
+ Commodore VIC-20 User Port emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+
+ 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 "emu.h"
+
+
+
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
+
+#define VIC20_USER_PORT_TAG "user"
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define VIC20_USER_PORT_INTERFACE(_name) \
+ const vic20_user_port_interface (_name) =
+
+
+#define MCFG_VIC20_USER_PORT_ADD(_tag, _config, _slot_intf, _def_slot, _def_inp) \
+ MCFG_DEVICE_ADD(_tag, VIC20_USER_PORT, 0) \
+ MCFG_DEVICE_CONFIG(_config) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false)
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> vic20_user_port_interface
+
+struct vic20_user_port_interface
+{
+ devcb_write_line m_out_cb1_cb;
+ devcb_write_line m_out_cb2_cb;
+ devcb_write_line m_out_reset_cb;
+};
+
+
+// ======================> vic20_user_port_device
+
+class device_vic20_user_port_interface;
+
+class vic20_user_port_device : public device_t,
+ public vic20_user_port_interface,
+ public device_slot_interface
+{
+public:
+ // construction/destruction
+ vic20_user_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ virtual ~vic20_user_port_device();
+
+ // computer interface
+ DECLARE_READ8_MEMBER( pb_r );
+ DECLARE_WRITE8_MEMBER( pb_w );
+ DECLARE_READ_LINE_MEMBER( joy0_r );
+ DECLARE_READ_LINE_MEMBER( joy1_r );
+ DECLARE_READ_LINE_MEMBER( joy2_r );
+ DECLARE_READ_LINE_MEMBER( light_pen_r );
+ DECLARE_READ_LINE_MEMBER( cassette_switch_r );
+ DECLARE_WRITE_LINE_MEMBER( cb1_w );
+ DECLARE_WRITE_LINE_MEMBER( cb2_w );
+ DECLARE_WRITE_LINE_MEMBER( atn_w );
+ DECLARE_WRITE_LINE_MEMBER( port_reset_w );
+
+ // cartridge interface
+ DECLARE_WRITE_LINE_MEMBER( via_cb1_w );
+ DECLARE_WRITE_LINE_MEMBER( via_cb2_w );
+ DECLARE_WRITE_LINE_MEMBER( reset_w );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete();
+
+ devcb_resolved_write_line m_out_cb1_func;
+ devcb_resolved_write_line m_out_cb2_func;
+ devcb_resolved_write_line m_out_reset_func;
+
+ device_vic20_user_port_interface *m_cart;
+};
+
+
+// ======================> device_vic20_user_port_interface
+
+// class representing interface-specific live vic20_expansion card
+class device_vic20_user_port_interface : public device_slot_card_interface
+{
+public:
+ // construction/destruction
+ device_vic20_user_port_interface(const machine_config &mconfig, device_t &device);
+ virtual ~device_vic20_user_port_interface();
+
+ virtual UINT8 vic20_pb_r(address_space &space, offs_t offset) { return 0xff; };
+ virtual void vic20_pb_w(address_space &space, offs_t offset, UINT8 data) { };
+
+ virtual int vic20_joy0_r() { return 1; };
+ virtual int vic20_joy1_r() { return 1; };
+ virtual int vic20_joy2_r() { return 1; };
+ virtual int vic20_light_pen_r() { return 1; };
+ virtual int vic20_cassette_switch_r() { return 1; };
+ virtual void vic20_cb1_w(int state) { };
+ virtual void vic20_cb2_w(int state) { };
+ virtual void vic20_atn_w(int state) { };
+
+ // reset
+ virtual void vic20_reset_w(int state) { };
+
+protected:
+ vic20_user_port_device *m_slot;
+};
+
+
+// device type definition
+extern const device_type VIC20_USER_PORT;
+
+
+
+#endif
diff --git a/src/mess/machine/victor9kb.c b/src/mess/machine/victor9kb.c
new file mode 100644
index 00000000000..e9b20cdcaa7
--- /dev/null
+++ b/src/mess/machine/victor9kb.c
@@ -0,0 +1,389 @@
+/**********************************************************************
+
+ Victor 9000 keyboard emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#include "victor9kb.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define I8021_TAG "z3"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type VICTOR9K_KEYBOARD = &device_creator<victor9k_keyboard_device>;
+
+
+
+//-------------------------------------------------
+// ROM( victor9k_keyboard )
+//-------------------------------------------------
+
+ROM_START( victor9k_keyboard )
+ ROM_REGION( 0x400, I8021_TAG, 0)
+ ROM_LOAD( "20-8021-139.z3", 0x000, 0x400, CRC(0fe9d53d) SHA1(61d92ba90f98f8978bbd9303c1ac3134cde8cdcb) )
+ROM_END
+
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *victor9k_keyboard_device::device_rom_region() const
+{
+ return ROM_NAME( victor9k_keyboard );
+}
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( kb_io )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( victor9k_keyboard_io, AS_IO, 8, victor9k_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( victor9k_keyboard )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( victor9k_keyboard )
+ MCFG_CPU_ADD(I8021_TAG, I8021, XTAL_3_579545MHz)
+ MCFG_CPU_IO_MAP(victor9k_keyboard_io)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor victor9k_keyboard_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( victor9k_keyboard );
+}
+
+
+//-------------------------------------------------
+// INPUT_PORTS( victor9k_keyboard )
+//-------------------------------------------------
+
+INPUT_PORTS_START( victor9k_keyboard )
+ PORT_START("Y0")
+ 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_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("Y1")
+ 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_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("Y2")
+ 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_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("Y3")
+ 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_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("Y4")
+ 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_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("Y5")
+ 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_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("Y6")
+ 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_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("Y7")
+ 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_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("Y8")
+ 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_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("Y9")
+ 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_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("YA")
+ 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_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("YB")
+ 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_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+
+ PORT_START("YC")
+ 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_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD )
+INPUT_PORTS_END
+
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+ioport_constructor victor9k_keyboard_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( victor9k_keyboard );
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// victor9k_keyboard_device - constructor
+//-------------------------------------------------
+
+victor9k_keyboard_device::victor9k_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, VICTOR9K_KEYBOARD, "Victor 9000 Keyboard", tag, owner, clock),
+ m_maincpu(*this, I8021_TAG),
+ m_y(0),
+ m_kbrdy(1),
+ m_kbdata(1),
+ m_kback(1)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void victor9k_keyboard_device::device_start()
+{
+ // resolve callbacks
+ m_out_kbrdy_func.resolve(m_out_kbrdy_cb, *this);
+
+ // state saving
+ save_item(NAME(m_y));
+ save_item(NAME(m_kbrdy));
+ save_item(NAME(m_kbdata));
+ save_item(NAME(m_kback));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void victor9k_keyboard_device::device_reset()
+{
+}
+
+
+//-------------------------------------------------
+// kbrdy_r -
+//-------------------------------------------------
+
+READ_LINE_MEMBER( victor9k_keyboard_device::kbrdy_r )
+{
+ return m_kbrdy;
+}
+
+
+//-------------------------------------------------
+// kback_w -
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( victor9k_keyboard_device::kback_w )
+{
+ m_kback = state;
+}
+
+
+//-------------------------------------------------
+// kbdata_r -
+//-------------------------------------------------
+
+READ_LINE_MEMBER( victor9k_keyboard_device::kbdata_r )
+{
+ return m_kbdata;
+}
+
+
+//-------------------------------------------------
+// kb_p1_r -
+//-------------------------------------------------
+
+READ8_MEMBER( victor9k_keyboard_device::kb_p1_r )
+{
+ UINT8 data = 0xff;
+
+ switch (m_y)
+ {
+ case 0: data &= ioport("Y0")->read(); break;
+ case 1: data &= ioport("Y1")->read(); break;
+ case 2: data &= ioport("Y2")->read(); break;
+ case 3: data &= ioport("Y3")->read(); break;
+ case 4: data &= ioport("Y4")->read(); break;
+ case 5: data &= ioport("Y5")->read(); break;
+ case 6: data &= ioport("Y6")->read(); break;
+ case 7: data &= ioport("Y7")->read(); break;
+ case 8: data &= ioport("Y8")->read(); break;
+ case 9: data &= ioport("Y9")->read(); break;
+ case 0xa: data &= ioport("YA")->read(); break;
+ case 0xb: data &= ioport("YB")->read(); break;
+ case 0xc: data &= ioport("YC")->read(); break;
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// kb_p1_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( victor9k_keyboard_device::kb_p1_w )
+{
+ if ((data & 0xf0) == 0x20)
+ {
+ m_y = data & 0x0f;
+ }
+
+ logerror("P1 %02x\n", data);
+}
+
+
+//-------------------------------------------------
+// kb_p2_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( victor9k_keyboard_device::kb_p2_w )
+{
+ /*
+
+ bit description
+
+ P20 keylatch enable ?
+ P21
+ P22 key available ?
+ P23 data ?
+
+ */
+
+ int kbrdy = BIT(data, 2);
+
+ if (m_kbrdy != kbrdy)
+ {
+ m_kbrdy = kbrdy;
+ m_out_kbrdy_func(m_kbrdy);
+ }
+
+ m_kbdata = BIT(data, 3);
+
+ logerror("P2 %01x\n", data & 0x0f);
+}
+
+
+//-------------------------------------------------
+// kb_t1_r -
+//-------------------------------------------------
+
+READ8_MEMBER( victor9k_keyboard_device::kb_t1_r )
+{
+ logerror("read T1 %u\n", m_kback);
+
+ return m_kback;
+}
diff --git a/src/mess/machine/victor9kb.h b/src/mess/machine/victor9kb.h
new file mode 100644
index 00000000000..ed63f400cff
--- /dev/null
+++ b/src/mess/machine/victor9kb.h
@@ -0,0 +1,102 @@
+/**********************************************************************
+
+ Victor 9000 keyboard emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#pragma once
+
+#ifndef __VICTOR9K_KEYBOARD__
+#define __VICTOR9K_KEYBOARD__
+
+
+#include "emu.h"
+#include "cpu/mcs48/mcs48.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define VICTOR9K_KEYBOARD_TAG "victor9kb"
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_VICTOR9K_KEYBOARD_ADD(_config) \
+ MCFG_DEVICE_ADD(VICTOR9K_KEYBOARD_TAG, VICTOR9K_KEYBOARD, 0) \
+ MCFG_DEVICE_CONFIG(_config)
+
+
+#define VICTOR9K_KEYBOARD_INTERFACE(_name) \
+ const victor9k_keyboard_interface (_name) =
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> victor9k_keyboard_interface
+
+struct victor9k_keyboard_interface
+{
+ devcb_write_line m_out_kbrdy_cb;
+};
+
+
+// ======================> victor9k_keyboard_device
+
+class victor9k_keyboard_device : public device_t,
+ public victor9k_keyboard_interface
+{
+public:
+ // construction/destruction
+ victor9k_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_READ_LINE_MEMBER( kbrdy_r );
+ DECLARE_WRITE_LINE_MEMBER( kback_w );
+ DECLARE_READ_LINE_MEMBER( kbdata_r );
+
+ // 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_config_complete() { m_shortname = "victor9kb"; }
+
+private:
+ devcb_resolved_write_line m_out_kbrdy_func;
+
+ required_device<cpu_device> m_maincpu;
+
+ UINT8 m_y;
+ int m_kbrdy;
+ int m_kbdata;
+ int m_kback;
+};
+
+
+// device type definition
+extern const device_type VICTOR9K_KEYBOARD;
+
+
+
+#endif
diff --git a/src/mess/machine/vidbrain_exp.c b/src/mess/machine/vidbrain_exp.c
new file mode 100644
index 00000000000..ee0f23f002c
--- /dev/null
+++ b/src/mess/machine/vidbrain_exp.c
@@ -0,0 +1,247 @@
+/**********************************************************************
+
+ VideoBrain Expansion Port emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "machine/vidbrain_exp.h"
+
+
+
+//**************************************************************************
+// MACROS/CONSTANTS
+//**************************************************************************
+
+#define LOG 0
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type VIDEOBRAIN_EXPANSION_SLOT = &device_creator<videobrain_expansion_slot_device>;
+
+
+
+//**************************************************************************
+// 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(NULL),
+ m_ram(NULL),
+ m_rom_mask(0),
+ m_ram_mask(0)
+{
+ m_slot = dynamic_cast<videobrain_expansion_slot_device *>(device.owner());
+}
+
+
+//-------------------------------------------------
+// ~device_videobrain_expansion_card_interface - destructor
+//-------------------------------------------------
+
+device_videobrain_expansion_card_interface::~device_videobrain_expansion_card_interface()
+{
+}
+
+
+//-------------------------------------------------
+// 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 == NULL)
+ {
+ m_rom = auto_alloc_array(machine, UINT8, size);
+
+ m_rom_mask = size - 1;
+ }
+
+ return m_rom;
+}
+
+
+//-------------------------------------------------
+// videobrain_ram_pointer - get RAM pointer
+//-------------------------------------------------
+
+UINT8* device_videobrain_expansion_card_interface::videobrain_ram_pointer(running_machine &machine, size_t size)
+{
+ if (m_ram == NULL)
+ {
+ m_ram = auto_alloc_array(machine, UINT8, size);
+
+ m_ram_mask = size - 1;
+ }
+
+ return m_ram;
+}
+
+
+
+//**************************************************************************
+// 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),
+ device_slot_interface(mconfig, *this),
+ device_image_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// videobrain_expansion_slot_device - destructor
+//-------------------------------------------------
+
+videobrain_expansion_slot_device::~videobrain_expansion_slot_device()
+{
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void videobrain_expansion_slot_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const videobrain_expansion_slot_interface *intf = reinterpret_cast<const videobrain_expansion_slot_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<videobrain_expansion_slot_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_extres_cb, 0, sizeof(m_out_extres_cb));
+ }
+
+ // set brief and instance name
+ update_names();
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void videobrain_expansion_slot_device::device_start()
+{
+ m_cart = dynamic_cast<device_videobrain_expansion_card_interface *>(get_card_device());
+
+ // resolve callbacks
+ m_out_extres_func.resolve(m_out_extres_cb, *this);
+}
+
+
+//-------------------------------------------------
+// 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(char *swlist, char *swname, rom_entry *start_entry)
+{
+ load_software_part_region(this, swlist, swname, start_entry);
+
+ return true;
+}
+
+
+//-------------------------------------------------
+// get_default_card_software -
+//-------------------------------------------------
+
+const char * videobrain_expansion_slot_device::get_default_card_software(const machine_config &config, emu_options &options)
+{
+ return software_get_default_slot(config, options, this, "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);
+ }
+}
+
+
+READ8_MEMBER( videobrain_expansion_slot_device::cs1_r ) { return bo_r(space, offset + 0x1000, 0, 1); }
+WRITE8_MEMBER( videobrain_expansion_slot_device::cs1_w ) { bo_w(space, offset + 0x1000, data, 0, 1); }
+READ8_MEMBER( videobrain_expansion_slot_device::cs2_r ) { return bo_r(space, offset + 0x1800, 1, 0); }
+WRITE8_MEMBER( videobrain_expansion_slot_device::cs2_w ) { bo_w(space, offset + 0x1800, data, 1, 0); }
+READ8_MEMBER( videobrain_expansion_slot_device::unmap_r ) { return bo_r(space, offset + 0x3000, 1, 0); }
+WRITE8_MEMBER( videobrain_expansion_slot_device::unmap_w ) { bo_w(space, offset + 0x3000, data, 1, 0); }
+
+
+WRITE_LINE_MEMBER( videobrain_expansion_slot_device::extres_w ) { m_out_extres_func(state); }
diff --git a/src/mess/machine/vidbrain_exp.h b/src/mess/machine/vidbrain_exp.h
new file mode 100644
index 00000000000..7dfb030c904
--- /dev/null
+++ b/src/mess/machine/vidbrain_exp.h
@@ -0,0 +1,175 @@
+/**********************************************************************
+
+ VideoBrain Expansion Port emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+
+ 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 VIDEOBRAIN_EXPANSION_INTERFACE(_name) \
+ const videobrain_expansion_slot_interface (_name) =
+
+
+#define MCFG_VIDEOBRAIN_EXPANSION_SLOT_ADD(_tag, _config, _slot_intf, _def_slot, _def_inp) \
+ MCFG_DEVICE_ADD(_tag, VIDEOBRAIN_EXPANSION_SLOT, 0) \
+ MCFG_DEVICE_CONFIG(_config) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false)
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> videobrain_expansion_slot_interface
+
+struct videobrain_expansion_slot_interface
+{
+ devcb_write_line m_out_extres_cb;
+};
+
+
+// ======================> videobrain_expansion_slot_device
+
+class device_videobrain_expansion_card_interface;
+
+class videobrain_expansion_slot_device : public device_t,
+ public videobrain_expansion_slot_interface,
+ 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();
+
+ // 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 );
+ DECLARE_WRITE8_MEMBER( cs1_w );
+ DECLARE_READ8_MEMBER( cs2_r );
+ DECLARE_WRITE8_MEMBER( cs2_w );
+ DECLARE_READ8_MEMBER( unmap_r );
+ DECLARE_WRITE8_MEMBER( unmap_w );
+
+ // cartridge interface
+ DECLARE_WRITE_LINE_MEMBER( extres_w );
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+ virtual void device_start();
+
+ // image-level overrides
+ virtual bool call_load();
+ virtual bool call_softlist_load(char *swlist, char *swname, 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 const char * get_default_card_software(const machine_config &config, emu_options &options);
+
+ devcb_resolved_write_line m_out_extres_func;
+
+ device_videobrain_expansion_card_interface *m_cart;
+};
+
+
+// ======================> 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;
+
+ UINT8 *m_rom;
+ UINT8 *m_ram;
+
+ size_t m_rom_mask;
+ size_t m_ram_mask;
+};
+
+
+// device type definition
+extern const device_type VIDEOBRAIN_EXPANSION_SLOT;
+
+
+
+#endif
diff --git a/src/mess/machine/vip_byteio.c b/src/mess/machine/vip_byteio.c
new file mode 100644
index 00000000000..b7c4109eb0a
--- /dev/null
+++ b/src/mess/machine/vip_byteio.c
@@ -0,0 +1,132 @@
+/**********************************************************************
+
+ RCA Cosmac VIP Byte Input/Output port emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "machine/vip_byteio.h"
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type VIP_BYTEIO_PORT = &device_creator<vip_byteio_port_device>;
+
+
+
+//**************************************************************************
+// 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<vip_byteio_port_device *>(device.owner());
+}
+
+
+//-------------------------------------------------
+// ~device_vip_byteio_port_interface - destructor
+//-------------------------------------------------
+
+device_vip_byteio_port_interface::~device_vip_byteio_port_interface()
+{
+}
+
+
+
+//**************************************************************************
+// 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),
+ device_slot_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// vip_byteio_port_device - destructor
+//-------------------------------------------------
+
+vip_byteio_port_device::~vip_byteio_port_device()
+{
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void vip_byteio_port_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const vip_byteio_port_interface *intf = reinterpret_cast<const vip_byteio_port_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<vip_byteio_port_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_inst_cb, 0, sizeof(m_out_inst_cb));
+ }
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void vip_byteio_port_device::device_start()
+{
+ m_cart = dynamic_cast<device_vip_byteio_port_interface *>(get_card_device());
+
+ // resolve callbacks
+ m_out_inst_func.resolve(m_out_inst_cb, *this);
+}
+
+
+//-------------------------------------------------
+// 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); }
+
+WRITE_LINE_MEMBER( vip_byteio_port_device::inst_w ) { m_out_inst_func(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/mess/machine/vip_byteio.h b/src/mess/machine/vip_byteio.h
new file mode 100644
index 00000000000..0b04cb3da55
--- /dev/null
+++ b/src/mess/machine/vip_byteio.h
@@ -0,0 +1,148 @@
+/**********************************************************************
+
+ RCA Cosmac VIP Byte Input/Output port emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+
+ 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 VIP_BYTEIO_PORT_INTERFACE(_name) \
+ const vip_byteio_port_interface (_name) =
+
+
+#define MCFG_VIP_BYTEIO_PORT_ADD(_tag, _config, _slot_intf, _def_slot, _def_inp) \
+ MCFG_DEVICE_ADD(_tag, VIP_BYTEIO_PORT, 0) \
+ MCFG_DEVICE_CONFIG(_config) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false)
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> vip_byteio_port_interface
+
+struct vip_byteio_port_interface
+{
+ devcb_write_line m_out_inst_cb;
+};
+
+
+// ======================> vip_byteio_port_device
+
+class device_vip_byteio_port_interface;
+
+class vip_byteio_port_device : public device_t,
+ public vip_byteio_port_interface,
+ public device_slot_interface
+{
+public:
+ // construction/destruction
+ vip_byteio_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ virtual ~vip_byteio_port_device();
+
+ // 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 );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete();
+
+ devcb_resolved_write_line m_out_inst_func;
+
+ 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 ~device_vip_byteio_port_interface();
+
+ 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 "machine/vp620.h"
+
+SLOT_INTERFACE_EXTERN( vip_byteio_cards );
+
+
+
+#endif
diff --git a/src/mess/machine/vip_exp.c b/src/mess/machine/vip_exp.c
new file mode 100644
index 00000000000..4c1330a9b6d
--- /dev/null
+++ b/src/mess/machine/vip_exp.c
@@ -0,0 +1,253 @@
+/**********************************************************************
+
+ RCA Cosmac VIP Expansion Interface emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "machine/vip_exp.h"
+
+
+
+//**************************************************************************
+// MACROS/CONSTANTS
+//**************************************************************************
+
+#define LOG 0
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type VIP_EXPANSION_SLOT = &device_creator<vip_expansion_slot_device>;
+
+
+
+//**************************************************************************
+// 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<vip_expansion_slot_device *>(device.owner());
+}
+
+
+//-------------------------------------------------
+// ~device_vip_expansion_card_interface - destructor
+//-------------------------------------------------
+
+device_vip_expansion_card_interface::~device_vip_expansion_card_interface()
+{
+}
+
+
+
+//**************************************************************************
+// 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),
+ device_slot_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// vip_expansion_slot_device - destructor
+//-------------------------------------------------
+
+vip_expansion_slot_device::~vip_expansion_slot_device()
+{
+}
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void vip_expansion_slot_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const vip_expansion_slot_interface *intf = reinterpret_cast<const vip_expansion_slot_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<vip_expansion_slot_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_interrupt_cb, 0, sizeof(m_out_interrupt_cb));
+ memset(&m_out_dma_out_cb, 0, sizeof(m_out_dma_out_cb));
+ memset(&m_out_dma_in_cb, 0, sizeof(m_out_dma_in_cb));
+ }
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void vip_expansion_slot_device::device_start()
+{
+ m_cart = dynamic_cast<device_vip_expansion_card_interface *>(get_card_device());
+
+ // resolve callbacks
+ m_out_interrupt_func.resolve(m_out_interrupt_cb, *this);
+ m_out_dma_out_func.resolve(m_out_dma_out_cb, *this);
+ m_out_dma_in_func.resolve(m_out_dma_in_cb, *this);
+}
+
+
+//-------------------------------------------------
+// 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_cart != NULL)
+ {
+ data = m_cart->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_cart != NULL)
+ {
+ m_cart->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_cart != NULL)
+ {
+ data = m_cart->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_cart != NULL)
+ {
+ m_cart->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_cart != NULL)
+ {
+ data = m_cart->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_cart != NULL)
+ {
+ m_cart->vip_dma_w(space, offset, data);
+ }
+}
+
+
+//-------------------------------------------------
+// screen_update -
+//-------------------------------------------------
+
+UINT32 vip_expansion_slot_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ bool value = false;
+
+ if (m_cart != NULL)
+ {
+ value = m_cart->vip_screen_update(screen, bitmap, cliprect);
+ }
+
+ return value;
+}
+
+READ_LINE_MEMBER( vip_expansion_slot_device::ef1_r ) { int state = CLEAR_LINE; if (m_cart != NULL) state = m_cart->vip_ef1_r(); return state; }
+READ_LINE_MEMBER( vip_expansion_slot_device::ef3_r ) { int state = CLEAR_LINE; if (m_cart != NULL) state = m_cart->vip_ef3_r(); return state; }
+READ_LINE_MEMBER( vip_expansion_slot_device::ef4_r ) { int state = CLEAR_LINE; if (m_cart != NULL) state = m_cart->vip_ef4_r(); return state; }
+void vip_expansion_slot_device::sc_w(int data) { if (m_cart != NULL) m_cart->vip_sc_w(data); }
+WRITE_LINE_MEMBER( vip_expansion_slot_device::q_w ) { if (m_cart != NULL) m_cart->vip_q_w(state); }
+WRITE_LINE_MEMBER( vip_expansion_slot_device::run_w ) { if (m_cart != NULL) m_cart->vip_run_w(state); }
+
+WRITE_LINE_MEMBER( vip_expansion_slot_device::interrupt_w ) { m_out_interrupt_func(state); }
+WRITE_LINE_MEMBER( vip_expansion_slot_device::dma_out_w ) { m_out_dma_out_func(state); }
+WRITE_LINE_MEMBER( vip_expansion_slot_device::dma_in_w ) { m_out_dma_in_func(state); }
+
+
+
+//-------------------------------------------------
+// SLOT_INTERFACE vip_expansion_cards )
+//-------------------------------------------------
+
+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/mess/machine/vip_exp.h b/src/mess/machine/vip_exp.h
new file mode 100644
index 00000000000..981d8de4e9b
--- /dev/null
+++ b/src/mess/machine/vip_exp.h
@@ -0,0 +1,182 @@
+/**********************************************************************
+
+ RCA Cosmac VIP Expansion Interface emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+
+ 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 VIP_EXPANSION_INTERFACE(_name) \
+ const vip_expansion_slot_interface (_name) =
+
+
+#define MCFG_VIP_EXPANSION_SLOT_ADD(_tag, _clock, _config, _slot_intf, _def_slot, _def_inp) \
+ MCFG_DEVICE_ADD(_tag, VIP_EXPANSION_SLOT, _clock) \
+ MCFG_DEVICE_CONFIG(_config) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false)
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> vip_expansion_slot_interface
+
+struct vip_expansion_slot_interface
+{
+ devcb_write_line m_out_interrupt_cb;
+ devcb_write_line m_out_dma_out_cb;
+ devcb_write_line m_out_dma_in_cb;
+};
+
+
+// ======================> vip_expansion_slot_device
+
+class device_vip_expansion_card_interface;
+
+class vip_expansion_slot_device : public device_t,
+ public vip_expansion_slot_interface,
+ public device_slot_interface
+{
+public:
+ // construction/destruction
+ vip_expansion_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ virtual ~vip_expansion_slot_device();
+
+ // 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_ind16 &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 );
+ DECLARE_WRITE_LINE_MEMBER( dma_out_w );
+ DECLARE_WRITE_LINE_MEMBER( dma_in_w );
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+ virtual void device_start();
+
+ devcb_resolved_write_line m_out_interrupt_func;
+ devcb_resolved_write_line m_out_dma_out_func;
+ devcb_resolved_write_line m_out_dma_in_func;
+
+ device_vip_expansion_card_interface *m_cart;
+};
+
+
+// ======================> 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);
+ virtual ~device_vip_expansion_card_interface();
+
+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_ind16 &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 devices
+#include "machine/vp550.h"
+#include "machine/vp570.h"
+#include "machine/vp575.h"
+#include "machine/vp585.h"
+#include "machine/vp590.h"
+#include "machine/vp595.h"
+#include "machine/vp700.h"
+
+SLOT_INTERFACE_EXTERN( vip_expansion_cards );
+
+
+
+#endif
diff --git a/src/mess/machine/vp550.c b/src/mess/machine/vp550.c
new file mode 100644
index 00000000000..5106374a62e
--- /dev/null
+++ b/src/mess/machine/vp550.c
@@ -0,0 +1,250 @@
+/**********************************************************************
+
+ RCA VIP Super Sound System VP550 emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ 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<vp550_device>;
+
+
+//-------------------------------------------------
+// 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),
+ 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/mess/machine/vp550.h b/src/mess/machine/vp550.h
new file mode 100644
index 00000000000..515c12b03a0
--- /dev/null
+++ b/src/mess/machine/vp550.h
@@ -0,0 +1,68 @@
+/**********************************************************************
+
+ RCA VIP Super Sound System VP550 emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __VP550__
+#define __VP550__
+
+#include "emu.h"
+#include "machine/vip_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_config_complete() { m_shortname = "vp550"; }
+ 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<cdp1863_device> m_pfg_a;
+ required_device<cdp1863_device> m_pfg_b;
+
+ // timers
+ emu_timer *m_sync_timer;
+};
+
+
+// device type definition
+extern const device_type VP550;
+
+
+#endif
diff --git a/src/mess/machine/vp570.c b/src/mess/machine/vp570.c
new file mode 100644
index 00000000000..d2b8a1d01f8
--- /dev/null
+++ b/src/mess/machine/vp570.c
@@ -0,0 +1,118 @@
+/**********************************************************************
+
+ RCA VIP Expansion Board VP-570 emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "vp570.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type VP570 = &device_creator<vp570_device>;
+
+
+//-------------------------------------------------
+// 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),
+ device_vip_expansion_card_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void vp570_device::device_start()
+{
+ m_ram = auto_alloc_array(machine(), UINT8, 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 = ioport("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 = ioport("BASE")->read() << 12;
+
+ if (offset >= base && offset < base + 0x1000)
+ {
+ *minh = 1;
+
+ if (ioport("SW1")->read())
+ {
+ m_ram[offset & 0xfff] = data;
+ }
+ }
+}
diff --git a/src/mess/machine/vp570.h b/src/mess/machine/vp570.h
new file mode 100644
index 00000000000..93485ef8438
--- /dev/null
+++ b/src/mess/machine/vp570.h
@@ -0,0 +1,54 @@
+/**********************************************************************
+
+ RCA VIP Memory Expansion Board VP-570 emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __VP570__
+#define __VP570__
+
+#include "emu.h"
+#include "machine/vip_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_config_complete() { m_shortname = "vp570"; }
+ 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:
+ UINT8 *m_ram;
+};
+
+
+// device type definition
+extern const device_type VP570;
+
+
+#endif
diff --git a/src/mess/machine/vp575.c b/src/mess/machine/vp575.c
new file mode 100644
index 00000000000..818adb6388b
--- /dev/null
+++ b/src/mess/machine/vp575.c
@@ -0,0 +1,352 @@
+/**********************************************************************
+
+ RCA VIP Expansion Board VP-575 emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "vp575.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type VP575 = &device_creator<vp575_device>;
+
+
+//-------------------------------------------------
+// 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);
+}
+
+WRITE_LINE_MEMBER( vp575_device::exp1_int_w ) { m_int[0] = state; update_interrupts(); }
+WRITE_LINE_MEMBER( vp575_device::exp2_int_w ) { m_int[1] = state; update_interrupts(); }
+WRITE_LINE_MEMBER( vp575_device::exp3_int_w ) { m_int[2] = state; update_interrupts(); }
+WRITE_LINE_MEMBER( vp575_device::exp4_int_w ) { m_int[3] = state; update_interrupts(); }
+WRITE_LINE_MEMBER( vp575_device::exp5_int_w ) { m_int[4] = state; update_interrupts(); }
+
+WRITE_LINE_MEMBER( vp575_device::exp1_dma_out_w ) { m_dma_out[0] = state; update_interrupts(); }
+WRITE_LINE_MEMBER( vp575_device::exp2_dma_out_w ) { m_dma_out[1] = state; update_interrupts(); }
+WRITE_LINE_MEMBER( vp575_device::exp3_dma_out_w ) { m_dma_out[2] = state; update_interrupts(); }
+WRITE_LINE_MEMBER( vp575_device::exp4_dma_out_w ) { m_dma_out[3] = state; update_interrupts(); }
+WRITE_LINE_MEMBER( vp575_device::exp5_dma_out_w ) { m_dma_out[4] = state; update_interrupts(); }
+
+WRITE_LINE_MEMBER( vp575_device::exp1_dma_in_w ) { m_dma_in[0] = state; update_interrupts(); }
+WRITE_LINE_MEMBER( vp575_device::exp2_dma_in_w ) { m_dma_in[1] = state; update_interrupts(); }
+WRITE_LINE_MEMBER( vp575_device::exp3_dma_in_w ) { m_dma_in[2] = state; update_interrupts(); }
+WRITE_LINE_MEMBER( vp575_device::exp4_dma_in_w ) { m_dma_in[3] = state; update_interrupts(); }
+WRITE_LINE_MEMBER( vp575_device::exp5_dma_in_w ) { m_dma_in[4] = state; update_interrupts(); }
+
+static VIP_EXPANSION_INTERFACE( expansion1_intf )
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, vp575_device, exp1_int_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, vp575_device, exp1_dma_out_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, vp575_device, exp1_dma_in_w)
+};
+
+static VIP_EXPANSION_INTERFACE( expansion2_intf )
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, vp575_device, exp2_int_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, vp575_device, exp2_dma_out_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, vp575_device, exp2_dma_in_w)
+};
+
+static VIP_EXPANSION_INTERFACE( expansion3_intf )
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, vp575_device, exp3_int_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, vp575_device, exp3_dma_out_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, vp575_device, exp3_dma_in_w)
+};
+
+static VIP_EXPANSION_INTERFACE( expansion4_intf )
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, vp575_device, exp4_int_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, vp575_device, exp4_dma_out_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, vp575_device, exp4_dma_in_w)
+};
+
+static VIP_EXPANSION_INTERFACE( expansion5_intf )
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, vp575_device, exp5_int_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, vp575_device, exp5_dma_out_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, vp575_device, exp5_dma_in_w)
+};
+
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( vp575 )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( vp575 )
+ MCFG_VIP_EXPANSION_SLOT_ADD("exp1", XTAL_3_52128MHz/2, expansion1_intf, vip_expansion_cards, NULL, NULL)
+ MCFG_VIP_EXPANSION_SLOT_ADD("exp2", XTAL_3_52128MHz/2, expansion2_intf, vip_expansion_cards, NULL, NULL)
+ MCFG_VIP_EXPANSION_SLOT_ADD("exp3", XTAL_3_52128MHz/2, expansion3_intf, vip_expansion_cards, NULL, NULL)
+ MCFG_VIP_EXPANSION_SLOT_ADD("exp4", XTAL_3_52128MHz/2, expansion4_intf, vip_expansion_cards, NULL, NULL)
+ MCFG_VIP_EXPANSION_SLOT_ADD("exp5", XTAL_3_52128MHz/2, expansion5_intf, vip_expansion_cards, NULL, NULL)
+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),
+ 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<vip_expansion_slot_device *>(subdevice("exp1"));
+ m_expansion_slot[1] = dynamic_cast<vip_expansion_slot_device *>(subdevice("exp2"));
+ m_expansion_slot[2] = dynamic_cast<vip_expansion_slot_device *>(subdevice("exp3"));
+ m_expansion_slot[3] = dynamic_cast<vip_expansion_slot_device *>(subdevice("exp4"));
+ m_expansion_slot[4] = dynamic_cast<vip_expansion_slot_device *>(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_ind16 &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/mess/machine/vp575.h b/src/mess/machine/vp575.h
new file mode 100644
index 00000000000..103b426ae58
--- /dev/null
+++ b/src/mess/machine/vp575.h
@@ -0,0 +1,96 @@
+/**********************************************************************
+
+ RCA VIP Expansion Board VP-575 emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __VP575__
+#define __VP575__
+
+#include "emu.h"
+#include "machine/vip_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 );
+ DECLARE_WRITE_LINE_MEMBER( exp2_int_w );
+ DECLARE_WRITE_LINE_MEMBER( exp3_int_w );
+ DECLARE_WRITE_LINE_MEMBER( exp4_int_w );
+ DECLARE_WRITE_LINE_MEMBER( exp5_int_w );
+ DECLARE_WRITE_LINE_MEMBER( exp1_dma_out_w );
+ DECLARE_WRITE_LINE_MEMBER( exp2_dma_out_w );
+ DECLARE_WRITE_LINE_MEMBER( exp3_dma_out_w );
+ DECLARE_WRITE_LINE_MEMBER( exp4_dma_out_w );
+ DECLARE_WRITE_LINE_MEMBER( exp5_dma_out_w );
+ DECLARE_WRITE_LINE_MEMBER( exp1_dma_in_w );
+ DECLARE_WRITE_LINE_MEMBER( exp2_dma_in_w );
+ DECLARE_WRITE_LINE_MEMBER( exp3_dma_in_w );
+ DECLARE_WRITE_LINE_MEMBER( exp4_dma_in_w );
+ DECLARE_WRITE_LINE_MEMBER( exp5_dma_in_w );
+
+ void update_interrupts();
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "vp575"; }
+ 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_ind16 &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/mess/machine/vp585.c b/src/mess/machine/vp585.c
new file mode 100644
index 00000000000..0a848be5217
--- /dev/null
+++ b/src/mess/machine/vp585.c
@@ -0,0 +1,131 @@
+/**********************************************************************
+
+ RCA VIP Expansion Keypad Interface Board VP585 emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "vp585.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type VP585 = &device_creator<vp585_device>;
+
+
+//-------------------------------------------------
+// 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),
+ device_vip_expansion_card_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// 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(ioport("J1")->read(), m_keylatch) ? CLEAR_LINE : ASSERT_LINE;
+}
+
+
+//-------------------------------------------------
+// vip_ef4_r - EF4 read
+//-------------------------------------------------
+
+int vp585_device::vip_ef4_r()
+{
+ return BIT(ioport("J2")->read(), m_keylatch) ? CLEAR_LINE : ASSERT_LINE;
+}
diff --git a/src/mess/machine/vp585.h b/src/mess/machine/vp585.h
new file mode 100644
index 00000000000..e1cc9559bce
--- /dev/null
+++ b/src/mess/machine/vp585.h
@@ -0,0 +1,55 @@
+/**********************************************************************
+
+ RCA VIP Expansion Keypad Interface Board VP585 emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __VP585__
+#define __VP585__
+
+#include "emu.h"
+#include "machine/vip_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_config_complete() { m_shortname = "vp585"; }
+ 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:
+ UINT8 m_keylatch;
+};
+
+
+// device type definition
+extern const device_type VP585;
+
+
+#endif
diff --git a/src/mess/machine/vp590.c b/src/mess/machine/vp590.c
new file mode 100644
index 00000000000..cc66a74d956
--- /dev/null
+++ b/src/mess/machine/vp590.c
@@ -0,0 +1,269 @@
+/**********************************************************************
+
+ RCA VIP Color Board VP590 emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "vp590.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define CDP1862_TAG "u2"
+#define SCREEN_TAG ":screen"
+
+#define COLOR_RAM_SIZE 0x100
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type VP590 = &device_creator<vp590_device>;
+
+
+//-------------------------------------------------
+// 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);
+}
+
+static CDP1862_INTERFACE( cgc_intf )
+{
+ SCREEN_TAG,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, vp590_device, rd_r),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, vp590_device, bd_r),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, vp590_device, gd_r),
+ RES_R(510), // R3
+ RES_R(360), // R4
+ RES_K(1), // R5
+ RES_K(1.5), // R6
+ RES_K(3.9), // R7
+ RES_K(10), // R8
+ RES_K(2), // R9
+ RES_K(3.3) // R10
+};
+
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( vp590 )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( vp590 )
+ MCFG_CDP1862_ADD(CDP1862_TAG, CPD1862_CLOCK, cgc_intf)
+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),
+ device_vip_expansion_card_interface(mconfig, *this),
+ m_cgc(*this, CDP1862_TAG)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void vp590_device::device_start()
+{
+ // allocate memory
+ m_color_ram = auto_alloc_array(machine(), UINT8, COLOR_RAM_SIZE);
+
+ // state saving
+ save_pointer(NAME(m_color_ram), COLOR_RAM_SIZE);
+ 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_ind16 &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(ioport("J1")->read(), m_keylatch) ? CLEAR_LINE : ASSERT_LINE;
+}
+
+
+//-------------------------------------------------
+// vip_ef4_r - EF4 read
+//-------------------------------------------------
+
+int vp590_device::vip_ef4_r()
+{
+ return BIT(ioport("J2")->read(), m_keylatch) ? CLEAR_LINE : ASSERT_LINE;
+}
diff --git a/src/mess/machine/vp590.h b/src/mess/machine/vp590.h
new file mode 100644
index 00000000000..f3173602d57
--- /dev/null
+++ b/src/mess/machine/vp590.h
@@ -0,0 +1,72 @@
+/**********************************************************************
+
+ RCA VIP Color Board VP590 emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __VP590__
+#define __VP590__
+
+#include "emu.h"
+#include "machine/rescap.h"
+#include "machine/vip_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_config_complete() { m_shortname = "vp590"; }
+ 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_ind16 &bitmap, const rectangle &cliprect);
+ virtual int vip_ef3_r();
+ virtual int vip_ef4_r();
+
+private:
+ required_device<cdp1862_device> m_cgc;
+
+ int m_a12;
+ UINT8 *m_color_ram;
+ UINT8 m_color;
+
+ UINT8 m_keylatch;
+};
+
+
+// device type definition
+extern const device_type VP590;
+
+
+#endif
diff --git a/src/mess/machine/vp595.c b/src/mess/machine/vp595.c
new file mode 100644
index 00000000000..eed81ea539c
--- /dev/null
+++ b/src/mess/machine/vp595.c
@@ -0,0 +1,101 @@
+/**********************************************************************
+
+ RCA VIP Simple Sound Board VP595 emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "vp595.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define CDP1863_TAG "u1"
+#define CDP1863_XTAL 440560
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type VP595 = &device_creator<vp595_device>;
+
+
+//-------------------------------------------------
+// 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),
+ 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/mess/machine/vp595.h b/src/mess/machine/vp595.h
new file mode 100644
index 00000000000..2729e14ec82
--- /dev/null
+++ b/src/mess/machine/vp595.h
@@ -0,0 +1,55 @@
+/**********************************************************************
+
+ RCA VIP Simple Sound Board VP595 emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __VP595__
+#define __VP595__
+
+#include "emu.h"
+#include "machine/vip_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_config_complete() { m_shortname = "vp595"; }
+ 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<cdp1863_device> m_pfg;
+};
+
+
+// device type definition
+extern const device_type VP595;
+
+
+#endif
diff --git a/src/mess/machine/vp620.c b/src/mess/machine/vp620.c
new file mode 100644
index 00000000000..8f6791d5d2a
--- /dev/null
+++ b/src/mess/machine/vp620.c
@@ -0,0 +1,106 @@
+/**********************************************************************
+
+ RCA VIP ASCII Keyboard Interface VP-620 emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "vp620.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type VP620 = &device_creator<vp620_device>;
+
+
+//-------------------------------------------------
+// ASCII_KEYBOARD_INTERFACE( kb_intf )
+//-------------------------------------------------
+
+WRITE8_MEMBER( vp620_device::kb_w )
+{
+ m_keydata = data;
+
+ m_keystb = ASSERT_LINE;
+}
+
+static ASCII_KEYBOARD_INTERFACE( kb_intf )
+{
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, vp620_device, kb_w)
+};
+
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( vp620 )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( vp620 )
+ MCFG_ASCII_KEYBOARD_ADD("keyboard", kb_intf)
+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),
+ 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_ef3_r()
+{
+ int state = m_keystb;
+
+ m_keystb = CLEAR_LINE;
+
+ return state;
+}
diff --git a/src/mess/machine/vp620.h b/src/mess/machine/vp620.h
new file mode 100644
index 00000000000..cd7bb568d23
--- /dev/null
+++ b/src/mess/machine/vp620.h
@@ -0,0 +1,59 @@
+/**********************************************************************
+
+ RCA VIP ASCII Keyboard Interface VP-620 emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __VP620__
+#define __VP620__
+
+#include "emu.h"
+#include "machine/keyboard.h"
+#include "machine/vip_byteio.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_config_complete() { m_shortname = "vp620"; }
+ virtual void device_start();
+
+ // device_vip_byteio_port_interface overrides
+ virtual UINT8 vip_in_r();
+ virtual int vip_ef3_r();
+
+private:
+ UINT8 m_keydata;
+ int m_keystb;
+};
+
+
+// device type definition
+extern const device_type VP620;
+
+
+#endif
diff --git a/src/mess/machine/vp700.c b/src/mess/machine/vp700.c
new file mode 100644
index 00000000000..6a6fa91609c
--- /dev/null
+++ b/src/mess/machine/vp700.c
@@ -0,0 +1,83 @@
+/**********************************************************************
+
+ RCA VIP Tiny BASIC VP-700 emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "vp700.h"
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type VP700 = &device_creator<vp700_device>;
+
+
+//-------------------------------------------------
+// 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),
+ device_vip_expansion_card_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void vp700_device::device_start()
+{
+ // find memory regions
+ m_rom = memregion("vp700")->base();
+}
+
+
+//-------------------------------------------------
+// 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 (cs)
+ {
+ *minh = 1;
+
+ data = m_rom[offset & 0xfff];
+ }
+
+ return data;
+}
diff --git a/src/mess/machine/vp700.h b/src/mess/machine/vp700.h
new file mode 100644
index 00000000000..af0bce9c92c
--- /dev/null
+++ b/src/mess/machine/vp700.h
@@ -0,0 +1,54 @@
+/**********************************************************************
+
+ RCA VIP Tiny BASIC VP-700 emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __VP700__
+#define __VP700__
+
+#include "emu.h"
+#include "machine/vip_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_config_complete() { m_shortname = "vp700"; }
+ 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:
+ const UINT8 *m_rom;
+};
+
+
+// device type definition
+extern const device_type VP700;
+
+
+#endif
diff --git a/src/mess/machine/vtech2.c b/src/mess/machine/vtech2.c
new file mode 100644
index 00000000000..aa24352c96d
--- /dev/null
+++ b/src/mess/machine/vtech2.c
@@ -0,0 +1,536 @@
+/***************************************************************************
+ vtech2.c
+
+ machine driver
+ Juergen Buchmueller <pullmoll@t-online.de> MESS driver, Jan 2000
+ Davide Moretti <dave@rimini.com> ROM dump and hardware description
+
+ TODO:
+ Add loading images from WAV files.
+ Printer and RS232 support.
+ Check if the FDC is really the same as in the
+ Laser 210/310 (aka VZ200/300) series.
+
+****************************************************************************/
+
+#include "emu.h"
+#include "includes/vtech2.h"
+#include "imagedev/flopdrv.h"
+#include "imagedev/cassette.h"
+#include "sound/speaker.h"
+
+/* public */
+
+/* static */
+
+#define TRKSIZE_VZ 0x9a0 /* arbitrary (actually from analyzing format) */
+
+static const UINT8 laser_fdc_wrprot[2] = {0x80, 0x80};
+
+/* write to banked memory (handle memory mapped i/o and videoram) */
+static void mwa_bank(running_machine &machine, int bank, int offs, int data);
+
+/* wrappers for bank #1 to #4 */
+static WRITE8_HANDLER ( mwa_bank1 ) { mwa_bank(space->machine(), 0,offset,data); }
+static WRITE8_HANDLER ( mwa_bank2 ) { mwa_bank(space->machine(), 1,offset,data); }
+static WRITE8_HANDLER ( mwa_bank3 ) { mwa_bank(space->machine(), 2,offset,data); }
+static WRITE8_HANDLER ( mwa_bank4 ) { mwa_bank(space->machine(), 3,offset,data); }
+
+/* read from banked memory (handle memory mapped i/o) */
+static int mra_bank(running_machine &machine, int bank, int offs);
+
+/* wrappers for bank #1 to #4 */
+static READ8_HANDLER ( mra_bank1 ) { return mra_bank(space->machine(),0,offset); }
+static READ8_HANDLER ( mra_bank2 ) { return mra_bank(space->machine(),1,offset); }
+static READ8_HANDLER ( mra_bank3 ) { return mra_bank(space->machine(),2,offset); }
+static READ8_HANDLER ( mra_bank4 ) { return mra_bank(space->machine(),3,offset); }
+
+/* read banked memory (handle memory mapped i/o) */
+static const struct { read8_space_func func; const char *name; } mra_bank_soft[4] =
+{
+ { FUNC(mra_bank1) }, /* mapped in 0000-3fff */
+ { FUNC(mra_bank2) }, /* mapped in 4000-7fff */
+ { FUNC(mra_bank3) }, /* mapped in 8000-bfff */
+ { FUNC(mra_bank4) } /* mapped in c000-ffff */
+};
+
+/* write banked memory (handle memory mapped i/o and videoram) */
+static const struct { write8_space_func func; const char *name; } mwa_bank_soft[4] =
+{
+ { FUNC(mwa_bank1) }, /* mapped in 0000-3fff */
+ { FUNC(mwa_bank2) }, /* mapped in 4000-7fff */
+ { FUNC(mwa_bank3) }, /* mapped in 8000-bfff */
+ { FUNC(mwa_bank4) } /* mapped in c000-ffff */
+};
+
+/* read banked memory (plain ROM/RAM) */
+static const char *const mra_bank_hard[4] =
+{
+ "bank1", /* mapped in 0000-3fff */
+ "bank2", /* mapped in 4000-7fff */
+ "bank3", /* mapped in 8000-bfff */
+ "bank4" /* mapped in c000-ffff */
+};
+
+/* write banked memory (plain ROM/RAM) */
+static const char *const mwa_bank_hard[4] =
+{
+ "bank1", /* mapped in 0000-3fff */
+ "bank2", /* mapped in 4000-7fff */
+ "bank3", /* mapped in 8000-bfff */
+ "bank4" /* mapped in c000-ffff */
+};
+
+DRIVER_INIT_MEMBER(vtech2_state,laser)
+{
+ UINT8 *gfx = machine().root_device().memregion("gfx2")->base();
+ int i;
+
+ m_laser_track_x2[0] = m_laser_track_x2[1] = 80;
+ m_laser_fdc_bits = 8;
+ m_laser_drive = -1;
+
+ for (i = 0; i < 256; i++)
+ gfx[i] = i;
+
+ m_laser_latch = -1;
+ m_mem = memregion("maincpu")->base();
+
+ for (i = 0; i < ARRAY_LENGTH(m_laser_bank); i++)
+ m_laser_bank[i] = -1;
+}
+
+
+
+static void laser_machine_init(running_machine &machine, int bank_mask, int video_mask)
+{
+ vtech2_state *state = machine.driver_data<vtech2_state>();
+ int i;
+
+ state->m_laser_bank_mask = bank_mask;
+ state->m_laser_video_bank = video_mask;
+ state->m_videoram = state->m_mem + state->m_laser_video_bank * 0x04000;
+ logerror("laser_machine_init(): bank mask $%04X, video %d [$%05X]\n", state->m_laser_bank_mask, state->m_laser_video_bank, state->m_laser_video_bank * 0x04000);
+
+ for (i = 0; i < ARRAY_LENGTH(state->m_laser_bank); i++)
+ state->laser_bank_select_w(*machine.device("maincpu")->memory().space(AS_PROGRAM), i, 0);
+}
+
+MACHINE_RESET( laser350 )
+{
+ /* banks 0 to 3 only, optional ROM extension */
+ laser_machine_init(machine, 0xf00f, 3);
+}
+
+MACHINE_RESET( laser500 )
+{
+ /* banks 0 to 2, and 4-7 only , optional ROM extension */
+ laser_machine_init(machine, 0xf0f7, 7);
+}
+
+MACHINE_RESET( laser700 )
+{
+ /* all banks except #3 */
+ laser_machine_init(machine, 0xfff7, 7);
+}
+
+
+WRITE8_MEMBER(vtech2_state::laser_bank_select_w)
+{
+ static const char *const bank_name[16] = {
+ "ROM lo","ROM hi","MM I/O","Video RAM lo",
+ "RAM #0","RAM #1","RAM #2","RAM #3",
+ "RAM #4","RAM #5","RAM #6","RAM #7/Video RAM hi",
+ "ext ROM #0","ext ROM #1","ext ROM #2","ext ROM #3"
+ };
+ char bank[10];
+ offset %= 4;
+ data &= 15;
+
+ if( data != m_laser_bank[offset] )
+ {
+ m_laser_bank[offset] = data;
+ logerror("select bank #%d $%02X [$%05X] %s\n", offset+1, data, 0x4000 * (data & 15), bank_name[data]);
+
+ /* memory mapped I/O bank selected? */
+ if (data == 2)
+ {
+ machine().device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(offset * 0x4000, offset * 0x4000 + 0x3fff, mra_bank_soft[offset].func, mra_bank_soft[offset].name);
+ machine().device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(offset * 0x4000, offset * 0x4000 + 0x3fff, mwa_bank_soft[offset].func, mwa_bank_soft[offset].name);
+ }
+ else
+ {
+ sprintf(bank,"bank%d",offset+1);
+ membank(bank)->set_base(&m_mem[0x4000*m_laser_bank[offset]]);
+ if( m_laser_bank_mask & (1 << data) )
+ {
+ /* video RAM bank selected? */
+ if( data == m_laser_video_bank )
+ {
+ logerror("select bank #%d VIDEO!\n", offset+1);
+ }
+ machine().device("maincpu")->memory().space(AS_PROGRAM)->install_read_bank(offset * 0x4000, offset * 0x4000 + 0x3fff, mra_bank_hard[offset]);
+ machine().device("maincpu")->memory().space(AS_PROGRAM)->install_write_bank(offset * 0x4000, offset * 0x4000 + 0x3fff, mwa_bank_hard[offset]);
+
+ }
+ else
+ {
+ logerror("select bank #%d MASKED!\n", offset+1);
+ machine().device("maincpu")->memory().space(AS_PROGRAM)->nop_readwrite(offset * 0x4000, offset * 0x4000 + 0x3fff);
+
+ }
+ }
+ }
+}
+
+static cassette_image_device *vtech2_cassette_image(running_machine &machine)
+{
+ return machine.device<cassette_image_device>(CASSETTE_TAG);
+}
+
+/*************************************************
+ * memory mapped I/O read
+ * bit function
+ * 7 not assigned
+ * 6 column 6
+ * 5 column 5
+ * 4 column 4
+ * 3 column 3
+ * 2 column 2
+ * 1 column 1
+ * 0 column 0
+ ************************************************/
+static int mra_bank(running_machine &machine, int bank, int offs)
+{
+ vtech2_state *state = machine.driver_data<vtech2_state>();
+ int level, data = 0xff;
+
+ /* Laser 500/700 only: keyboard rows A through D */
+ if( (offs & 0x00ff) == 0x00ff )
+ {
+ if( (offs & 0x0300) == 0x0000 ) /* keyboard row A */
+ {
+ if( machine.root_device().ioport("ROWA")->read() != state->m_row_a )
+ {
+ state->m_row_a = machine.root_device().ioport("ROWA")->read();
+ data &= state->m_row_a;
+ }
+ }
+ if( (offs & 0x0300) == 0x0100 ) /* keyboard row B */
+ {
+ if( machine.root_device().ioport("ROWB")->read() != state->m_row_b )
+ {
+ state->m_row_b = machine.root_device().ioport("ROWB")->read();
+ data &= state->m_row_b;
+ }
+ }
+ if( (offs & 0x0300) == 0x0200 ) /* keyboard row C */
+ {
+ if( machine.root_device().ioport("ROWC")->read() != state->m_row_c )
+ {
+ state->m_row_c = machine.root_device().ioport("ROWC")->read();
+ data &= state->m_row_c;
+ }
+ }
+ if( (offs & 0x0300) == 0x0300 ) /* keyboard row D */
+ {
+ if( machine.root_device().ioport("ROWD")->read() != state->m_row_d )
+ {
+ state->m_row_d = machine.root_device().ioport("ROWD")->read();
+ data &= state->m_row_d;
+ }
+ }
+ }
+ else
+ {
+ /* All Lasers keyboard rows 0 through 7 */
+ if( !(offs & 0x01) )
+ data &= machine.root_device().ioport("ROW0")->read();
+ if( !(offs & 0x02) )
+ data &= machine.root_device().ioport("ROW1")->read();
+ if( !(offs & 0x04) )
+ data &= machine.root_device().ioport("ROW2")->read();
+ if( !(offs & 0x08) )
+ data &= machine.root_device().ioport("ROW3")->read();
+ if( !(offs & 0x10) )
+ data &= machine.root_device().ioport("ROW4")->read();
+ if( !(offs & 0x20) )
+ data &= machine.root_device().ioport("ROW5")->read();
+ if( !(offs & 0x40) )
+ data &= machine.root_device().ioport("ROW6")->read();
+ if( !(offs & 0x80) )
+ data &= machine.root_device().ioport("ROW7")->read();
+ }
+
+ /* what's bit 7 good for? tape input maybe? */
+ level = (vtech2_cassette_image(machine))->input() * 65536.0;
+ if( level < state->m_level_old - 511 )
+ state->m_cassette_bit = 0x00;
+ if( level > state->m_level_old + 511 )
+ state->m_cassette_bit = 0x80;
+ state->m_level_old = level;
+
+ data &= ~state->m_cassette_bit;
+ // logerror("bank #%d keyboard_r [$%04X] $%02X\n", bank, offs, data);
+
+ return data;
+}
+
+/*************************************************
+ * memory mapped I/O write
+ * bit function
+ * 7-6 not assigned
+ * 5 speaker B ???
+ * 4 ???
+ * 3 mode: 1 graphics, 0 text
+ * 2 cassette out (MSB)
+ * 1 cassette out (LSB)
+ * 0 speaker A
+ ************************************************/
+static void mwa_bank(running_machine &machine, int bank, int offs, int data)
+{
+ vtech2_state *state = machine.driver_data<vtech2_state>();
+ device_t *speaker = machine.device(SPEAKER_TAG);
+ offs += 0x4000 * state->m_laser_bank[bank];
+ switch (state->m_laser_bank[bank])
+ {
+ case 0: /* ROM lower 16K */
+ case 1: /* ROM upper 16K */
+ logerror("bank #%d write to ROM [$%05X] $%02X\n", bank+1, offs, data);
+ break;
+ case 2: /* memory mapped output */
+ if (data != state->m_laser_latch)
+ {
+ logerror("bank #%d write to I/O [$%05X] $%02X\n", bank+1, offs, data);
+ /* Toggle between graphics and text modes? */
+ if ((data ^ state->m_laser_latch) & 0x01)
+ speaker_level_w(speaker, data & 1);
+ state->m_laser_latch = data;
+ }
+ break;
+ case 12: /* ext. ROM #1 */
+ case 13: /* ext. ROM #2 */
+ case 14: /* ext. ROM #3 */
+ case 15: /* ext. ROM #4 */
+ logerror("bank #%d write to ROM [$%05X] $%02X\n", bank+1, offs, data);
+ break;
+ default: /* RAM */
+ if( state->m_laser_bank[bank] == state->m_laser_video_bank && state->m_mem[offs] != data )
+ {
+ logerror("bank #%d write to videoram [$%05X] $%02X\n", bank+1, offs, data);
+ }
+ state->m_mem[offs] = data;
+ break;
+ }
+}
+
+DEVICE_IMAGE_LOAD( laser_cart )
+{
+ vtech2_state *state = image.device().machine().driver_data<vtech2_state>();
+ int size = 0;
+
+ size = image.fread(&state->m_mem[0x30000], 0x10000);
+ state->m_laser_bank_mask &= ~0xf000;
+ if( size > 0 )
+ state->m_laser_bank_mask |= 0x1000;
+ if( size > 0x4000 )
+ state->m_laser_bank_mask |= 0x2000;
+ if( size > 0x8000 )
+ state->m_laser_bank_mask |= 0x4000;
+ if( size > 0xc000 )
+ state->m_laser_bank_mask |= 0x8000;
+
+ return size > 0 ? IMAGE_INIT_PASS : IMAGE_INIT_FAIL;
+}
+
+DEVICE_IMAGE_UNLOAD( laser_cart )
+{
+ vtech2_state *state = image.device().machine().driver_data<vtech2_state>();
+ state->m_laser_bank_mask &= ~0xf000;
+ /* wipe out the memory contents to be 100% sure */
+ memset(&state->m_mem[0x30000], 0xff, 0x10000);
+}
+
+static device_t *laser_file(running_machine &machine)
+{
+ vtech2_state *state = machine.driver_data<vtech2_state>();
+ return machine.device( state->m_laser_drive ? FLOPPY_1 : FLOPPY_0 );
+}
+
+static void laser_get_track(running_machine &machine)
+{
+ vtech2_state *state = machine.driver_data<vtech2_state>();
+ sprintf(state->m_laser_frame_message, "#%d get track %02d", state->m_laser_drive, state->m_laser_track_x2[state->m_laser_drive]/2);
+ state->m_laser_frame_time = 30;
+ /* drive selected or and image file ok? */
+ if( state->m_laser_drive >= 0 && laser_file(machine) != NULL )
+ {
+ int size, offs;
+ device_image_interface *image = dynamic_cast<device_image_interface *>(laser_file(machine));
+ size = TRKSIZE_VZ;
+ offs = TRKSIZE_VZ * state->m_laser_track_x2[state->m_laser_drive]/2;
+ image->fseek(offs, SEEK_SET);
+ size = image->fread(state->m_laser_fdc_data, size);
+ logerror("get track @$%05x $%04x bytes\n", offs, size);
+ }
+ state->m_laser_fdc_offs = 0;
+ state->m_laser_fdc_write = 0;
+}
+
+static void laser_put_track(running_machine &machine)
+{
+ vtech2_state *state = machine.driver_data<vtech2_state>();
+ device_image_interface *image = dynamic_cast<device_image_interface *>(laser_file(machine));
+ /* drive selected and image file ok? */
+ if( state->m_laser_drive >= 0 && laser_file(machine) != NULL )
+ {
+ int size, offs;
+ offs = TRKSIZE_VZ * state->m_laser_track_x2[state->m_laser_drive]/2;
+ image->fseek(offs + state->m_laser_fdc_start, SEEK_SET);
+ size = image->fwrite(&state->m_laser_fdc_data[state->m_laser_fdc_start], state->m_laser_fdc_write);
+ logerror("put track @$%05X+$%X $%04X/$%04X bytes\n", offs, state->m_laser_fdc_start, size, state->m_laser_fdc_write);
+ }
+}
+
+#define PHI0(n) (((n)>>0)&1)
+#define PHI1(n) (((n)>>1)&1)
+#define PHI2(n) (((n)>>2)&1)
+#define PHI3(n) (((n)>>3)&1)
+
+READ8_MEMBER(vtech2_state::laser_fdc_r)
+{
+ int data = 0xff;
+ switch( offset )
+ {
+ case 1: /* data (read-only) */
+ if( m_laser_fdc_bits > 0 )
+ {
+ if( m_laser_fdc_status & 0x80 )
+ m_laser_fdc_bits--;
+ data = (m_laser_data >> m_laser_fdc_bits) & 0xff;
+#if 0
+ logerror("laser_fdc_r bits %d%d%d%d%d%d%d%d\n",
+ (data>>7)&1,(data>>6)&1,(data>>5)&1,(data>>4)&1,
+ (data>>3)&1,(data>>2)&1,(data>>1)&1,(data>>0)&1 );
+#endif
+ }
+ if( m_laser_fdc_bits == 0 )
+ {
+ m_laser_data = m_laser_fdc_data[m_laser_fdc_offs];
+ logerror("laser_fdc_r %d : data ($%04X) $%02X\n", offset, m_laser_fdc_offs, m_laser_data);
+ if( m_laser_fdc_status & 0x80 )
+ {
+ m_laser_fdc_bits = 8;
+ m_laser_fdc_offs = (m_laser_fdc_offs + 1) % TRKSIZE_FM;
+ }
+ m_laser_fdc_status &= ~0x80;
+ }
+ break;
+ case 2: /* polling (read-only) */
+ /* fake */
+ if( m_laser_drive >= 0 )
+ m_laser_fdc_status |= 0x80;
+ data = m_laser_fdc_status;
+ break;
+ case 3: /* write protect status (read-only) */
+ if( m_laser_drive >= 0 )
+ data = laser_fdc_wrprot[m_laser_drive];
+ logerror("laser_fdc_r %d : write_protect $%02X\n", offset, data);
+ break;
+ }
+ return data;
+}
+
+WRITE8_MEMBER(vtech2_state::laser_fdc_w)
+{
+ int drive;
+
+ switch( offset )
+ {
+ case 0: /* latch (write-only) */
+ drive = (data & 0x10) ? 0 : (data & 0x80) ? 1 : -1;
+ if( drive != m_laser_drive )
+ {
+ m_laser_drive = drive;
+ if( m_laser_drive >= 0 )
+ laser_get_track(machine());
+ }
+ if( m_laser_drive >= 0 )
+ {
+ if( (PHI0(data) && !(PHI1(data) || PHI2(data) || PHI3(data)) && PHI1(m_laser_fdc_latch)) ||
+ (PHI1(data) && !(PHI0(data) || PHI2(data) || PHI3(data)) && PHI2(m_laser_fdc_latch)) ||
+ (PHI2(data) && !(PHI0(data) || PHI1(data) || PHI3(data)) && PHI3(m_laser_fdc_latch)) ||
+ (PHI3(data) && !(PHI0(data) || PHI1(data) || PHI2(data)) && PHI0(m_laser_fdc_latch)) )
+ {
+ if( m_laser_track_x2[m_laser_drive] > 0 )
+ m_laser_track_x2[m_laser_drive]--;
+ logerror("laser_fdc_w(%d) $%02X drive %d: stepout track #%2d.%d\n", offset, data, m_laser_drive, m_laser_track_x2[m_laser_drive]/2,5*(m_laser_track_x2[m_laser_drive]&1));
+ if( (m_laser_track_x2[m_laser_drive] & 1) == 0 )
+ laser_get_track(machine());
+ }
+ else
+ if( (PHI0(data) && !(PHI1(data) || PHI2(data) || PHI3(data)) && PHI3(m_laser_fdc_latch)) ||
+ (PHI1(data) && !(PHI0(data) || PHI2(data) || PHI3(data)) && PHI0(m_laser_fdc_latch)) ||
+ (PHI2(data) && !(PHI0(data) || PHI1(data) || PHI3(data)) && PHI1(m_laser_fdc_latch)) ||
+ (PHI3(data) && !(PHI0(data) || PHI1(data) || PHI2(data)) && PHI2(m_laser_fdc_latch)) )
+ {
+ if( m_laser_track_x2[m_laser_drive] < 2*40 )
+ m_laser_track_x2[m_laser_drive]++;
+ logerror("laser_fdc_w(%d) $%02X drive %d: stepin track #%2d.%d\n", offset, data, m_laser_drive, m_laser_track_x2[m_laser_drive]/2,5*(m_laser_track_x2[m_laser_drive]&1));
+ if( (m_laser_track_x2[m_laser_drive] & 1) == 0 )
+ laser_get_track(machine());
+ }
+ if( (data & 0x40) == 0 )
+ {
+ m_laser_data <<= 1;
+ if( (m_laser_fdc_latch ^ data) & 0x20 )
+ m_laser_data |= 1;
+ if( (m_laser_fdc_edge ^= 1) == 0 )
+ {
+ if( --m_laser_fdc_bits == 0 )
+ {
+ UINT8 value = 0;
+ m_laser_data &= 0xffff;
+ if( m_laser_data & 0x4000 ) value |= 0x80;
+ if( m_laser_data & 0x1000 ) value |= 0x40;
+ if( m_laser_data & 0x0400 ) value |= 0x20;
+ if( m_laser_data & 0x0100 ) value |= 0x10;
+ if( m_laser_data & 0x0040 ) value |= 0x08;
+ if( m_laser_data & 0x0010 ) value |= 0x04;
+ if( m_laser_data & 0x0004 ) value |= 0x02;
+ if( m_laser_data & 0x0001 ) value |= 0x01;
+ logerror("laser_fdc_w(%d) data($%04X) $%02X <- $%02X ($%04X)\n", offset, m_laser_fdc_offs, m_laser_fdc_data[m_laser_fdc_offs], value, m_laser_data);
+ m_laser_fdc_data[m_laser_fdc_offs] = value;
+ m_laser_fdc_offs = (m_laser_fdc_offs + 1) % TRKSIZE_FM;
+ m_laser_fdc_write++;
+ m_laser_fdc_bits = 8;
+ }
+ }
+ }
+ /* change of write signal? */
+ if( (m_laser_fdc_latch ^ data) & 0x40 )
+ {
+ /* falling edge? */
+ if ( m_laser_fdc_latch & 0x40 )
+ {
+ sprintf(m_laser_frame_message, "#%d put track %02d", m_laser_drive, m_laser_track_x2[m_laser_drive]/2);
+ m_laser_frame_time = 30;
+ m_laser_fdc_start = m_laser_fdc_offs;
+ m_laser_fdc_edge = 0;
+ }
+ else
+ {
+ /* data written to track before? */
+ if( m_laser_fdc_write )
+ laser_put_track(machine());
+ }
+ m_laser_fdc_bits = 8;
+ m_laser_fdc_write = 0;
+ }
+ }
+ m_laser_fdc_latch = data;
+ break;
+ }
+}
+
+
diff --git a/src/mess/machine/wangpc_emb.c b/src/mess/machine/wangpc_emb.c
new file mode 100644
index 00000000000..0fdfdea3854
--- /dev/null
+++ b/src/mess/machine/wangpc_emb.c
@@ -0,0 +1,176 @@
+/**********************************************************************
+
+ Wang PC-PM031-B Extended Memory Board emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "wangpc_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<wangpc_emb_device>;
+
+
+
+//**************************************************************************
+// 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),
+ device_wangpcbus_card_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void wangpc_emb_device::device_start()
+{
+ // allocate memory
+ m_ram = auto_alloc_array(machine(), UINT16, RAM_SIZE);
+
+ // state saving
+ save_pointer(NAME(m_ram), RAM_SIZE);
+ 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/mess/machine/wangpc_emb.h b/src/mess/machine/wangpc_emb.h
new file mode 100644
index 00000000000..855a55c37f1
--- /dev/null
+++ b/src/mess/machine/wangpc_emb.h
@@ -0,0 +1,58 @@
+/**********************************************************************
+
+ Wang PC-PM031-B Extended Memory Board emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __WANGPC_EMB__
+#define __WANGPC_EMB__
+
+
+#include "emu.h"
+#include "machine/wangpcbus.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();
+ virtual void device_config_complete() { m_shortname = "wangpc_emb"; }
+
+ // 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:
+ UINT16 *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/mess/machine/wangpc_lic.c b/src/mess/machine/wangpc_lic.c
new file mode 100644
index 00000000000..0ecf501e481
--- /dev/null
+++ b/src/mess/machine/wangpc_lic.c
@@ -0,0 +1,160 @@
+/**********************************************************************
+
+ Wang PC Network card emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "wangpc_lic.h"
+
+
+
+//**************************************************************************
+// MACROS/CONSTANTS
+//**************************************************************************
+
+#define OPTION_ID 0x30
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type WANGPC_LIC = &device_creator<wangpc_lic_device>;
+
+
+//-------------------------------------------------
+// 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),
+ 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/mess/machine/wangpc_lic.h b/src/mess/machine/wangpc_lic.h
new file mode 100644
index 00000000000..e3fdaa4ef60
--- /dev/null
+++ b/src/mess/machine/wangpc_lic.h
@@ -0,0 +1,56 @@
+/**********************************************************************
+
+ Wang PC-PM070 Local Interconnect option card emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __WANGPC_LIC__
+#define __WANGPC_LIC__
+
+
+#include "emu.h"
+#include "machine/wangpcbus.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();
+ virtual void device_config_complete() { m_shortname = "wangpc_lic"; }
+
+ // 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/mess/machine/wangpc_lvc.c b/src/mess/machine/wangpc_lvc.c
new file mode 100644
index 00000000000..30671a66019
--- /dev/null
+++ b/src/mess/machine/wangpc_lvc.c
@@ -0,0 +1,363 @@
+/**********************************************************************
+
+ Wang PC Low-Resolution Video Controller emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ TODO:
+
+ - cursor
+ - scroll
+ - option bit 1?
+
+*/
+
+#include "wangpc_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<wangpc_lvc_device>;
+
+
+//-------------------------------------------------
+// mc6845_interface crtc_intf
+//-------------------------------------------------
+
+void wangpc_lvc_device::crtc_update_row(mc6845_device *device, bitmap_rgb32 &bitmap, const rectangle &cliprect, UINT16 ma, UINT8 ra, UINT16 y, UINT8 x_count, INT8 cursor_x, void *param)
+{
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+
+ 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(y, x) = palette[color];
+
+ 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(y, x) = palette[color];
+
+ data <<= 1;
+ }
+
+ addr += 2;
+ }
+ }
+}
+
+static MC6845_UPDATE_ROW( wangpc_lvc_update_row )
+{
+ wangpc_lvc_device *lvc = downcast<wangpc_lvc_device *>(device->owner());
+
+ lvc->crtc_update_row(device, bitmap, cliprect, ma, ra, y, x_count, cursor_x, param);
+}
+
+WRITE_LINE_MEMBER( wangpc_lvc_device::vsync_w )
+{
+ if (OPTION_VSYNC && state)
+ {
+ set_irq(ASSERT_LINE);
+ }
+}
+
+static const mc6845_interface crtc_intf =
+{
+ SCREEN_TAG,
+ 8,
+ NULL,
+ wangpc_lvc_update_row,
+ NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, wangpc_lvc_device, vsync_w),
+ NULL
+};
+
+
+//-------------------------------------------------
+// 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_PALETTE_LENGTH(16)
+
+ MCFG_MC6845_ADD(MC6845_TAG, MC6845_1, XTAL_14_31818MHz/16, crtc_intf)
+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),
+ device_wangpcbus_card_interface(mconfig, *this),
+ m_crtc(*this, MC6845_TAG),
+ m_option(0),
+ m_irq(CLEAR_LINE)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void wangpc_lvc_device::device_start()
+{
+ // allocate memory
+ m_video_ram = auto_alloc_array(machine(), UINT16, RAM_SIZE);
+
+ // state saving
+ save_pointer(NAME(m_video_ram), RAM_SIZE);
+ 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;
+
+ palette_set_color_rgb(machine(), index, r, g, b);
+ }
+ break;
+
+ case 0x70/2:
+ set_irq(CLEAR_LINE);
+ break;
+ }
+ }
+}
diff --git a/src/mess/machine/wangpc_lvc.h b/src/mess/machine/wangpc_lvc.h
new file mode 100644
index 00000000000..7e604090d58
--- /dev/null
+++ b/src/mess/machine/wangpc_lvc.h
@@ -0,0 +1,71 @@
+/**********************************************************************
+
+ Wang PC Low-Resolution Video Controller emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __WANGPC_LVC__
+#define __WANGPC_LVC__
+
+
+#include "emu.h"
+#include "machine/wangpcbus.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
+ void crtc_update_row(mc6845_device *device, bitmap_rgb32 &bitmap, const rectangle &cliprect, UINT16 ma, UINT8 ra, UINT16 y, UINT8 x_count, INT8 cursor_x, void *param);
+ DECLARE_WRITE_LINE_MEMBER( vsync_w );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "wangpc_lvc"; }
+
+ // 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);
+
+ // internal state
+ required_device<mc6845_device> m_crtc;
+
+ UINT16 *m_video_ram;
+ UINT8 m_option;
+ UINT16 m_scroll;
+ int m_irq;
+};
+
+
+// device type definition
+extern const device_type WANGPC_LVC;
+
+
+#endif
diff --git a/src/mess/machine/wangpc_mcc.c b/src/mess/machine/wangpc_mcc.c
new file mode 100644
index 00000000000..6c850f4c2c5
--- /dev/null
+++ b/src/mess/machine/wangpc_mcc.c
@@ -0,0 +1,336 @@
+/**********************************************************************
+
+ Wang PC-PM043 Multiport Communications Controller emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ TODO:
+
+ - all
+
+*/
+
+#include "wangpc_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<wangpc_mcc_device>;
+
+
+//-------------------------------------------------
+// Z80DART_INTERFACE( sio_intf )
+//-------------------------------------------------
+
+static Z80DART_INTERFACE( sio_intf )
+{
+ 0, 0, 0, 0,
+
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// Z80DART_INTERFACE( dart_intf )
+//-------------------------------------------------
+
+static Z80DART_INTERFACE( dart_intf )
+{
+ 0, 0, 0, 0,
+
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( wangpc_mcc )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( wangpc_mcc )
+ MCFG_Z80SIO2_ADD(Z80SIO2_TAG, 4000000, sio_intf)
+ MCFG_Z80DART_ADD(Z80DART_TAG, 4000000, dart_intf)
+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),
+ 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:
+ if (ACCESSING_BITS_0_7)
+ {
+ data = 0xff00 | m_sio->data_read(offset & 0x01);
+ }
+ break;
+
+ case 0x04/2:
+ case 0x06/2:
+ if (ACCESSING_BITS_0_7)
+ {
+ data = 0xff00 | m_sio->control_read(offset & 0x01);
+ }
+ break;
+
+ case 0x08/2:
+ case 0x0a/2:
+ if (ACCESSING_BITS_0_7)
+ {
+ data = 0xff00 | m_dart->data_read(offset & 0x01);
+ }
+ break;
+
+ case 0x0c/2:
+ case 0x0e/2:
+ if (ACCESSING_BITS_0_7)
+ {
+ data = 0xff00 | m_dart->control_read(offset & 0x01);
+ }
+ 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:
+ m_sio->data_write(offset & 0x01, data & 0xff);
+ break;
+
+ case 0x04/2:
+ case 0x06/2:
+ m_sio->control_write(offset & 0x01, data & 0xff);
+ break;
+
+ case 0x08/2:
+ case 0x0a/2:
+ m_dart->data_write(offset & 0x01, data & 0xff);
+ break;
+
+ case 0x0c/2:
+ case 0x0e/2:
+ m_dart->control_write(offset & 0x01, 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/mess/machine/wangpc_mcc.h b/src/mess/machine/wangpc_mcc.h
new file mode 100644
index 00000000000..dedc47649c9
--- /dev/null
+++ b/src/mess/machine/wangpc_mcc.h
@@ -0,0 +1,63 @@
+/**********************************************************************
+
+ Wang PC-PM043 Multiport Communications Controller emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __WANGPC_MCC__
+#define __WANGPC_MCC__
+
+
+#include "emu.h"
+#include "machine/wangpcbus.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();
+ virtual void device_config_complete() { m_shortname = "wangpc_mcc"; }
+
+ // 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<z80dart_device> m_sio;
+ required_device<z80dart_device> m_dart;
+
+ UINT8 m_option;
+ int m_irq;
+};
+
+
+// device type definition
+extern const device_type WANGPC_MCC;
+
+
+#endif
diff --git a/src/mess/machine/wangpc_mvc.c b/src/mess/machine/wangpc_mvc.c
new file mode 100644
index 00000000000..32a6546113d
--- /dev/null
+++ b/src/mess/machine/wangpc_mvc.c
@@ -0,0 +1,354 @@
+/**********************************************************************
+
+ Wang PC PM-001B Medium-Resolution Video Controller emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ TODO:
+
+ - character clock
+ - blink
+
+*/
+
+#include "wangpc_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)
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type WANGPC_MVC = &device_creator<wangpc_mvc_device>;
+
+
+//-------------------------------------------------
+// mc6845_interface crtc_intf
+//-------------------------------------------------
+
+void wangpc_mvc_device::crtc_update_row(mc6845_device *device, bitmap_rgb32 &bitmap, const rectangle &cliprect, UINT16 ma, UINT8 ra, UINT16 y, UINT8 x_count, INT8 cursor_x, void *param)
+{
+ const rgb_t *palette = palette_entry_list_raw(bitmap.palette());
+
+ 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);
+
+ bitmap.pix32(y, x) = palette[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(y, x)) & ATTR_BOLD) color = 2;
+ if (color) bitmap.pix32(y, x) = palette[color];
+
+ data <<= 1;
+ }
+ }
+}
+
+static MC6845_UPDATE_ROW( wangpc_mvc_update_row )
+{
+ wangpc_mvc_device *mvc = downcast<wangpc_mvc_device *>(device->owner());
+
+ mvc->crtc_update_row(device, bitmap, cliprect, ma, ra, y, x_count, cursor_x, param);
+}
+
+WRITE_LINE_MEMBER( wangpc_mvc_device::vsync_w )
+{
+ if (OPTION_VSYNC && state)
+ {
+ set_irq(ASSERT_LINE);
+ }
+}
+
+static const mc6845_interface crtc_intf =
+{
+ SCREEN_TAG,
+ 10,
+ NULL,
+ wangpc_mvc_update_row,
+ NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, wangpc_mvc_device, vsync_w),
+ NULL
+};
+
+
+//-------------------------------------------------
+// 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_PALETTE_LENGTH(3)
+
+ MCFG_MC6845_ADD(MC6845_TAG, MC6845_1, XTAL_14_31818MHz/16, crtc_intf)
+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),
+ device_wangpcbus_card_interface(mconfig, *this),
+ m_crtc(*this, MC6845_TAG),
+ m_option(0),
+ m_irq(CLEAR_LINE)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void wangpc_mvc_device::device_start()
+{
+ // allocate memory
+ m_video_ram = auto_alloc_array(machine(), UINT16, VIDEO_RAM_SIZE);
+ m_char_ram = auto_alloc_array(machine(), UINT16, CHAR_RAM_SIZE);
+ m_bitmap_ram = auto_alloc_array(machine(), UINT16, BITMAP_RAM_SIZE);
+
+ // initialize palette
+ palette_set_color_rgb(machine(), 0, 0, 0, 0);
+ palette_set_color_rgb(machine(), 1, 0, 0x80, 0);
+ palette_set_color_rgb(machine(), 2, 0, 0xff, 0);
+
+ // state saving
+ save_pointer(NAME(m_video_ram), VIDEO_RAM_SIZE);
+ save_pointer(NAME(m_char_ram), CHAR_RAM_SIZE);
+ save_pointer(NAME(m_bitmap_ram), BITMAP_RAM_SIZE);
+ 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/mess/machine/wangpc_mvc.h b/src/mess/machine/wangpc_mvc.h
new file mode 100644
index 00000000000..ea9d8cd372b
--- /dev/null
+++ b/src/mess/machine/wangpc_mvc.h
@@ -0,0 +1,72 @@
+/**********************************************************************
+
+ Wang PC PM-001B Medium-Resolution Video Controller emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __WANGPC_MVC__
+#define __WANGPC_MVC__
+
+
+#include "emu.h"
+#include "machine/wangpcbus.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
+ void crtc_update_row(mc6845_device *device, bitmap_rgb32 &bitmap, const rectangle &cliprect, UINT16 ma, UINT8 ra, UINT16 y, UINT8 x_count, INT8 cursor_x, void *param);
+ DECLARE_WRITE_LINE_MEMBER( vsync_w );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "wangpc_mvc"; }
+
+ // 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);
+
+ // internal state
+ required_device<mc6845_device> m_crtc;
+
+ UINT16 *m_video_ram;
+ UINT16 *m_char_ram;
+ UINT16 *m_bitmap_ram;
+ UINT8 m_option;
+ int m_irq;
+};
+
+
+// device type definition
+extern const device_type WANGPC_MVC;
+
+
+#endif
diff --git a/src/mess/machine/wangpc_rtc.c b/src/mess/machine/wangpc_rtc.c
new file mode 100644
index 00000000000..35ffa95f04b
--- /dev/null
+++ b/src/mess/machine/wangpc_rtc.c
@@ -0,0 +1,349 @@
+/**********************************************************************
+
+ Wang PC-PM040-B Remote Telecommunication controller emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "wangpc_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<wangpc_rtc_device>;
+
+
+//-------------------------------------------------
+// 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_LEGACY(Z80SIO_TAG, z80dart_cd_ba_r, z80dart_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 }
+};
+
+
+//-------------------------------------------------
+// I8237_INTERFACE( dmac_intf )
+//-------------------------------------------------
+
+static I8237_INTERFACE( dmac_intf )
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ { DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL, },
+ { DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL, },
+ { DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL }
+};
+
+
+//-------------------------------------------------
+// Z80CTC_INTERFACE( ctc0_intf )
+//-------------------------------------------------
+
+static Z80CTC_INTERFACE( ctc0_intf )
+{
+ DEVCB_CPU_INPUT_LINE(Z80_TAG, INPUT_LINE_IRQ0),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// Z80CTC_INTERFACE( ctc1_intf )
+//-------------------------------------------------
+
+static Z80CTC_INTERFACE( ctc1_intf )
+{
+ DEVCB_CPU_INPUT_LINE(Z80_TAG, INPUT_LINE_IRQ0),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// Z80DART_INTERFACE( sio_intf )
+//-------------------------------------------------
+
+static Z80DART_INTERFACE( sio_intf )
+{
+ 0, 0, 0, 0,
+
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+
+ DEVCB_CPU_INPUT_LINE(Z80_TAG, INPUT_LINE_IRQ0)
+};
+
+
+//-------------------------------------------------
+// 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_I8237_ADD(AM9517A_TAG, 2000000, dmac_intf)
+ MCFG_Z80CTC_ADD(Z80CTC_0_TAG, 2000000, ctc0_intf)
+ MCFG_Z80CTC_ADD(Z80CTC_1_TAG, 2000000, ctc1_intf)
+ MCFG_Z80DART_ADD(Z80SIO_TAG, 2000000, sio_intf)
+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),
+ 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)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void wangpc_rtc_device::device_start()
+{
+}
+
+
+//-------------------------------------------------
+// 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/mess/machine/wangpc_rtc.h b/src/mess/machine/wangpc_rtc.h
new file mode 100644
index 00000000000..37f5bf24a6d
--- /dev/null
+++ b/src/mess/machine/wangpc_rtc.h
@@ -0,0 +1,70 @@
+/**********************************************************************
+
+ Wang PC-PM040-B Remote Telecommunication controller emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __WANGPC_RTC__
+#define __WANGPC_RTC__
+
+
+#include "emu.h"
+#include "cpu/z80/z80.h"
+#include "machine/am9517a.h"
+#include "machine/wangpcbus.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();
+ virtual void device_config_complete() { m_shortname = "wangpc_rtc"; }
+
+ // 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<cpu_device> m_maincpu;
+ required_device<am9517a_device> m_dmac;
+ required_device<z80ctc_device> m_ctc0;
+ required_device<z80ctc_device> m_ctc1;
+ required_device<z80dart_device> m_sio;
+
+ UINT8 m_char_ram[256];
+};
+
+
+// device type definition
+extern const device_type WANGPC_RTC;
+
+
+#endif
diff --git a/src/mess/machine/wangpc_tig.c b/src/mess/machine/wangpc_tig.c
new file mode 100644
index 00000000000..03b5bea2b9e
--- /dev/null
+++ b/src/mess/machine/wangpc_tig.c
@@ -0,0 +1,342 @@
+/**********************************************************************
+
+ Wang PC Text/Image/Graphics controller emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ TODO:
+
+ - all
+
+*/
+
+#include "wangpc_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<wangpc_tig_device>;
+
+
+//-------------------------------------------------
+// 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, 8, 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
+
+static UPD7220_DRAW_TEXT_LINE( hgdc_display_text)
+{
+}
+
+static UPD7220_INTERFACE( hgdc0_intf )
+{
+ SCREEN_TAG,
+ NULL,
+ hgdc_display_text,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// UPD7220_INTERFACE( hgdc1_intf )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( upd7220_1_map, AS_0, 8, wangpc_tig_device )
+ ADDRESS_MAP_GLOBAL_MASK(0xffff)
+ AM_RANGE(0x0000, 0xffff) AM_RAM // graphics memory
+ADDRESS_MAP_END
+
+static UPD7220_DISPLAY_PIXELS( hgdc_display_pixels )
+{
+}
+
+static UPD7220_INTERFACE( hgdc1_intf )
+{
+ SCREEN_TAG,
+ hgdc_display_pixels,
+ NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// 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_LENGTH(3)
+
+ MCFG_UPD7220_ADD(UPD7720_0_TAG, XTAL_52_832MHz/10, hgdc0_intf, upd7220_0_map)
+ MCFG_UPD7220_ADD(UPD7720_1_TAG, XTAL_52_832MHz/16, hgdc1_intf, upd7220_1_map)
+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),
+ device_wangpcbus_card_interface(mconfig, *this),
+ m_hgdc0(*this, UPD7720_0_TAG),
+ m_hgdc1(*this, UPD7720_1_TAG),
+ m_option(0)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void wangpc_tig_device::device_start()
+{
+ // initialize palette
+ palette_set_color_rgb(machine(), 0, 0, 0, 0);
+ palette_set_color_rgb(machine(), 1, 0, 0x80, 0);
+ palette_set_color_rgb(machine(), 2, 0, 0xff, 0);
+
+ // 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_ind16 &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/mess/machine/wangpc_tig.h b/src/mess/machine/wangpc_tig.h
new file mode 100644
index 00000000000..c091cff615b
--- /dev/null
+++ b/src/mess/machine/wangpc_tig.h
@@ -0,0 +1,68 @@
+/**********************************************************************
+
+ Wang PC PM-001B Medium-Resolution Video Controller emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __WANGPC_TIG__
+#define __WANGPC_TIG__
+
+
+#include "emu.h"
+#include "machine/wangpcbus.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_ind16 &bitmap, const rectangle &cliprect);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "wangpc_tig"; }
+
+ // 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<upd7220_device> m_hgdc0;
+ required_device<upd7220_device> m_hgdc1;
+
+ UINT8 m_option;
+ UINT8 m_attr[16];
+ UINT8 m_underline;
+};
+
+
+// device type definition
+extern const device_type WANGPC_TIG;
+
+
+#endif
diff --git a/src/mess/machine/wangpc_wdc.c b/src/mess/machine/wangpc_wdc.c
new file mode 100644
index 00000000000..663c580a7ec
--- /dev/null
+++ b/src/mess/machine/wangpc_wdc.c
@@ -0,0 +1,356 @@
+/**********************************************************************
+
+ Wang PC-PM001 Winchester Disk Controller emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "wangpc_wdc.h"
+#include "machine/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<wangpc_wdc_device>;
+
+
+//-------------------------------------------------
+// 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
+
+
+//-------------------------------------------------
+// Z80CTC_INTERFACE( ctc_intf )
+//-------------------------------------------------
+
+static Z80CTC_INTERFACE( ctc_intf )
+{
+ DEVCB_CPU_INPUT_LINE(Z80_TAG, INPUT_LINE_IRQ0), // interrupt handler
+ DEVCB_NULL, // ZC/TO0 callback
+ DEVCB_NULL, // ZC/TO1 callback
+ DEVCB_NULL // ZC/TO2 callback
+};
+
+
+//-------------------------------------------------
+// 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_Z80CTC_ADD(MK3882_TAG, 2000000, ctc_intf)
+
+ 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),
+ 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(0); };
+WRITE8_MEMBER( wangpc_wdc_device::ctc_ch0_w ) { m_ctc->write(0, data); };
+READ8_MEMBER( wangpc_wdc_device::ctc_ch1_r ) { return m_ctc->read(1); };
+WRITE8_MEMBER( wangpc_wdc_device::ctc_ch1_w ) { m_ctc->write(1, data); };
+READ8_MEMBER( wangpc_wdc_device::ctc_ch2_r ) { return m_ctc->read(2); };
+WRITE8_MEMBER( wangpc_wdc_device::ctc_ch2_w ) { m_ctc->write(2, data); };
+READ8_MEMBER( wangpc_wdc_device::ctc_ch3_r ) { return m_ctc->read(3); };
+WRITE8_MEMBER( wangpc_wdc_device::ctc_ch3_w ) { m_ctc->write(3, data); };
diff --git a/src/mess/machine/wangpc_wdc.h b/src/mess/machine/wangpc_wdc.h
new file mode 100644
index 00000000000..98710a75dd4
--- /dev/null
+++ b/src/mess/machine/wangpc_wdc.h
@@ -0,0 +1,84 @@
+/**********************************************************************
+
+ Wang PC-PM001 Winchester Disk Controller emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __WANGPC_WDC__
+#define __WANGPC_WDC__
+
+
+#include "emu.h"
+#include "cpu/z80/z80.h"
+#include "imagedev/harddriv.h"
+#include "machine/wangpcbus.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();
+ virtual void device_config_complete() { m_shortname = "wangpc_wdc"; }
+
+ // 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<cpu_device> m_maincpu;
+ required_device<z80ctc_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/mess/machine/wangpcbus.c b/src/mess/machine/wangpcbus.c
new file mode 100644
index 00000000000..0e35cb00288
--- /dev/null
+++ b/src/mess/machine/wangpcbus.c
@@ -0,0 +1,328 @@
+/**********************************************************************
+
+ Wang Professional Computer bus emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "emu.h"
+#include "emuopts.h"
+#include "machine/wangpcbus.h"
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type WANGPC_BUS_SLOT = &device_creator<wangpcbus_slot_device>;
+
+
+
+//**************************************************************************
+// 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),
+ 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<wangpcbus_slot_device &>(device);
+ wangpcbus_card.m_sid = sid;
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void wangpcbus_slot_device::device_start()
+{
+ m_bus = machine().device<wangpcbus_device>(WANGPC_BUS_TAG);
+ device_wangpcbus_card_interface *dev = dynamic_cast<device_wangpcbus_card_interface *>(get_card_device());
+ if (dev) m_bus->add_wangpcbus_card(dev, m_sid);
+}
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type WANGPC_BUS = &device_creator<wangpcbus_device>;
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void wangpcbus_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const wangpcbus_interface *intf = reinterpret_cast<const wangpcbus_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<wangpcbus_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_irq2_cb, 0, sizeof(m_out_irq2_cb));
+ memset(&m_out_irq3_cb, 0, sizeof(m_out_irq3_cb));
+ memset(&m_out_irq4_cb, 0, sizeof(m_out_irq4_cb));
+ memset(&m_out_irq5_cb, 0, sizeof(m_out_irq5_cb));
+ memset(&m_out_irq6_cb, 0, sizeof(m_out_irq6_cb));
+ memset(&m_out_irq7_cb, 0, sizeof(m_out_irq7_cb));
+ memset(&m_out_drq1_cb, 0, sizeof(m_out_drq1_cb));
+ memset(&m_out_drq2_cb, 0, sizeof(m_out_drq2_cb));
+ memset(&m_out_drq3_cb, 0, sizeof(m_out_drq3_cb));
+ memset(&m_out_ioerror_cb, 0, sizeof(m_out_ioerror_cb));
+ }
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// 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)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void wangpcbus_device::device_start()
+{
+ // resolve callbacks
+ m_out_irq2_func.resolve(m_out_irq2_cb, *this);
+ m_out_irq3_func.resolve(m_out_irq3_cb, *this);
+ m_out_irq4_func.resolve(m_out_irq4_cb, *this);
+ m_out_irq5_func.resolve(m_out_irq5_cb, *this);
+ m_out_irq6_func.resolve(m_out_irq6_cb, *this);
+ m_out_irq7_func.resolve(m_out_irq7_cb, *this);
+ m_out_drq1_func.resolve(m_out_drq1_cb, *this);
+ m_out_drq2_func.resolve(m_out_drq2_cb, *this);
+ m_out_drq3_func.resolve(m_out_drq3_cb, *this);
+ m_out_ioerror_func.resolve(m_out_ioerror_cb, *this);
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void wangpcbus_device::device_reset()
+{
+}
+
+
+//-------------------------------------------------
+// add_wangpcbus_card - add S100 card
+//-------------------------------------------------
+
+void wangpcbus_device::add_wangpcbus_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();
+ }
+}
+
+
+WRITE_LINE_MEMBER( wangpcbus_device::irq2_w ) { m_out_irq2_func(state); }
+WRITE_LINE_MEMBER( wangpcbus_device::irq3_w ) { m_out_irq3_func(state); }
+WRITE_LINE_MEMBER( wangpcbus_device::irq4_w ) { m_out_irq4_func(state); }
+WRITE_LINE_MEMBER( wangpcbus_device::irq5_w ) { m_out_irq5_func(state); }
+WRITE_LINE_MEMBER( wangpcbus_device::irq6_w ) { m_out_irq6_func(state); }
+WRITE_LINE_MEMBER( wangpcbus_device::irq7_w ) { m_out_irq7_func(state); }
+WRITE_LINE_MEMBER( wangpcbus_device::drq1_w ) { m_out_drq1_func(state); }
+WRITE_LINE_MEMBER( wangpcbus_device::drq2_w ) { m_out_drq2_func(state); }
+WRITE_LINE_MEMBER( wangpcbus_device::drq3_w ) { m_out_drq3_func(state); }
+WRITE_LINE_MEMBER( wangpcbus_device::ioerror_w ) { m_out_ioerror_func(state); }
+
+
+//-------------------------------------------------
+// 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();
+ }
+}
+
+READ8_MEMBER( wangpcbus_device::dack0_r ) { return dack_r(space, 0); }
+WRITE8_MEMBER( wangpcbus_device::dack0_w ) { dack_w(space, 0, data); }
+READ8_MEMBER( wangpcbus_device::dack1_r ) { return dack_r(space, 1); }
+WRITE8_MEMBER( wangpcbus_device::dack1_w ) { dack_w(space, 1, data); }
+READ8_MEMBER( wangpcbus_device::dack2_r ) { return dack_r(space, 2); }
+WRITE8_MEMBER( wangpcbus_device::dack2_w ) { dack_w(space, 2, data); }
+READ8_MEMBER( wangpcbus_device::dack3_r ) { return dack_r(space, 3); }
+WRITE8_MEMBER( wangpcbus_device::dack3_w ) { dack_w(space, 3, data); }
+
+
+//-------------------------------------------------
+// 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<wangpcbus_slot_device *>(device.owner());
+}
+
+
+//-------------------------------------------------
+// ~device_wangpcbus_card_interface - destructor
+//-------------------------------------------------
+
+device_wangpcbus_card_interface::~device_wangpcbus_card_interface()
+{
+}
diff --git a/src/mess/machine/wangpcbus.h b/src/mess/machine/wangpcbus.h
new file mode 100644
index 00000000000..8f0777a1298
--- /dev/null
+++ b/src/mess/machine/wangpcbus.h
@@ -0,0 +1,207 @@
+/**********************************************************************
+
+ Wang Professional Computer bus emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+
+
+**********************************************************************/
+
+#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(_config) \
+ MCFG_DEVICE_ADD(WANGPC_BUS_TAG, WANGPC_BUS, 0) \
+ MCFG_DEVICE_CONFIG(_config)
+
+
+#define WANGPC_BUS_INTERFACE(_name) \
+ const wangpcbus_interface (_name) =
+
+
+#define MCFG_WANGPC_BUS_SLOT_ADD(_tag, _sid, _slot_intf, _def_slot, _def_inp) \
+ MCFG_DEVICE_ADD(_tag, WANGPC_BUS_SLOT, 0) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false) \
+ wangpcbus_slot_device::static_set_wangpcbus_slot(*device, _sid);
+
+
+
+//**************************************************************************
+// 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;
+
+
+// ======================> wangpcbus_interface
+
+struct wangpcbus_interface
+{
+ 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;
+ devcb_write_line m_out_ioerror_cb;
+};
+
+class device_wangpcbus_card_interface;
+
+
+// ======================> wangpcbus_device
+
+class wangpcbus_device : public device_t,
+ public wangpcbus_interface
+{
+public:
+ // construction/destruction
+ wangpcbus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ void add_wangpcbus_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 );
+ DECLARE_WRITE8_MEMBER( dack0_w );
+ DECLARE_READ8_MEMBER( dack1_r );
+ DECLARE_WRITE8_MEMBER( dack1_w );
+ DECLARE_READ8_MEMBER( dack2_r );
+ DECLARE_WRITE8_MEMBER( dack2_w );
+ DECLARE_READ8_MEMBER( dack3_r );
+ DECLARE_WRITE8_MEMBER( dack3_w );
+
+ DECLARE_WRITE_LINE_MEMBER( tc_w );
+
+ // peripheral interface
+ 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 );
+ DECLARE_WRITE_LINE_MEMBER( ioerror_w );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete();
+
+private:
+ devcb_resolved_write_line m_out_irq2_func;
+ devcb_resolved_write_line m_out_irq3_func;
+ devcb_resolved_write_line m_out_irq4_func;
+ devcb_resolved_write_line m_out_irq5_func;
+ devcb_resolved_write_line m_out_irq6_func;
+ devcb_resolved_write_line m_out_irq7_func;
+ devcb_resolved_write_line m_out_drq1_func;
+ devcb_resolved_write_line m_out_drq2_func;
+ devcb_resolved_write_line m_out_drq3_func;
+ devcb_resolved_write_line m_out_ioerror_func;
+
+ simple_list<device_wangpcbus_card_interface> 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;
+};
+
+#endif
diff --git a/src/mess/machine/wangpckb.c b/src/mess/machine/wangpckb.c
new file mode 100644
index 00000000000..2bc846daa8c
--- /dev/null
+++ b/src/mess/machine/wangpckb.c
@@ -0,0 +1,583 @@
+/**********************************************************************
+
+ Wang PC keyboard emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+/*
+
+PCB Layout
+----------
+
+Key Tronic A65-02454-002
+PCB 201
+
+|-----------------------------------------------------------------------|
+| LS273 PSG 555 LS04 4MHz LS132 CN1 LS374 XR |
+| CPU |
+| LD1 LD2 LD3 LD4 LD5 |
+| SW1 LS259 SW2 LS259 |
+| |
+| |
+| |
+| |
+| |
+| |
+| |
+|-----------------------------------------------------------------------|
+
+Notes:
+ Relevant IC's shown.
+
+ CPU - Intel P8051AH "20-8051-225"
+ PSG - Texas Instruments SN76496N
+ XR - Exar Semiconductor XR22-908-03B? (hard to read)
+ CN1 - 1x6 pin PCB header
+ SW1 - 8-way DIP switch
+ SW2 - 8-way DIP switch
+
+*/
+
+/*
+
+ TODO:
+
+ - rewrite the mcs51.c serial I/O to replace this horrible, horrible hack
+ - dip switches
+
+*/
+
+#include "wangpckb.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LOG 0
+
+#define I8051_TAG "z5"
+#define SN76496_TAG "z4"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type WANGPC_KEYBOARD = &device_creator<wangpc_keyboard_device>;
+
+
+
+//-------------------------------------------------
+// ROM( wangpc_keyboard )
+//-------------------------------------------------
+
+ROM_START( wangpc_keyboard )
+ ROM_REGION( 0x1000, I8051_TAG, 0 )
+ ROM_LOAD( "20-8051-225.z5", 0x0000, 0x1000, CRC(82d2999f) SHA1(2bb34a1de2d94b2885d9e8fcd4964296f6276c5c) )
+ROM_END
+
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *wangpc_keyboard_device::device_rom_region() const
+{
+ return ROM_NAME( wangpc_keyboard );
+}
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( wangpc_keyboard_io )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( wangpc_keyboard_io, AS_IO, 8, wangpc_keyboard_device )
+ //AM_RANGE(0x0000, 0xfeff) AM_READNOP
+ AM_RANGE(0x47, 0x58) AM_MIRROR(0xff00) AM_READNOP
+ AM_RANGE(0x00, 0x00) AM_MIRROR(0xff00) AM_DEVWRITE(SN76496_TAG, sn76496_new_device, write)
+ AM_RANGE(MCS51_PORT_P1, MCS51_PORT_P1) AM_READWRITE(kb_p1_r, kb_p1_w)
+ AM_RANGE(MCS51_PORT_P2, MCS51_PORT_P2) AM_WRITE(kb_p2_w)
+ AM_RANGE(MCS51_PORT_P3, MCS51_PORT_P3) AM_WRITE(kb_p3_w)
+ADDRESS_MAP_END
+
+
+//-------------------------------------------------
+// sn76496_config psg_intf
+//-------------------------------------------------
+
+static const sn76496_config psg_intf =
+{
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( wangpc_keyboard )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( wangpc_keyboard )
+ MCFG_CPU_ADD(I8051_TAG, I8051, XTAL_4MHz)
+ MCFG_CPU_IO_MAP(wangpc_keyboard_io)
+
+ // sound hardware
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+ MCFG_SOUND_ADD(SN76496_TAG, SN76496_NEW, 2000000) // ???
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00)
+ MCFG_SOUND_CONFIG(psg_intf)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor wangpc_keyboard_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( wangpc_keyboard );
+}
+
+
+//-------------------------------------------------
+// INPUT_PORTS( wangpc_keyboard )
+//-------------------------------------------------
+
+INPUT_PORTS_START( wangpc_keyboard )
+ PORT_START("Y0")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("\xE2\x86\x90") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) // 2b
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) // 63
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("EXEC") PORT_CODE(KEYCODE_INSERT) PORT_CHAR(UCHAR_MAMEKEY(INSERT)) // 53
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("DELETE") PORT_CODE(KEYCODE_END) PORT_CHAR(UCHAR_MAMEKEY(END)) // 52
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) // 43
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(UTF8_UP) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) // 29
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("\xE2\x86\x96") // 26
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(UTF8_RIGHT) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) // 2e
+
+ PORT_START("Y1")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+') // 64
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED ) // 1f
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED ) // 21
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_NAME("GL") // 54
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('"')// 45
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("ENTER") PORT_CODE(KEYCODE_ENTER) PORT_CHAR('\r') // 44
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("RIGHT SHIFT") PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) // 35
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(UTF8_LEFT) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) // 2d
+
+ PORT_START("Y2")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') // 65
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_') // 2f
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') // 56
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR(']') // 55
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':') // 46
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) // 22
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) // 23
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') // 37
+
+ PORT_START("Y3")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*') // 67
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') // 66
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') // 58
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') // 57
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') // 48
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') // 47
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<') // 38
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>') // 2a
+
+ PORT_START("Y4")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("6 \xC2\xA3") PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR(0xa3) // 69
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&') // 68
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') // 5a
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') // 59
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') // 4a
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') // 49
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') // 3a
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') // 39
+
+ PORT_START("Y5")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') // 6b
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') // 6a
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') // 5c
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') // 5b
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') // 4c
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') // 4b
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') // 3c
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') // 3b
+
+ PORT_START("Y6")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@') // 6d
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') // 6c
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') // 5e
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') // 5d
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') // 4e
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') // 4d
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') // 3e
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') // 3d
+
+ PORT_START("Y7")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("\xE2\x87\xA4") PORT_CODE(KEYCODE_TILDE) // 1f
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') // 6e
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("\xE2\x87\xA5") PORT_CODE(KEYCODE_TAB) PORT_CHAR('\t') // 6f
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') // 5f
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("LOCK") PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) // 1e
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') // 4f
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("LEFT SHIFT") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) // 1b
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') // 3f
+
+ PORT_START("Y8")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("STOP") PORT_CODE(KEYCODE_F8) // 77
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("SRCH") PORT_CODE(KEYCODE_F9) // 76
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad ENTER") PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD)) // 1c
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad . ;") PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD)) // 32
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) // 33
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 0 '") PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD)) // 34
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) // 35
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(UTF8_DOWN) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) // 28
+
+ PORT_START("Y9")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("MERGE") PORT_CODE(KEYCODE_F6) // 79
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("NOTE") PORT_CODE(KEYCODE_F7) // 78
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("GOTO") // 11
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("CANCEL") // 12
+ 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_KEYBOARD ) PORT_NAME("2ND") PORT_CODE(KEYCODE_RCONTROL) PORT_CHAR(UCHAR_MAMEKEY(RCONTROL)) // 25
+
+ PORT_START("YA")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("DEC TAB") PORT_CODE(KEYCODE_F4) // 7b
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("FORMAT") PORT_CODE(KEYCODE_F5) // 7a
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("\xE2\x86\x95") // 71
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("(blank)") // 70
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("SPACE") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') // 2c
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) // 27
+
+ PORT_START("YB")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("PAGE") PORT_CODE(KEYCODE_F2) // 7d
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("CENTER") PORT_CODE(KEYCODE_F3) // 7c
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("MOVE") PORT_CODE(KEYCODE_F12) // 73
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("COMMAND") // 72
+ 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("YC")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("HELP") PORT_CODE(KEYCODE_ESC) // 36
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("INDENT") PORT_CODE(KEYCODE_F1) // 7e
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("REPLC") PORT_CODE(KEYCODE_F10) // 75
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("COPY") PORT_CODE(KEYCODE_F11) // 74
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("CTRL") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) // 24
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) // 1d
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("YD")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad \xC3\x97") PORT_CODE(KEYCODE_ASTERISK) PORT_CHAR(UCHAR_MAMEKEY(ASTERISK)) // 14
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad \xC3\xB7") PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD)) // 18
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("PRINT") // 19
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED ) // 20
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(PLUS_PAD)) PORT_NAME("ERASE") // 1a
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) // 1c
+
+ PORT_START("YE")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad + *") PORT_CODE(KEYCODE_NUMLOCK) PORT_CHAR(UCHAR_MAMEKEY(NUMLOCK))// 60
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad - !") PORT_CODE(KEYCODE_SLASH_PAD) PORT_CHAR(UCHAR_MAMEKEY(SLASH_PAD)) // 13
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 8 >") PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD)) // 15
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 9 "UTF8_UP) PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD)) // 16
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 5 ]") PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD)) // 40
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 6 $") PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD)) // 17
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 3 #") PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD)) // 10
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) // 1b
+
+ PORT_START("YF")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("INSERT") PORT_CODE(KEYCODE_HOME) PORT_CHAR(UCHAR_MAMEKEY(HOME)) // 62
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("PREV") PORT_CODE(KEYCODE_PGUP) PORT_CHAR(UCHAR_MAMEKEY(PGUP)) // 61
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("NEXT") PORT_CODE(KEYCODE_PGDN) PORT_CHAR(UCHAR_MAMEKEY(PGDN)) // 51
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 7 <") PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD)) // 50
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) // 42
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 4 [") PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD)) // 41
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 1 &") PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) // 31
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Keypad 2 @") PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) // 30
+
+ PORT_START("SW1")
+ PORT_DIPNAME( 0x01, 0x01, DEF_STR( Unknown ) ) PORT_DIPLOCATION("SW1:1")
+ PORT_DIPSETTING( 0x01, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x02, 0x02, DEF_STR( Unknown ) ) PORT_DIPLOCATION("SW1:2")
+ PORT_DIPSETTING( 0x02, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x04, 0x04, DEF_STR( Unknown ) ) PORT_DIPLOCATION("SW1:3")
+ PORT_DIPSETTING( 0x04, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x08, 0x08, DEF_STR( Unknown ) ) PORT_DIPLOCATION("SW1:4")
+ PORT_DIPSETTING( 0x08, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x10, 0x10, DEF_STR( Unknown ) ) PORT_DIPLOCATION("SW1:5")
+ PORT_DIPSETTING( 0x10, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x20, 0x20, DEF_STR( Unknown ) ) PORT_DIPLOCATION("SW1:6")
+ PORT_DIPSETTING( 0x20, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x40, 0x40, DEF_STR( Unknown ) ) PORT_DIPLOCATION("SW1:7")
+ PORT_DIPSETTING( 0x40, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x80, 0x80, DEF_STR( Unknown ) ) PORT_DIPLOCATION("SW1:8")
+ PORT_DIPSETTING( 0x80, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+
+ PORT_START("SW2")
+ PORT_DIPNAME( 0x01, 0x01, DEF_STR( Unknown ) ) PORT_DIPLOCATION("SW2:1")
+ PORT_DIPSETTING( 0x01, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x02, 0x02, DEF_STR( Unknown ) ) PORT_DIPLOCATION("SW2:2")
+ PORT_DIPSETTING( 0x02, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x04, 0x04, DEF_STR( Unknown ) ) PORT_DIPLOCATION("SW2:3")
+ PORT_DIPSETTING( 0x04, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x08, 0x08, DEF_STR( Unknown ) ) PORT_DIPLOCATION("SW2:4")
+ PORT_DIPSETTING( 0x08, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x10, 0x10, DEF_STR( Unknown ) ) PORT_DIPLOCATION("SW2:5")
+ PORT_DIPSETTING( 0x10, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x20, 0x20, DEF_STR( Unknown ) ) PORT_DIPLOCATION("SW2:6")
+ PORT_DIPSETTING( 0x20, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x40, 0x40, DEF_STR( Unknown ) ) PORT_DIPLOCATION("SW2:7")
+ PORT_DIPSETTING( 0x40, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x80, 0x80, DEF_STR( Unknown ) ) PORT_DIPLOCATION("SW2:8")
+ PORT_DIPSETTING( 0x80, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+INPUT_PORTS_END
+
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+ioport_constructor wangpc_keyboard_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( wangpc_keyboard );
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// wangpc_keyboard_device - constructor
+//-------------------------------------------------
+
+wangpc_keyboard_device::wangpc_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, WANGPC_KEYBOARD, "Wang PC Keyboard", tag, owner, clock),
+ device_serial_interface(mconfig, *this),
+ m_maincpu(*this, I8051_TAG)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void wangpc_keyboard_device::device_start()
+{
+ // set serial callbacks
+ i8051_set_serial_tx_callback(m_maincpu, wangpc_keyboard_device::mcs51_tx_callback);
+ i8051_set_serial_rx_callback(m_maincpu, wangpc_keyboard_device::mcs51_rx_callback);
+ set_data_frame(8, 2, SERIAL_PARITY_NONE);
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void wangpc_keyboard_device::device_reset()
+{
+ transmit_register_reset();
+ receive_register_reset();
+
+ set_out_data_bit(1);
+ serial_connection_out();
+}
+
+
+//-------------------------------------------------
+// input_callback -
+//-------------------------------------------------
+
+void wangpc_keyboard_device::input_callback(UINT8 state)
+{
+ int bit = (state & SERIAL_STATE_RX_DATA) ? 1 : 0;
+
+ receive_register_update_bit(bit);
+
+ if (is_receive_register_full())
+ {
+ m_maincpu->set_input_line(MCS51_RX_LINE, ASSERT_LINE);
+ receive_register_extract();
+
+ if (LOG) logerror("Wang PC keyboard receive data %02x\n", get_received_char());
+ }
+}
+
+
+//-------------------------------------------------
+// mcs51_rx_callback -
+//-------------------------------------------------
+
+int wangpc_keyboard_device::mcs51_rx_callback(device_t *device)
+{
+ wangpc_keyboard_device *kb = static_cast<wangpc_keyboard_device *>(device->owner());
+
+ return kb->get_received_char();
+}
+
+
+//-------------------------------------------------
+// mcs51_tx_callback -
+//-------------------------------------------------
+
+void wangpc_keyboard_device::mcs51_tx_callback(device_t *device, int data)
+{
+ wangpc_keyboard_device *kb = static_cast<wangpc_keyboard_device *>(device->owner());
+
+ if (LOG) logerror("Wang PC keyboard transmit data %02x\n", data);
+
+ kb->transmit_register_setup(data);
+
+ // HACK bang the bits out immediately
+ while (!kb->is_transmit_register_empty())
+ {
+ kb->transmit_register_send_bit();
+ }
+}
+
+
+//-------------------------------------------------
+// kb_p1_r -
+//-------------------------------------------------
+
+READ8_MEMBER( wangpc_keyboard_device::kb_p1_r )
+{
+ UINT8 data = 0xff;
+
+ switch (m_y & 0x0f)
+ {
+ case 0: data &= ioport("Y0")->read(); break;
+ case 1: data &= ioport("Y1")->read(); break;
+ case 2: data &= ioport("Y2")->read(); break;
+ case 3: data &= ioport("Y3")->read(); break;
+ case 4: data &= ioport("Y4")->read(); break;
+ case 5: data &= ioport("Y5")->read(); break;
+ case 6: data &= ioport("Y6")->read(); break;
+ case 7: data &= ioport("Y7")->read(); break;
+ case 8: data &= ioport("Y8")->read(); break;
+ case 9: data &= ioport("Y9")->read(); break;
+ case 0xa: data &= ioport("YA")->read(); break;
+ case 0xb: data &= ioport("YB")->read(); break;
+ case 0xc: data &= ioport("YC")->read(); break;
+ case 0xd: data &= ioport("YD")->read(); break;
+ case 0xe: data &= ioport("YE")->read(); break;
+ case 0xf: data &= ioport("YF")->read(); break;
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// kb_p1_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( wangpc_keyboard_device::kb_p1_w )
+{
+ /*
+
+ bit description
+
+ P1.0 led 0
+ P1.1 led 1
+ P1.2 led 2
+ P1.3 led 3
+ P1.4 led 4
+ P1.5 led 5
+ P1.6
+ P1.7
+
+ */
+
+ for (int i = 0; i < 6; i++)
+ {
+ output_set_led_value(i, !BIT(data, i));
+ }
+
+ if (LOG) logerror("P1 %02x\n", data);
+}
+
+
+//-------------------------------------------------
+// kb_p2_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( wangpc_keyboard_device::kb_p2_w )
+{
+ /*
+
+ bit description
+
+ P2.0 row 0
+ P2.1 row 1
+ P2.2 row 2
+ P2.3 row 3
+ P2.4
+ P2.5
+ P2.6 chip enable for something
+ P2.7
+
+ */
+
+ m_y = data & 0x0f;
+
+ if (LOG) logerror("P2 %02x\n", data);
+}
+
+
+//-------------------------------------------------
+// kb_p3_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( wangpc_keyboard_device::kb_p3_w )
+{
+ /*
+
+ bit description
+
+ P3.0 RxD
+ P3.1 TxD
+ P3.2
+ P3.3 chip enable for something
+ P3.4
+ P3.5
+ P3.6
+ P3.7
+
+ */
+
+ if (LOG) logerror("P3 %02x\n", data);
+}
diff --git a/src/mess/machine/wangpckb.h b/src/mess/machine/wangpckb.h
new file mode 100644
index 00000000000..4385b87f2fb
--- /dev/null
+++ b/src/mess/machine/wangpckb.h
@@ -0,0 +1,87 @@
+/**********************************************************************
+
+ Wang PC keyboard emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#pragma once
+
+#ifndef __WANGPC_KEYBOARD__
+#define __WANGPC_KEYBOARD__
+
+
+#include "emu.h"
+#include "cpu/mcs51/mcs51.h"
+#include "sound/sn76496.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define WANGPC_KEYBOARD_TAG "wangpckb"
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_WANGPC_KEYBOARD_ADD() \
+ MCFG_DEVICE_ADD(WANGPC_KEYBOARD_TAG, WANGPC_KEYBOARD, 0)
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> wangpc_keyboard_device
+
+class wangpc_keyboard_device : public device_t,
+ public device_serial_interface
+{
+public:
+ // construction/destruction
+ wangpc_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( kb_p1_r );
+ DECLARE_WRITE8_MEMBER( kb_p1_w );
+ DECLARE_WRITE8_MEMBER( kb_p2_w );
+ DECLARE_WRITE8_MEMBER( kb_p3_w );
+
+ static int mcs51_rx_callback(device_t *device);
+ static void mcs51_tx_callback(device_t *device, int data);
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "wangpckb"; }
+ virtual void device_start();
+ virtual void device_reset();
+
+ // device_serial_interface overrides
+ virtual void input_callback(UINT8 state);
+
+private:
+ required_device<cpu_device> m_maincpu;
+
+ UINT8 m_y;
+};
+
+
+// device type definition
+extern const device_type WANGPC_KEYBOARD;
+
+
+
+#endif
diff --git a/src/mess/machine/wd11c00_17.c b/src/mess/machine/wd11c00_17.c
new file mode 100644
index 00000000000..7806eef35f9
--- /dev/null
+++ b/src/mess/machine/wd11c00_17.c
@@ -0,0 +1,495 @@
+/**********************************************************************
+
+ Western Digital WD11C00-17 PC/XT Host Interface Logic Device
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#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<wd11c00_17_device>;
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void wd11c00_17_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const wd11c00_17_interface *intf = reinterpret_cast<const wd11c00_17_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<wd11c00_17_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_irq5_cb, 0, sizeof(m_out_irq5_cb));
+ memset(&m_out_drq3_cb, 0, sizeof(m_out_drq3_cb));
+ memset(&m_out_mr_cb, 0, sizeof(m_out_mr_cb));
+ memset(&m_out_busy_cb, 0, sizeof(m_out_busy_cb));
+ memset(&m_out_req_cb, 0, sizeof(m_out_req_cb));
+ memset(&m_out_ra3_cb, 0, sizeof(m_out_ra3_cb));
+ memset(&m_in_rd322_cb, 0, sizeof(m_in_rd322_cb));
+ memset(&m_in_ramcs_cb, 0, sizeof(m_in_ramcs_cb));
+ memset(&m_out_ramwr_cb, 0, sizeof(m_out_ramwr_cb));
+ memset(&m_in_cs1010_cb, 0, sizeof(m_in_cs1010_cb));
+ memset(&m_out_cs1010_cb, 0, sizeof(m_out_cs1010_cb));
+ }
+}
+
+
+
+//**************************************************************************
+// 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_func(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_func(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_func(drq3);
+ m_drq3 = drq3;
+ }
+
+ int busy = (m_status & STATUS_BUSY) ? 0 : 1;
+
+ if (m_busy != busy)
+ {
+ m_out_busy_func(busy);
+ m_busy = busy;
+ }
+
+ int req = (m_status & STATUS_REQ) ? 1 : 0;
+
+ if (m_req != req)
+ {
+ m_out_req_func(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_func(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_func(m_ra & 0x7ff, data);
+
+ increment_address();
+ }
+}
+
+
+//-------------------------------------------------
+// software_reset -
+//-------------------------------------------------
+
+inline void wd11c00_17_device::software_reset()
+{
+ m_out_mr_func(ASSERT_LINE);
+ m_out_mr_func(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),
+ m_status(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_func.resolve(m_out_irq5_cb, *this);
+ m_out_drq3_func.resolve(m_out_drq3_cb, *this);
+ m_out_mr_func.resolve(m_out_mr_cb, *this);
+ m_out_busy_func.resolve(m_out_busy_cb, *this);
+ m_out_req_func.resolve(m_out_req_cb, *this);
+ m_out_ra3_func.resolve(m_out_ra3_cb, *this);
+ m_in_rd322_func.resolve(m_in_rd322_cb, *this);
+ m_in_ramcs_func.resolve(m_in_ramcs_cb, *this);
+ m_out_ramwr_func.resolve(m_out_ramwr_cb, *this);
+ m_in_cs1010_func.resolve(m_in_cs1010_cb, *this);
+ m_out_cs1010_func.resolve(m_out_cs1010_cb, *this);
+}
+
+
+//-------------------------------------------------
+// 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_func(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_func(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_func(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/mess/machine/wd11c00_17.h b/src/mess/machine/wd11c00_17.h
new file mode 100644
index 00000000000..dbd2fa8e7cb
--- /dev/null
+++ b/src/mess/machine/wd11c00_17.h
@@ -0,0 +1,128 @@
+/**********************************************************************
+
+ Western Digital WD11C00-17 PC/XT Host Interface Logic Device
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __WD11C00_17__
+#define __WD11C00_17__
+
+
+#include "emu.h"
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_WD11C00_17_ADD(_tag, _clock, _config) \
+ MCFG_DEVICE_ADD(_tag, WD11C00_17, _clock) \
+ MCFG_DEVICE_CONFIG(_config)
+
+
+#define WD11C00_17_INTERFACE(_name) \
+ const wd11c00_17_interface (_name) =
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> wd11c00_17_interface
+
+struct wd11c00_17_interface
+{
+ 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;
+};
+
+
+// ======================> wd11c00_17_device
+
+class wd11c00_17_device : public device_t,
+ public wd11c00_17_interface
+{
+public:
+ // construction/destruction
+ wd11c00_17_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ 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();
+ virtual void device_config_complete();
+
+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_resolved_write_line m_out_irq5_func;
+ devcb_resolved_write_line m_out_drq3_func;
+ devcb_resolved_write_line m_out_mr_func;
+ devcb_resolved_write_line m_out_busy_func;
+ devcb_resolved_write_line m_out_req_func;
+ devcb_resolved_write_line m_out_ra3_func;
+ devcb_resolved_read8 m_in_rd322_func;
+ devcb_resolved_read8 m_in_ramcs_func;
+ devcb_resolved_write8 m_out_ramwr_func;
+ devcb_resolved_read8 m_in_cs1010_func;
+ devcb_resolved_write8 m_out_cs1010_func;
+
+ 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/mess/machine/wd1772.c b/src/mess/machine/wd1772.c
new file mode 100644
index 00000000000..43db7961c4d
--- /dev/null
+++ b/src/mess/machine/wd1772.c
@@ -0,0 +1,1779 @@
+/***************************************************************************
+
+ Copyright Olivier Galibert
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name 'MAME' nor the names of its contributors may be
+ used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+****************************************************************************/
+
+#include "wd1772.h"
+
+#include "debugger.h"
+
+const device_type WD1770x = &device_creator<wd1770_t>;
+const device_type WD1772x = &device_creator<wd1772_t>;
+const device_type WD1773x = &device_creator<wd1773_t>;
+
+wd177x_t::wd177x_t(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)
+{
+}
+
+void wd177x_t::device_start()
+{
+ 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 = false;
+ floppy = 0;
+
+ 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(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 wd177x_t::device_reset()
+{
+ command = 0x00;
+ main_state = IDLE;
+ sub_state = IDLE;
+ cur_live.state = IDLE;
+ track = 0x00;
+ sector = 0x00;
+ status = 0x00;
+ data = 0x00;
+ cmd_buffer = track_buffer = sector_buffer = -1;
+ counter = 0;
+ status_type_1 = true;
+ last_dir = 1;
+ intrq = false;
+ drq = false;
+ live_abort();
+}
+
+void wd177x_t::set_floppy(floppy_image_device *_floppy)
+{
+ if(floppy == _floppy)
+ return;
+
+ if(floppy) {
+ floppy->mon_w(1);
+ floppy->setup_index_pulse_cb(floppy_image_device::index_pulse_cb());
+ }
+
+ floppy = _floppy;
+
+ if(floppy) {
+ if(has_motor())
+ floppy->mon_w(status & S_MON ? 0 : 1);
+ floppy->setup_index_pulse_cb(floppy_image_device::index_pulse_cb(FUNC(wd177x_t::index_callback), this));
+ }
+}
+
+void wd177x_t::setup_intrq_cb(line_cb cb)
+{
+ intrq_cb = cb;
+}
+
+void wd177x_t::setup_drq_cb(line_cb cb)
+{
+ drq_cb = cb;
+}
+
+void wd177x_t::dden_w(bool _dden)
+{
+ dden = _dden;
+}
+
+astring wd177x_t::tts(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;
+}
+
+astring wd177x_t::ttsn()
+{
+ return tts(machine().time());
+}
+
+void wd177x_t::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ 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 wd177x_t::command_end()
+{
+ main_state = sub_state = IDLE;
+ status &= ~S_BUSY;
+ intrq = true;
+ motor_timeout = 0;
+ if(!intrq_cb.isnull())
+ intrq_cb(intrq);
+}
+
+void wd177x_t::seek_start(int state)
+{
+ main_state = state;
+ status = (status & ~(S_CRC|S_RNF|S_SPIN)) | S_BUSY;
+ sub_state = has_motor() ? SPINUP : SPINUP_DONE;
+ status_type_1 = true;
+ seek_continue();
+}
+
+void wd177x_t::seek_continue()
+{
+ for(;;) {
+ switch(sub_state) {
+ case SPINUP:
+ if(!(status & S_MON)) {
+ spinup();
+ return;
+ }
+ if(!(command & 0x08))
+ status |= S_SPIN;
+ sub_state = SPINUP_DONE;
+ break;
+
+ case SPINUP_WAIT:
+ return;
+
+ case SPINUP_DONE:
+ if(main_state == RESTORE && floppy && !floppy->trk00_r())
+ sub_state = SEEK_DONE;
+
+ if(main_state == SEEK && track == data)
+ sub_state = SEEK_DONE;
+
+ if(sub_state == SPINUP_DONE) {
+ counter = 0;
+ sub_state = SEEK_MOVE;
+ }
+ break;
+
+ case SEEK_MOVE:
+ 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_time(command & 3));
+ return;
+
+ case SEEK_WAIT_STEP_TIME:
+ return;
+
+ case SEEK_WAIT_STEP_TIME_DONE: {
+ 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, 120000);
+ return;
+ } else
+ sub_state = SEEK_DONE;
+
+ } else
+ sub_state = SEEK_MOVE;
+
+ break;
+ }
+
+ case SEEK_WAIT_STABILIZATION_TIME:
+ return;
+
+ case SEEK_WAIT_STABILIZATION_TIME_DONE:
+ sub_state = SEEK_DONE;
+ break;
+
+ case SEEK_DONE:
+ if(command & 0x04) {
+ sub_state = SCAN_ID;
+ counter = 0;
+ live_start(SEARCH_ADDRESS_MARK_HEADER);
+ return;
+ }
+ command_end();
+ return;
+
+ case SCAN_ID:
+ 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:
+ status |= S_RNF;
+ command_end();
+ return;
+
+ default:
+ logerror("%s: seek unknown sub-state %d\n", ttsn().cstr(), sub_state);
+ return;
+ }
+ }
+}
+
+bool wd177x_t::sector_matches() const
+{
+ if(cur_live.idbuf[0] != track || cur_live.idbuf[2] != sector)
+ return false;
+ if(!has_side_check())
+ return true;
+ if(command & 8)
+ return cur_live.idbuf[1] & 1;
+ else
+ return !(cur_live.idbuf[1] & 1);
+}
+
+void wd177x_t::read_sector_start()
+{
+ main_state = READ_SECTOR;
+ status = (status & ~(S_CRC|S_LOST|S_RNF|S_WP|S_DDM)) | S_BUSY;
+ drop_drq();
+ sub_state = has_motor() ? SPINUP : SPINUP_DONE;
+ status_type_1 = false;
+ read_sector_continue();
+}
+
+void wd177x_t::read_sector_continue()
+{
+ for(;;) {
+ switch(sub_state) {
+ case SPINUP:
+ if(!(status & S_MON)) {
+ spinup();
+ return;
+ }
+ sub_state = SPINUP_DONE;
+ break;
+
+ case SPINUP_WAIT:
+ return;
+
+ case SPINUP_DONE:
+ if(command & 4) {
+ sub_state = SETTLE_WAIT;
+ delay_cycles(t_gen, settle_time());
+ return;
+ } else {
+ sub_state = SETTLE_DONE;
+ break;
+ }
+
+ case SETTLE_WAIT:
+ return;
+
+ case SETTLE_DONE:
+ sub_state = SCAN_ID;
+ counter = 0;
+ live_start(SEARCH_ADDRESS_MARK_HEADER);
+ return;
+
+ case SCAN_ID:
+ 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 = 128 << (cur_live.idbuf[3] & 3);
+ sub_state = SECTOR_READ;
+ live_start(SEARCH_ADDRESS_MARK_DATA);
+ return;
+
+ case SCAN_ID_FAILED:
+ status |= S_RNF;
+ command_end();
+ return;
+
+ case SECTOR_READ:
+ 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().cstr(), sub_state);
+ return;
+ }
+ }
+}
+
+void wd177x_t::read_track_start()
+{
+ main_state = READ_TRACK;
+ status = (status & ~(S_LOST|S_RNF)) | S_BUSY;
+ drop_drq();
+ sub_state = has_motor() ? SPINUP : SPINUP_DONE;
+ status_type_1 = false;
+ read_track_continue();
+}
+
+void wd177x_t::read_track_continue()
+{
+ for(;;) {
+ switch(sub_state) {
+ case SPINUP:
+ if(!(status & S_MON)) {
+ spinup();
+ return;
+ }
+ sub_state = SPINUP_DONE;
+ break;
+
+ case SPINUP_WAIT:
+ return;
+
+ case SPINUP_DONE:
+ if(command & 4) {
+ sub_state = SETTLE_WAIT;
+ delay_cycles(t_gen, settle_time());
+ return;
+
+ } else {
+ sub_state = SETTLE_DONE;
+ break;
+ }
+
+ case SETTLE_WAIT:
+ return;
+
+ case SETTLE_DONE:
+ sub_state = WAIT_INDEX;
+ return;
+
+ case WAIT_INDEX:
+ return;
+
+ case WAIT_INDEX_DONE:
+ sub_state = TRACK_DONE;
+ live_start(READ_TRACK_DATA);
+ return;
+
+ case TRACK_DONE:
+ command_end();
+ return;
+
+ default:
+ logerror("%s: read track unknown sub-state %d\n", ttsn().cstr(), sub_state);
+ return;
+ }
+ }
+}
+
+void wd177x_t::read_id_start()
+{
+ main_state = READ_ID;
+ status = (status & ~(S_WP|S_DDM|S_LOST|S_RNF)) | S_BUSY;
+ drop_drq();
+ sub_state = has_motor() ? SPINUP : SPINUP_DONE;
+ status_type_1 = false;
+ read_id_continue();
+}
+
+void wd177x_t::read_id_continue()
+{
+ for(;;) {
+ switch(sub_state) {
+ case SPINUP:
+ if(!(status & S_MON)) {
+ spinup();
+ return;
+ }
+ sub_state = SPINUP_DONE;
+ break;
+
+ case SPINUP_WAIT:
+ return;
+
+ case SPINUP_DONE:
+ if(command & 4) {
+ sub_state = SETTLE_WAIT;
+ delay_cycles(t_gen, settle_time());
+ return;
+ } else {
+ sub_state = SETTLE_DONE;
+ break;
+ }
+
+ case SETTLE_WAIT:
+ return;
+
+ case SETTLE_DONE:
+ sub_state = SCAN_ID;
+ counter = 0;
+ live_start(SEARCH_ADDRESS_MARK_HEADER);
+ return;
+
+ case SCAN_ID:
+ command_end();
+ return;
+
+ case SCAN_ID_FAILED:
+ status |= S_RNF;
+ command_end();
+ return;
+
+ default:
+ logerror("%s: read id unknown sub-state %d\n", ttsn().cstr(), sub_state);
+ return;
+ }
+ }
+}
+
+void wd177x_t::write_track_start()
+{
+ main_state = WRITE_TRACK;
+ status = (status & ~(S_WP|S_DDM|S_LOST|S_RNF)) | S_BUSY;
+ drop_drq();
+ sub_state = has_motor() ? SPINUP : SPINUP_DONE;
+ status_type_1 = false;
+ write_track_continue();
+}
+
+void wd177x_t::write_track_continue()
+{
+ for(;;) {
+ switch(sub_state) {
+ case SPINUP:
+ if(!(status & S_MON)) {
+ spinup();
+ return;
+ }
+ sub_state = SPINUP_DONE;
+ break;
+
+ case SPINUP_WAIT:
+ return;
+
+ case SPINUP_DONE:
+ if(command & 4) {
+ sub_state = SETTLE_WAIT;
+ delay_cycles(t_gen, settle_time());
+ return;
+ } else {
+ sub_state = SETTLE_DONE;
+ break;
+ }
+
+ case SETTLE_WAIT:
+ return;
+
+ case SETTLE_DONE:
+ set_drq();
+ sub_state = DATA_LOAD_WAIT;
+ delay_cycles(t_gen, 768);
+ return;
+
+ case DATA_LOAD_WAIT:
+ return;
+
+ case DATA_LOAD_WAIT_DONE:
+ if(drq) {
+ status |= S_LOST;
+ command_end();
+ return;
+ }
+ sub_state = WAIT_INDEX;
+ break;
+
+ case WAIT_INDEX:
+ return;
+
+ case WAIT_INDEX_DONE:
+ sub_state = TRACK_DONE;
+ live_start(WRITE_TRACK_DATA);
+ cur_live.pll.start_writing(machine().time());
+ return;
+
+ case TRACK_DONE:
+ command_end();
+ return;
+
+ default:
+ logerror("%s: write track unknown sub-state %d\n", ttsn().cstr(), sub_state);
+ return;
+ }
+ }
+}
+
+
+void wd177x_t::write_sector_start()
+{
+ main_state = WRITE_SECTOR;
+ status = (status & ~(S_CRC|S_LOST|S_RNF|S_WP|S_DDM)) | S_BUSY;
+ drop_drq();
+ sub_state = has_motor() ? SPINUP : SPINUP_DONE;
+ status_type_1 = false;
+ write_sector_continue();
+}
+
+void wd177x_t::write_sector_continue()
+{
+ for(;;) {
+ switch(sub_state) {
+ case SPINUP:
+ if(!(status & S_MON)) {
+ spinup();
+ return;
+ }
+ sub_state = SPINUP_DONE;
+ break;
+
+ case SPINUP_WAIT:
+ return;
+
+ case SPINUP_DONE:
+ if(command & 4) {
+ sub_state = SETTLE_WAIT;
+ delay_cycles(t_gen, settle_time());
+ return;
+ } else {
+ sub_state = SETTLE_DONE;
+ break;
+ }
+
+ case SETTLE_WAIT:
+ return;
+
+ case SETTLE_DONE:
+ sub_state = SCAN_ID;
+ counter = 0;
+ live_start(SEARCH_ADDRESS_MARK_HEADER);
+ return;
+
+ case SCAN_ID:
+ 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 = 128 << (cur_live.idbuf[3] & 3);
+ sub_state = SECTOR_WRITE;
+ live_start(WRITE_SECTOR_PRE);
+ return;
+
+ case SCAN_ID_FAILED:
+ status |= S_RNF;
+ command_end();
+ return;
+
+ case SECTOR_WRITE:
+ if(command & 0x10) {
+ sector++;
+ sub_state = SPINUP_DONE;
+ } else {
+ command_end();
+ return;
+ }
+ break;
+
+ default:
+ logerror("%s: write sector unknown sub-state %d\n", ttsn().cstr(), sub_state);
+ return;
+ }
+ }
+}
+
+void wd177x_t::interrupt_start()
+{
+ 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;
+ }
+ if(command & 0x0f) {
+ logerror("%s: unhandled interrupt generation (%02x)\n", ttsn().cstr(), command);
+ }
+}
+
+void wd177x_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().cstr(), main_state);
+ break;
+ }
+}
+
+void wd177x_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().cstr(), sub_state);
+ break;
+ }
+}
+
+void wd177x_t::do_cmd_w()
+{
+ // fprintf(stderr, "%s: command %02x\n", ttsn().cstr(), cmd_buffer);
+
+ // 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: logerror("wd1772: restore\n"); last_dir = 1; seek_start(RESTORE); break;
+ case 0x10: logerror("wd1772: seek %d\n", data); last_dir = data > track ? 0 : 1; seek_start(SEEK); break;
+ case 0x20: case 0x30: logerror("wd1772: step\n"); seek_start(STEP); break;
+ case 0x40: case 0x50: logerror("wd1772: step +\n"); last_dir = 0; seek_start(STEP); break;
+ case 0x60: case 0x70: logerror("wd1772: step -\n"); last_dir = 1; seek_start(STEP); break;
+ case 0x80: case 0x90: logerror("wd1772: read sector%s %d, %d\n", command & 0x10 ? " multiple" : "", track, sector); read_sector_start(); break;
+ case 0xa0: case 0xb0: logerror("wd1772: write sector%s %d, %d\n", command & 0x10 ? " multiple" : "", track, sector); write_sector_start(); break;
+ case 0xc0: logerror("wd1772: read id\n"); read_id_start(); break;
+ case 0xd0: logerror("wd1772: interrupt\n"); interrupt_start(); break;
+ case 0xe0: logerror("wd1772: read track %d\n", track); read_track_start(); break;
+ case 0xf0: logerror("wd1772: write track %d\n", track); write_track_start(); break;
+ }
+}
+
+void wd177x_t::cmd_w(UINT8 val)
+{
+ if(intrq && ((command & 0xf8) != 0xd8)) {
+ intrq = false;
+ if(!intrq_cb.isnull())
+ intrq_cb(intrq);
+ }
+
+ // No more than one write in flight
+ if(cmd_buffer != -1)
+ return;
+
+ cmd_buffer = val;
+
+ delay_cycles(t_cmd, dden ? 384 : 184);
+}
+
+UINT8 wd177x_t::status_r()
+{
+ if(intrq && ((command & 0xf8) != 0xd8)) {
+ intrq = false;
+ if(!intrq_cb.isnull())
+ intrq_cb(intrq);
+ }
+
+ 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(main_state == IDLE || 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;
+ }
+
+ return status;
+}
+
+void wd177x_t::do_track_w()
+{
+ track = track_buffer;
+ track_buffer = -1;
+}
+
+void wd177x_t::track_w(UINT8 val)
+{
+ // No more than one write in flight
+ if(track_buffer != -1)
+ return;
+
+ track_buffer = val;
+ delay_cycles(t_track, dden ? 256 : 128);
+}
+
+UINT8 wd177x_t::track_r()
+{
+ return track;
+}
+
+void wd177x_t::do_sector_w()
+{
+ sector = sector_buffer;
+ sector_buffer = -1;
+}
+
+void wd177x_t::sector_w(UINT8 val)
+{
+ // No more than one write in flight
+ if(sector_buffer != -1)
+ return;
+
+ sector_buffer = val;
+ delay_cycles(t_sector, dden ? 256 : 128);
+}
+
+UINT8 wd177x_t::sector_r()
+{
+ return sector;
+}
+
+void wd177x_t::data_w(UINT8 val)
+{
+ data = val;
+ drop_drq();
+}
+
+UINT8 wd177x_t::data_r()
+{
+ drop_drq();
+ return data;
+}
+
+void wd177x_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 wd177x_t::gen_r(int reg)
+{
+ switch(reg) {
+ case 0: return status_r(); break;
+ case 1: return track_r(); break;
+ case 2: return sector_r(); break;
+ case 3: return data_r(); break;
+ }
+ return 0xff;
+}
+
+void wd177x_t::delay_cycles(emu_timer *tm, int cycles)
+{
+ tm->adjust(clocks_to_attotime(cycles));
+}
+
+void wd177x_t::spinup()
+{
+ if(command & 0x08)
+ sub_state = SPINUP_DONE;
+ else {
+ sub_state = SPINUP_WAIT;
+ counter = 0;
+ }
+
+ status |= S_MON;
+ if(floppy)
+ floppy->mon_w(0);
+
+}
+
+void wd177x_t::index_callback(floppy_image_device *floppy, int state)
+{
+ live_sync();
+
+ if(!state) {
+ general_continue();
+ return;
+ }
+
+ switch(sub_state) {
+ case IDLE:
+ if(has_motor()) {
+ motor_timeout ++;
+ if(motor_timeout >= 5) {
+ status &= ~S_MON;
+ if(floppy)
+ floppy->mon_w(1);
+ }
+ }
+ 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().cstr(), sub_state);
+ break;
+ }
+
+ general_continue();
+}
+
+bool wd177x_t::intrq_r()
+{
+ return intrq;
+}
+
+bool wd177x_t::drq_r()
+{
+ return drq;
+}
+
+void wd177x_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;
+ cur_live.pll.reset(cur_live.tm);
+ cur_live.pll.set_clock(clocks_to_attotime(1));
+ checkpoint_live = cur_live;
+
+ live_run();
+}
+
+void wd177x_t::checkpoint()
+{
+ cur_live.pll.commit(floppy, cur_live.tm);
+ checkpoint_live = cur_live;
+}
+
+void wd177x_t::rollback()
+{
+ cur_live = checkpoint_live;
+}
+
+void wd177x_t::live_delay(int state)
+{
+ cur_live.next_state = state;
+ t_gen->adjust(cur_live.tm - machine().time());
+}
+
+void wd177x_t::live_sync()
+{
+ if(!cur_live.tm.is_never()) {
+ if(cur_live.tm > machine().time()) {
+ // fprintf(stderr, "%s: Rolling back and replaying (%s)\n", ttsn().cstr(), tts(cur_live.tm).cstr());
+ rollback();
+ live_run(machine().time());
+ cur_live.pll.commit(floppy, cur_live.tm);
+ } else {
+ // fprintf(stderr, "%s: Committing (%s)\n", ttsn().cstr(), tts(cur_live.tm).cstr());
+ 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 wd177x_t::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;
+}
+
+bool wd177x_t::read_one_bit(attotime limit)
+{
+ int bit = cur_live.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 wd177x_t::write_one_bit(attotime limit)
+{
+ bool bit = cur_live.shift_reg & 0x8000;
+ if(cur_live.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 wd177x_t::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 wd177x_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;
+ // logerror("write %02x %04x %04x\n", mfm, cur_live.crc, raw);
+}
+
+void wd177x_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().cstr(), tts(limit).cstr());
+
+ 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).cstr(), 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.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;
+ }
+ 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).cstr(), 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.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;
+ 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) {
+ // 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 0
+ fprintf(stderr, "%s: shift = %04x data=%02x c=%d.%x\n", tts(cur_live.tm).cstr(), 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(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;
+ }
+ 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).cstr(), 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 & 0xfe) != 0xfa && (cur_live.data_reg & 0xfe) != 0xfc) {
+ 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:
+ 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;
+ }
+
+ 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;
+ 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(cur_live.byte_counter <= 11)
+ live_write_mfm(0x00);
+ else if(cur_live.byte_counter == 12) {
+ cur_live.crc = 0xffff;
+ live_write_raw(0x4489);
+ } else if(cur_live.byte_counter <= 14)
+ live_write_raw(0x4489);
+ else if(cur_live.byte_counter == 15)
+ live_write_mfm(command & 1 ? 0xf8 : 0xfb);
+ else if(cur_live.byte_counter <= sector_size + 16-2) {
+ if(drq) {
+ status |= S_LOST;
+ data = 0;
+ }
+ live_write_mfm(data);
+ set_drq();
+ } else if(cur_live.byte_counter == sector_size + 16-1) {
+ if(drq) {
+ status |= S_LOST;
+ data = 0;
+ }
+ live_write_mfm(data);
+ } else if(cur_live.byte_counter <= sector_size + 16+1)
+ live_write_mfm(cur_live.crc >> 8);
+ else if(cur_live.byte_counter == sector_size + 16+2)
+ // Is that correct? It seems required (try ST formatting)
+ live_write_mfm(0xff);
+ else {
+ cur_live.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).cstr(), 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;
+ case 11:
+ if(drq) {
+ status |= S_LOST;
+ cur_live.state = IDLE;
+ return;
+ }
+ 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;
+ cur_live.pll.start_writing(cur_live.tm);
+ live_write_mfm(0x00);
+ break;
+ }
+ break;
+
+ default:
+ logerror("%s: Unknown live state %d\n", tts(cur_live.tm).cstr(), cur_live.state);
+ return;
+ }
+ }
+}
+
+void wd177x_t::set_drq()
+{
+ if(drq)
+ status |= S_LOST;
+ else {
+ drq = true;
+ if(!drq_cb.isnull())
+ drq_cb(true);
+ }
+}
+
+void wd177x_t::drop_drq()
+{
+ if(drq) {
+ drq = false;
+ if(!drq_cb.isnull())
+ drq_cb(false);
+ }
+}
+
+void wd177x_t::pll_t::set_clock(attotime period)
+{
+ for(int i=0; i<42; i++)
+ delays[i] = period*(i+1);
+}
+
+void wd177x_t::pll_t::reset(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 wd177x_t::pll_t::get_next_bit(attotime &tm, floppy_image_device *floppy, attotime limit)
+{
+ attotime when = floppy ? floppy->get_next_transition(ctime) : attotime::never;
+#if 0
+ if(!when.is_never())
+ fprintf(stderr, "transition_time=%s\n", tts(when).cstr());
+#endif
+
+ for(;;) {
+ // fprintf(stderr, "slot=%2d, counter=%03x\n", slot, counter);
+ attotime etime = ctime+delays[slot];
+ // fprintf(stderr, "etime=%s\n", tts(etime).cstr());
+ 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;
+ }
+ // fprintf(stderr, "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 wd177x_t::pll_t::start_writing(attotime tm)
+{
+ write_start_time = tm;
+ write_position = 0;
+}
+
+void wd177x_t::pll_t::stop_writing(floppy_image_device *floppy, attotime tm)
+{
+ commit(floppy, tm);
+ write_start_time = attotime::never;
+}
+
+bool wd177x_t::pll_t::write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, 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 wd177x_t::pll_t::commit(floppy_image_device *floppy, 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 wd177x_t::step_time(int mode) const
+{
+ const static int step_times[4] = { 48000, 96000, 160000, 240000 };
+ return step_times[mode];
+}
+
+int wd177x_t::settle_time() const
+{
+ return 240000;
+}
+
+bool wd177x_t::has_side_check() const
+{
+ return false;
+}
+
+wd1770_t::wd1770_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd177x_t(mconfig, WD1770x, "WD1770", tag, owner, clock)
+{
+}
+
+bool wd1770_t::has_motor() const
+{
+ return true;
+}
+
+wd1772_t::wd1772_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd177x_t(mconfig, WD1772x, "WD1772", tag, owner, clock)
+{
+}
+
+bool wd1772_t::has_motor() const
+{
+ return true;
+}
+
+int wd1772_t::step_time(int mode) const
+{
+ const static int step_times[4] = { 48000, 96000, 16000, 24000 };
+ return step_times[mode];
+}
+
+int wd1772_t::settle_time() const
+{
+ return 120000;
+}
+
+wd1773_t::wd1773_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : wd177x_t(mconfig, WD1773x, "WD1773", tag, owner, clock)
+{
+}
+
+bool wd1773_t::has_motor() const
+{
+ return false;
+}
+
+bool wd1773_t::has_side_check() const
+{
+ return false;
+}
diff --git a/src/mess/machine/wd1772.h b/src/mess/machine/wd1772.h
new file mode 100644
index 00000000000..2cd7187da2c
--- /dev/null
+++ b/src/mess/machine/wd1772.h
@@ -0,0 +1,321 @@
+#ifndef WD1772_H
+#define WD1772_H
+
+#include "emu.h"
+#include "imagedev/floppy.h"
+
+#define MCFG_WD1770x_ADD(_tag, _clock) \
+ MCFG_DEVICE_ADD(_tag, WD1770x, _clock)
+
+#define MCFG_WD1772x_ADD(_tag, _clock) \
+ MCFG_DEVICE_ADD(_tag, WD1772x, _clock)
+
+#define MCFG_WD1773x_ADD(_tag, _clock) \
+ MCFG_DEVICE_ADD(_tag, WD1773x, _clock)
+
+class wd177x_t : public device_t {
+public:
+ typedef delegate<void (bool state)> line_cb;
+
+ wd177x_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
+
+ void dden_w(bool dden);
+ void set_floppy(floppy_image_device *floppy);
+ void setup_intrq_cb(line_cb cb);
+ void setup_drq_cb(line_cb cb);
+
+ void cmd_w(UINT8 val);
+ UINT8 status_r();
+
+ void track_w(UINT8 val);
+ UINT8 track_r();
+
+ void sector_w(UINT8 val);
+ UINT8 sector_r();
+
+ void data_w(UINT8 val);
+ UINT8 data_r();
+
+ void gen_w(int reg, UINT8 val);
+ UINT8 gen_r(int reg);
+
+ bool intrq_r();
+ bool drq_r();
+
+ DECLARE_READ8_MEMBER( read ) { return gen_r(offset);}
+ DECLARE_WRITE8_MEMBER( write ) { gen_w(offset,data); }
+
+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 bool has_motor() const = 0;
+ virtual bool has_side_check() const;
+ virtual int step_time(int mode) const;
+ virtual int settle_time() const;
+
+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 happen the 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 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(attotime period);
+ void reset(attotime when);
+ int get_next_bit(attotime &tm, floppy_image_device *floppy, attotime limit);
+ bool write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, attotime limit);
+ void start_writing(attotime tm);
+ void commit(floppy_image_device *floppy, attotime tm);
+ void stop_writing(floppy_image_device *floppy, attotime tm);
+ };
+
+ 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];
+ pll_t pll;
+ };
+
+ enum {
+ S_BUSY = 0x01,
+ S_DRQ = 0x02,
+ S_IP = 0x02,
+ S_TR00 = 0x04,
+ S_LOST = 0x04,
+ S_CRC = 0x08,
+ S_RNF = 0x10,
+ S_SPIN = 0x20,
+ S_DDM = 0x20,
+ S_WP = 0x40,
+ S_MON = 0x80
+ };
+
+ floppy_image_device *floppy;
+
+ emu_timer *t_gen, *t_cmd, *t_track, *t_sector;
+
+ bool dden, status_type_1, intrq, drq;
+ int main_state, sub_state;
+ UINT8 command, track, sector, data, status;
+ int last_dir;
+
+ int counter, motor_timeout, sector_size;
+
+ int cmd_buffer, track_buffer, sector_buffer;
+
+ live_info cur_live, checkpoint_live;
+ line_cb intrq_cb, drq_cb;
+
+ static astring tts(attotime t);
+ astring 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 index_callback(floppy_image_device *floppy, int state);
+ bool sector_matches() const;
+
+ 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(attotime limit);
+ bool write_one_bit(attotime limit);
+
+ void live_write_raw(UINT16 raw);
+ void live_write_mfm(UINT8 mfm);
+
+ void drop_drq();
+ void set_drq();
+};
+
+class wd1770_t : public wd177x_t {
+public:
+ wd1770_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+protected:
+ virtual bool has_motor() const;
+};
+
+class wd1772_t : public wd177x_t {
+public:
+ wd1772_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+protected:
+ virtual bool has_motor() const;
+ virtual int step_time(int mode) const;
+ virtual int settle_time() const;
+};
+
+class wd1773_t : public wd177x_t {
+public:
+ wd1773_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+protected:
+ virtual bool has_motor() const;
+ virtual bool has_side_check() const;
+};
+
+extern const device_type WD1770x;
+extern const device_type WD1772x;
+extern const device_type WD1773x;
+
+#endif
diff --git a/src/mess/machine/wd2010.c b/src/mess/machine/wd2010.c
new file mode 100644
index 00000000000..b6ddfa2e07b
--- /dev/null
+++ b/src/mess/machine/wd2010.c
@@ -0,0 +1,426 @@
+/**********************************************************************
+
+ Western Digital WD2010 Winchester Disk Controller
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#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] & 0x07) << 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<wd2010_device>;
+
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void wd2010_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const wd2010_interface *intf = reinterpret_cast<const wd2010_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<wd2010_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_intrq_cb, 0, sizeof(m_out_intrq_cb));
+ memset(&m_out_bdrq_cb, 0, sizeof(m_out_bdrq_cb));
+ memset(&m_out_bcr_cb, 0, sizeof(m_out_bcr_cb));
+ memset(&m_in_bcs_cb, 0, sizeof(m_in_bcs_cb));
+ memset(&m_out_bcs_cb, 0, sizeof(m_out_bcs_cb));
+ memset(&m_out_dirin_cb, 0, sizeof(m_out_dirin_cb));
+ memset(&m_out_step_cb, 0, sizeof(m_out_step_cb));
+ memset(&m_out_rwc_cb, 0, sizeof(m_out_rwc_cb));
+ memset(&m_in_drdy_cb, 0, sizeof(m_in_drdy_cb));
+ memset(&m_in_index_cb, 0, sizeof(m_in_index_cb));
+ memset(&m_in_wf_cb, 0, sizeof(m_in_wf_cb));
+ memset(&m_in_tk000_cb, 0, sizeof(m_in_tk000_cb));
+ memset(&m_in_sc_cb, 0, sizeof(m_in_sc_cb));
+ }
+}
+
+
+
+//**************************************************************************
+// 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),
+ m_status(0),
+ m_error(0)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void wd2010_device::device_start()
+{
+ // resolve callbacks
+ m_out_intrq_func.resolve(m_out_intrq_cb, *this);
+ m_out_bdrq_func.resolve(m_out_bdrq_cb, *this);
+ m_out_bcr_func.resolve(m_out_bcr_cb, *this);
+ m_in_bcs_func.resolve(m_in_bcs_cb, *this);
+ m_out_bcs_func.resolve(m_out_bcs_cb, *this);
+ m_out_dirin_func.resolve(m_out_dirin_cb, *this);
+ m_out_step_func.resolve(m_out_step_cb, *this);
+ m_out_rwc_func.resolve(m_out_rwc_cb, *this);
+ m_in_drdy_func.resolve(m_in_drdy_cb, *this);
+ m_in_index_func.resolve(m_in_index_cb, *this);
+ m_in_wf_func.resolve(m_in_wf_cb, *this);
+ m_in_tk000_func.resolve(m_in_tk000_cb, *this);
+ m_in_sc_func.resolve(m_in_sc_cb, *this);
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void wd2010_device::device_reset()
+{
+}
+
+
+//-------------------------------------------------
+// read -
+//-------------------------------------------------
+
+READ8_MEMBER( wd2010_device::read )
+{
+ UINT8 data = 0;
+
+ switch (offset)
+ {
+ case TASK_FILE_ERROR:
+ data = m_error;
+ break;
+
+ case TASK_FILE_STATUS:
+ m_out_intrq_func(CLEAR_LINE);
+ data = m_status | STATUS_RDY | STATUS_SC;
+ break;
+
+ default:
+ data = m_task_file[offset];
+ 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 Low: %u\n", machine().describe_context(), tag(), CYLINDER);
+ break;
+
+ case TASK_FILE_CYLINDER_HIGH:
+ if (LOG) logerror("%s WD2010 '%s' Cylinder Low: %u\n", machine().describe_context(), tag(), CYLINDER);
+ break;
+
+ case TASK_FILE_SDH_REGISTER:
+ if (LOG)
+ {
+ logerror("%s WD2010 '%s' Head: %u\n", machine().describe_context(), tag(), HEAD);
+ logerror("%s WD2010 '%s' Drive: %u\n", machine().describe_context(), tag(), DRIVE);
+ logerror("%s WD2010 '%s' Sector Size: %u\n", machine().describe_context(), tag(), SECTOR_SIZE);
+ }
+ break;
+
+ case TASK_FILE_COMMAND:
+ 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\n", machine().describe_context(), tag());
+ read_sector(data);
+ break;
+
+ case COMMAND_WRITE_SECTOR:
+ if (LOG) logerror("%s WD2010 '%s' WRITE SECTOR\n", machine().describe_context(), tag());
+ 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;
+ }
+}
+
+
+//-------------------------------------------------
+// compute_correction -
+//-------------------------------------------------
+
+void wd2010_device::compute_correction(UINT8 data)
+{
+}
+
+
+//-------------------------------------------------
+// set_parameter -
+//-------------------------------------------------
+
+void wd2010_device::set_parameter(UINT8 data)
+{
+}
+
+
+//-------------------------------------------------
+// restore -
+//-------------------------------------------------
+
+void wd2010_device::restore(UINT8 data)
+{
+ // reset INTRQ, errors, set BUSY, CIP
+ m_out_intrq_func(CLEAR_LINE);
+ m_error = 0;
+ m_status = STATUS_BSY | STATUS_CIP;
+
+ // reset RWC, set direction=OUT, store step rate
+ m_out_rwc_func(0);
+ m_out_dirin_func(0);
+
+ int step_pulses = 0;
+
+ while (step_pulses < 2048)
+ {
+ while (!m_in_sc_func())
+ {
+ // drive not ready or write fault?
+ if (!m_in_drdy_func() || m_in_wf_func())
+ {
+ // pulse BCR, set AC, INTRQ, reset BSY, CIP
+ m_out_bcr_func(0);
+ m_out_bcr_func(1);
+ m_error = ERROR_AC;
+ m_status = (m_in_drdy_func() << 6) | (m_in_wf_func() << 5) | STATUS_ERR;
+ m_out_intrq_func(ASSERT_LINE);
+ return;
+ }
+ }
+
+ if (m_in_tk000_func())
+ {
+ // pulse BCR, set INTRQ, reset BSY, CIP
+ m_out_bcr_func(0);
+ m_out_bcr_func(1);
+ m_status &= ~(STATUS_BSY | STATUS_CIP);
+ m_out_intrq_func(ASSERT_LINE);
+ return;
+ }
+
+ if (step_pulses == 2047)
+ {
+ // set TK000 error
+ m_error = ERROR_TK;
+ m_status |= STATUS_ERR;
+
+ // pulse BCR, set INTRQ, reset BSY, CIP
+ m_out_bcr_func(0);
+ m_out_bcr_func(1);
+ m_status &= ~(STATUS_BSY | STATUS_CIP);
+ m_out_intrq_func(ASSERT_LINE);
+ return;
+ }
+
+ // issue a step pulse
+ m_out_step_func(1);
+ m_out_step_func(0);
+ step_pulses++;
+ }
+}
+
+
+//-------------------------------------------------
+// seek -
+//-------------------------------------------------
+
+void wd2010_device::seek(UINT8 data)
+{
+}
+
+
+//-------------------------------------------------
+// read_sector -
+//-------------------------------------------------
+
+void wd2010_device::read_sector(UINT8 data)
+{
+}
+
+
+//-------------------------------------------------
+// write_sector -
+//-------------------------------------------------
+
+void wd2010_device::write_sector(UINT8 data)
+{
+}
+
+
+//-------------------------------------------------
+// scan_id -
+//-------------------------------------------------
+
+void wd2010_device::scan_id(UINT8 data)
+{
+}
+
+
+//-------------------------------------------------
+// format -
+//-------------------------------------------------
+
+void wd2010_device::format(UINT8 data)
+{
+}
diff --git a/src/mess/machine/wd2010.h b/src/mess/machine/wd2010.h
new file mode 100644
index 00000000000..6d79f9f3647
--- /dev/null
+++ b/src/mess/machine/wd2010.h
@@ -0,0 +1,109 @@
+/**********************************************************************
+
+ Western Digital WD2010 Winchester Disk Controller
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __WD2010__
+#define __WD2010__
+
+
+#include "emu.h"
+
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_WD2010_ADD(_tag, _clock, _config) \
+ MCFG_DEVICE_ADD(_tag, WD2010, _clock) \
+ MCFG_DEVICE_CONFIG(_config)
+
+
+#define WD2010_INTERFACE(_name) \
+ const wd2010_interface (_name) =
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> wd2010_interface
+
+struct wd2010_interface
+{
+ 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_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_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;
+};
+
+
+// ======================> wd2010_device
+
+class wd2010_device : public device_t,
+ public wd2010_interface
+{
+public:
+ // construction/destruction
+ wd2010_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();
+ virtual void device_config_complete();
+
+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 format(UINT8 data);
+
+ devcb_resolved_write_line m_out_intrq_func;
+ devcb_resolved_write_line m_out_bdrq_func;
+ devcb_resolved_write_line m_out_bcr_func;
+ devcb_resolved_read8 m_in_bcs_func;
+ devcb_resolved_write8 m_out_bcs_func;
+ devcb_resolved_write_line m_out_dirin_func;
+ devcb_resolved_write_line m_out_step_func;
+ devcb_resolved_write_line m_out_rwc_func;
+ devcb_resolved_read_line m_in_drdy_func;
+ devcb_resolved_read_line m_in_index_func;
+ devcb_resolved_read_line m_in_wf_func;
+ devcb_resolved_read_line m_in_tk000_func;
+ devcb_resolved_read_line m_in_sc_func;
+
+ UINT8 m_status;
+ UINT8 m_error;
+ UINT8 m_task_file[8];
+};
+
+
+// device type definition
+extern const device_type WD2010;
+
+#endif
diff --git a/src/mess/machine/wswan.c b/src/mess/machine/wswan.c
new file mode 100644
index 00000000000..23608e2b528
--- /dev/null
+++ b/src/mess/machine/wswan.c
@@ -0,0 +1,1518 @@
+/***************************************************************************
+
+ wswan.c
+
+ Machine file to handle emulation of the Bandai WonderSwan.
+
+ Anthony Kruize
+ Wilbert Pol
+
+TODO:
+ SRAM sizes should be in kbit instead of kbytes(?). This raises a few
+ interesting issues:
+ - mirror of smaller <64KBYTE/512kbit sram sizes
+ - banking when using 1M or 2M sram sizes
+
+***************************************************************************/
+
+#include "includes/wswan.h"
+
+#define INTERNAL_EEPROM_SIZE 1024
+
+enum enum_system { TYPE_WSWAN=0, TYPE_WSC };
+enum enum_sram { SRAM_NONE=0, SRAM_64K, SRAM_256K, SRAM_512K, SRAM_1M, SRAM_2M, EEPROM_1K, EEPROM_16K, EEPROM_8K, SRAM_UNKNOWN };
+static const char *const wswan_sram_str[] = { "none", "64Kbit SRAM", "256Kbit SRAM", "512Kbit SRAM", "1Mbit SRAM", "2Mbit SRAM", "1Kbit EEPROM", "16Kbit EEPROM", "8Kbit EEPROM", "Unknown" };
+static const int wswan_sram_size[] = { 0, 64*1024/8, 256*1024/8, 512*1024/8, 1024*1024/8, 2*1024*1024/8, 1024/8, 16*1024/8, 8*1024/8, 0 };
+
+static TIMER_CALLBACK(wswan_scanline_interrupt);
+
+
+static const UINT8 ws_portram_init[256] =
+{
+ 0x00, 0x00, 0x00/*?*/, 0xbb, 0x00, 0x00, 0x00, 0x26, 0xfe, 0xde, 0xf9, 0xfb, 0xdb, 0xd7, 0x7f, 0xf5,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x9e, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x99, 0xfd, 0xb7, 0xdf,
+ 0x30, 0x57, 0x75, 0x76, 0x15, 0x73, 0x70/*77?*/, 0x77, 0x20, 0x75, 0x50, 0x36, 0x70, 0x67, 0x50, 0x77,
+ 0x57, 0x54, 0x75, 0x77, 0x75, 0x17, 0x37, 0x73, 0x50, 0x57, 0x60, 0x77, 0x70, 0x77, 0x10, 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, 0x00,
+ 0x0a, 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, 0x1f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
+ 0x87, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x4f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xdb, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x42, 0x00, 0x83, 0x00,
+ 0x2f, 0x3f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1,
+ 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1,
+ 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1,
+ 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1
+};
+
+/*
+ Some fake bios code to initialize some registers and set up some things on the wonderswan.
+ The code from f:ffe0 which gets copied to 0:0400 is taken from a wonderswan crystal's initial
+ memory settings. Lacking real bios dumps we will use this....
+
+ The setting of SP to 2000h is what's needed to get Wonderswan Colloseum to boot.
+
+ f000:ffc0
+ FC cld
+ BC 00 20 mov sp,2000h
+ 68 00 00 push 0000h
+ 07 pop es
+ 68 00 F0 push F000h
+ 1F pop ds
+ BF 00 04 mov di,0400h
+ BE E0 FF mov si,FFE0h
+ B9 10 00 mov cx,0010h
+ F3 A4 rep movsb
+ B0 2F mov al,2Fh
+ E6 C0 out al,C0h
+ EA 00 04 00 00 jmp 0000:0400
+
+ f000:ffe0
+ E4 A0 in al, A0h
+ 0C 01 or al,01h
+ E6 A0 out al,A0h
+ EA 00 00 FF FF jmp FFFFh:0000h
+
+*/
+static const UINT8 ws_fake_bios_code[] = {
+ 0xfc, 0xbc, 0x00, 0x20, 0x68, 0x00, 0x00, 0x07, 0x68, 0x00, 0xf0, 0x1f, 0xbf, 0x00, 0x04, 0xbe,
+ 0xe0, 0xff, 0xb9, 0x10, 0x00, 0xf3, 0xa4, 0xb0, 0x2f, 0xe6, 0xc0, 0xea, 0x00, 0x04, 0x00, 0x00,
+ 0xe4, 0xa0, 0x0c, 0x01, 0xe6, 0xa0, 0xea, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xea, 0xc0, 0xff, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static void wswan_handle_irqs( running_machine &machine )
+{
+ wswan_state *state = machine.driver_data<wswan_state>();
+ if ( state->m_ws_portram[0xb2] & state->m_ws_portram[0xb6] & WSWAN_IFLAG_HBLTMR ) {
+ cputag_set_input_line_and_vector( machine, "maincpu", 0, HOLD_LINE, state->m_ws_portram[0xb0] + WSWAN_INT_HBLTMR );
+ } else if ( state->m_ws_portram[0xb2] & state->m_ws_portram[0xb6] & WSWAN_IFLAG_VBL ) {
+ cputag_set_input_line_and_vector( machine, "maincpu", 0, HOLD_LINE, state->m_ws_portram[0xb0] + WSWAN_INT_VBL );
+ } else if ( state->m_ws_portram[0xb2] & state->m_ws_portram[0xb6] & WSWAN_IFLAG_VBLTMR ) {
+ cputag_set_input_line_and_vector( machine, "maincpu", 0, HOLD_LINE, state->m_ws_portram[0xb0] + WSWAN_INT_VBLTMR );
+ } else if ( state->m_ws_portram[0xb2] & state->m_ws_portram[0xb6] & WSWAN_IFLAG_LCMP ) {
+ cputag_set_input_line_and_vector( machine, "maincpu", 0, HOLD_LINE, state->m_ws_portram[0xb0] + WSWAN_INT_LCMP );
+ } else if ( state->m_ws_portram[0xb2] & state->m_ws_portram[0xb6] & WSWAN_IFLAG_SRX ) {
+ cputag_set_input_line_and_vector( machine, "maincpu", 0, HOLD_LINE, state->m_ws_portram[0xb0] + WSWAN_INT_SRX );
+ } else if ( state->m_ws_portram[0xb2] & state->m_ws_portram[0xb6] & WSWAN_IFLAG_RTC ) {
+ cputag_set_input_line_and_vector( machine, "maincpu", 0, HOLD_LINE, state->m_ws_portram[0xb0] + WSWAN_INT_RTC );
+ } else if ( state->m_ws_portram[0xb2] & state->m_ws_portram[0xb6] & WSWAN_IFLAG_KEY ) {
+ cputag_set_input_line_and_vector( machine, "maincpu", 0, HOLD_LINE, state->m_ws_portram[0xb0] + WSWAN_INT_KEY );
+ } else if ( state->m_ws_portram[0xb2] & state->m_ws_portram[0xb6] & WSWAN_IFLAG_STX ) {
+ cputag_set_input_line_and_vector( machine, "maincpu", 0, HOLD_LINE, state->m_ws_portram[0xb0] + WSWAN_INT_STX );
+ } else {
+ cputag_set_input_line(machine, "maincpu", 0, CLEAR_LINE );
+ }
+}
+
+static void wswan_set_irq_line( running_machine &machine, int irq)
+{
+ wswan_state *state = machine.driver_data<wswan_state>();
+ if ( state->m_ws_portram[0xb2] & irq )
+ {
+ state->m_ws_portram[0xb6] |= irq;
+ wswan_handle_irqs( machine );
+ }
+}
+
+void wswan_state::wswan_clear_irq_line(int irq)
+{
+ m_ws_portram[0xb6] &= ~irq;
+ wswan_handle_irqs( machine() );
+}
+
+static TIMER_CALLBACK(wswan_rtc_callback)
+{
+ wswan_state *state = machine.driver_data<wswan_state>();
+ /* A second passed */
+ state->m_rtc.second = state->m_rtc.second + 1;
+ if ( ( state->m_rtc.second & 0x0F ) > 9 )
+ {
+ state->m_rtc.second = ( state->m_rtc.second & 0xF0 ) + 0x10;
+ }
+
+ /* Check for minute passed */
+ if ( state->m_rtc.second >= 0x60 )
+ {
+ state->m_rtc.second = 0;
+ state->m_rtc.minute = state->m_rtc.minute + 1;
+ if ( ( state->m_rtc.minute & 0x0F ) > 9 )
+ {
+ state->m_rtc.minute = ( state->m_rtc.minute & 0xF0 ) + 0x10;
+ }
+ }
+
+ /* Check for hour passed */
+ if ( state->m_rtc.minute >= 0x60 )
+ {
+ state->m_rtc.minute = 0;
+ state->m_rtc.hour = state->m_rtc.hour + 1;
+ if ( ( state->m_rtc.hour & 0x0F ) > 9 )
+ {
+ state->m_rtc.hour = ( state->m_rtc.hour & 0xF0 ) + 0x10;
+ }
+ if ( state->m_rtc.hour == 0x12 )
+ {
+ state->m_rtc.hour |= 0x80;
+ }
+ }
+
+ /* Check for day passed */
+ if ( state->m_rtc.hour >= 0x24 )
+ {
+ state->m_rtc.hour = 0;
+ state->m_rtc.day = state->m_rtc.day + 1;
+ }
+}
+
+static void wswan_machine_stop( running_machine &machine )
+{
+ wswan_state *state = machine.driver_data<wswan_state>();
+ device_image_interface *image = dynamic_cast<device_image_interface *>(machine.device("cart"));
+ if ( state->m_eeprom.size )
+ {
+ image->battery_save(state->m_eeprom.data, state->m_eeprom.size );
+ }
+}
+
+static void wswan_setup_bios( running_machine &machine )
+{
+ wswan_state *state = machine.driver_data<wswan_state>();
+ if ( state->m_ws_bios_bank == NULL )
+ {
+ state->m_ws_bios_bank = auto_alloc_array(machine, UINT8, 0x10000 );
+ memcpy( state->m_ws_bios_bank + 0xffc0, ws_fake_bios_code, 0x40 );
+ }
+}
+
+MACHINE_START( wswan )
+{
+ wswan_state *state = machine.driver_data<wswan_state>();
+ state->m_ws_bios_bank = NULL;
+ state->m_system_type = TYPE_WSWAN;
+ machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(wswan_machine_stop),&machine));
+ state->m_vdp.timer = machine.scheduler().timer_alloc(FUNC(wswan_scanline_interrupt), &state->m_vdp );
+ state->m_vdp.timer->adjust( attotime::from_ticks( 256, 3072000 ), 0, attotime::from_ticks( 256, 3072000 ) );
+
+ wswan_setup_bios(machine);
+
+ /* Set up RTC timer */
+ if ( state->m_rtc.present )
+ machine.scheduler().timer_pulse(attotime::from_seconds(1), FUNC(wswan_rtc_callback));
+
+ machine.device<nvram_device>("nvram")->set_base(state->m_internal_eeprom, INTERNAL_EEPROM_SIZE);
+}
+
+MACHINE_START( wscolor )
+{
+ wswan_state *state = machine.driver_data<wswan_state>();
+ state->m_ws_bios_bank = NULL;
+ state->m_system_type = TYPE_WSC;
+ machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(wswan_machine_stop),&machine));
+ state->m_vdp.timer = machine.scheduler().timer_alloc(FUNC(wswan_scanline_interrupt), &state->m_vdp );
+ state->m_vdp.timer->adjust( attotime::from_ticks( 256, 3072000 ), 0, attotime::from_ticks( 256, 3072000 ) );
+
+ wswan_setup_bios(machine);
+
+ /* Set up RTC timer */
+ if ( state->m_rtc.present )
+ machine.scheduler().timer_pulse(attotime::from_seconds(1), FUNC(wswan_rtc_callback));
+
+ machine.device<nvram_device>("nvram")->set_base(state->m_internal_eeprom, INTERNAL_EEPROM_SIZE);
+}
+
+MACHINE_RESET( wswan )
+{
+ wswan_state *state = machine.driver_data<wswan_state>();
+ address_space *space = machine.device( "maincpu")->memory().space( AS_PROGRAM );
+
+ /* Intialize ports */
+ memcpy( state->m_ws_portram, ws_portram_init, 256 );
+
+ /* Initialize VDP */
+ memset( &state->m_vdp, 0, sizeof( state->m_vdp ) );
+
+ state->m_vdp.vram = (UINT8*)space->get_read_ptr(0);
+ state->m_vdp.palette_vram = (UINT8*)space->get_read_ptr(( state->m_system_type == TYPE_WSC ) ? 0xFE00 : 0 );
+ state->m_vdp.current_line = 145; /* Randomly chosen, beginning of VBlank period to give cart some time to boot up */
+ state->m_vdp.color_mode = 0;
+ state->m_vdp.colors_16 = 0;
+ state->m_vdp.tile_packed = 0;
+
+ render_target *target = machine.render().first_target();
+ target->set_view(state->m_rotate);
+
+ /* Initialize sound DMA */
+ memset( &state->m_sound_dma, 0, sizeof( state->m_sound_dma ) );
+
+ /* Switch in the banks */
+ state->membank( "bank2" )->set_base( state->m_ROMMap[(state->m_ROMBanks - 1) & (state->m_ROMBanks - 1)] );
+ state->membank( "bank3" )->set_base( state->m_ROMMap[(state->m_ROMBanks - 1) & (state->m_ROMBanks - 1)] );
+ state->membank( "bank4" )->set_base( state->m_ROMMap[(state->m_ROMBanks - 12) & (state->m_ROMBanks - 1)] );
+ state->membank( "bank5" )->set_base( state->m_ROMMap[(state->m_ROMBanks - 11) & (state->m_ROMBanks - 1)] );
+ state->membank( "bank6" )->set_base( state->m_ROMMap[(state->m_ROMBanks - 10) & (state->m_ROMBanks - 1)] );
+ state->membank( "bank7" )->set_base( state->m_ROMMap[(state->m_ROMBanks - 9) & (state->m_ROMBanks - 1)] );
+ state->membank( "bank8" )->set_base( state->m_ROMMap[(state->m_ROMBanks - 8) & (state->m_ROMBanks - 1)] );
+ state->membank( "bank9" )->set_base( state->m_ROMMap[(state->m_ROMBanks - 7) & (state->m_ROMBanks - 1)] );
+ state->membank( "bank10" )->set_base( state->m_ROMMap[(state->m_ROMBanks - 6) & (state->m_ROMBanks - 1)] );
+ state->membank( "bank11" )->set_base( state->m_ROMMap[(state->m_ROMBanks - 5) & (state->m_ROMBanks - 1)] );
+ state->membank( "bank12" )->set_base( state->m_ROMMap[(state->m_ROMBanks - 4) & (state->m_ROMBanks - 1)] );
+ state->membank( "bank13" )->set_base( state->m_ROMMap[(state->m_ROMBanks - 3) & (state->m_ROMBanks - 1)] );
+ state->membank( "bank14" )->set_base( state->m_ROMMap[(state->m_ROMBanks - 2) & (state->m_ROMBanks - 1)] );
+ state->m_bios_disabled = 0;
+ state->membank( "bank15" )->set_base( state->m_ws_bios_bank );
+// state->membank( 15 )->set_base( state->m_ROMMap[(state->m_ROMBanks - 1) & (state->m_ROMBanks - 1)] );
+}
+
+READ8_MEMBER( wswan_state::wswan_sram_r )
+{
+ if ( m_eeprom.data == NULL )
+ {
+ return 0xFF;
+ }
+ return m_eeprom.page[ offset & ( m_eeprom.size - 1 ) ];
+}
+
+WRITE8_MEMBER( wswan_state::wswan_sram_w )
+{
+ if ( m_eeprom.data == NULL )
+ {
+ return;
+ }
+ m_eeprom.page[ offset & ( m_eeprom.size - 1 ) ] = data;
+}
+
+READ8_MEMBER( wswan_state::wswan_port_r )
+{
+ UINT8 value = m_ws_portram[offset];
+
+ if ( offset != 2 )
+ logerror( "PC=%X: port read %02X\n", cpu_get_pc( machine().device("maincpu") ), offset );
+ switch( offset )
+ {
+ case 0x02: /* Current line */
+ value = m_vdp.current_line;
+ break;
+ case 0x4A: /* Sound DMA source address (low) */
+ value = m_sound_dma.source & 0xFF;
+ break;
+ case 0x4B: /* Sound DMA source address (high) */
+ value = ( m_sound_dma.source >> 8 ) & 0xFF;
+ break;
+ case 0x4C: /* Sound DMA source memory segment */
+ value = ( m_sound_dma.source >> 16 ) & 0xFF;
+ break;
+ case 0x4E: /* Sound DMA transfer size (low) */
+ value = m_sound_dma.size & 0xFF;
+ break;
+ case 0x4F: /* Sound DMA transfer size (high) */
+ value = ( m_sound_dma.size >> 8 ) & 0xFF;
+ break;
+ case 0x52: /* Sound DMA start/stop */
+ value = m_sound_dma.enable;
+ break;
+ case 0xA0: /* Hardware type */
+ /* Bit 0 - Disable/enable Bios */
+ /* Bit 1 - Determine mono/color */
+ /* Bit 2 - Determine color/crystal */
+ value = value & ~ 0x02;
+ if ( m_system_type == TYPE_WSC )
+ {
+ value |= 2;
+ }
+ break;
+ case 0xA8:
+ value = m_vdp.timer_hblank_count & 0xFF;
+ break;
+ case 0xA9:
+ value = m_vdp.timer_hblank_count >> 8;
+ break;
+ case 0xAA:
+ value = m_vdp.timer_vblank_count & 0xFF;
+ break;
+ case 0xAB:
+ value = m_vdp.timer_vblank_count >> 8;
+ break;
+ case 0xCB: /* RTC data */
+ if ( m_ws_portram[0xca] == 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++;
+ }
+ }
+
+ return value;
+}
+
+WRITE8_MEMBER( wswan_state::wswan_port_w )
+{
+ address_space *mem = m_maincpu->memory().space(AS_PROGRAM);
+ wswan_state *state = machine().driver_data<wswan_state>();
+ UINT8 input;
+ logerror( "PC=%X: port write %02X <- %02X\n", cpu_get_pc( &mem->device() ), offset, data );
+ switch( offset )
+ {
+ case 0x00: /* Display control
+ Bit 0 - Background layer enable
+ Bit 1 - Foreground layer enable
+ Bit 2 - Sprites enable
+ Bit 3 - Sprite window enable
+ Bit 4-5 - Foreground window configuration
+ 00 - Foreground layer is displayed inside and outside foreground window area
+ 01 - Unknown
+ 10 - Foreground layer is displayed only inside foreground window area
+ 11 - Foreground layer is displayed outside foreground window area
+ Bit 6-7 - Unknown
+ */
+ m_vdp.layer_bg_enable = data & 0x1;
+ m_vdp.layer_fg_enable = (data & 0x2) >> 1;
+ m_vdp.sprites_enable = (data & 0x4) >> 2;
+ m_vdp.window_sprites_enable = (data & 0x8) >> 3;
+ m_vdp.window_fg_mode = (data & 0x30) >> 4;
+ break;
+ case 0x01: /* Background colour
+ In 16 colour mode:
+ Bit 0-3 - Palette index
+ Bit 4-7 - Palette number
+ Otherwise:
+ Bit 0-2 - Main palette index
+ Bit 3-7 - Unknown
+ */
+ break;
+ case 0x02: /* Current scanline
+ Bit 0-7 - Current scanline (Most likely read-only)
+ */
+ logerror( "Write to current scanline! Current value: %d Data to write: %d\n", m_vdp.current_line, data );
+ /* Returning so we don't overwrite the value here, not that it
+ * really matters */
+ return;
+ case 0x03: /* Line compare
+ Bit 0-7 - Line compare
+ */
+ m_vdp.line_compare = data;
+ logerror( "Write to line compare: %d\n", data );
+ break;
+ case 0x04: /* Sprite table base address
+ Bit 0-5 - Determine sprite table base address 0 0xxxxxx0 00000000
+ Bit 6-7 - Unknown
+ */
+ m_vdp.sprite_table_address = ( data & 0x3F ) << 9;
+ break;
+ case 0x05: /* Number of sprite to start drawing with
+ Bit 0-7 - First sprite number
+ */
+ //m_vdp.sprite_first = data;
+ if (data) logerror("non-zero first sprite %d\n", m_vdp.sprite_first);
+ break;
+ case 0x06: /* Number of sprites to draw
+ Bit 0-7 - Number of sprites to draw
+ */
+ //m_vdp.sprite_count = data;
+ break;
+ case 0x07: /* Background/Foreground table base addresses
+ Bit 0-2 - Determine background table base address 00xxx000 00000000
+ Bit 3 - Unknown
+ Bit 4-6 - Determine foreground table base address 00xxx000 00000000
+ Bit 7 - Unknown
+ */
+ m_vdp.layer_bg_address = (data & 0x7) << 11;
+ m_vdp.layer_fg_address = (data & 0x70) << 7;
+ break;
+ case 0x08: /* Left coordinate of foreground window
+ Bit 0-7 - Left coordinate of foreground window area
+ */
+ m_vdp.window_fg_left = data;
+ break;
+ case 0x09: /* Top coordinate of foreground window
+ Bit 0-7 - Top coordinatte of foreground window area
+ */
+ m_vdp.window_fg_top = data;
+ break;
+ case 0x0A: /* Right coordinate of foreground window
+ Bit 0-7 - Right coordinate of foreground window area
+ */
+ m_vdp.window_fg_right = data;
+ break;
+ case 0x0B: /* Bottom coordinate of foreground window
+ Bit 0-7 - Bottom coordinate of foreground window area
+ */
+ m_vdp.window_fg_bottom = data;
+ break;
+ case 0x0C: /* Left coordinate of sprite window
+ Bit 0-7 - Left coordinate of sprite window area
+ */
+ m_vdp.window_sprites_left = data;
+ break;
+ case 0x0D: /* Top coordinate of sprite window
+ Bit 0-7 - Top coordinate of sprite window area
+ */
+ m_vdp.window_sprites_top = data;
+ break;
+ case 0x0E: /* Right coordinate of sprite window
+ Bit 0-7 - Right coordinate of sprite window area
+ */
+ m_vdp.window_sprites_right = data;
+ break;
+ case 0x0F: /* Bottom coordinate of sprite window
+ Bit 0-7 - Bottom coordiante of sprite window area
+ */
+ m_vdp.window_sprites_bottom = data;
+ break;
+ case 0x10: /* Background layer X scroll
+ Bit 0-7 - Background layer X scroll
+ */
+ m_vdp.layer_bg_scroll_x = data;
+ break;
+ case 0x11: /* Background layer Y scroll
+ Bit 0-7 - Background layer Y scroll
+ */
+ m_vdp.layer_bg_scroll_y = data;
+ break;
+ case 0x12: /* Foreground layer X scroll
+ Bit 0-7 - Foreground layer X scroll
+ */
+ m_vdp.layer_fg_scroll_x = data;
+ break;
+ case 0x13: /* Foreground layer Y scroll
+ Bit 0-7 - Foreground layer Y scroll
+ */
+ m_vdp.layer_fg_scroll_y = data;
+ break;
+ case 0x14: /* LCD control
+ Bit 0 - LCD enable
+ Bit 1-7 - Unknown
+ */
+ m_vdp.lcd_enable = data & 0x1;
+ break;
+ case 0x15: /* LCD icons
+ Bit 0 - LCD sleep icon enable
+ Bit 1 - Vertical position icon enable
+ Bit 2 - Horizontal position icon enable
+ Bit 3 - Dot 1 icon enable
+ Bit 4 - Dot 2 icon enable
+ Bit 5 - Dot 3 icon enable
+ Bit 6-7 - Unknown
+ */
+ m_vdp.icons = data; /* ummmmm */
+ break;
+ case 0x1c: /* Palette colors 0 and 1
+ Bit 0-3 - Gray tone setting for main palette index 0
+ Bit 4-7 - Gray tone setting for main palette index 1
+ */
+ if ( m_system_type == TYPE_WSC )
+ {
+ int i = 15 - ( data & 0x0F );
+ int j = 15 - ( ( data & 0xF0 ) >> 4 );
+ m_vdp.main_palette[0] = ( i << 8 ) | ( i << 4 ) | i;
+ m_vdp.main_palette[1] = ( j << 8 ) | ( j << 4 ) | j;
+ }
+ else
+ {
+ m_vdp.main_palette[0] = data & 0x0F;
+ m_vdp.main_palette[1] = ( data & 0xF0 ) >> 4;
+ }
+ break;
+ case 0x1d: /* Palette colors 2 and 3
+ Bit 0-3 - Gray tone setting for main palette index 2
+ Bit 4-7 - Gray tone setting for main palette index 3
+ */
+ if ( m_system_type == TYPE_WSC )
+ {
+ int i = 15 - ( data & 0x0F );
+ int j = 15 - ( ( data & 0xF0 ) >> 4 );
+ m_vdp.main_palette[2] = ( i << 8 ) | ( i << 4 ) | i;
+ m_vdp.main_palette[3] = ( j << 8 ) | ( j << 4 ) | j;
+ }
+ else
+ {
+ m_vdp.main_palette[2] = data & 0x0F;
+ m_vdp.main_palette[3] = ( data & 0xF0 ) >> 4;
+ }
+ break;
+ case 0x1e: /* Palette colors 4 and 5
+ Bit 0-3 - Gray tone setting for main palette index 4
+ Bit 4-7 - Gray tone setting for main paeltte index 5
+ */
+ if ( m_system_type == TYPE_WSC )
+ {
+ int i = 15 - ( data & 0x0F );
+ int j = 15 - ( ( data & 0xF0 ) >> 4 );
+ m_vdp.main_palette[4] = ( i << 8 ) | ( i << 4 ) | i;
+ m_vdp.main_palette[5] = ( j << 8 ) | ( j << 4 ) | j;
+ }
+ else
+ {
+ m_vdp.main_palette[4] = data & 0x0F;
+ m_vdp.main_palette[5] = ( data & 0xF0 ) >> 4;
+ }
+ break;
+ case 0x1f: /* Palette colors 6 and 7
+ Bit 0-3 - Gray tone setting for main palette index 6
+ Bit 4-7 - Gray tone setting for main palette index 7
+ */
+ if ( m_system_type == TYPE_WSC )
+ {
+ int i = 15 - ( data & 0x0F );
+ int j = 15 - ( ( data & 0xF0 ) >> 4 );
+ m_vdp.main_palette[6] = ( i << 8 ) | ( i << 4 ) | i;
+ m_vdp.main_palette[7] = ( j << 8 ) | ( j << 4 ) | j;
+ }
+ else
+ {
+ m_vdp.main_palette[6] = data & 0x0F;
+ m_vdp.main_palette[7] = ( data & 0xF0 ) >> 4;
+ }
+ break;
+ case 0x20: /* tile/sprite palette settings
+ Bit 0-3 - Palette 0 index 0
+ Bit 4-7 - Palette 0 index 1 */
+ case 0x21: /* Bit 0-3 - Palette 0 index 2
+ Bit 4-7 - Palette 0 index 3 */
+ case 0x22: /* Bit 0-3 - Palette 1 index 0
+ Bit 4-7 - Palette 1 index 1 */
+ case 0x23: /* Bit 0-3 - Palette 1 index 2
+ Bit 4-7 - Palette 1 index 3 */
+ case 0x24: /* Bit 0-3 - Palette 2 index 0
+ Bit 4-7 - Palette 2 index 1 */
+ case 0x25: /* Bit 0-3 - Palette 2 index 2
+ Bit 4-7 - Palette 2 index 3 */
+ case 0x26: /* Bit 0-3 - Palette 3 index 0
+ Bit 4-7 - Palette 3 index 1 */
+ case 0x27: /* Bit 0-3 - Palette 3 index 2
+ Bit 4-7 - Palette 3 index 3 */
+ case 0x28: /* Bit 0-3 - Palette 4 index 0
+ Bit 4-7 - Palette 4 index 1 */
+ case 0x29: /* Bit 0-3 - Palette 4 index 2
+ Bit 4-7 - Palette 4 index 3 */
+ case 0x2A: /* Bit 0-3 - Palette 5 index 0
+ Bit 4-7 - Palette 5 index 1 */
+ case 0x2B: /* Bit 0-3 - Palette 5 index 2
+ Bit 4-7 - Palette 5 index 3 */
+ case 0x2C: /* Bit 0-3 - Palette 6 index 0
+ Bit 4-7 - Palette 6 index 1 */
+ case 0x2D: /* Bit 0-3 - Palette 6 index 2
+ Bit 4-7 - Palette 6 index 3 */
+ case 0x2E: /* Bit 0-3 - Palette 7 index 0
+ Bit 4-7 - Palette 7 index 1 */
+ case 0x2F: /* Bit 0-3 - Palette 7 index 2
+ Bit 4-7 - Palette 7 index 3 */
+ case 0x30: /* Bit 0-3 - Palette 8 / Sprite Palette 0 index 0
+ Bit 4-7 - Palette 8 / Sprite Palette 0 index 1 */
+ case 0x31: /* Bit 0-3 - Palette 8 / Sprite Palette 0 index 2
+ Bit 4-7 - Palette 8 / Sprite Palette 0 index 3 */
+ case 0x32: /* Bit 0-3 - Palette 9 / Sprite Palette 1 index 0
+ Bit 4-7 - Palette 9 / Sprite Palette 1 index 1 */
+ case 0x33: /* Bit 0-3 - Palette 9 / Sprite Palette 1 index 2
+ Bit 4-7 - Palette 9 / Sprite Palette 1 index 3 */
+ case 0x34: /* Bit 0-3 - Palette 10 / Sprite Palette 2 index 0
+ Bit 4-7 - Palette 10 / Sprite Palette 2 index 1 */
+ case 0x35: /* Bit 0-3 - Palette 10 / Sprite Palette 2 index 2
+ Bit 4-7 - Palette 10 / Sprite Palette 2 index 3 */
+ case 0x36: /* Bit 0-3 - Palette 11 / Sprite Palette 3 index 0
+ Bit 4-7 - Palette 11 / Sprite Palette 3 index 1 */
+ case 0x37: /* Bit 0-3 - Palette 11 / Sprite Palette 3 index 2
+ Bit 4-7 - Palette 11 / Sprite Palette 3 index 3 */
+ case 0x38: /* Bit 0-3 - Palette 12 / Sprite Palette 4 index 0
+ Bit 4-7 - Palette 12 / Sprite Palette 4 index 1 */
+ case 0x39: /* Bit 0-3 - Palette 12 / Sprite Palette 4 index 2
+ Bit 4-7 - Palette 12 / Sprite Palette 4 index 3 */
+ case 0x3A: /* Bit 0-3 - Palette 13 / Sprite Palette 5 index 0
+ Bit 4-7 - Palette 13 / Sprite Palette 5 index 1 */
+ case 0x3B: /* Bit 0-3 - Palette 13 / Sprite Palette 5 index 2
+ Bit 4-7 - Palette 13 / Sprite Palette 5 index 3 */
+ case 0x3C: /* Bit 0-3 - Palette 14 / Sprite Palette 6 index 0
+ Bit 4-7 - Palette 14 / Sprite Palette 6 index 1 */
+ case 0x3D: /* Bit 0-3 - Palette 14 / Sprite Palette 6 index 2
+ Bit 4-7 - Palette 14 / Sprite Palette 6 index 3 */
+ case 0x3E: /* Bit 0-3 - Palette 15 / Sprite Palette 7 index 0
+ Bit 4-7 - Palette 15 / Sprite Palette 7 index 1 */
+ case 0x3F: /* Bit 0-3 - Palette 15 / Sprite Palette 7 index 2
+ Bit 4-7 - Palette 15 / Sprite Palette 7 index 3 */
+ break;
+ case 0x40: /* DMA source address (low)
+ Bit 0-7 - DMA source address bit 0-7
+ */
+ case 0x41: /* DMA source address (high)
+ Bit 0-7 - DMA source address bit 8-15
+ */
+ case 0x42: /* DMA source bank
+ Bit 0-7 - DMA source bank number
+ */
+ case 0x43: /* DMA destination bank
+ Bit 0-7 - DMA destination bank number
+ */
+ case 0x44: /* DMA destination address (low)
+ Bit 0-7 - DMA destination address bit 0-7
+ */
+ case 0x45: /* DMA destination address (high)
+ Bit 0-7 - DMA destination address bit 8-15
+ */
+ case 0x46: /* Size of copied data (low)
+ Bit 0-7 - DMA size bit 0-7
+ */
+ case 0x47: /* Size of copied data (high)
+ Bit 0-7 - DMA size bit 8-15
+ */
+ break;
+ case 0x48: /* DMA control
+ Bit 0-6 - Unknown
+ Bit 7 - DMA stop/start
+ */
+ if( data & 0x80 )
+ {
+ UINT32 src, dst;
+ UINT16 length;
+
+ src = m_ws_portram[0x40] + (m_ws_portram[0x41] << 8) + (m_ws_portram[0x42] << 16);
+ dst = m_ws_portram[0x44] + (m_ws_portram[0x45] << 8) + (m_ws_portram[0x43] << 16);
+ length = m_ws_portram[0x46] + (m_ws_portram[0x47] << 8);
+ for( ; length > 0; length-- )
+ {
+ mem->write_byte(dst, mem->read_byte(src ) );
+ src++;
+ dst++;
+ }
+#ifdef DEBUG
+ logerror( "DMA src:%X dst:%X length:%d\n", src, dst, length );
+#endif
+ m_ws_portram[0x40] = src & 0xFF;
+ m_ws_portram[0x41] = ( src >> 8 ) & 0xFF;
+ m_ws_portram[0x44] = dst & 0xFF;
+ m_ws_portram[0x45] = ( dst >> 8 ) & 0xFF;
+ m_ws_portram[0x46] = length & 0xFF;
+ m_ws_portram[0x47] = ( length >> 8 ) & 0xFF;
+ data &= 0x7F;
+ }
+ break;
+ case 0x4A: /* Sound DMA source address (low)
+ Bit 0-7 - Sound DMA source address bit 0-7
+ */
+ m_sound_dma.source = ( m_sound_dma.source & 0x0FFF00 ) | data;
+ break;
+ case 0x4B: /* Sound DMA source address (high)
+ Bit 0-7 - Sound DMA source address bit 8-15
+ */
+ m_sound_dma.source = ( m_sound_dma.source & 0x0F00FF ) | ( data << 8 );
+ break;
+ case 0x4C: /* Sound DMA source memory segment
+ Bit 0-3 - Sound DMA source address segment
+ Bit 4-7 - Unknown
+ */
+ m_sound_dma.source = ( m_sound_dma.source & 0xFFFF ) | ( ( data & 0x0F ) << 16 );
+ break;
+ case 0x4D: /* Unknown */
+ break;
+ case 0x4E: /* Sound DMA transfer size (low)
+ Bit 0-7 - Sound DMA transfer size bit 0-7
+ */
+ m_sound_dma.size = ( m_sound_dma.size & 0xFF00 ) | data;
+ break;
+ case 0x4F: /* Sound DMA transfer size (high)
+ Bit 0-7 - Sound DMA transfer size bit 8-15
+ */
+ m_sound_dma.size = ( m_sound_dma.size & 0xFF ) | ( data << 8 );
+ break;
+ case 0x50: /* Unknown */
+ case 0x51: /* Unknown */
+ break;
+ case 0x52: /* Sound DMA start/stop
+ Bit 0-6 - Unknown
+ Bit 7 - Sound DMA stop/start
+ */
+ m_sound_dma.enable = data;
+ break;
+ case 0x60: /* Video mode
+ Bit 0-4 - Unknown
+ Bit 5 - Packed mode 0 = not packed mode, 1 = packed mode
+ Bit 6 - 4/16 colour mode select: 0 = 4 colour mode, 1 = 16 colour mode
+ Bit 7 - monochrome/colour mode select: 0 = monochrome mode, 1 = colour mode
+ */
+ /*
+ * 111 - packed, 16 color, use 4000/8000, color
+ * 110 - not packed, 16 color, use 4000/8000, color
+ * 101 - packed, 4 color, use 2000, color
+ * 100 - not packed, 4 color, use 2000, color
+ * 011 - packed, 16 color, use 4000/8000, monochrome
+ * 010 - not packed, 16 color , use 4000/8000, monochrome
+ * 001 - packed, 4 color, use 2000, monochrome
+ * 000 - not packed, 4 color, use 2000, monochrome - Regular WS monochrome
+ */
+ if ( m_system_type == TYPE_WSC )
+ {
+ m_vdp.color_mode = data & 0x80;
+ m_vdp.colors_16 = data & 0x40;
+ m_vdp.tile_packed = data & 0x20;
+ }
+ break;
+ case 0x80: /* Audio 1 freq (lo)
+ Bit 0-7 - Audio channel 1 frequency bit 0-7
+ */
+ case 0x81: /* Audio 1 freq (hi)
+ Bit 0-7 - Audio channel 1 frequency bit 8-15
+ */
+ case 0x82: /* Audio 2 freq (lo)
+ Bit 0-7 - Audio channel 2 frequency bit 0-7
+ */
+ case 0x83: /* Audio 2 freq (hi)
+ Bit 0-7 - Audio channel 2 frequency bit 8-15
+ */
+ case 0x84: /* Audio 3 freq (lo)
+ Bit 0-7 - Audio channel 3 frequency bit 0-7
+ */
+ case 0x85: /* Audio 3 freq (hi)
+ Bit 0-7 - Audio channel 3 frequency bit 8-15
+ */
+ case 0x86: /* Audio 4 freq (lo)
+ Bit 0-7 - Audio channel 4 frequency bit 0-7
+ */
+ case 0x87: /* Audio 4 freq (hi)
+ Bit 0-7 - Audio channel 4 frequency bit 8-15
+ */
+ case 0x88: /* Audio 1 volume
+ Bit 0-3 - Right volume audio channel 1
+ Bit 4-7 - Left volume audio channel 1
+ */
+ case 0x89: /* Audio 2 volume
+ Bit 0-3 - Right volume audio channel 2
+ Bit 4-7 - Left volume audio channel 2
+ */
+ case 0x8A: /* Audio 3 volume
+ Bit 0-3 - Right volume audio channel 3
+ Bit 4-7 - Left volume audio channel 3
+ */
+ case 0x8B: /* Audio 4 volume
+ Bit 0-3 - Right volume audio channel 4
+ Bit 4-7 - Left volume audio channel 4
+ */
+ case 0x8C: /* Sweep step
+ Bit 0-7 - Sweep step
+ */
+ case 0x8D: /* Sweep time
+ Bit 0-7 - Sweep time
+ */
+ case 0x8E: /* Noise control
+ Bit 0-2 - Noise generator type
+ Bit 3 - Reset
+ Bit 4 - Enable
+ Bit 5-7 - Unknown
+ */
+ case 0x8F: /* Sample location
+ Bit 0-7 - Sample address location 0 00xxxxxx xx000000
+ */
+ case 0x90: /* Audio control
+ Bit 0 - Audio 1 enable
+ Bit 1 - Audio 2 enable
+ Bit 2 - Audio 3 enable
+ Bit 3 - Audio 4 enable
+ Bit 4 - Unknown
+ Bit 5 - Audio 2 voice mode enable
+ Bit 6 - Audio 3 sweep mode enable
+ Bit 7 - Audio 4 noise mode enable
+ */
+ case 0x91: /* Audio output
+ Bit 0 - Mono select
+ Bit 1-2 - Output volume
+ Bit 3 - External stereo
+ Bit 4-6 - Unknown
+ Bit 7 - External speaker (Read-only, set by hardware)
+ */
+ case 0x92: /* Noise counter shift register (lo)
+ Bit 0-7 - Noise counter shift register bit 0-7
+ */
+ case 0x93: /* Noise counter shift register (hi)
+ Bit 0-6 - Noise counter shift register bit 8-14
+ bit 7 - Unknown
+ */
+ case 0x94: /* Master volume
+ Bit 0-3 - Master volume
+ Bit 4-7 - Unknown
+ */
+ wswan_sound_port_w( machine().device("custom"), offset, data );
+ break;
+ case 0xa0: /* Hardware type - this is probably read only
+ Bit 0 - Enable cartridge slot and/or disable bios
+ Bit 1 - Hardware type: 0 = WS, 1 = WSC
+ Bit 2-7 - Unknown
+ */
+ if ( ( data & 0x01 ) && !m_bios_disabled )
+ {
+ m_bios_disabled = 1;
+ membank( "bank15" )->set_base( m_ROMMap[ ( ( ( m_ws_portram[0xc0] & 0x0F ) << 4 ) | 15 ) & ( m_ROMBanks - 1 ) ] );
+ }
+ break;
+ case 0xa2: /* Timer control
+ Bit 0 - HBlank Timer enable
+ Bit 1 - HBlank Timer mode: 0 = one shot, 1 = auto reset
+ Bit 2 - VBlank Timer(1/75s) enable
+ Bit 3 - VBlank Timer mode: 0 = one shot, 1 = auto reset
+ Bit 4-7 - Unknown
+ */
+ m_vdp.timer_hblank_enable = data & 0x1;
+ m_vdp.timer_hblank_mode = (data & 0x2) >> 1;
+ m_vdp.timer_vblank_enable = (data & 0x4) >> 2;
+ m_vdp.timer_vblank_mode = (data & 0x8) >> 3;
+ break;
+ case 0xa4: /* HBlank timer frequency (low) - reload value
+ Bit 0-7 - HBlank timer reload value bit 0-7
+ */
+ m_vdp.timer_hblank_reload &= 0xff00;
+ m_vdp.timer_hblank_reload += data;
+ m_vdp.timer_hblank_count = m_vdp.timer_hblank_reload;
+ break;
+ case 0xa5: /* HBlank timer frequency (high) - reload value
+ Bit 8-15 - HBlank timer reload value bit 8-15
+ */
+ m_vdp.timer_hblank_reload &= 0xff;
+ m_vdp.timer_hblank_reload += data << 8;
+ m_vdp.timer_hblank_count = m_vdp.timer_hblank_reload;
+ break;
+ case 0xa6: /* VBlank timer frequency (low) - reload value
+ Bit 0-7 - VBlank timer reload value bit 0-7
+ */
+ m_vdp.timer_vblank_reload &= 0xff00;
+ m_vdp.timer_vblank_reload += data;
+ m_vdp.timer_vblank_count = m_vdp.timer_vblank_reload;
+ break;
+ case 0xa7: /* VBlank timer frequency (high) - reload value
+ Bit 0-7 - VBlank timer reload value bit 8-15
+ */
+ m_vdp.timer_vblank_reload &= 0xff;
+ m_vdp.timer_vblank_reload += data << 8;
+ m_vdp.timer_vblank_count = m_vdp.timer_vblank_reload;
+ break;
+ case 0xa8: /* HBlank counter (low)
+ Bit 0-7 - HBlank counter bit 0-7
+ */
+ case 0xa9: /* HBlank counter (high)
+ Bit 0-7 - HBlank counter bit 8-15
+ */
+ case 0xaa: /* VBlank counter (low)
+ Bit 0-7 - VBlank counter bit 0-7
+ */
+ case 0xab: /* VBlank counter (high)
+ Bit 0-7 - VBlank counter bit 8-15
+ */
+ break;
+
+ case 0xb0: /* Interrupt base vector
+ Bit 0-7 - Interrupt base vector
+ */
+ break;
+ case 0xb1: /* Communication byte
+ Bit 0-7 - Communication byte
+ */
+ break;
+ case 0xb2: /* Interrupt enable
+ Bit 0 - Serial transmit interrupt enable
+ Bit 1 - Key press interrupt enable
+ Bit 2 - RTC alarm interrupt enable
+ Bit 3 - Serial receive interrupt enable
+ Bit 4 - Drawing line detection interrupt enable
+ Bit 5 - VBlank timer interrupt enable
+ Bit 6 - VBlank interrupt enable
+ Bit 7 - HBlank timer interrupt enable
+ */
+ break;
+ case 0xb3: /* serial communication control
+ Bit 0 - Receive complete
+ Bit 1 - Error
+ Bit 2 - Send complete
+ Bit 3-4 - Unknown
+ Bit 5 - Send data interrupt generation
+ Bit 6 - Connection speed: 0 = 9600 bps, 1 = 38400 bps
+ bit 7 - Receive data interrupt generation
+ */
+// data |= 0x02;
+ m_ws_portram[0xb1] = 0xFF;
+ if ( data & 0x80 )
+ {
+// m_ws_portram[0xb1] = 0x00;
+ data |= 0x04;
+ }
+ if (data & 0x20 )
+ {
+// data |= 0x01;
+ }
+ break;
+ case 0xb5: /* Read controls
+ Bit 0-3 - Current state of input lines (read-only)
+ Bit 4-6 - Select line of inputs to read
+ 001 - Read Y cursors
+ 010 - Read X cursors
+ 100 - Read START,A,B buttons
+ Bit 7 - Unknown
+ */
+ data = data & 0xF0;
+ switch( data )
+ {
+ case 0x10: /* Read Y cursors: Y1 - Y2 - Y3 - Y4 */
+ input = ioport("CURSY")->read();
+ if (state->m_rotate) // reorient controls if the console is rotated
+ {
+ if (input & 0x01) data |= 0x02;
+ if (input & 0x02) data |= 0x04;
+ if (input & 0x04) data |= 0x08;
+ if (input & 0x08) data |= 0x01;
+ }
+ else
+ data = data | input;
+ break;
+ case 0x20: /* Read X cursors: X1 - X2 - X3 - X4 */
+ input = ioport("CURSX")->read();
+ if (state->m_rotate) // reorient controls if the console is rotated
+ {
+ if (input & 0x01) data |= 0x02;
+ if (input & 0x02) data |= 0x04;
+ if (input & 0x04) data |= 0x08;
+ if (input & 0x08) data |= 0x01;
+ }
+ else
+ data = data | input;
+ break;
+ case 0x40: /* Read buttons: START - A - B */
+ data = data | ioport("BUTTONS")->read();
+ break;
+ }
+ break;
+ case 0xb6: /* Interrupt acknowledge
+ Bit 0 - Serial transmit interrupt acknowledge
+ Bit 1 - Key press interrupt acknowledge
+ Bit 2 - RTC alarm interrupt acknowledge
+ Bit 3 - Serial receive interrupt acknowledge
+ Bit 4 - Drawing line detection interrupt acknowledge
+ Bit 5 - VBlank timer interrupt acknowledge
+ Bit 6 - VBlank interrupt acknowledge
+ Bit 7 - HBlank timer interrupt acknowledge
+ */
+ wswan_clear_irq_line(data);
+ data = m_ws_portram[0xB6];
+ break;
+ case 0xba: /* Internal EEPROM data (low)
+ Bit 0-7 - Internal EEPROM data transfer bit 0-7
+ */
+ case 0xbb: /* Internal EEPROM data (high)
+ Bit 0-7 - Internal EEPROM data transfer bit 8-15
+ */
+ break;
+ case 0xbc: /* Internal EEPROM address (low)
+ Bit 0-7 - Internal EEPROM address bit 1-8
+ */
+ case 0xbd: /* Internal EEPROM address (high)
+ Bit 0 - Internal EEPROM address bit 9(?)
+ Bit 1-7 - Unknown
+ Only 1KByte internal EEPROM??
+ */
+ break;
+ case 0xbe: /* Internal 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 & 0x20 )
+ {
+ UINT16 addr = ( ( ( m_ws_portram[0xbd] << 8 ) | m_ws_portram[0xbc] ) << 1 ) & 0x1FF;
+ m_internal_eeprom[ addr ] = m_ws_portram[0xba];
+ m_internal_eeprom[ addr + 1 ] = m_ws_portram[0xbb];
+ data |= 0x02;
+ }
+ else if ( data & 0x10 )
+ {
+ UINT16 addr = ( ( ( m_ws_portram[0xbd] << 8 ) | m_ws_portram[0xbc] ) << 1 ) & 0x1FF;
+ m_ws_portram[0xba] = m_internal_eeprom[ addr ];
+ m_ws_portram[0xbb] = m_internal_eeprom[ addr + 1];
+ data |= 0x01;
+ }
+ else
+ {
+ logerror( "Unsupported internal EEPROM command: %X\n", data );
+ }
+ break;
+ case 0xc0: /* ROM bank select for banks 4-15
+ Bit 0-3 - ROM bank base register for banks 4-15
+ Bit 4-7 - Unknown
+ */
+ membank( "bank4" )->set_base( m_ROMMap[ ( ( ( data & 0x0F ) << 4 ) | 4 ) & ( m_ROMBanks - 1 ) ] );
+ membank( "bank5" )->set_base( m_ROMMap[ ( ( ( data & 0x0F ) << 4 ) | 5 ) & ( m_ROMBanks - 1 ) ] );
+ membank( "bank6" )->set_base( m_ROMMap[ ( ( ( data & 0x0F ) << 4 ) | 6 ) & ( m_ROMBanks - 1 ) ] );
+ membank( "bank7" )->set_base( m_ROMMap[ ( ( ( data & 0x0F ) << 4 ) | 7 ) & ( m_ROMBanks - 1 ) ] );
+ membank( "bank8" )->set_base( m_ROMMap[ ( ( ( data & 0x0F ) << 4 ) | 8 ) & ( m_ROMBanks - 1 ) ] );
+ membank( "bank9" )->set_base( m_ROMMap[ ( ( ( data & 0x0F ) << 4 ) | 9 ) & ( m_ROMBanks - 1 ) ] );
+ membank( "bank10" )->set_base( m_ROMMap[ ( ( ( data & 0x0F ) << 4 ) | 10 ) & ( m_ROMBanks - 1 ) ] );
+ membank( "bank11" )->set_base( m_ROMMap[ ( ( ( data & 0x0F ) << 4 ) | 11 ) & ( m_ROMBanks - 1 ) ] );
+ membank( "bank12" )->set_base( m_ROMMap[ ( ( ( data & 0x0F ) << 4 ) | 12 ) & ( m_ROMBanks - 1 ) ] );
+ membank( "bank13" )->set_base( m_ROMMap[ ( ( ( data & 0x0F ) << 4 ) | 13 ) & ( m_ROMBanks - 1 ) ] );
+ membank( "bank14" )->set_base( m_ROMMap[ ( ( ( data & 0x0F ) << 4 ) | 14 ) & ( m_ROMBanks - 1 ) ] );
+ if ( m_bios_disabled )
+ {
+ membank( "bank15" )->set_base( m_ROMMap[ ( ( ( data & 0x0F ) << 4 ) | 15 ) & ( m_ROMBanks - 1 ) ] );
+ }
+ break;
+ case 0xc1: /* SRAM bank select
+ Bit 0-7 - SRAM bank to select
+ */
+ if ( m_eeprom.mode == SRAM_64K || m_eeprom.mode == SRAM_256K || m_eeprom.mode == SRAM_512K || m_eeprom.mode == SRAM_1M || m_eeprom.mode == SRAM_2M )
+ {
+ m_eeprom.page = &m_eeprom.data[ ( data * 64 * 1024 ) & ( m_eeprom.size - 1 ) ];
+ }
+ break;
+ case 0xc2: /* ROM bank select for segment 2 (0x20000 - 0x2ffff)
+ Bit 0-7 - ROM bank for segment 2
+ */
+ membank( "bank2" )->set_base( m_ROMMap[ data & ( m_ROMBanks - 1 ) ]);
+ break;
+ case 0xc3: /* ROM bank select for segment 3 (0x30000-0x3ffff)
+ Bit 0-7 - ROM bank for segment 3
+ */
+ membank( "bank3" )->set_base( m_ROMMap[ data & ( m_ROMBanks - 1 ) ]);
+ break;
+ case 0xc6: /* 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_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 0xc7: /* 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_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 0xc8: /* 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 ( m_eeprom.mode == EEPROM_1K || m_eeprom.mode == EEPROM_16K )
+ {
+ 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 );
+ }
+ }
+ if ( data & 0x20 )
+ { /* Write */
+ if ( m_eeprom.write_enabled )
+ {
+ switch( m_eeprom.command )
+ {
+ case 0x04:
+ m_eeprom.data[ ( m_eeprom.address << 1 ) + 1 ] = m_ws_portram[0xc4];
+ m_eeprom.data[ m_eeprom.address << 1 ] = m_ws_portram[0xc5];
+ data |= 0x02;
+ break;
+ default:
+ logerror( "Unsupported 'Write' command %X\n", m_eeprom.command );
+ }
+ }
+ }
+ if ( data & 0x10 )
+ { /* Read */
+ m_ws_portram[0xc4] = m_eeprom.data[ ( m_eeprom.address << 1 ) + 1 ];
+ m_ws_portram[0xc5] = m_eeprom.data[ m_eeprom.address << 1 ];
+ data |= 0x01;
+ }
+ }
+ else
+ {
+ logerror( "EEPROM command for unknown EEPROM type\n" );
+ }
+ break;
+ case 0xca: /* 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)
+ */
+ 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_ws_portram[0xcb];
+ data |= 0x80;
+ break;
+ case 0x13: /* Read Timer Settings (Alarm) */
+ m_rtc.index = 8;
+ m_ws_portram[0xcb] = m_rtc.setting;
+ data |= 0x80;
+ break;
+ case 0x14: /* Set Time/Date */
+ m_rtc.year = m_ws_portram[0xcb];
+ m_rtc.index = 1;
+ data |= 0x80;
+ break;
+ case 0x15: /* Get Time/Date */
+ m_rtc.index = 0;
+ data |= 0x80;
+ m_ws_portram[0xcb] = m_rtc.year;
+ break;
+ default:
+ logerror( "%X: Unknown RTC command (%X) requested\n", cpu_get_pc( &mem->device() ), data );
+ }
+ break;
+ case 0xcb: /* RTC Data */
+ if ( m_ws_portram[0xca] == 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;
+ default:
+ logerror( "Write to unsupported port: %X - %X\n", offset, data );
+ break;
+ }
+
+ /* Update the port value */
+ m_ws_portram[offset] = data;
+}
+
+static const char* wswan_determine_sram( wswan_state *state, UINT8 data )
+{
+ state->m_eeprom.write_enabled = 0;
+ state->m_eeprom.mode = SRAM_UNKNOWN;
+ switch( data )
+ {
+ case 0x00: state->m_eeprom.mode = SRAM_NONE; break;
+ case 0x01: state->m_eeprom.mode = SRAM_64K; break;
+ case 0x02: state->m_eeprom.mode = SRAM_256K; break;
+ case 0x03: state->m_eeprom.mode = SRAM_1M; break;
+ case 0x04: state->m_eeprom.mode = SRAM_2M; break;
+ case 0x05: state->m_eeprom.mode = SRAM_512K; break;
+ case 0x10: state->m_eeprom.mode = EEPROM_1K; break;
+ case 0x20: state->m_eeprom.mode = EEPROM_16K; break;
+ case 0x50: state->m_eeprom.mode = EEPROM_8K; break;
+ }
+ state->m_eeprom.size = wswan_sram_size[ state->m_eeprom.mode ];
+ return wswan_sram_str[ state->m_eeprom.mode ];
+}
+
+enum enum_romsize { ROM_4M=0, ROM_8M, ROM_16M, ROM_32M, ROM_64M, ROM_128M, ROM_UNKNOWN };
+static const char *const wswan_romsize_str[] = {
+ "4Mbit", "8Mbit", "16Mbit", "32Mbit", "64Mbit", "128Mbit", "Unknown"
+};
+
+static const char* wswan_determine_romsize( UINT8 data )
+{
+ switch( data )
+ {
+ case 0x02: return wswan_romsize_str[ ROM_4M ];
+ case 0x03: return wswan_romsize_str[ ROM_8M ];
+ case 0x04: return wswan_romsize_str[ ROM_16M ];
+ case 0x06: return wswan_romsize_str[ ROM_32M ];
+ case 0x08: return wswan_romsize_str[ ROM_64M ];
+ case 0x09: return wswan_romsize_str[ ROM_128M ];
+ }
+ return wswan_romsize_str[ ROM_UNKNOWN ];
+}
+
+DEVICE_START(wswan_cart)
+{
+ wswan_state *state = device->machine().driver_data<wswan_state>();
+ /* Initialize EEPROM structure */
+ memset( &state->m_eeprom, 0, sizeof( state->m_eeprom ) );
+ state->m_eeprom.data = NULL;
+ state->m_eeprom.page = NULL;
+
+ /* Initialize RTC structure */
+ state->m_rtc.present = 0;
+ state->m_rtc.index = 0;
+ state->m_rtc.year = 0;
+ state->m_rtc.month = 0;
+ state->m_rtc.day = 0;
+ state->m_rtc.day_of_week = 0;
+ state->m_rtc.hour = 0;
+ state->m_rtc.minute = 0;
+ state->m_rtc.second = 0;
+ state->m_rtc.setting = 0xFF;
+}
+
+DEVICE_IMAGE_LOAD(wswan_cart)
+{
+ wswan_state *state = image.device().machine().driver_data<wswan_state>();
+ UINT32 ii, size;
+ const char *sram_str;
+
+ if (image.software_entry() == NULL)
+ size = image.length();
+ else
+ size = image.get_software_region_length("rom");
+
+ state->m_ws_ram = (UINT8*) image.device().machine().device("maincpu")->memory().space(AS_PROGRAM)->get_read_ptr(0);
+ memset(state->m_ws_ram, 0, 0xffff);
+ state->m_ROMBanks = size / 65536;
+
+ for (ii = 0; ii < state->m_ROMBanks; ii++)
+ {
+ if ((state->m_ROMMap[ii] = auto_alloc_array(image.device().machine(), UINT8, 0x10000)))
+ {
+ if (image.software_entry() == NULL)
+ {
+ if (image.fread( state->m_ROMMap[ii], 0x10000) != 0x10000)
+ {
+ image.seterror(IMAGE_ERROR_INVALIDIMAGE, "Wrongly sized ROM");
+ image.message(" Wrongly sized ROM");
+ logerror("Error while reading loading rom!\n");
+ return IMAGE_INIT_FAIL;
+ }
+ }
+ else
+ memcpy(state->m_ROMMap[ii], image.get_software_region("rom") + ii * 0x10000, 0x10000);
+ }
+ else
+ {
+ image.seterror(IMAGE_ERROR_INVALIDIMAGE, "Unable to allocate memory for ROM");
+ image.message(" Unable to allocate memory for ROM");
+ logerror("Memory allocation failed reading rom!\n");
+ return IMAGE_INIT_FAIL;
+ }
+ }
+
+ sram_str = wswan_determine_sram(state, state->m_ROMMap[state->m_ROMBanks - 1][0xfffb]);
+
+ state->m_rtc.present = state->m_ROMMap[state->m_ROMBanks - 1][0xfffd] ? 1 : 0;
+ state->m_rotate = state->m_ROMMap[state->m_ROMBanks-1][0xfffc] & 0x01;
+
+ {
+ int sum = 0;
+ /* Spit out some info */
+ logerror("ROM DETAILS\n" );
+ logerror("\tDeveloper ID: %X\n", state->m_ROMMap[state->m_ROMBanks - 1][0xfff6]);
+ logerror("\tMinimum system: %s\n", state->m_ROMMap[state->m_ROMBanks - 1][0xfff7] ? "WonderSwan Color" : "WonderSwan");
+ logerror("\tCart ID: %X\n", state->m_ROMMap[state->m_ROMBanks - 1][0xfff8]);
+ logerror("\tROM size: %s\n", wswan_determine_romsize(state->m_ROMMap[state->m_ROMBanks - 1][0xfffa]));
+ logerror("\tSRAM size: %s\n", sram_str);
+ logerror("\tFeatures: %X\n", state->m_ROMMap[state->m_ROMBanks - 1][0xfffc]);
+ logerror("\tRTC: %s\n", state->m_ROMMap[state->m_ROMBanks - 1][0xfffd] ? "yes" : "no");
+ for (ii = 0; ii < state->m_ROMBanks; ii++)
+ {
+ int count;
+ for (count = 0; count < 0x10000; count++)
+ {
+ sum += state->m_ROMMap[ii][count];
+ }
+ }
+ sum -= state->m_ROMMap[state->m_ROMBanks - 1][0xffff];
+ sum -= state->m_ROMMap[state->m_ROMBanks - 1][0xfffe];
+ sum &= 0xffff;
+ logerror("\tChecksum: %X%X (calculated: %04X)\n", state->m_ROMMap[state->m_ROMBanks - 1][0xffff], state->m_ROMMap[state->m_ROMBanks - 1][0xfffe], sum);
+ }
+
+ if (state->m_eeprom.size != 0)
+ {
+ state->m_eeprom.data = auto_alloc_array(image.device().machine(), UINT8, state->m_eeprom.size);
+ image.battery_load(state->m_eeprom.data, state->m_eeprom.size, 0x00);
+ state->m_eeprom.page = state->m_eeprom.data;
+ }
+
+ if (image.software_entry() == NULL)
+ {
+ logerror("Image Name: %s\n", image.longname());
+ logerror("Image Year: %s\n", image.year());
+ logerror("Image Manufacturer: %s\n", image.manufacturer());
+ }
+
+ /* All done */
+ return IMAGE_INIT_PASS;
+}
+
+static TIMER_CALLBACK(wswan_scanline_interrupt)
+{
+ wswan_state *state = machine.driver_data<wswan_state>();
+ if( state->m_vdp.current_line < 144 )
+ {
+ wswan_refresh_scanline(machine);
+ }
+
+ /* Decrement 12kHz (HBlank) counter */
+ if ( state->m_vdp.timer_hblank_enable && state->m_vdp.timer_hblank_reload != 0 )
+ {
+ state->m_vdp.timer_hblank_count--;
+ logerror( "timer_hblank_count: %X\n", state->m_vdp.timer_hblank_count );
+ if ( state->m_vdp.timer_hblank_count == 0 )
+ {
+ if ( state->m_vdp.timer_hblank_mode )
+ {
+ state->m_vdp.timer_hblank_count = state->m_vdp.timer_hblank_reload;
+ }
+ else
+ {
+ state->m_vdp.timer_hblank_reload = 0;
+ }
+ logerror( "trigerring hbltmr interrupt\n" );
+ wswan_set_irq_line( machine, WSWAN_IFLAG_HBLTMR );
+ }
+ }
+
+ /* Handle Sound DMA */
+ if ( ( state->m_sound_dma.enable & 0x88 ) == 0x80 )
+ {
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM );
+ /* TODO: Output sound DMA byte */
+ state->wswan_port_w( *space, 0x89, space->read_byte(state->m_sound_dma.source ) );
+ state->m_sound_dma.size--;
+ state->m_sound_dma.source = ( state->m_sound_dma.source + 1 ) & 0x0FFFFF;
+ if ( state->m_sound_dma.size == 0 )
+ {
+ state->m_sound_dma.enable &= 0x7F;
+ }
+ }
+
+// state->m_vdp.current_line = (state->m_vdp.current_line + 1) % 159;
+
+ if( state->m_vdp.current_line == 144 ) // buffer sprite table
+ {
+ memcpy(state->m_vdp.sprite_table_buffer, &state->m_vdp.vram[state->m_vdp.sprite_table_address], 512);
+ state->m_vdp.sprite_count = state->m_ws_portram[0x06];
+ state->m_vdp.sprite_first = state->m_ws_portram[0x05]; // always zero?
+ }
+
+ if( state->m_vdp.current_line == 144 )
+ {
+ wswan_set_irq_line( machine, WSWAN_IFLAG_VBL );
+ /* Decrement 75Hz (VBlank) counter */
+ if ( state->m_vdp.timer_vblank_enable && state->m_vdp.timer_vblank_reload != 0 )
+ {
+ state->m_vdp.timer_vblank_count--;
+ logerror( "timer_vblank_count: %X\n", state->m_vdp.timer_vblank_count );
+ if ( state->m_vdp.timer_vblank_count == 0 )
+ {
+ if ( state->m_vdp.timer_vblank_mode )
+ {
+ state->m_vdp.timer_vblank_count = state->m_vdp.timer_vblank_reload;
+ }
+ else
+ {
+ state->m_vdp.timer_vblank_reload = 0;
+ }
+ logerror( "triggering vbltmr interrupt\n" );
+ wswan_set_irq_line( machine, WSWAN_IFLAG_VBLTMR );
+ }
+ }
+ }
+
+// state->m_vdp.current_line = (state->m_vdp.current_line + 1) % 159;
+
+ if ( state->m_vdp.current_line == state->m_vdp.line_compare )
+ {
+ wswan_set_irq_line( machine, WSWAN_IFLAG_LCMP );
+ }
+
+ state->m_vdp.current_line = (state->m_vdp.current_line + 1) % 159;
+}
+
diff --git a/src/mess/machine/x1.c b/src/mess/machine/x1.c
new file mode 100644
index 00000000000..c8cf472e689
--- /dev/null
+++ b/src/mess/machine/x1.c
@@ -0,0 +1,67 @@
+
+#include "includes/x1.h"
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+const device_type X1_KEYBOARD = &device_creator<x1_keyboard_device>;
+
+//-------------------------------------------------
+// z80ctc_device - constructor
+//-------------------------------------------------
+
+x1_keyboard_device::x1_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, X1_KEYBOARD, "X1 Keyboard", tag, owner, clock),
+ device_z80daisy_interface(mconfig, *this)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void x1_keyboard_device::device_start()
+{
+}
+
+//**************************************************************************
+// DAISY CHAIN INTERFACE
+//**************************************************************************
+
+//-------------------------------------------------
+// z80daisy_irq_state - return the overall IRQ
+// state for this device
+//-------------------------------------------------
+
+int x1_keyboard_device::z80daisy_irq_state()
+{
+ x1_state *state = machine().driver_data<x1_state>();
+ if(state->m_key_irq_flag != 0)
+ return Z80_DAISY_INT;
+ return 0;
+}
+
+
+//-------------------------------------------------
+// z80daisy_irq_ack - acknowledge an IRQ and
+// return the appropriate vector
+//-------------------------------------------------
+
+int x1_keyboard_device::z80daisy_irq_ack()
+{
+ x1_state *state = machine().driver_data<x1_state>();
+ state->m_key_irq_flag = 0;
+ cputag_set_input_line(device().machine(),"x1_cpu",INPUT_LINE_IRQ0,CLEAR_LINE);
+ return state->m_key_irq_vector;
+}
+
+//-------------------------------------------------
+// z80daisy_irq_reti - clear the interrupt
+// pending state to allow other interrupts through
+//-------------------------------------------------
+
+void x1_keyboard_device::z80daisy_irq_reti()
+{
+}
diff --git a/src/mess/machine/x68k_hdc.c b/src/mess/machine/x68k_hdc.c
new file mode 100644
index 00000000000..4c976f9b993
--- /dev/null
+++ b/src/mess/machine/x68k_hdc.c
@@ -0,0 +1,430 @@
+/*
+
+ X68000 custom SASI Hard Disk controller
+
+ 0xe96001 (R/W) - SASI data I/O
+ 0xe96003 (W) - SEL signal high (0)
+ 0xe96003 (R) - SASI status
+ - bit 4 = MSG - if 1, content of data line is a message
+ - bit 3 = Command / Data - if 1, content of data line is a command or status, otherwise it is data.
+ - bit 2 = I/O - if 0, Host -> Controller (Output), otherwise Controller -> Host (Input).
+ - bit 1 = BSY - if 1, HD is busy.
+ - bit 0 = REQ - if 1, host is demanding data transfer to the host.
+ 0xe96005 (W/O) - data is arbitrary (?)
+ 0xe96007 (W/O) - SEL signal low (1)
+
+*/
+
+#include "x68k_hdc.h"
+#include "imagedev/harddriv.h"
+#include "image.h"
+
+const device_type X68KHDC = &device_creator<x68k_hdc_image_device>;
+
+x68k_hdc_image_device::x68k_hdc_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, X68KHDC, "SASI Hard Disk", tag, owner, clock),
+ device_image_interface(mconfig, *this)
+{
+}
+
+void x68k_hdc_image_device::device_config_complete()
+{
+ update_names(X68KHDC, "sasihd", "sasi");
+}
+
+void x68k_hdc_image_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ m_req = 1;
+ m_status_port |= 0x01;
+}
+
+void x68k_hdc_image_device::device_start()
+{
+ m_status = 0x00;
+ m_status_port = 0x00;
+ m_phase = SASI_PHASE_BUSFREE;
+}
+
+bool x68k_hdc_image_device::call_create(int format_type, option_resolution *format_options)
+{
+ // create 20MB HD
+ int x;
+ int ret;
+ unsigned char sectordata[256]; // empty block data
+
+ memset(sectordata,0,sizeof(sectordata));
+ for(x=0;x<0x013c98;x++) // 0x13c98 = number of blocks on a 20MB HD
+ {
+ ret = fwrite(sectordata,256);
+ if(ret < 256)
+ return IMAGE_INIT_FAIL;
+ }
+
+ return IMAGE_INIT_PASS;
+}
+
+WRITE16_MEMBER( x68k_hdc_image_device::hdc_w )
+{
+ unsigned int lba = 0;
+ char* blk;
+ switch(offset)
+ {
+ case 0x00: // data I/O
+ if(m_phase == SASI_PHASE_WRITE)
+ {
+ if(m_transfer_byte_count == 0)
+ {
+ switch(m_command[0])
+ {
+ case SASI_CMD_SPECIFY:
+ m_transfer_byte_total = 10;
+ break;
+ case SASI_CMD_WRITE:
+ m_transfer_byte_total = (0x100 * m_command[4]);
+ break;
+ default:
+ m_transfer_byte_total = 0x100;
+ }
+ }
+
+ if(m_command[0] == SASI_CMD_SPECIFY)
+ {
+ logerror("SPECIFY: wrote 0x%02x\n",data);
+ }
+
+ if(m_command[0] == SASI_CMD_WRITE)
+ {
+ if(!exists())
+ {
+ m_phase = SASI_PHASE_STATUS;
+ m_io = 1; // Output
+ m_status_port |= 0x04; // C/D remains the same
+ m_status = 0x02;
+ logerror("SASI: No HD connected.\n");
+ }
+ else
+ {
+ fwrite(&data,1);
+ }
+ }
+
+ m_req = 0;
+ m_status_port &= ~0x01;
+ timer_set(attotime::from_nsec(450));
+ m_transfer_byte_count++;
+ if(m_transfer_byte_count >= m_transfer_byte_total)
+ {
+ // End of transfer
+ m_phase = SASI_PHASE_STATUS;
+ m_io = 1;
+ m_status_port |= 0x04;
+ m_cd = 1;
+ m_status_port |= 0x08;
+ logerror("SASI: Write transfer complete\n");
+ }
+ }
+ if(m_phase == SASI_PHASE_COMMAND)
+ {
+ if(m_command_byte_count == 0)
+ {
+ // first command byte
+ m_current_command = data;
+ switch(data >> 5) // high 3 bits determine command class, and therefore, length
+ {
+ case 0:
+ m_command_byte_total = 6;
+ break;
+ case 1:
+ m_command_byte_total = 10;
+ break;
+ case 2:
+ m_command_byte_total = 8;
+ break;
+ default:
+ m_command_byte_total = 6;
+ }
+ }
+ m_command[m_command_byte_count] = data;
+ // reset REQ temporarily
+ m_req = 0;
+ m_status_port &= ~0x01;
+ timer_set(attotime::from_nsec(450));
+
+ m_command_byte_count++;
+ if(m_command_byte_count >= m_command_byte_total)
+ {
+ // End of command
+
+ switch(m_command[0])
+ {
+ case SASI_CMD_REZERO_UNIT:
+ m_phase = SASI_PHASE_STATUS;
+ m_io = 1; // Output
+ m_status_port |= 0x04; // C/D remains the same
+ logerror("SASI: REZERO UNIT\n");
+ break;
+ case SASI_CMD_REQUEST_SENSE:
+ m_phase = SASI_PHASE_READ;
+ m_io = 1;
+ m_status_port |= 0x04;
+ m_cd = 0;
+ m_status_port &= ~0x08;
+ m_transfer_byte_count = 0;
+ m_transfer_byte_total = 0;
+ logerror("SASI: REQUEST SENSE\n");
+ break;
+ case SASI_CMD_SPECIFY:
+ m_phase = SASI_PHASE_WRITE;
+ m_io = 0;
+ m_status_port &= ~0x04;
+ m_cd = 0; // Data
+ m_status_port &= ~0x08;
+ m_transfer_byte_count = 0;
+ m_transfer_byte_total = 0;
+ logerror("SASI: SPECIFY\n");
+ break;
+ case SASI_CMD_READ:
+ if(!exists())
+ {
+ m_phase = SASI_PHASE_STATUS;
+ m_io = 1; // Output
+ m_status_port |= 0x04; // C/D remains the same
+ m_cd = 1;
+ m_status_port |= 0x08;
+ m_status = 0x02;
+ logerror("SASI: No HD connected\n");
+ }
+ else
+ {
+ m_phase = SASI_PHASE_READ;
+ m_io = 1;
+ m_status_port |= 0x04;
+ m_cd = 0;
+ m_status_port &= ~0x08;
+ m_transfer_byte_count = 0;
+ m_transfer_byte_total = 0;
+ lba = m_command[3];
+ lba |= m_command[2] << 8;
+ lba |= (m_command[1] & 0x1f) << 16;
+ fseek(lba * 256,SEEK_SET);
+ logerror("SASI: READ (LBA 0x%06x, blocks = %i)\n",lba,m_command[4]);
+ }
+ break;
+ case SASI_CMD_WRITE:
+ if(!exists())
+ {
+ m_phase = SASI_PHASE_STATUS;
+ m_io = 1; // Output
+ m_status_port |= 0x04; // C/D remains the same
+ m_cd = 1;
+ m_status_port |= 0x08;
+ m_status = 0x02;
+ logerror("SASI: No HD connected\n");
+ }
+ else
+ {
+ m_phase = SASI_PHASE_WRITE;
+ m_io = 0;
+ m_status_port &= ~0x04;
+ m_cd = 0;
+ m_status_port &= ~0x08;
+ m_transfer_byte_count = 0;
+ m_transfer_byte_total = 0;
+ lba = m_command[3];
+ lba |= m_command[2] << 8;
+ lba |= (m_command[1] & 0x1f) << 16;
+ fseek(lba * 256,SEEK_SET);
+ logerror("SASI: WRITE (LBA 0x%06x, blocks = %i)\n",lba,m_command[4]);
+ }
+ break;
+ case SASI_CMD_SEEK:
+ m_phase = SASI_PHASE_STATUS;
+ m_io = 1; // Output
+ m_status_port |= 0x04; // C/D remains the same
+ m_cd = 1;
+ m_status_port |= 0x08;
+ logerror("SASI: SEEK (LBA 0x%06x)\n",lba);
+ break;
+ case SASI_CMD_FORMAT_UNIT:
+ case SASI_CMD_FORMAT_UNIT_06:
+ /*
+ Format Unit command format (differs from SASI spec?)
+ 0 | 0x06
+ 1 | Unit number (0-7) | LBA MSB (high 5 bits)
+ 2 | LBA
+ 3 | LBA LSB
+ 4 | ?? (usually 0x01)
+ 5 | ??
+ */
+ m_phase = SASI_PHASE_STATUS;
+ m_io = 1; // Output
+ m_status_port |= 0x04; // C/D remains the same
+ m_cd = 1;
+ m_status_port |= 0x08;
+ lba = m_command[3];
+ lba |= m_command[2] << 8;
+ lba |= (m_command[1] & 0x1f) << 16;
+ fseek(lba * 256,SEEK_SET);
+ blk = (char*)malloc(256*33);
+ memset(blk,0,256*33);
+ // formats 33 256-byte blocks
+ fwrite(blk,256*33);
+ free(blk);
+ logerror("SASI: FORMAT UNIT (LBA 0x%06x)\n",lba);
+ break;
+ default:
+ m_phase = SASI_PHASE_STATUS;
+ m_io = 1; // Output
+ m_status_port |= 0x04; // C/D remains the same
+ m_status = 0x02;
+ logerror("SASI: Invalid or unimplemented SASI command (0x%02x) received.\n",m_command[0]);
+ }
+ }
+ }
+ break;
+ case 0x01:
+ if(data == 0)
+ {
+ if(m_phase == SASI_PHASE_SELECTION)
+ {
+ // Go to Command phase
+ m_phase = SASI_PHASE_COMMAND;
+ m_cd = 1; // data port expects a command or status
+ m_status_port |= 0x08;
+ m_command_byte_count = 0;
+ m_command_byte_total = 0;
+ timer_set(attotime::from_nsec(45));
+ }
+ }
+ break;
+ case 0x02:
+ break;
+ case 0x03:
+ if(data != 0)
+ {
+ if(m_phase == SASI_PHASE_BUSFREE)
+ {
+ // Go to Selection phase
+ m_phase = SASI_PHASE_SELECTION;
+ m_bsy = 1; // HDC is now busy
+ m_status_port |= 0x02;
+ }
+ }
+ break;
+ }
+
+// logerror("SASI: write to HDC, offset %04x, data %04x\n",offset,data);
+}
+
+READ16_MEMBER( x68k_hdc_image_device::hdc_r )
+{
+ int retval = 0xff;
+
+ switch(offset)
+ {
+ case 0x00:
+ if(m_phase == SASI_PHASE_MESSAGE)
+ {
+ m_phase = SASI_PHASE_BUSFREE;
+ m_msg = 0;
+ m_cd = 0;
+ m_io = 0;
+ m_bsy = 0;
+ m_req = 0;
+ m_status = 0;
+ m_status_port = 0; // reset all status bits to 0
+ return 0x00;
+ }
+ if(m_phase == SASI_PHASE_STATUS)
+ {
+ m_phase = SASI_PHASE_MESSAGE;
+ m_msg = 1;
+ m_status_port |= 0x10;
+ // reset REQ temporarily
+ m_req = 0;
+ m_status_port &= ~0x01;
+ timer_set(attotime::from_nsec(450));
+
+ return m_status;
+ }
+ if(m_phase == SASI_PHASE_READ)
+ {
+ if(m_transfer_byte_count == 0)
+ {
+ switch(m_command[0])
+ {
+ case SASI_CMD_REQUEST_SENSE:
+ // set up sense bytes
+ m_sense[0] = 0x01; // "No index signal"
+ m_sense[1] = 0;
+ m_sense[2] = 0;
+ m_sense[3] = 0;
+ if(m_command[3] == 0)
+ m_transfer_byte_total = 4;
+ else
+ m_transfer_byte_total = m_command[3];
+ break;
+ case SASI_CMD_READ:
+ m_transfer_byte_total = (0x100 * m_command[4]);
+ m_transfer_byte_count = 0;
+ break;
+ default:
+ m_transfer_byte_total = 0;
+ }
+ }
+
+ switch(m_command[0])
+ {
+ case SASI_CMD_REQUEST_SENSE:
+ retval = m_sense[m_transfer_byte_count];
+ logerror("REQUEST SENSE: read value 0x%02x\n",retval);
+ break;
+ case SASI_CMD_READ:
+ if(!exists())
+ {
+ m_phase = SASI_PHASE_STATUS;
+ m_io = 1; // Output
+ m_status_port |= 0x04; // C/D remains the same
+ m_status = 0x02;
+ logerror("SASI: No HD connected.\n");
+ }
+ else
+ {
+ unsigned char val;
+ fread(&val,1);
+ retval = val;
+ }
+ break;
+ default:
+ retval = 0;
+ }
+
+ m_req = 0;
+ m_status_port &= ~0x01;
+ timer_set(attotime::from_nsec(450));
+ m_transfer_byte_count++;
+ if(m_transfer_byte_count >= m_transfer_byte_total)
+ {
+ // End of transfer
+ m_phase = SASI_PHASE_STATUS;
+ m_io = 1;
+ m_status_port |= 0x04;
+ m_cd = 1;
+ m_status_port |= 0x08;
+ logerror("SASI: Read transfer complete\n");
+ }
+
+ return retval;
+ }
+ return 0x00;
+ case 0x01:
+// logerror("SASI: [%08x] read from status port, read 0x%02x\n",activecpu_get_pc(),m_status_port);
+ return m_status_port;
+ case 0x02:
+ return 0xff; // write-only
+ case 0x03:
+ return 0xff; // write-only
+ default:
+ return 0xff;
+ }
+}
diff --git a/src/mess/machine/x68k_hdc.h b/src/mess/machine/x68k_hdc.h
new file mode 100644
index 00000000000..3348ff5bd4d
--- /dev/null
+++ b/src/mess/machine/x68k_hdc.h
@@ -0,0 +1,129 @@
+/*
+
+ X68000 Custom SASI HD controller
+
+*/
+
+#include "emu.h"
+
+enum
+{
+ SASI_PHASE_BUSFREE = 0,
+ SASI_PHASE_ARBITRATION,
+ SASI_PHASE_SELECTION,
+ SASI_PHASE_RESELECTION,
+ SASI_PHASE_COMMAND,
+ SASI_PHASE_DATA,
+ SASI_PHASE_STATUS,
+ SASI_PHASE_MESSAGE,
+ SASI_PHASE_READ,
+ SASI_PHASE_WRITE
+};
+
+// SASI commands, based on the SASI standard
+enum
+{
+ // Class 0 (6-byte) commands
+ SASI_CMD_TEST_UNIT_READY = 0,
+ SASI_CMD_REZERO_UNIT,
+ SASI_CMD_RESERVED_02,
+ SASI_CMD_REQUEST_SENSE,
+ SASI_CMD_FORMAT_UNIT,
+ SASI_CMD_RESERVED_05,
+ SASI_CMD_FORMAT_UNIT_06, // the X68000 uses command 0x06 for Format Unit, despite the SASI specs saying 0x04
+ SASI_CMD_RESERVED_07,
+ SASI_CMD_READ,
+ SASI_CMD_RESERVED_09,
+ SASI_CMD_WRITE,
+ SASI_CMD_SEEK,
+ SASI_CMD_RESERVED_0C,
+ SASI_CMD_RESERVED_0D,
+ SASI_CMD_RESERVED_0E,
+ SASI_CMD_WRITE_FILE_MARK,
+ SASI_CMD_INVALID_10,
+ SASI_CMD_INVALID_11,
+ SASI_CMD_RESERVE_UNIT,
+ SASI_CMD_RELEASE_UNIT,
+ SASI_CMD_INVALID_14,
+ SASI_CMD_INVALID_15,
+ SASI_CMD_READ_CAPACITY,
+ SASI_CMD_INVALID_17,
+ SASI_CMD_INVALID_18,
+ SASI_CMD_INVALID_19,
+ SASI_CMD_READ_DIAGNOSTIC,
+ SASI_CMD_WRITE_DIAGNOSTIC,
+ SASI_CMD_INVALID_1C,
+ SASI_CMD_INVALID_1D,
+ SASI_CMD_INVALID_1E,
+ SASI_CMD_INQUIRY,
+ // Class 1 commands (yes, just the one)
+ SASI_CMD_RESERVED_20,
+ SASI_CMD_RESERVED_21,
+ SASI_CMD_RESERVED_22,
+ SASI_CMD_SET_BLOCK_LIMITS = 0x28,
+ // Class 2 commands
+ SASI_CMD_EXTENDED_ADDRESS_READ = 0x48,
+ SASI_CMD_INVALID_49,
+ SASI_CMD_EXTENDED_ADDRESS_WRITE,
+ SASI_CMD_WRITE_AND_VERIFY = 0x54,
+ SASI_CMD_VERIFY,
+ SASI_CMD_INVALID_56,
+ SASI_CMD_SEARCH_DATA_HIGH,
+ SASI_CMD_SEARCH_DATA_EQUAL,
+ SASI_CMD_SEARCH_DATA_LOW,
+ // controller-specific commands
+ SASI_CMD_SPECIFY = 0xc2
+};
+
+class x68k_hdc_image_device : public device_t,
+ public device_image_interface
+{
+public:
+ // construction/destruction
+ x68k_hdc_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 "hdf"; }
+ virtual const option_guide *create_option_guide() const { return NULL; }
+ virtual bool call_create(int format_type, option_resolution *format_options);
+
+ DECLARE_WRITE16_MEMBER( hdc_w );
+ DECLARE_READ16_MEMBER( hdc_r );
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+ virtual void device_start();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+private:
+ int m_phase;
+ unsigned char m_status_port; // read at 0xe96003
+ unsigned char m_status; // status phase output
+ unsigned char m_message;
+ unsigned char m_command[10];
+ unsigned char m_sense[4];
+ int m_command_byte_count;
+ int m_command_byte_total;
+ int m_current_command;
+ int m_transfer_byte_count;
+ int m_transfer_byte_total;
+ int m_msg; // MSG
+ int m_cd; // C/D (Command/Data)
+ int m_bsy; // BSY
+ int m_io; // I/O
+ int m_req; // REQ
+};
+
+// device type definition
+extern const device_type X68KHDC;
+
+#define MCFG_X68KHDC_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, X68KHDC, 0)
+
diff --git a/src/mess/machine/x68k_neptunex.c b/src/mess/machine/x68k_neptunex.c
new file mode 100644
index 00000000000..d616dbb7029
--- /dev/null
+++ b/src/mess/machine/x68k_neptunex.c
@@ -0,0 +1,153 @@
+/*
+ * x68k_neptunex.c
+ */
+
+#include "emu.h"
+#include "machine/dp8390.h"
+#include "machine/x68k_neptunex.h"
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type X68K_NEPTUNEX = &device_creator<x68k_neptune_device>;
+
+static const dp8390_interface neptune_dp8390_interface = {
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, x68k_neptune_device, x68k_neptune_irq_w),
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, x68k_neptune_device, x68k_neptune_mem_read),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, x68k_neptune_device, x68k_neptune_mem_write)
+};
+
+
+// device machine config
+static MACHINE_CONFIG_FRAGMENT( x68k_neptunex )
+ MCFG_DP8390D_ADD("dp8390d", neptune_dp8390_interface)
+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),
+ 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<x68k_expansion_slot_device *>(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("ne2000: 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("ne2000: 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("ne2000: 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("ne2000: invalid memory write %04X\n", offset);
+ return;
+ }
+ m_board_ram[offset - (16*1024)] = data;
+}
+
+WRITE_LINE_MEMBER(x68k_neptune_device::x68k_neptune_irq_w)
+{
+ device_set_input_line_vector(machine().device("maincpu"),2, NEPTUNE_IRQ_VECTOR);
+ m_slot->irq2_w(state);
+ logerror("Neptune: IRQ2 set to %i\n",state);
+}
+
diff --git a/src/mess/machine/x68k_neptunex.h b/src/mess/machine/x68k_neptunex.h
new file mode 100644
index 00000000000..3bfba21a2c2
--- /dev/null
+++ b/src/mess/machine/x68k_neptunex.h
@@ -0,0 +1,53 @@
+/*
+ * 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 "machine/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();
+ virtual void device_config_complete() { m_shortname = "x68k_neptunex"; }
+
+private:
+ x68k_expansion_slot_device *m_slot;
+
+ required_device<dp8390d_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/mess/machine/x68k_scsiext.c b/src/mess/machine/x68k_scsiext.c
new file mode 100644
index 00000000000..f30a6c55662
--- /dev/null
+++ b/src/mess/machine/x68k_scsiext.c
@@ -0,0 +1,115 @@
+/*
+ * x68k_scsiext.c
+ *
+ * Sharp CZ-6BS1 SCSI-1 controller
+ *
+ * Created on: 5/06/2012
+ */
+
+#include "emu.h"
+#include "machine/scsihd.h"
+#include "machine/mb89352.h"
+#include "machine/x68k_scsiext.h"
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type X68K_SCSIEXT = &device_creator<x68k_scsiext_device>;
+
+static const SCSIConfigTable x68k_scsiext_devtable =
+{
+ 7, /* 7 SCSI devices */
+ {
+ { SCSI_ID_0, ":exp:cz6bs1:extharddisk0" },
+ { SCSI_ID_1, ":exp:cz6bs1:extharddisk1" },
+ { SCSI_ID_2, ":exp:cz6bs1:extharddisk2" },
+ { SCSI_ID_3, ":exp:cz6bs1:extharddisk3" },
+ { SCSI_ID_4, ":exp:cz6bs1:extharddisk4" },
+ { SCSI_ID_5, ":exp:cz6bs1:extharddisk5" },
+ { SCSI_ID_6, ":exp:cz6bs1:extharddisk6" },
+ }
+};
+
+static const mb89352_interface x68k_scsiext_intf =
+{
+ &x68k_scsiext_devtable,
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER,x68k_scsiext_device,irq_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER,x68k_scsiext_device,drq_w)
+};
+
+//-------------------------------------------------
+// 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_MB89352A_ADD("mb89352_ext",x68k_scsiext_intf)
+ MCFG_DEVICE_ADD("extharddisk0", SCSIHD, 0)
+ MCFG_DEVICE_ADD("extharddisk1", SCSIHD, 0)
+ MCFG_DEVICE_ADD("extharddisk2", SCSIHD, 0)
+ MCFG_DEVICE_ADD("extharddisk3", SCSIHD, 0)
+ MCFG_DEVICE_ADD("extharddisk4", SCSIHD, 0)
+ MCFG_DEVICE_ADD("extharddisk5", SCSIHD, 0)
+ MCFG_DEVICE_ADD("extharddisk6", SCSIHD, 0)
+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),
+ device_x68k_expansion_card_interface(mconfig, *this),
+ m_spc(*this, "mb89352_ext")
+{
+}
+
+void x68k_scsiext_device::device_start()
+{
+ device_t* cpu = machine().device("maincpu");
+ UINT8* ROM;
+ astring temp;
+ address_space* space = cpu->memory().space(AS_PROGRAM);
+ m_slot = dynamic_cast<x68k_expansion_slot_device *>(owner());
+ space->install_read_bank(0xea0020,0xea1fff,0,0,"scsi_ext");
+ space->unmap_write(0xea0020,0xea1fff,0,0);
+ ROM = machine().root_device().memregion(subtag(temp,"scsiexrom"))->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/mess/machine/x68k_scsiext.h b/src/mess/machine/x68k_scsiext.h
new file mode 100644
index 00000000000..339e5139cef
--- /dev/null
+++ b/src/mess/machine/x68k_scsiext.h
@@ -0,0 +1,45 @@
+/*
+ * x68k_scsiext.h
+ *
+ * Created on: 5/06/2012
+ */
+
+#ifndef X68K_SCSIEXT_H_
+#define X68K_SCSIEXT_H_
+
+#include "emu.h"
+#include "machine/mb89352.h"
+#include "machine/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();
+ virtual void device_config_complete() { m_shortname = "x68k_cz6bs1"; }
+private:
+ x68k_expansion_slot_device *m_slot;
+
+ required_device<mb89352_device> m_spc;
+};
+
+// device type definition
+extern const device_type X68K_SCSIEXT;
+
+
+#endif /* X68K_SCSIEXT_H_ */
diff --git a/src/mess/machine/x68kexp.c b/src/mess/machine/x68kexp.c
new file mode 100644
index 00000000000..0de89a0d77f
--- /dev/null
+++ b/src/mess/machine/x68kexp.c
@@ -0,0 +1,98 @@
+/*
+ * x68kexp.c
+ */
+
+#include "emu.h"
+#include "emuopts.h"
+#include "machine/x68kexp.h"
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type X68K_EXPANSION_SLOT = &device_creator<x68k_expansion_slot_device>;
+
+
+//**************************************************************************
+// 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),
+ device_slot_interface(mconfig, *this)
+{
+}
+
+x68k_expansion_slot_device::~x68k_expansion_slot_device()
+{
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void x68k_expansion_slot_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const x68k_expansion_slot_interface *intf = reinterpret_cast<const x68k_expansion_slot_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<x68k_expansion_slot_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_irq2_cb, 0, sizeof(m_out_irq2_cb));
+ memset(&m_out_irq4_cb, 0, sizeof(m_out_irq4_cb));
+ memset(&m_out_nmi_cb, 0, sizeof(m_out_nmi_cb));
+ memset(&m_out_reset_cb, 0, sizeof(m_out_reset_cb));
+ }
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void x68k_expansion_slot_device::device_start()
+{
+ m_card = dynamic_cast<device_x68k_expansion_card_interface *>(get_card_device());
+
+ // resolve callbacks
+ m_out_irq2_func.resolve(m_out_irq2_cb, *this);
+ m_out_irq4_func.resolve(m_out_irq4_cb, *this);
+ m_out_nmi_func.resolve(m_out_nmi_cb, *this);
+ m_out_reset_func.resolve(m_out_reset_cb, *this);
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void x68k_expansion_slot_device::device_reset()
+{
+}
+
+
+WRITE_LINE_MEMBER( x68k_expansion_slot_device::irq2_w ) { m_out_irq2_func(state); }
+WRITE_LINE_MEMBER( x68k_expansion_slot_device::irq4_w ) { m_out_irq4_func(state); }
+WRITE_LINE_MEMBER( x68k_expansion_slot_device::nmi_w ) { m_out_nmi_func(state); }
+WRITE_LINE_MEMBER( x68k_expansion_slot_device::reset_w ) { m_out_reset_func(state); }
diff --git a/src/mess/machine/x68kexp.h b/src/mess/machine/x68kexp.h
new file mode 100644
index 00000000000..d35d19ae640
--- /dev/null
+++ b/src/mess/machine/x68kexp.h
@@ -0,0 +1,149 @@
+/*
+ * 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 X68K_EXPANSION_INTERFACE(_name) \
+ const x68k_expansion_slot_interface (_name) =
+
+
+#define MCFG_X68K_EXPANSION_SLOT_ADD(_tag, _config, _slot_intf, _def_slot, _def_inp) \
+ MCFG_DEVICE_ADD(_tag, X68K_EXPANSION_SLOT, 0) \
+ MCFG_DEVICE_CONFIG(_config) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false)
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// expansion slot interface
+
+struct x68k_expansion_slot_interface
+{
+ 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
+
+// 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 x68k_expansion_slot_interface,
+ 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();
+
+ 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();
+ virtual void device_config_complete();
+
+ devcb_resolved_write_line m_out_irq2_func;
+ devcb_resolved_write_line m_out_irq4_func;
+ devcb_resolved_write_line m_out_nmi_func;
+ devcb_resolved_write_line m_out_reset_func;
+
+ device_x68k_expansion_card_interface *m_card;
+};
+
+
+// device type definition
+extern const device_type X68K_EXPANSION_SLOT;
+
+#endif /* X68KEXP_H_ */
diff --git a/src/mess/machine/z80ne.c b/src/mess/machine/z80ne.c
new file mode 100644
index 00000000000..869b3ebb48b
--- /dev/null
+++ b/src/mess/machine/z80ne.c
@@ -0,0 +1,796 @@
+/***********************************************************************
+
+ machine/z80ne.c
+
+ Functions to emulate general aspects of the machine (RAM, ROM,
+ interrupts, I/O ports)
+
+***********************************************************************/
+
+/* Core includes */
+#include "emu.h"
+#include "includes/z80ne.h"
+
+/* Components */
+#include "machine/ay31015.h"
+#include "machine/kr2376.h"
+#include "video/mc6847.h"
+#include "machine/wd17xx.h"
+
+/* Devices */
+#include "imagedev/cassette.h"
+#include "imagedev/flopdrv.h"
+
+#define VERBOSE 0
+#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+
+
+
+/* timer to read cassette waveforms */
+
+static cassette_image_device *cassette_device_image(running_machine &machine)
+{
+ z80ne_state *state = machine.driver_data<z80ne_state>();
+ if (state->m_lx385_ctrl & 0x08)
+ return machine.device<cassette_image_device>(CASSETTE2_TAG);
+ else
+ return machine.device<cassette_image_device>(CASSETTE_TAG);
+}
+
+static TIMER_CALLBACK(z80ne_cassette_tc)
+{
+ z80ne_state *state = machine.driver_data<z80ne_state>();
+ UINT8 cass_ws = 0;
+ state->m_cass_data.input.length++;
+
+ cass_ws = ((cassette_device_image(machine))->input() > +0.02) ? 1 : 0;
+
+ if ((cass_ws ^ state->m_cass_data.input.level) & cass_ws)
+ {
+ state->m_cass_data.input.level = cass_ws;
+ state->m_cass_data.input.bit = ((state->m_cass_data.input.length < state->m_cass_data.wave_filter) || (state->m_cass_data.input.length > 0x20)) ? 1 : 0;
+ state->m_cass_data.input.length = 0;
+ ay31015_set_input_pin( state->m_ay31015, AY31015_SI, state->m_cass_data.input.bit );
+ }
+ state->m_cass_data.input.level = cass_ws;
+
+ /* saving a tape - convert the serial stream from the uart */
+
+ state->m_cass_data.output.length--;
+
+ if (!(state->m_cass_data.output.length))
+ {
+ if (state->m_cass_data.output.level)
+ state->m_cass_data.output.level = 0;
+ else
+ {
+ state->m_cass_data.output.level=1;
+ cass_ws = ay31015_get_output_pin( state->m_ay31015, AY31015_SO );
+ state->m_cass_data.wave_length = cass_ws ? state->m_cass_data.wave_short : state->m_cass_data.wave_long;
+ }
+ cassette_device_image(machine)->output(state->m_cass_data.output.level ? -1.0 : +1.0);
+ state->m_cass_data.output.length = state->m_cass_data.wave_length;
+ }
+}
+
+
+DRIVER_INIT_MEMBER(z80ne_state,z80ne)
+{
+ /* first two entries point to rom on reset */
+ UINT8 *RAM = memregion("z80ne")->base();
+ membank("bank1")->configure_entry(0, &RAM[0x00000]); /* RAM at 0x0000 */
+ membank("bank1")->configure_entry(1, &RAM[0x14000]); /* ep382 at 0x0000 */
+ membank("bank2")->configure_entry(0, &RAM[0x14000]); /* ep382 at 0x8000 */
+}
+
+DRIVER_INIT_MEMBER(z80ne_state,z80net)
+{
+ DRIVER_INIT_CALL(z80ne);
+}
+
+DRIVER_INIT_MEMBER(z80ne_state,z80netb)
+{
+}
+
+DRIVER_INIT_MEMBER(z80ne_state,z80netf)
+{
+ /* first two entries point to rom on reset */
+ UINT8 *RAM = memregion("z80ne")->base();
+ membank("bank1")->configure_entry(0, &RAM[0x00000]); /* RAM at 0x0000-0x03FF */
+ membank("bank1")->configure_entries(1, 3, &RAM[0x14400], 0x0400); /* ep390, ep1390, ep2390 at 0x0000-0x03FF */
+ membank("bank1")->configure_entry(4, &RAM[0x14000]); /* ep382 at 0x0000-0x03FF */
+ membank("bank1")->configure_entry(5, &RAM[0x10000]); /* ep548 at 0x0000-0x03FF */
+
+ membank("bank2")->configure_entry(0, &RAM[0x00400]); /* RAM at 0x0400 */
+ membank("bank2")->configure_entry(1, &RAM[0x10400]); /* ep548 at 0x0400-0x3FFF */
+
+ membank("bank3")->configure_entry(0, &RAM[0x08000]); /* RAM at 0x8000 */
+ membank("bank3")->configure_entry(1, &RAM[0x14000]); /* ep382 at 0x8000 */
+
+ membank("bank4")->configure_entry(0, &RAM[0x0F000]); /* RAM at 0xF000 */
+ membank("bank4")->configure_entries(1, 3, &RAM[0x14400], 0x0400); /* ep390, ep1390, ep2390 at 0xF000 */
+
+}
+
+static TIMER_CALLBACK( z80ne_kbd_scan )
+{
+ z80ne_state *state = machine.driver_data<z80ne_state>();
+ /*
+ * NE555 is connected to a 74LS93 binary counter
+ * 74LS93 output:
+ * QA-QC: column index for LEDs and keyboard
+ * QD: keyboard row select
+ *
+ * Port F0 input bit assignment:
+ * 0 QA bits 0..3 of row counter
+ * 1 QB
+ * 2 QC
+ * 3 QD
+ * 4 Control button pressed, active high
+ * 5 Always low
+ * 6 Always low
+ * 7 Selected button pressed, active low
+ *
+ *
+ */
+
+ UINT16 key_bits;
+ UINT8 ctrl; //, rst;
+ UINT8 i;
+
+ /* 4-bit counter */
+ --state->m_lx383_scan_counter;
+ state->m_lx383_scan_counter &= 0x0f;
+
+ if ( --state->m_lx383_downsampler == 0 )
+ {
+ state->m_lx383_downsampler = LX383_DOWNSAMPLING;
+ key_bits = (machine.root_device().ioport("ROW1")->read() << 8) | machine.root_device().ioport("ROW0")->read();
+// rst = machine.root_device().ioport("RST")->read();
+ ctrl = machine.root_device().ioport("CTRL")->read();
+
+ for ( i = 0; i<LX383_KEYS; i++)
+ {
+ state->m_lx383_key[i] = ( i | (key_bits & 0x01 ? 0x80 : 0x00) | ~ctrl);
+ key_bits >>= 1;
+ }
+ }
+}
+
+DIRECT_UPDATE_MEMBER(z80ne_state::z80ne_default)
+{
+ return address;
+}
+/*
+ * Handle NMI delay for single step instruction
+ */
+DIRECT_UPDATE_MEMBER(z80ne_state::z80ne_nmi_delay_count)
+{
+ m_nmi_delay_counter--;
+
+ if (!m_nmi_delay_counter)
+ {
+ machine().device("z80ne")->memory().space(AS_PROGRAM)->set_direct_update_handler(direct_update_delegate(FUNC(z80ne_state::z80ne_default), this));
+ cputag_set_input_line(machine(), "z80ne", INPUT_LINE_NMI, PULSE_LINE);
+ }
+ return address;
+}
+
+/*
+ * Handle delayed ROM/RAM banking at RESET
+ * after the first reset_delay_counter bytes have been read from ROM, switch the RAM back in
+ */
+DIRECT_UPDATE_MEMBER(z80ne_state::z80ne_reset_delay_count)
+{
+ address_space *space = machine().device("z80ne")->memory().space(AS_PROGRAM);
+ /*
+ * TODO: when debugger is active, his memory access causes this callback
+ *
+ */
+ if(!space->debugger_access())
+ m_reset_delay_counter--;
+
+ if (!m_reset_delay_counter)
+ {
+ /* remove this callback */
+ machine().device("z80ne")->memory().space(AS_PROGRAM)->set_direct_update_handler(direct_update_delegate(FUNC(z80ne_state::z80ne_default), this));
+ /* and switch to RAM bank at address 0x0000 */
+ membank( "bank1" )->set_entry( 0 ); /* RAM at 0x0000 (bank 1) */
+ }
+ return address;
+}
+
+static void reset_lx388(running_machine &machine)
+{
+ z80ne_state *state = machine.driver_data<z80ne_state>();
+ state->m_lx388_kr2376 = machine.device("lx388_kr2376");
+ kr2376_set_input_pin( state->m_lx388_kr2376, KR2376_DSII, 0);
+ kr2376_set_input_pin( state->m_lx388_kr2376, KR2376_PII, 0);
+}
+
+static void reset_lx382_banking(running_machine &machine)
+{
+ z80ne_state *state = machine.driver_data<z80ne_state>();
+ address_space *space = machine.device("z80ne")->memory().space(AS_PROGRAM);
+
+ /* switch to ROM bank at address 0x0000 */
+ state->membank("bank1")->set_entry(1);
+ state->membank("bank2")->set_entry(0); /* ep382 at 0x8000 */
+
+ /* after the first 3 bytes have been read from ROM, switch the RAM back in */
+ state->m_reset_delay_counter = 2;
+ space->set_direct_update_handler(direct_update_delegate(FUNC(z80ne_state::z80ne_reset_delay_count), state));
+}
+
+static void reset_lx390_banking(running_machine &machine)
+{
+ z80ne_state *state = machine.driver_data<z80ne_state>();
+ address_space *space = machine.device("z80ne")->memory().space(AS_PROGRAM);
+ state->m_reset_delay_counter = 0;
+
+ switch (machine.root_device().ioport("CONFIG")->read() & 0x07) {
+ case 0x01: /* EP382 Hex Monitor */
+ if (VERBOSE)
+ logerror("reset_lx390_banking: banking ep382\n");
+ state->membank("bank1")->set_entry(4); /* ep382 at 0x0000 for 3 cycles, then RAM */
+ state->membank("bank2")->set_entry(0); /* RAM at 0x0400 */
+ state->membank("bank3")->set_entry(1); /* ep382 at 0x8000 */
+ state->membank("bank4")->set_entry(0); /* RAM at 0xF000 */
+ /* after the first 3 bytes have been read from ROM, switch the RAM back in */
+ state->m_reset_delay_counter = 2;
+ space->set_direct_update_handler(direct_update_delegate(FUNC(z80ne_state::z80ne_reset_delay_count), state));
+ break;
+ case 0x02: /* EP548 16k BASIC */
+ if (VERBOSE)
+ logerror("reset_lx390_banking: banking ep548\n");
+ state->membank("bank1")->set_entry(5); /* ep548 at 0x0000-0x03FF */
+ state->membank("bank2")->set_entry(1); /* ep548 at 0x0400-0x3FFF */
+ state->membank("bank3")->set_entry(0); /* RAM at 0x8000 */
+ state->membank("bank4")->set_entry(0); /* RAM at 0xF000 */
+ machine.device("z80ne")->memory().space(AS_PROGRAM)->set_direct_update_handler(direct_update_delegate(FUNC(z80ne_state::z80ne_default), state));
+ break;
+ case 0x03: /* EP390 Boot Loader for 5.5k floppy BASIC */
+ if (VERBOSE)
+ logerror("reset_lx390_banking: banking ep390\n");
+ state->membank("bank1")->set_entry(1); /* ep390 at 0x0000-0 x03FF for 3 cycles, then RAM */
+ state->membank("bank2")->set_entry(0); /* RAM at 0x0400-0x3FFF */
+ state->membank("bank3")->set_entry(0); /* RAM at 0x8000 */
+ state->membank("bank4")->set_entry(1); /* ep390 at 0xF000 */
+ machine.device("z80ne")->memory().space(AS_PROGRAM)->set_direct_update_handler(direct_update_delegate(FUNC(z80ne_state::z80ne_default), state));
+ break;
+ case 0x04: /* EP1390 Boot Loader for NE DOS 1.0/1.5 */
+ if (VERBOSE)
+ logerror("reset_lx390_banking: banking ep1390\n");
+ state->membank("bank1")->set_entry(2); /* ep1390 at 0x0000-0x03FF for 3 cycles, then RAM */
+ state->membank("bank2")->set_entry(0); /* RAM at 0x0400-0x3FFF */
+ state->membank("bank3")->set_entry(0); /* RAM at 0x8000 */
+ state->membank("bank4")->set_entry(2); /* ep1390 at 0xF000 */
+ machine.device("z80ne")->memory().space(AS_PROGRAM)->set_direct_update_handler(direct_update_delegate(FUNC(z80ne_state::z80ne_default), state));
+ break;
+ case 0x05: /* EP2390 Boot Loader for NE DOS G.1 */
+ if (VERBOSE)
+ logerror("reset_lx390_banking: banking ep2390\n");
+ state->membank("bank1")->set_entry(3); /* ep2390 at 0x0000-0x03FF for 3 cycles, then RAM */
+ state->membank("bank2")->set_entry(0); /* RAM at 0x0400-0x3FFF */
+ state->membank("bank3")->set_entry(0); /* RAM at 0x8000 */
+ state->membank("bank4")->set_entry(3); /* ep2390 at 0xF000 */
+ machine.device("z80ne")->memory().space(AS_PROGRAM)->set_direct_update_handler(direct_update_delegate(FUNC(z80ne_state::z80ne_default), state));
+ break;
+ }
+
+ /* TODO: in real hardware the ENH bus line is pulled down
+ * until a I/O read is performed on a address with A0 address bit low and A1 or A2 address bit high
+ */
+}
+
+static MACHINE_RESET(z80ne_base)
+{
+ z80ne_state *state = machine.driver_data<z80ne_state>();
+ int i;
+ address_space *space = machine.device("z80ne")->memory().space(AS_PROGRAM);
+
+ LOG(("In MACHINE_RESET z80ne_base\n"));
+
+ for ( i=0; i<LX383_KEYS; i++)
+ state->m_lx383_key[i] = 0xf0 | i;
+ state->m_lx383_scan_counter = 0x0f;
+ state->m_lx383_downsampler = LX383_DOWNSAMPLING;
+
+ /* Initialize cassette interface */
+ switch(machine.root_device().ioport("LX.385")->read() & 0x07)
+ {
+ case 0x01:
+ state->m_cass_data.speed = TAPE_300BPS;
+ state->m_cass_data.wave_filter = LX385_TAPE_SAMPLE_FREQ / 1600;
+ state->m_cass_data.wave_short = LX385_TAPE_SAMPLE_FREQ / (2400 * 2);
+ state->m_cass_data.wave_long = LX385_TAPE_SAMPLE_FREQ / (1200 * 2);
+ break;
+ case 0x02:
+ state->m_cass_data.speed = TAPE_600BPS;
+ state->m_cass_data.wave_filter = LX385_TAPE_SAMPLE_FREQ / 3200;
+ state->m_cass_data.wave_short = LX385_TAPE_SAMPLE_FREQ / (4800 * 2);
+ state->m_cass_data.wave_long = LX385_TAPE_SAMPLE_FREQ / (2400 * 2);
+ break;
+ case 0x04:
+ state->m_cass_data.speed = TAPE_1200BPS;
+ state->m_cass_data.wave_filter = LX385_TAPE_SAMPLE_FREQ / 6400;
+ state->m_cass_data.wave_short = LX385_TAPE_SAMPLE_FREQ / (9600 * 2);
+ state->m_cass_data.wave_long = LX385_TAPE_SAMPLE_FREQ / (4800 * 2);
+ }
+ state->m_cass_data.wave_length = state->m_cass_data.wave_short;
+ state->m_cass_data.output.length = state->m_cass_data.wave_length;
+ state->m_cass_data.output.level = 1;
+ state->m_cass_data.input.length = 0;
+ state->m_cass_data.input.bit = 1;
+
+ state->m_ay31015 = machine.device("ay_3_1015");
+ ay31015_set_input_pin( state->m_ay31015, AY31015_CS, 0 );
+ ay31015_set_input_pin( state->m_ay31015, AY31015_NB1, 1 );
+ ay31015_set_input_pin( state->m_ay31015, AY31015_NB2, 1 );
+ ay31015_set_input_pin( state->m_ay31015, AY31015_TSB, 1 );
+ ay31015_set_input_pin( state->m_ay31015, AY31015_EPS, 1 );
+ ay31015_set_input_pin( state->m_ay31015, AY31015_NP, machine.root_device().ioport("LX.385")->read() & 0x80 ? 1 : 0 );
+ ay31015_set_input_pin( state->m_ay31015, AY31015_CS, 1 );
+ ay31015_set_receiver_clock( state->m_ay31015, state->m_cass_data.speed * 16.0);
+ ay31015_set_transmitter_clock( state->m_ay31015, state->m_cass_data.speed * 16.0);
+
+ state->m_nmi_delay_counter = 0;
+ state->lx385_ctrl_w(*space, 0, 0);
+
+}
+
+MACHINE_RESET(z80ne)
+{
+ LOG(("In MACHINE_RESET z80ne\n"));
+ reset_lx382_banking(machine);
+ MACHINE_RESET_CALL( z80ne_base );
+}
+
+MACHINE_RESET(z80net)
+{
+ LOG(("In MACHINE_RESET z80net\n"));
+ MACHINE_RESET_CALL( z80ne );
+ reset_lx388(machine);
+}
+
+MACHINE_RESET(z80netb)
+{
+ LOG(("In MACHINE_RESET z80netb\n"));
+ MACHINE_RESET_CALL( z80ne_base );
+ reset_lx388(machine);
+}
+
+MACHINE_RESET(z80netf)
+{
+ LOG(("In MACHINE_RESET z80netf\n"));
+ reset_lx390_banking(machine);
+ MACHINE_RESET_CALL( z80ne_base );
+ reset_lx388(machine);
+}
+
+INPUT_CHANGED( z80ne_reset )
+{
+ UINT8 rst;
+ rst = field.machine().root_device().ioport("RST")->read();
+
+ if ( ! BIT(rst, 0))
+ {
+ running_machine &machine = field.machine();
+ machine.schedule_soft_reset();
+ }
+}
+
+INPUT_CHANGED( z80ne_nmi )
+{
+ UINT8 nmi;
+ nmi = field.machine().root_device().ioport("LX388_BRK")->read();
+
+ if ( ! BIT(nmi, 0))
+ {
+ cputag_set_input_line(field.machine(), "z80ne", INPUT_LINE_NMI, PULSE_LINE);
+ }
+}
+
+MACHINE_START( z80ne )
+{
+ z80ne_state *state = machine.driver_data<z80ne_state>();
+ LOG(("In MACHINE_START z80ne\n"));
+ state->m_lx385_ctrl = 0x1f;
+ state_save_register_item( machine, "z80ne", NULL, 0, state->m_lx383_scan_counter );
+ state_save_register_item( machine, "z80ne", NULL, 0, state->m_lx383_downsampler );
+ state_save_register_item_array( machine, "z80ne", NULL, 0, state->m_lx383_key );
+ state_save_register_item( machine, "z80ne", NULL, 0, state->m_nmi_delay_counter );
+ state->m_cassette_timer = machine.scheduler().timer_alloc(FUNC(z80ne_cassette_tc));
+ machine.scheduler().timer_pulse( attotime::from_hz(1000), FUNC(z80ne_kbd_scan));
+}
+
+MACHINE_START( z80net )
+{
+ MACHINE_START_CALL( z80ne );
+ LOG(("In MACHINE_START z80net\n"));
+}
+
+MACHINE_START( z80netb )
+{
+ MACHINE_START_CALL( z80net );
+ LOG(("In MACHINE_START z80netb\n"));
+}
+
+MACHINE_START( z80netf )
+{
+ MACHINE_START_CALL( z80net );
+ LOG(("In MACHINE_START z80netf\n"));
+}
+
+/******************************************************************************
+ Drivers
+******************************************************************************/
+
+/* LX.383 - LX.384 HEX keyboard and display */
+READ8_MEMBER(z80ne_state::lx383_r)
+{
+ /*
+ * Keyboard scanning
+ *
+ * IC14 NE555 astable oscillator
+ * IC13 74LS93 binary counter
+ * IC5 74LS240 tri-state buffer
+ *
+ * l'oscillatore NE555 alimenta il clock del contatore 74LS93
+ * D0 - Q(A) --\
+ * D1 - Q(B) |-- column
+ * D2 - Q(C) --/
+ * D3 - Q(D) row
+ * D4 - CTRL
+ * D5 - 0
+ * D6 - 0
+ * D7 - ~KEY Pressed
+ */
+ return m_lx383_key[m_lx383_scan_counter];
+}
+
+WRITE8_MEMBER(z80ne_state::lx383_w)
+{
+ /*
+ * First 8 locations (F0-F7) are mapped to a dual-port 8-byte RAM
+ * The 1KHz NE-555 astable oscillator circuit drive
+ * a 4-bit 74LS93 binary counter.
+ * The 3 least sigificant bits of the counter are connected
+ * both to the read addres of the dual-port ram and to
+ * a 74LS156 3 to 8 binary decoder driving the cathode
+ * of 8 7-segments LEDS.
+ * The data output of the dual-port ram drive the anodes
+ * of the LEDS through 74LS07 buffers.
+ * LED segments - dual-port RAM bit:
+ * A 0x01
+ * B 0x02
+ * C 0x04
+ * D 0x08
+ * E 0x10
+ * F 0x20
+ * G 0x40
+ * P 0x80 (represented by DP in original schematics)
+ *
+ * A write in the range F0-FF starts a 74LS90 counter
+ * that trigger the NMI line of the CPU afther 2 instruction
+ * fetch cycles for single step execution.
+ */
+
+ if ( offset < 8 )
+ output_set_digit_value( offset, data ^ 0xff );
+ else
+ /* after writing to port 0xF8 and the first ~M1 cycles strike a NMI for single step execution */
+ m_nmi_delay_counter = 1;
+ machine().device("z80ne")->memory().space(AS_PROGRAM)->set_direct_update_handler(direct_update_delegate(FUNC(z80ne_state::z80ne_nmi_delay_count), this));
+}
+
+
+/* LX.385 Cassette tape interface */
+/*
+ * NE555 is connected to a 74LS93 binary counter
+ * 74LS93 output:
+ * QA-QC: column index for LEDs and keyboard
+ * QD: keyboard row select
+ *
+ * Port EE: UART Data Read/Write
+ * Port EF: Status/Control
+ * read, UART status bits read
+ * 0 OR Overrun
+ * 1 FE Framing Error
+ * 2 PE Parity Error
+ * 3 TBMT Transmitter Buffer Empty
+ * 4 DAV Data Available
+ * 5 EOC End Of Character
+ * 6 1
+ * 7 1
+ * write, UART control bits / Tape Unit select / Modulation control
+ * 0 bit1=0, bit0=0 UART Reset pulse
+ * 1 bit1=0, bit0=1 UART RDAV (Reset Data Available) pulse
+ * 2 Tape modulation enable
+ * 3 *TAPEA Enable (active low) (at reset: low)
+ * 4 *TAPEB Enable (active low) (at reset: low)
+ * Cassette is connected to the uart data input and output via the cassette
+ * interface hardware.
+ *
+ * The cassette interface hardware converts square-wave pulses into bits which the uart receives.
+ *
+ * 1. the cassette format: "frequency shift" is converted
+ into the uart data format "non-return to zero"
+
+ 2. on cassette a 1 data bit is stored as 8 2400 Hz pulses
+ and a 0 data bit as 4 1200 Hz pulses
+ - At 1200 baud, a logic 1 is 1 cycle of 1200 Hz and a logic 0 is 1/2 cycle of 600 Hz.
+ - At 300 baud, a logic 1 is 8 cycles of 2400 Hz and a logic 0 is 4 cycles of 1200 Hz.
+
+ Attenuation is applied to the signal and the square wave edges are rounded.
+
+ A manchester encoder is used. A flip-flop synchronises input
+ data on the positive-edge of the clock pulse.
+ *
+ */
+READ8_MEMBER(z80ne_state::lx385_data_r)
+{
+ return ay31015_get_received_data( m_ay31015 );
+}
+
+READ8_MEMBER(z80ne_state::lx385_ctrl_r)
+{
+ /* set unused bits high */
+ UINT8 data = 0xc0;
+
+ ay31015_set_input_pin( m_ay31015, AY31015_SWE, 0 );
+ data |= (ay31015_get_output_pin( m_ay31015, AY31015_OR ) ? 0x01 : 0);
+ data |= (ay31015_get_output_pin( m_ay31015, AY31015_FE ) ? 0x02 : 0);
+ data |= (ay31015_get_output_pin( m_ay31015, AY31015_PE ) ? 0x04 : 0);
+ data |= (ay31015_get_output_pin( m_ay31015, AY31015_TBMT ) ? 0x08 : 0);
+ data |= (ay31015_get_output_pin( m_ay31015, AY31015_DAV ) ? 0x10 : 0);
+ data |= (ay31015_get_output_pin( m_ay31015, AY31015_EOC ) ? 0x20 : 0);
+ ay31015_set_input_pin( m_ay31015, AY31015_SWE, 1 );
+
+ return data;
+}
+
+WRITE8_MEMBER(z80ne_state::lx385_data_w)
+{
+ ay31015_set_transmit_data( m_ay31015, data );
+}
+
+#define LX385_CASSETTE_MOTOR_MASK ((1<<3)|(1<<4))
+
+WRITE8_MEMBER(z80ne_state::lx385_ctrl_w)
+{
+ /* Translate data to control signals
+ * 0 bit1=0, bit0=0 UART Reset pulse
+ * 1 bit1=0, bit0=1 UART RDAV (Reset Data Available) pulse
+ * 2 UART Tx Clock Enable (active high)
+ * 3 *TAPEA Enable (active low) (at reset: low)
+ * 4 *TAPEB Enable (active low) (at reset: low)
+ */
+ UINT8 uart_reset, uart_rdav, uart_tx_clock;
+ UINT8 motor_a, motor_b;
+ UINT8 changed_bits = (m_lx385_ctrl ^ data) & 0x1C;
+ m_lx385_ctrl = data;
+
+ uart_reset = ((data & 0x03) == 0x00);
+ uart_rdav = ((data & 0x03) == 0x01);
+ uart_tx_clock = ((data & 0x04) == 0x04);
+ motor_a = ((data & 0x08) == 0x00);
+ motor_b = ((data & 0x10) == 0x00);
+
+ /* UART Reset and RDAV */
+ if(uart_reset)
+ {
+ ay31015_set_input_pin( m_ay31015, AY31015_XR, 1 );
+ ay31015_set_input_pin( m_ay31015, AY31015_XR, 0 );
+ }
+
+ if(uart_rdav)
+ {
+ ay31015_set_input_pin( m_ay31015, AY31015_RDAV, 1 );
+ ay31015_set_input_pin( m_ay31015, AY31015_RDAV, 0 );
+ }
+
+ if (!changed_bits) return;
+
+ /* UART Tx Clock enable/disable */
+ if(changed_bits & 0x04)
+ ay31015_set_transmitter_clock( m_ay31015, uart_tx_clock ? m_cass_data.speed * 16.0 : 0.0);
+
+ /* motors */
+ if(changed_bits & 0x18)
+ {
+ machine().device<cassette_image_device>(CASSETTE_TAG)->change_state(
+ (motor_a) ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED,CASSETTE_MASK_MOTOR);
+
+ machine().device<cassette_image_device>(CASSETTE2_TAG)->change_state(
+ (motor_b) ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED,CASSETTE_MASK_MOTOR);
+
+ if (motor_a || motor_b)
+ m_cassette_timer->adjust(attotime::zero, 0, attotime::from_hz(LX385_TAPE_SAMPLE_FREQ));
+ else
+ m_cassette_timer->adjust(attotime::zero);
+ }
+}
+
+READ8_DEVICE_HANDLER( lx388_mc6847_videoram_r )
+{
+ z80ne_state *state = device->machine().driver_data<z80ne_state>();
+ if (offset == ~0) return 0xff;
+
+ UINT8 *videoram = state->m_videoram;
+ int d6 = BIT(videoram[offset], 6);
+ int d7 = BIT(videoram[offset], 7);
+
+ state->m_vdg->inv_w(d6 && d7);
+ state->m_vdg->as_w(!d6 && d7);
+ state->m_vdg->intext_w(!d6 && d7);
+
+ return videoram[offset];
+}
+
+READ8_MEMBER(z80ne_state::lx388_data_r)
+{
+ UINT8 data;
+
+ data = kr2376_data_r(m_lx388_kr2376, 0) & 0x7f;
+ data |= kr2376_get_output_pin(m_lx388_kr2376, KR2376_SO) << 7;
+ return data;
+}
+
+READ8_MEMBER(z80ne_state::lx388_read_field_sync)
+{
+ return m_vdg->fs_r() << 7;
+}
+
+/*
+ * DRQ INTRQ IC9B.10 IC8B.*Q
+ * 0 0 1 0
+ * 0 1 0 x
+ * 1 0 0 x
+ * 1 1 0 x
+ *
+ */
+
+WRITE8_DEVICE_HANDLER(lx390_motor_w)
+{
+ z80ne_state *state = device->machine().driver_data<z80ne_state>();
+ /* Selection of drive and parameters
+ A write also causes the selected drive motor to turn on for about 3 seconds.
+ When the motor turns off, the drive is deselected.
+ d7 Unused (trs80: 1=MFM, 0=FM)
+ d6 (trs80: 1=Wait)
+ d5 0=Side 0, 1=Side 1 (trs80: 1=Write Precompensation enabled)
+ d4 Unused (trs80: 0=Side 0, 1=Side 1)
+ d3 1=select drive 3
+ d2 1=select drive 2
+ d1 1=select drive 1
+ d0 1=select drive 0 */
+
+ UINT8 drive = 255;
+
+ if (data & 1)
+ drive = 0;
+ else
+ if (data & 2)
+ drive = 1;
+ else
+ if (data & 4)
+ drive = 2;
+ else
+ if (data & 8)
+ drive = 3;
+
+ state->m_wd17xx_state.head = (data & 32) ? 1 : 0;
+ state->m_wd17xx_state.drive = data & 0x0F;
+
+ /* no drive selected, turn off all leds */
+ if (!state->m_wd17xx_state.drive)
+ {
+ output_set_value("drv0", 0);
+ output_set_value("drv1", 0);
+ }
+
+ if (drive < 4)
+ {
+ LOG(("lx390_motor_w, set drive %1d\n", drive));
+ wd17xx_set_drive(device,drive);
+ LOG(("lx390_motor_w, set side %1d\n", state->m_wd17xx_state.head));
+ wd17xx_set_side(device, state->m_wd17xx_state.head);
+ }
+}
+
+READ8_DEVICE_HANDLER(lx390_reset_bank)
+{
+ z80ne_state *state = device->machine().driver_data<z80ne_state>();
+ offs_t pc;
+
+ /* if PC is not in range, we are under integrated debugger control, DON'T SWAP */
+ pc = cpu_get_pc(device->machine().device("z80ne"));
+ if((pc >= 0xf000) && (pc <=0xffff))
+ {
+ LOG(("lx390_reset_bank, reset memory bank 1\n"));
+ state->membank("bank1")->set_entry(0); /* RAM at 0x0000 (bank 1) */
+ }
+ else
+ {
+ LOG(("lx390_reset_bank, bypass because in debugger\n"));
+ }
+ return 0xff;
+}
+
+READ8_DEVICE_HANDLER(lx390_fdc_r)
+{
+ UINT8 d;
+
+ switch(offset)
+ {
+ case 0:
+ d = wd17xx_status_r(device, 0) ^ 0xff;
+ LOG(("lx390_fdc_r, WD17xx status: %02x\n", d));
+ break;
+ case 1:
+ d = wd17xx_track_r(device, 0) ^ 0xff;
+ LOG(("lx390_fdc_r, WD17xx track: %02x\n", d));
+ break;
+ case 2:
+ d = wd17xx_sector_r(device, 0) ^ 0xff;
+ LOG(("lx390_fdc_r, WD17xx sector: %02x\n", d));
+ break;
+ case 3:
+ d = wd17xx_data_r(device, 0) ^ 0xff;
+ LOG(("lx390_fdc_r, WD17xx data3: %02x\n", d));
+ break;
+ case 6:
+ d = 0xff;
+ lx390_reset_bank(device, 0);
+ break;
+ case 7:
+ d = wd17xx_data_r(device, 3) ^ 0xff;
+ LOG(("lx390_fdc_r, WD17xx data7, force: %02x\n", d));
+ break;
+ default:
+ d = 0x00;
+ }
+ return d;
+}
+
+WRITE8_DEVICE_HANDLER(lx390_fdc_w)
+{
+ z80ne_state *state = device->machine().driver_data<z80ne_state>();
+ UINT8 d;
+
+ d = data;
+ switch(offset)
+ {
+ case 0:
+ LOG(("lx390_fdc_w, WD17xx command: %02x\n", d));
+ wd17xx_command_w(device, offset, d ^ 0xff);
+ if (state->m_wd17xx_state.drive & 1)
+ output_set_value("drv0", 2);
+ else if (state->m_wd17xx_state.drive & 2)
+ output_set_value("drv1", 2);
+ break;
+ case 1:
+ LOG(("lx390_fdc_w, WD17xx track: %02x\n", d));
+ wd17xx_track_w(device, offset, d ^ 0xff);
+ break;
+ case 2:
+ LOG(("lx390_fdc_w, WD17xx sector: %02x\n", d));
+ wd17xx_sector_w(device, offset, d ^ 0xff);
+ break;
+ case 3:
+ wd17xx_data_w(device, 0, d ^ 0xff);
+ LOG(("lx390_fdc_w, WD17xx data3: %02x\n", d));
+ break;
+ case 6:
+ LOG(("lx390_fdc_w, motor_w: %02x\n", d));
+ lx390_motor_w(device, 0, d);
+ break;
+ case 7:
+ LOG(("lx390_fdc_w, WD17xx data7, force: %02x\n", d));
+ wd17xx_data_w(device, 3, d ^ 0xff);
+ break;
+ }
+}
diff --git a/src/mess/machine/z88_flash.c b/src/mess/machine/z88_flash.c
new file mode 100644
index 00000000000..593d3ef6441
--- /dev/null
+++ b/src/mess/machine/z88_flash.c
@@ -0,0 +1,92 @@
+/***************************************************************************
+
+ z88_flash.c
+
+ Z88 Flash cartridges emulation
+
+***************************************************************************/
+
+#include "emu.h"
+#include "z88_flash.h"
+
+
+//**************************************************************************
+// MACROS/CONSTANTS
+//**************************************************************************
+
+#define FLASH_TAG "flash"
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type Z88_1024K_FLASH = &device_creator<z88_1024k_flash_device>;
+
+//-------------------------------------------------
+// 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),
+ 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/mess/machine/z88_flash.h b/src/mess/machine/z88_flash.h
new file mode 100644
index 00000000000..c6f61b7def6
--- /dev/null
+++ b/src/mess/machine/z88_flash.h
@@ -0,0 +1,45 @@
+#pragma once
+
+#ifndef __Z88_FLASH_H__
+#define __Z88_FLASH_H__
+
+#include "emu.h"
+#include "machine/z88cart.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();
+ virtual void device_config_complete() { m_shortname = "z88_1024k_flash"; }
+
+ // 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<intelfsh8_device> m_flash;
+};
+
+// device type definition
+extern const device_type Z88_1024K_FLASH;
+
+
+#endif /* __Z88_FLASH_H__ */
diff --git a/src/mess/machine/z88_ram.c b/src/mess/machine/z88_ram.c
new file mode 100644
index 00000000000..e531b7097a1
--- /dev/null
+++ b/src/mess/machine/z88_ram.c
@@ -0,0 +1,108 @@
+/***************************************************************************
+
+ z88_ram.c
+
+ Z88 RAM cartridges emulation
+
+***************************************************************************/
+
+#include "emu.h"
+#include "z88_ram.h"
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type Z88_32K_RAM = &device_creator<z88_32k_ram_device>;
+const device_type Z88_128K_RAM = &device_creator<z88_128k_ram_device>;
+const device_type Z88_512K_RAM = &device_creator<z88_512k_ram_device>;
+const device_type Z88_1024K_RAM = &device_creator<z88_1024k_ram_device>;
+
+//**************************************************************************
+// 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),
+ 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)
+ : device_t(mconfig, type, name, tag, owner, clock),
+ 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_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_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)
+{
+}
+
+
+//-------------------------------------------------
+// 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/mess/machine/z88_ram.h b/src/mess/machine/z88_ram.h
new file mode 100644
index 00000000000..e87bb72ccc7
--- /dev/null
+++ b/src/mess/machine/z88_ram.h
@@ -0,0 +1,93 @@
+#pragma once
+
+#ifndef __Z88_RAM_H__
+#define __Z88_RAM_H__
+
+#include "emu.h"
+#include "machine/z88cart.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);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_config_complete() { m_shortname = "z88_32k_ram"; }
+
+ // 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:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "z88_128k_ram"; }
+
+ // 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:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "z88_512k_ram"; }
+
+ // 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:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "z88_1024k_ram"; }
+
+ // 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/mess/machine/z88_rom.c b/src/mess/machine/z88_rom.c
new file mode 100644
index 00000000000..26970fd55a6
--- /dev/null
+++ b/src/mess/machine/z88_rom.c
@@ -0,0 +1,88 @@
+/***************************************************************************
+
+ z88_rom.c
+
+ Z88 ROM cartridges emulation
+
+***************************************************************************/
+
+#include "emu.h"
+#include "z88_rom.h"
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type Z88_32K_ROM = &device_creator<z88_32k_rom_device>;
+const device_type Z88_128K_ROM = &device_creator<z88_128k_rom_device>;
+const device_type Z88_256K_ROM = &device_creator<z88_256k_rom_device>;
+
+//**************************************************************************
+// 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),
+ 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)
+ : device_t(mconfig, type, name, tag, owner, clock),
+ 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_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)
+{
+}
+
+//-------------------------------------------------
+// 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/mess/machine/z88_rom.h b/src/mess/machine/z88_rom.h
new file mode 100644
index 00000000000..7eb0b51b179
--- /dev/null
+++ b/src/mess/machine/z88_rom.h
@@ -0,0 +1,75 @@
+#pragma once
+
+#ifndef __Z88_ROM_H__
+#define __Z88_ROM_H__
+
+#include "emu.h"
+#include "machine/z88cart.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);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_config_complete() { m_shortname = "z88_32k_rom"; }
+
+ // 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:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "z88_128k_rom"; }
+
+ // 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:
+ // device-level overrides
+ virtual void device_config_complete() { m_shortname = "z88_256k_rom"; }
+
+ // 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/mess/machine/z88cart.c b/src/mess/machine/z88cart.c
new file mode 100644
index 00000000000..a0a03f8e2a1
--- /dev/null
+++ b/src/mess/machine/z88cart.c
@@ -0,0 +1,222 @@
+/*********************************************************************
+
+ z88cart.c
+
+ Z88 cartridge slots emulation
+
+*********************************************************************/
+
+#include "emu.h"
+#include "z88cart.h"
+#include "emuopts.h"
+
+
+/***************************************************************************
+ PARAMETERS
+***************************************************************************/
+
+#define CLOSE_FLAP_TIME attotime::from_msec(200)
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type Z88CART_SLOT = &device_creator<z88cart_slot_device>;
+
+
+//**************************************************************************
+// 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),
+ device_image_interface(mconfig, *this),
+ device_slot_interface(mconfig, *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<device_z88cart_interface *>(get_card_device());
+
+ // resolve callbacks
+ m_out_flp_func.resolve(m_out_flp_cb, *this);
+
+ 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()
+{
+ // inherit a copy of the static data
+ const z88cart_interface *intf = reinterpret_cast<const z88cart_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<z88cart_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_flp_cb, 0, sizeof(m_out_flp_cb));
+ }
+
+ // 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_func(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_func(ASSERT_LINE);
+
+ // setup the timer for close the flap
+ m_flp_timer->adjust(CLOSE_FLAP_TIME);
+
+ return IMAGE_INIT_PASS;
+}
+
+
+/*-------------------------------------------------
+ call_unloadload
+-------------------------------------------------*/
+
+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_func(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(char *swlist, char *swname, rom_entry *start_entry)
+{
+ load_software_part_region(this, swlist, swname, start_entry );
+ return TRUE;
+}
+
+/*-------------------------------------------------
+ get default card software
+-------------------------------------------------*/
+
+const char * z88cart_slot_device::get_default_card_software(const machine_config &config, emu_options &options)
+{
+ return software_get_default_slot(config, options, this, "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/mess/machine/z88cart.h b/src/mess/machine/z88cart.h
new file mode 100644
index 00000000000..cb1ffcc7dcd
--- /dev/null
+++ b/src/mess/machine/z88cart.h
@@ -0,0 +1,145 @@
+/*********************************************************************
+
+ z88cart.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
+***************************************************************************/
+
+// ======================> z88cart_interface
+
+struct z88cart_interface
+{
+ devcb_write_line m_out_flp_cb;
+};
+
+
+// ======================> 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 z88cart_interface,
+ 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();
+
+ // 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(char *swlist, char *swname, 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 const char * get_default_card_software(const machine_config &config, emu_options &options);
+
+ // reading and writing
+ virtual DECLARE_READ8_MEMBER(read);
+ virtual DECLARE_WRITE8_MEMBER(write);
+
+private:
+ static const device_timer_id TIMER_FLP_CLEAR = 0;
+
+ devcb_resolved_write_line m_out_flp_func;
+ device_z88cart_interface* m_cart;
+ emu_timer * m_flp_timer;
+};
+
+
+// device type definition
+extern const device_type Z88CART_SLOT;
+
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+#define MCFG_Z88_CARTRIDGE_ADD(_tag,_config,_slot_intf,_def_slot,_def_inp) \
+ MCFG_DEVICE_ADD(_tag, Z88CART_SLOT, 0) \
+ MCFG_DEVICE_CONFIG(_config) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp, false)
+
+#endif /* __Z88CART_H__ */
diff --git a/src/mess/machine/zx.c b/src/mess/machine/zx.c
new file mode 100644
index 00000000000..3ced7842752
--- /dev/null
+++ b/src/mess/machine/zx.c
@@ -0,0 +1,397 @@
+/***************************************************************************
+ zx.c
+
+ machine driver
+ Juergen Buchmueller <pullmoll@t-online.de>, Dec 1999
+
+****************************************************************************/
+
+#include "includes/zx.h"
+
+#define video_screen_get_refresh(screen) (((screen_config *)(screen)->inline_config)->refresh)
+
+#define DEBUG_ZX81_PORTS 1
+#define DEBUG_ZX81_VSYNC 1
+
+#define LOG_ZX81_IOR(_comment) do { if (DEBUG_ZX81_PORTS) logerror("ZX81 IOR: %04x, Data: %02x, Scanline: %d (%s)\n", offset, data, space->machine().primary_screen->vpos(), _comment); } while (0)
+#define LOG_ZX81_IOW(_comment) do { if (DEBUG_ZX81_PORTS) logerror("ZX81 IOW: %04x, Data: %02x, Scanline: %d (%s)\n", offset, data, space->machine().primary_screen->vpos(), _comment); } while (0)
+#define LOG_ZX81_VSYNC do { if (DEBUG_ZX81_VSYNC) logerror("VSYNC starts in scanline: %d\n", space->machine().primary_screen->vpos()); } while (0)
+
+
+WRITE8_MEMBER(zx_state::zx_ram_w)
+{
+ UINT8 *RAM = memregion("maincpu")->base();
+ RAM[offset + 0x4000] = data;
+
+ if (data & 0x40)
+ {
+ space.write_byte(offset | 0xc000, data);
+ RAM[offset | 0xc000] = data;
+ }
+ else
+ {
+ space.write_byte(offset | 0xc000, 0);
+ RAM[offset | 0xc000] = 0;
+ }
+}
+
+/* I know this looks really pointless... but it has to be here */
+READ8_MEMBER( zx_state::zx_ram_r )
+{
+ UINT8 *RAM = memregion("maincpu")->base();
+ return RAM[offset | 0xc000];
+}
+
+DRIVER_INIT_MEMBER(zx_state,zx)
+{
+ address_space *space = machine().device("maincpu")->memory().space(AS_PROGRAM);
+
+ space->install_read_bank(0x4000, 0x4000 + machine().device<ram_device>(RAM_TAG)->size() - 1, "bank1");
+ space->install_write_handler(0x4000, 0x4000 + machine().device<ram_device>(RAM_TAG)->size() - 1, write8_delegate(FUNC(zx_state::zx_ram_w),this));
+ membank("bank1")->set_base(memregion("maincpu")->base() + 0x4000);
+}
+
+DIRECT_UPDATE_MEMBER(zx_state::zx_setdirect)
+{
+ if (address & 0xc000)
+ zx_ula_r(machine(), address, "maincpu", 0);
+ return address;
+}
+
+DIRECT_UPDATE_MEMBER(zx_state::pc8300_setdirect)
+{
+ if (address & 0xc000)
+ zx_ula_r(machine(), address, "gfx1", 0);
+ return address;
+}
+
+DIRECT_UPDATE_MEMBER(zx_state::pow3000_setdirect)
+{
+ if (address & 0xc000)
+ zx_ula_r(machine(), address, "gfx1", 1);
+ return address;
+}
+
+MACHINE_RESET( zx80 )
+{
+ zx_state *state = machine.driver_data<zx_state>();
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->set_direct_update_handler(direct_update_delegate(FUNC(zx_state::zx_setdirect), state));
+ state->m_tape_bit = 0x80;
+}
+
+MACHINE_RESET( pow3000 )
+{
+ zx_state *state = machine.driver_data<zx_state>();
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->set_direct_update_handler(direct_update_delegate(FUNC(zx_state::pow3000_setdirect), state));
+ state->m_tape_bit = 0x80;
+}
+
+MACHINE_RESET( pc8300 )
+{
+ zx_state *state = machine.driver_data<zx_state>();
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->set_direct_update_handler(direct_update_delegate(FUNC(zx_state::pc8300_setdirect), state));
+ state->m_tape_bit = 0x80;
+}
+
+static TIMER_CALLBACK(zx_tape_pulse)
+{
+ zx_state *state = machine.driver_data<zx_state>();
+ state->m_tape_bit = 0x80;
+}
+
+READ8_MEMBER( zx_state::zx80_io_r )
+{
+/* port FE = read keyboard, NTSC/PAL diode, and cass bit; turn off HSYNC-generator/cass-out
+ The upper 8 bits are used to select a keyboard scan line */
+
+ UINT8 data = 0xff;
+ UINT8 offs = offset & 0xff;
+
+ if (offs == 0xfe)
+ {
+ if ((offset & 0x0100) == 0)
+ data &= ioport("ROW0")->read();
+ if ((offset & 0x0200) == 0)
+ data &= ioport("ROW1")->read();
+ if ((offset & 0x0400) == 0)
+ data &= ioport("ROW2")->read();
+ if ((offset & 0x0800) == 0)
+ data &= ioport("ROW3")->read();
+ if ((offset & 0x1000) == 0)
+ data &= ioport("ROW4")->read();
+ if ((offset & 0x2000) == 0)
+ data &= ioport("ROW5")->read();
+ if ((offset & 0x4000) == 0)
+ data &= ioport("ROW6")->read();
+ if ((offset & 0x8000) == 0)
+ data &= ioport("ROW7")->read();
+
+ if (!ioport("CONFIG")->read())
+ data &= ~0x40;
+
+ machine().device<cassette_image_device>(CASSETTE_TAG)->output(+1.0);
+
+ if (m_ula_irq_active)
+ {
+ zx_ula_bkgnd(0);
+ m_ula_irq_active = 0;
+ }
+// else
+// {
+ if (((machine().device<cassette_image_device>(CASSETTE_TAG))->input() < -0.75) && m_tape_bit)
+ {
+ m_tape_bit = 0x00;
+ machine().scheduler().timer_set(attotime::from_usec(362), FUNC(zx_tape_pulse));
+ }
+
+ data &= ~m_tape_bit;
+// }
+ if (m_ula_frame_vsync == 3)
+ {
+ m_ula_frame_vsync = 2;
+ }
+ }
+
+ return data;
+}
+
+READ8_MEMBER( zx_state::zx81_io_r )
+{
+/* port FB = read printer status, not emulated
+ FE = read keyboard, NTSC/PAL diode, and cass bit; turn off HSYNC-generator/cass-out
+ The upper 8 bits are used to select a keyboard scan line */
+
+ UINT8 data = 0xff;
+ UINT8 offs = offset & 0xff;
+
+ if (offs == 0xfe)
+ {
+ if ((offset & 0x0100) == 0)
+ data &= ioport("ROW0")->read();
+ if ((offset & 0x0200) == 0)
+ data &= ioport("ROW1")->read();
+ if ((offset & 0x0400) == 0)
+ data &= ioport("ROW2")->read();
+ if ((offset & 0x0800) == 0)
+ data &= ioport("ROW3")->read();
+ if ((offset & 0x1000) == 0)
+ data &= ioport("ROW4")->read();
+ if ((offset & 0x2000) == 0)
+ data &= ioport("ROW5")->read();
+ if ((offset & 0x4000) == 0)
+ data &= ioport("ROW6")->read();
+ if ((offset & 0x8000) == 0)
+ data &= ioport("ROW7")->read();
+
+ if (!ioport("CONFIG")->read())
+ data &= ~0x40;
+
+ machine().device<cassette_image_device>(CASSETTE_TAG)->output(+1.0);
+
+ if (m_ula_irq_active)
+ {
+ zx_ula_bkgnd(0);
+ m_ula_irq_active = 0;
+ }
+ else
+ {
+ if (((machine().device<cassette_image_device>(CASSETTE_TAG))->input() < -0.75) && m_tape_bit)
+ {
+ m_tape_bit = 0x00;
+ machine().scheduler().timer_set(attotime::from_usec(362), FUNC(zx_tape_pulse));
+ }
+
+ data &= ~m_tape_bit;
+ }
+ if (m_ula_frame_vsync == 3)
+ {
+ m_ula_frame_vsync = 2;
+ }
+ }
+
+ return data;
+}
+
+READ8_MEMBER( zx_state::pc8300_io_r )
+{
+/* port F5 = sound
+ F6 = unknown
+ FB = read printer status, not emulated
+ FE = read keyboard and cass bit; turn off HSYNC-generator/cass-out
+ The upper 8 bits are used to select a keyboard scan line.
+ No TV diode */
+
+ UINT8 data = 0xff;
+ UINT8 offs = offset & 0xff;
+ device_t *speaker = machine().device(SPEAKER_TAG);
+
+ if (offs == 0xf5)
+ {
+ m_speaker_state ^= 1;
+ speaker_level_w(speaker, m_speaker_state);
+ }
+ else
+ if (offs == 0xfe)
+ {
+ if ((offset & 0x0100) == 0)
+ data &= ioport("ROW0")->read();
+ if ((offset & 0x0200) == 0)
+ data &= ioport("ROW1")->read();
+ if ((offset & 0x0400) == 0)
+ data &= ioport("ROW2")->read();
+ if ((offset & 0x0800) == 0)
+ data &= ioport("ROW3")->read();
+ if ((offset & 0x1000) == 0)
+ data &= ioport("ROW4")->read();
+ if ((offset & 0x2000) == 0)
+ data &= ioport("ROW5")->read();
+ if ((offset & 0x4000) == 0)
+ data &= ioport("ROW6")->read();
+ if ((offset & 0x8000) == 0)
+ data &= ioport("ROW7")->read();
+
+ machine().device<cassette_image_device>(CASSETTE_TAG)->output(+1.0);
+
+ if (m_ula_irq_active)
+ {
+ zx_ula_bkgnd(0);
+ m_ula_irq_active = 0;
+ }
+ else
+ {
+ if (((machine().device<cassette_image_device>(CASSETTE_TAG))->input() < -0.75) && m_tape_bit)
+ {
+ m_tape_bit = 0x00;
+ machine().scheduler().timer_set(attotime::from_usec(362), FUNC(zx_tape_pulse));
+ }
+
+ data &= ~m_tape_bit;
+ }
+ if (m_ula_frame_vsync == 3)
+ {
+ m_ula_frame_vsync = 2;
+ }
+ }
+
+ return data;
+}
+
+READ8_MEMBER( zx_state::pow3000_io_r )
+{
+/* port 7E = read NTSC/PAL diode
+ F5 = sound
+ F6 = unknown
+ FB = read printer status, not emulated
+ FE = read keyboard and cass bit; turn off HSYNC-generator/cass-out
+ The upper 8 bits are used to select a keyboard scan line */
+
+ UINT8 data = 0xff;
+ UINT8 offs = offset & 0xff;
+ device_t *speaker = machine().device(SPEAKER_TAG);
+
+ if (offs == 0x7e)
+ {
+ data = (ioport("CONFIG")->read());
+ }
+ else
+ if (offs == 0xf5)
+ {
+ m_speaker_state ^= 1;
+ speaker_level_w(speaker, m_speaker_state);
+ }
+ else
+ if (offs == 0xfe)
+ {
+ if ((offset & 0x0100) == 0)
+ data &= ioport("ROW0")->read();
+ if ((offset & 0x0200) == 0)
+ data &= ioport("ROW1")->read();
+ if ((offset & 0x0400) == 0)
+ data &= ioport("ROW2")->read();
+ if ((offset & 0x0800) == 0)
+ data &= ioport("ROW3")->read();
+ if ((offset & 0x1000) == 0)
+ data &= ioport("ROW4")->read();
+ if ((offset & 0x2000) == 0)
+ data &= ioport("ROW5")->read();
+ if ((offset & 0x4000) == 0)
+ data &= ioport("ROW6")->read();
+ if ((offset & 0x8000) == 0)
+ data &= ioport("ROW7")->read();
+
+ machine().device<cassette_image_device>(CASSETTE_TAG)->output(+1.0);
+
+ if (m_ula_irq_active)
+ {
+ zx_ula_bkgnd(0);
+ m_ula_irq_active = 0;
+ }
+ else
+ {
+ if (((machine().device<cassette_image_device>(CASSETTE_TAG))->input() < -0.75) && m_tape_bit)
+ {
+ m_tape_bit = 0x00;
+ machine().scheduler().timer_set(attotime::from_usec(362), FUNC(zx_tape_pulse));
+ }
+
+ data &= ~m_tape_bit;
+ }
+ if (m_ula_frame_vsync == 3)
+ {
+ m_ula_frame_vsync = 2;
+ }
+ }
+
+ return data;
+}
+
+WRITE8_MEMBER( zx_state::zx80_io_w )
+{
+/* port FF = write HSYNC and cass data */
+
+ UINT8 offs = offset & 0xff;
+
+ if (offs == 0xff)
+ machine().device<cassette_image_device>(CASSETTE_TAG)->output(-1.0);
+}
+
+WRITE8_MEMBER( zx_state::zx81_io_w )
+{
+ address_space *mem = machine().device("maincpu")->memory().space(AS_PROGRAM);
+/* port F5 = unknown, pc8300/pow3000/lambda only
+ F6 = unknown, pc8300/pow3000/lambda only
+ FB = write data to printer, not emulated
+ FD = turn off NMI generator
+ FE = turn on NMI generator
+ FF = write HSYNC and cass data */
+
+ screen_device *screen = machine().first_screen();
+ int height = screen->height();
+ UINT8 offs = offset & 0xff;
+
+ if (offs == 0xfd)
+ {
+ m_ula_nmi->reset();
+ }
+ else
+ if (offs == 0xfe)
+ {
+ m_ula_nmi->adjust(attotime::zero, 0, machine().device<cpu_device>("maincpu")->cycles_to_attotime(207));
+
+ /* remove the IRQ */
+ m_ula_irq_active = 0;
+ }
+ else
+ if (offs == 0xff)
+ {
+ machine().device<cassette_image_device>(CASSETTE_TAG)->output(-1.0);
+ zx_ula_bkgnd(1);
+ if (m_ula_frame_vsync == 2)
+ {
+ device_spin_until_time(&mem->device(),machine().primary_screen->time_until_pos(height - 1, 0));
+ m_ula_scanline_count = height - 1;
+ logerror ("S: %d B: %d\n", machine().primary_screen->vpos(), machine().primary_screen->hpos());
+ }
+ }
+}
+
diff --git a/src/mess/machine/zx8302.c b/src/mess/machine/zx8302.c
new file mode 100644
index 00000000000..bebd5110e4d
--- /dev/null
+++ b/src/mess/machine/zx8302.c
@@ -0,0 +1,685 @@
+/**********************************************************************
+
+ Sinclair ZX8302 emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+ TODO:
+
+ - set time
+ - read from microdrive
+ - write to microdrive
+ - DTR/CTS handling
+ - network
+
+*/
+
+#include "emu.h"
+#include <time.h>
+#include "devices/microdrv.h"
+#include "machine/devhelpr.h"
+#include "zx8302.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define LOG 0
+
+
+// IPC serial state
+enum
+{
+ IPC_START,
+ IPC_DATA,
+ IPC_STOP
+};
+
+
+// baud rate
+enum
+{
+ BAUD_19200 = 0x00,
+ BAUD_9600 = 0x01,
+ BAUD_4800 = 0x02,
+ BAUD_2400 = 0x03,
+ BAUD_1200 = 0x04,
+ BAUD_600 = 0x05,
+ BAUD_300 = 0x06,
+ BAUD_75 = 0x07,
+ BAUD_MASK = 0x07,
+};
+
+// transmit mode
+enum
+{
+ MODE_SER1 = 0x00,
+ MODE_SER2 = 0x08,
+ MODE_MDV = 0x10,
+ MODE_NET = 0x18,
+ MODE_MASK = 0x18,
+};
+
+// interrupts
+enum
+{
+ INT_GAP = 0x01,
+ INT_INTERFACE = 0x02,
+ INT_TRANSMIT = 0x04,
+ INT_FRAME = 0x08,
+ INT_EXTERNAL = 0x10,
+};
+
+// status register
+enum
+{
+ STATUS_NETWORK_PORT = 0x01,
+ STATUS_TX_BUFFER_FULL = 0x02,
+ STATUS_RX_BUFFER_FULL = 0x04,
+ STATUS_MICRODRIVE_GAP = 0x08,
+};
+
+// transmit bits
+enum
+{
+ TXD_START = 0,
+ TXD_STOP = 9,
+ TXD_STOP2 = 10,
+};
+
+
+// Monday 1st January 1979 00:00:00 UTC
+enum
+{
+ RTC_BASE_ADJUST = 283996800,
+};
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type ZX8302 = &device_creator<zx8302_device>;
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void zx8302_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const zx8302_interface *intf = reinterpret_cast<const zx8302_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<zx8302_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&out_ipl1l_cb, 0, sizeof(out_ipl1l_cb));
+ memset(&out_baudx4_cb, 0, sizeof(out_baudx4_cb));
+ memset(&out_comdata_cb, 0, sizeof(out_comdata_cb));
+ memset(&out_txd1_cb, 0, sizeof(out_txd1_cb));
+ memset(&out_txd2_cb, 0, sizeof(out_txd2_cb));
+ memset(&in_dtr1_cb, 0, sizeof(in_dtr1_cb));
+ memset(&in_cts2_cb, 0, sizeof(in_cts2_cb));
+ memset(&out_netout_cb, 0, sizeof(out_netout_cb));
+ memset(&in_netin_cb, 0, sizeof(in_netin_cb));
+ memset(&out_mdselck_cb, 0, sizeof(out_mdselck_cb));
+ memset(&out_mdseld_cb, 0, sizeof(out_mdseld_cb));
+ memset(&out_mdrdw_cb, 0, sizeof(out_mdrdw_cb));
+ memset(&out_erase_cb, 0, sizeof(out_erase_cb));
+ memset(&out_raw1_cb, 0, sizeof(out_raw1_cb));
+ memset(&in_raw1_cb, 0, sizeof(in_raw1_cb));
+ memset(&out_raw2_cb, 0, sizeof(out_raw2_cb));
+ memset(&in_raw2_cb, 0, sizeof(in_raw2_cb));
+ }
+}
+
+
+
+//**************************************************************************
+// INLINE HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// trigger_interrupt -
+//-------------------------------------------------
+
+inline void zx8302_device::trigger_interrupt(UINT8 line)
+{
+ m_irq |= line;
+
+ m_out_ipl1l_func(ASSERT_LINE);
+}
+
+
+//-------------------------------------------------
+// transmit_ipc_data - transmit IPC data
+//-------------------------------------------------
+
+inline void zx8302_device::transmit_ipc_data()
+{
+ /*
+
+ IPC <-> ZX8302 serial link protocol
+ ***********************************
+
+ Send bit to IPC
+ ---------------
+
+ 1. ZX start bit (COMDATA = 0)
+ 2. IPC clock (COMCTL = 0, COMTL = 1)
+ 3. ZX data bit (COMDATA = 0/1)
+ 4. IPC clock (COMCTL = 0, COMTL = 1)
+ 5. ZX stop bit (COMDATA = 1)
+
+ Receive bit from IPC
+ --------------------
+
+ 1. ZX start bit (COMDATA = 0)
+ 2. IPC clock (COMCTL = 0, COMTL = 1)
+ 3. IPC data bit (COMDATA = 0/1)
+ 4. IPC clock (COMCTL = 0, COMTL = 1)
+ 5. IPC stop bit (COMDATA = 1)
+
+ */
+
+ switch (m_ipc_state)
+ {
+ case IPC_START:
+ if (LOG) logerror("ZX8302 '%s' COMDATA Start Bit\n", tag());
+
+ m_out_comdata_func(0);
+ m_ipc_busy = 1;
+ m_ipc_state = IPC_DATA;
+ break;
+
+ case IPC_DATA:
+ if (LOG) logerror("ZX8302 '%s' COMDATA Data Bit: %x\n", tag(), BIT(m_idr, 1));
+
+ m_comdata = BIT(m_idr, 1);
+ m_out_comdata_func(m_comdata);
+ m_ipc_state = IPC_STOP;
+ break;
+
+ case IPC_STOP:
+ if (!m_ipc_rx)
+ {
+ if (LOG) logerror("ZX8302 '%s' COMDATA Stop Bit\n", tag());
+
+ m_out_comdata_func(1);
+ m_ipc_busy = 0;
+ m_ipc_state = IPC_START;
+ }
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// transmit_bit - transmit serial bit
+//-------------------------------------------------
+
+inline void zx8302_device::transmit_bit(int state)
+{
+ switch (m_tcr & MODE_MASK)
+ {
+ case MODE_SER1:
+ m_out_txd1_func(state);
+ break;
+
+ case MODE_SER2:
+ m_out_txd2_func(state);
+ break;
+
+ case MODE_MDV:
+ // TODO
+ break;
+
+ case MODE_NET:
+ m_out_netout_func(state);
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// transmit_data - transmit serial data
+//-------------------------------------------------
+
+inline void zx8302_device::transmit_serial_data()
+{
+ switch (m_tx_bits)
+ {
+ case TXD_START:
+ if (!(m_irq & INT_TRANSMIT))
+ {
+ transmit_bit(0);
+ m_tx_bits++;
+ }
+ break;
+
+ default:
+ transmit_bit(BIT(m_tdr, 0));
+ m_tdr >>= 1;
+ m_tx_bits++;
+ break;
+
+ case TXD_STOP:
+ transmit_bit(1);
+ m_tx_bits++;
+ break;
+
+ case TXD_STOP2:
+ transmit_bit(1);
+ m_tx_bits = TXD_START;
+ m_status &= ~STATUS_TX_BUFFER_FULL;
+ trigger_interrupt(INT_TRANSMIT);
+ break;
+ }
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// zx8302_device - constructor
+//-------------------------------------------------
+zx8302_device::zx8302_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, ZX8302, "Sinclair ZX8302", tag, owner, clock),
+ m_idr(1),
+ m_irq(0),
+ m_ctr(time(NULL) + RTC_BASE_ADJUST),
+ m_status(0),
+ m_comdata(1),
+ m_comctl(1),
+ m_ipc_state(0),
+ m_ipc_rx(0),
+ m_ipc_busy(0),
+ m_track(0)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void zx8302_device::device_start()
+{
+ // resolve callbacks
+ m_out_ipl1l_func.resolve(out_ipl1l_cb, *this);
+ m_out_baudx4_func.resolve(out_baudx4_cb, *this);
+ m_out_comdata_func.resolve(out_comdata_cb, *this);
+ m_out_txd1_func.resolve(out_txd1_cb, *this);
+ m_out_txd2_func.resolve(out_txd2_cb, *this);
+ m_in_dtr1_func.resolve(in_dtr1_cb, *this);
+ m_in_cts2_func.resolve(in_cts2_cb, *this);
+ m_out_netout_func.resolve(out_netout_cb, *this);
+ m_in_netin_func.resolve(in_netin_cb, *this);
+ m_out_mdselck_func.resolve(out_mdselck_cb, *this);
+ m_out_mdseld_func.resolve(out_mdseld_cb, *this);
+ m_out_mdrdw_func.resolve(out_mdrdw_cb, *this);
+ m_out_erase_func.resolve(out_erase_cb, *this);
+ m_out_raw1_func.resolve(out_raw1_cb, *this);
+ m_in_raw1_func.resolve(in_raw1_cb, *this);
+ m_out_raw2_func.resolve(out_raw2_cb, *this);
+ m_in_raw2_func.resolve(in_raw2_cb, *this);
+
+ // allocate timers
+ m_txd_timer = timer_alloc(TIMER_TXD);
+ m_baudx4_timer = timer_alloc(TIMER_BAUDX4);
+ m_rtc_timer = timer_alloc(TIMER_RTC);
+ m_gap_timer = timer_alloc(TIMER_GAP);
+ m_ipc_timer = timer_alloc(TIMER_IPC);
+
+ m_rtc_timer->adjust(attotime::zero, 0, attotime::from_hz(rtc_clock / 32768));
+ m_gap_timer->adjust(attotime::zero, 0, attotime::from_msec(31));
+
+ // register for state saving
+ save_item(NAME(m_idr));
+ save_item(NAME(m_tcr));
+ save_item(NAME(m_tdr));
+ save_item(NAME(m_irq));
+ save_item(NAME(m_ctr));
+ save_item(NAME(m_status));
+ save_item(NAME(m_comdata));
+ save_item(NAME(m_comctl));
+ save_item(NAME(m_ipc_state));
+ save_item(NAME(m_ipc_rx));
+ save_item(NAME(m_ipc_busy));
+ save_item(NAME(m_baudx4));
+ save_item(NAME(m_tx_bits));
+ save_item(NAME(m_mdv_data));
+ save_item(NAME(m_track));
+}
+
+
+//-------------------------------------------------
+// device_timer - handler timer events
+//-------------------------------------------------
+
+void zx8302_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch (id)
+ {
+ case TIMER_TXD:
+ transmit_serial_data();
+ break;
+
+ case TIMER_BAUDX4:
+ m_baudx4 = !m_baudx4;
+ m_out_baudx4_func(m_baudx4);
+ break;
+
+ case TIMER_RTC:
+ m_ctr++;
+ break;
+
+ case TIMER_GAP:
+ trigger_interrupt(INT_GAP);
+ break;
+
+ case TIMER_IPC:
+ m_idr = param;
+ m_ipc_state = IPC_START;
+ m_ipc_rx = 0;
+
+ transmit_ipc_data();
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// rtc_r - real time clock read
+//-------------------------------------------------
+
+READ8_MEMBER( zx8302_device::rtc_r )
+{
+ UINT8 data = 0;
+
+ switch (offset)
+ {
+ case 0:
+ data = (m_ctr >> 24) & 0xff;
+ break;
+ case 1:
+ data = (m_ctr >> 16) & 0xff;
+ break;
+ case 2:
+ data = (m_ctr >> 8) & 0xff;
+ break;
+ case 3:
+ data = m_ctr & 0xff;
+ break;
+ }
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// rtc_w - real time clock write
+//-------------------------------------------------
+
+WRITE8_MEMBER( zx8302_device::rtc_w )
+{
+ if (LOG) logerror("ZX8302 '%s' Set Real Time Clock: %02x\n", tag(), data);
+}
+
+
+//-------------------------------------------------
+// control_w - serial transmit clock
+//-------------------------------------------------
+
+WRITE8_MEMBER( zx8302_device::control_w )
+{
+ if (LOG) logerror("ZX8302 '%s' Transmit Control: %02x\n", tag(), data);
+
+ int baud = (19200 >> (data & BAUD_MASK));
+ int baudx4 = baud * 4;
+
+ m_tcr = data;
+
+ m_txd_timer->adjust(attotime::zero, 0, attotime::from_hz(baud));
+ m_baudx4_timer->adjust(attotime::zero, 0, attotime::from_hz(baudx4));
+}
+
+
+//-------------------------------------------------
+// mdv_track_r - microdrive track data
+//-------------------------------------------------
+
+READ8_MEMBER( zx8302_device::mdv_track_r )
+{
+ if (LOG) logerror("ZX8302 '%s' Microdrive Track %u: %02x\n", tag(), m_track, m_mdv_data[m_track]);
+
+ UINT8 data = m_mdv_data[m_track];
+
+ m_track = !m_track;
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// status_r - status register
+//-------------------------------------------------
+
+READ8_MEMBER( zx8302_device::status_r )
+{
+ /*
+
+ bit description
+
+ 0 Network port
+ 1 Transmit buffer full
+ 2 Receive buffer full
+ 3 Microdrive GAP
+ 4 SER1 DTR
+ 5 SER2 CTS
+ 6 IPC busy
+ 7 COMDATA
+
+ */
+
+ UINT8 data = 0;
+
+ // TODO network port
+
+ // serial status
+ data |= m_status;
+
+ // TODO microdrive GAP
+
+ // data terminal ready
+ data |= m_in_dtr1_func() << 4;
+
+ // clear to send
+ data |= m_in_cts2_func() << 5;
+
+ // IPC busy
+ data |= m_ipc_busy << 6;
+
+ // COMDATA
+ data |= m_comdata << 7;
+
+ if (LOG) logerror("ZX8302 '%s' Status: %02x\n", tag(), data);
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// ipc_command_w - IPC command
+//-------------------------------------------------
+
+WRITE8_MEMBER( zx8302_device::ipc_command_w )
+{
+ if (LOG) logerror("ZX8302 '%s' IPC Command: %02x\n", tag(), data);
+
+ if (data != 0x01)
+ {
+ m_ipc_timer->adjust(attotime::from_nsec(480), data);
+ }
+}
+
+
+//-------------------------------------------------
+// mdv_control_w - microdrive control
+//-------------------------------------------------
+
+WRITE8_MEMBER( zx8302_device::mdv_control_w )
+{
+ /*
+
+ bit description
+
+ 0 MDSELDH
+ 1 MDSELCKH
+ 2 MDRDWL
+ 3 ERASE
+ 4
+ 5
+ 6
+ 7
+
+ */
+
+ if (LOG) logerror("ZX8302 '%s' Microdrive Control: %02x\n", tag(), data);
+
+ m_out_mdseld_func(BIT(data, 0));
+ m_out_mdselck_func(BIT(data, 1));
+ m_out_mdrdw_func(BIT(data, 2));
+ m_out_erase_func(BIT(data, 3));
+
+ if (BIT(data, 1))
+ {
+ m_status &= ~STATUS_RX_BUFFER_FULL;
+ }
+}
+
+
+//-------------------------------------------------
+// irq_status_r - interrupt status
+//-------------------------------------------------
+
+READ8_MEMBER( zx8302_device::irq_status_r )
+{
+ if (LOG) logerror("ZX8302 '%s' Interrupt Status: %02x\n", tag(), m_irq);
+
+ return m_irq;
+}
+
+
+//-------------------------------------------------
+// irq_acknowledge_w - interrupt acknowledge
+//-------------------------------------------------
+
+WRITE8_MEMBER( zx8302_device::irq_acknowledge_w )
+{
+ if (LOG) logerror("ZX8302 '%s' Interrupt Acknowledge: %02x\n", tag(), data);
+
+ m_irq &= ~data;
+
+ if (!m_irq)
+ {
+ m_out_ipl1l_func(CLEAR_LINE);
+ }
+}
+
+
+//-------------------------------------------------
+// data_w - transmit buffer
+//-------------------------------------------------
+
+WRITE8_MEMBER( zx8302_device::data_w )
+{
+ if (LOG) logerror("ZX8302 '%s' Data Register: %02x\n", tag(), data);
+
+ m_tdr = data;
+ m_status |= STATUS_TX_BUFFER_FULL;
+}
+
+
+//-------------------------------------------------
+// vsync_w - vertical sync
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( zx8302_device::vsync_w )
+{
+ if (state)
+ {
+ if (LOG) logerror("ZX8302 '%s' Frame Interrupt\n", tag());
+
+ trigger_interrupt(INT_FRAME);
+ }
+}
+
+
+//-------------------------------------------------
+// comctl_w - IPC COMCTL
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( zx8302_device::comctl_w )
+{
+ if (LOG) logerror("ZX8302 '%s' COMCTL: %x\n", tag(), state);
+
+ if (state)
+ {
+ transmit_ipc_data();
+ }
+}
+
+
+//-------------------------------------------------
+// comdata_w - IPC COMDATA
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( zx8302_device::comdata_w )
+{
+ if (LOG) logerror("ZX8302 '%s' COMDATA: %x\n", tag(), state);
+
+ if (m_ipc_state == IPC_DATA || m_ipc_state == IPC_STOP)
+ {
+ if (m_ipc_rx)
+ {
+ m_ipc_rx = 0;
+ m_ipc_busy = 0;
+ m_ipc_state = IPC_START;
+ }
+ else
+ {
+ m_ipc_rx = 1;
+ m_comdata = state;
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// extint_w - external interrupt
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( zx8302_device::extint_w )
+{
+ if (LOG) logerror("ZX8302 '%s' EXTINT: %x\n", tag(), state);
+
+ if (state == ASSERT_LINE)
+ {
+ trigger_interrupt(INT_EXTERNAL);
+ }
+}
diff --git a/src/mess/machine/zx8302.h b/src/mess/machine/zx8302.h
new file mode 100644
index 00000000000..7ff6246f846
--- /dev/null
+++ b/src/mess/machine/zx8302.h
@@ -0,0 +1,192 @@
+/**********************************************************************
+
+ Sinclair ZX8302 emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+ _____ _____
+ ERASE 1 |* \_/ | 40 Vdd
+ EXTINTL 2 | | 39 DB4
+ MDRDWL 3 | | 38 DB5
+ NETOUT 4 | | 37 DB0
+ BAUDX4 5 | | 36 DB1
+ DTR1L 6 | | 35 COMDATA
+ CTS2L 7 | | 34 MDSELDH
+ DCSML 8 | | 33 MDSELCKN
+ ROWL 9 | | 32 VSYNCH
+ PCENL 10 | ZX8302 | 31 XTAL2
+ Vdd 11 | ULA | 30 XTAL1
+ DB2 12 | | 29
+ TXD1 13 | | 28 RESETOUTL
+ TXD2 14 | | 27 DB7
+ A5 15 | | 26 IPL1L
+ NETIN 16 | | 25 CLKCPU
+ A1 17 | | 24 DB3
+ A0 18 | | 23 DB6
+ RAW2 19 | | 22 COMCTL
+ GND 20 |_____________| 21 RAW1
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __ZX8302__
+#define __ZX8302__
+
+#include "emu.h"
+
+
+
+///*************************************************************************
+// MACROS / CONSTANTS
+///*************************************************************************
+
+
+
+
+///*************************************************************************
+// INTERFACE CONFIGURATION MACROS
+///*************************************************************************
+
+#define MCFG_ZX8302_ADD(_tag, _clock, _intrf) \
+ MCFG_DEVICE_ADD(_tag, ZX8302, _clock) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#define ZX8302_INTERFACE(name) \
+ const zx8302_interface (name)=
+
+
+
+///*************************************************************************
+// TYPE DEFINITIONS
+///*************************************************************************
+
+// ======================> zx8302_interface
+
+struct zx8302_interface
+{
+ int rtc_clock; // the RTC clock (pin 30) of the chip
+
+ // serial
+ devcb_write_line out_ipl1l_cb;
+ devcb_write_line out_baudx4_cb;
+ devcb_write_line out_comdata_cb;
+ devcb_write_line out_txd1_cb;
+ devcb_write_line out_txd2_cb;
+ devcb_read_line in_dtr1_cb;
+ devcb_read_line in_cts2_cb;
+ devcb_write_line out_netout_cb;
+ devcb_read_line in_netin_cb;
+
+ // microdrive
+ devcb_write_line out_mdselck_cb;
+ devcb_write_line out_mdseld_cb;
+ devcb_write_line out_mdrdw_cb;
+ devcb_write_line out_erase_cb;
+ devcb_write_line out_raw1_cb;
+ devcb_read_line in_raw1_cb;
+ devcb_write_line out_raw2_cb;
+ devcb_read_line in_raw2_cb;
+};
+
+// ======================> zx8302_device
+
+class zx8302_device : public device_t,
+ public zx8302_interface
+{
+public:
+ // construction/destruction
+ zx8302_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ DECLARE_READ8_MEMBER( rtc_r );
+ DECLARE_WRITE8_MEMBER( rtc_w );
+ DECLARE_WRITE8_MEMBER( control_w );
+ DECLARE_READ8_MEMBER( mdv_track_r );
+ DECLARE_READ8_MEMBER( status_r );
+ DECLARE_WRITE8_MEMBER( ipc_command_w );
+ DECLARE_WRITE8_MEMBER( mdv_control_w );
+ DECLARE_READ8_MEMBER( irq_status_r );
+ DECLARE_WRITE8_MEMBER( irq_acknowledge_w );
+ DECLARE_WRITE8_MEMBER( data_w );
+ DECLARE_WRITE_LINE_MEMBER( vsync_w );
+ DECLARE_WRITE_LINE_MEMBER( comctl_w );
+ DECLARE_WRITE_LINE_MEMBER( comdata_w );
+ DECLARE_WRITE_LINE_MEMBER( extint_w );
+
+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_config_complete();
+
+ inline void trigger_interrupt(UINT8 line);
+ inline void transmit_ipc_data();
+ inline void transmit_bit(int state);
+ inline void transmit_serial_data();
+
+private:
+ static const device_timer_id TIMER_TXD = 0;
+ static const device_timer_id TIMER_BAUDX4 = 1;
+ static const device_timer_id TIMER_RTC = 2;
+ static const device_timer_id TIMER_GAP = 3;
+ static const device_timer_id TIMER_IPC = 4;
+
+ devcb_resolved_write_line m_out_ipl1l_func;
+ devcb_resolved_write_line m_out_baudx4_func;
+ devcb_resolved_write_line m_out_comdata_func;
+ devcb_resolved_write_line m_out_txd1_func;
+ devcb_resolved_write_line m_out_txd2_func;
+ devcb_resolved_read_line m_in_dtr1_func;
+ devcb_resolved_read_line m_in_cts2_func;
+ devcb_resolved_write_line m_out_netout_func;
+ devcb_resolved_read_line m_in_netin_func;
+
+ devcb_resolved_write_line m_out_mdselck_func;
+ devcb_resolved_write_line m_out_mdseld_func;
+ devcb_resolved_write_line m_out_mdrdw_func;
+ devcb_resolved_write_line m_out_erase_func;
+ devcb_resolved_write_line m_out_raw1_func;
+ devcb_resolved_read_line m_in_raw1_func;
+ devcb_resolved_write_line m_out_raw2_func;
+ devcb_resolved_read_line m_in_raw2_func;
+
+ // registers
+ UINT8 m_idr; // IPC data register
+ UINT8 m_tcr; // transfer control register
+ UINT8 m_tdr; // transfer data register
+ UINT8 m_irq; // interrupt register
+ UINT32 m_ctr; // counter register
+ UINT8 m_status; // status register
+
+ // IPC communication state
+ int m_comdata; // communication data
+ int m_comctl; // communication control
+ int m_ipc_state; // communication state
+ int m_ipc_rx; // receiving data from IPC
+ int m_ipc_busy; // IPC busy
+ int m_baudx4; // IPC baud x4
+
+ // serial transmit state
+ int m_tx_bits; // bits transmitted
+
+ // microdrive state
+ UINT8 m_mdv_data[2]; // track data register
+ int m_track; // current track
+
+ // timers
+ emu_timer *m_txd_timer; // transmit timer
+ emu_timer *m_baudx4_timer; // baud x4 timer
+ emu_timer *m_rtc_timer; // real time clock timer
+ emu_timer *m_gap_timer; // microdrive gap timer
+ emu_timer *m_ipc_timer; // delayed IPC command timer
+};
+
+
+// device type definition
+extern const device_type ZX8302;
+
+
+
+#endif